*/
#include "amanda.h"
#include "arglist.h"
+#include "find.h"
#include "conffile.h"
#include "diskfile.h"
#include "tapefile.h"
char *cfg_opt = NULL;
int planner_setuid;
int exit_status = EXIT_SUCCESS;
+ gboolean no_taper = FALSE;
+ gboolean from_client = FALSE;
+
+ if (argc > 1 && argv && argv[1] && g_str_equal(argv[1], "--version")) {
+ printf("planner-%s\n", VERSION);
+ return (0);
+ }
/*
* Configure program for internationalization:
g_fprintf(stderr, _("%s: %s"), get_pname(), version_info[i]);
diskarg_offset = 2;
- if (argc > 3 && strcmp(argv[2], "--starttime") == 0) {
- planner_timestamp = stralloc(argv[3]);
+ if (argc - diskarg_offset > 1 && strcmp(argv[diskarg_offset], "--starttime") == 0) {
+ planner_timestamp = stralloc(argv[diskarg_offset+1]);
diskarg_offset += 2;
}
+ if (argc - diskarg_offset > 0 && strcmp(argv[diskarg_offset], "--no-taper") == 0) {
+ no_taper = TRUE;
+ diskarg_offset += 1;
+ }
+ if (argc - diskarg_offset > 0 && strcmp(argv[diskarg_offset], "--from-client") == 0) {
+ from_client = TRUE;
+ diskarg_offset += 1;
+ }
+ run_server_global_scripts(EXECUTE_ON_PRE_ESTIMATE, get_config_name());
+
/*
* 1. Networking Setup
*
conf_tapecycle = getconf_int(CNF_TAPECYCLE);
conf_etimeout = (time_t)getconf_int(CNF_ETIMEOUT);
conf_reserve = getconf_int(CNF_RESERVE);
- conf_autoflush = getconf_boolean(CNF_AUTOFLUSH);
+ conf_autoflush = getconf_no_yes_all(CNF_AUTOFLUSH);
conf_usetimestamps = getconf_boolean(CNF_USETIMESTAMPS);
today = time(0);
g_fprintf(stderr,"%s",errstr);
exit_status = EXIT_FAILURE;
}
+
+ for (dp = origq.head; dp != NULL; dp = dp->next) {
+ if (dp->todo) {
+ if (from_client) {
+ if (!dp->dump_limit || !dp->dump_limit->same_host)
+ dp->todo = 0;
+ } else {
+ if (dp->dump_limit && !dp->dump_limit->server)
+ dp->todo = 0;
+ }
+ }
+ }
+
nb_disk = 0;
for (dp = origq.head; dp != NULL; dp = dp->next) {
if (dp->todo) {
g_fprintf(stderr,_("\nSENDING FLUSHES...\n"));
- if(conf_autoflush) {
+ if(conf_autoflush && !no_taper) {
dumpfile_t file;
GSList *holding_list, *holding_file;
char *qdisk, *qhname;
- /* get *all* flushable files in holding */
+ /* get *all* flushable files in holding, without checking against
+ * the disklist (which may not contain some of the dumps) */
holding_list = holding_get_files_for_flush(NULL);
for(holding_file=holding_list; holding_file != NULL;
holding_file = holding_file->next) {
continue;
}
+ /* see if this matches the command-line arguments */
+ if (conf_autoflush == 1 &&
+ !match_dumpfile(&file, argc-diskarg_offset,
+ argv+diskarg_offset)) {
+ continue;
+ }
+
qdisk = quote_string(file.disk);
qhname = quote_string((char *)holding_file->data);
log_add(L_DISK, "%s %s", file.name, qdisk);
amfree(qhname);
dumpfile_free_data(&file);
}
- g_slist_free_full(holding_list);
+ slist_free_full(holding_list, g_free);
holding_list = NULL;
}
g_fprintf(stderr, _("ENDFLUSH\n"));
while(!empty(estq)) analyze_estimate(dequeue_disk(&estq));
while(!empty(failq)) handle_failed(dequeue_disk(&failq));
+ run_server_global_scripts(EXECUTE_ON_POST_ESTIMATE, get_config_name());
+
/*
* At this point, all the disks are on schedq sorted by priority.
* The total estimated size of the backups is in total_size.
amfree(qname);
return;
} else if (dp->to_holdingdisk == HOLD_AUTO) {
- log_add(L_INFO, _("Disabling holding disk for %s:%s."),
- dp->host->hostname, qname);
g_fprintf(stderr,_("%s:%s Disabling holding disk\n"),
dp->host->hostname, qname);
dp->to_holdingdisk = HOLD_NEVER;
* hosed when that tape gets re-used next. Disallow this for
* now.
*/
- log_add(L_ERROR,
+ log_add(L_WARNING,
_("Cannot force full dump of %s:%s with no-full option."),
dp->host->hostname, qname);
/* clear force command */
CLR(info.command, FORCE_FULL);
- if(put_info(dp->host->hostname, dp->name, &info)) {
- error(_("could not put info record for %s:%s: %s"),
- dp->host->hostname, qname, strerror(errno));
- /*NOTREACHED*/
- }
ep->last_level = last_level(&info);
ep->next_level0 = next_level0(dp, &info);
- }
- else {
+ } else if (dp->strategy == DS_INCRONLY) {
+ log_add(L_WARNING,
+ _("Cannot force full dump of %s:%s with incronly option."),
+ dp->host->hostname, qname);
+
+ /* clear force command */
+ CLR(info.command, FORCE_FULL);
+ ep->last_level = last_level(&info);
+ ep->next_level0 = next_level0(dp, &info);
+ } else {
ep->degr_mesg = _("Skipping: force-full disk can't be dumped in degraded mode");
ep->last_level = -1;
ep->next_level0 = -conf_dumpcycle;
(!ISSET(info.command, FORCE_BUMP) ||
dp->skip_incr ||
ep->last_level == -1))) {
- if(info.command & FORCE_BUMP && ep->last_level == -1) {
+ if(ISSET(info.command, FORCE_BUMP) && ep->last_level == -1) {
log_add(L_INFO,
_("Remove force-bump command of %s:%s because it's a new disk."),
dp->host->hostname, qname);
case DS_STANDARD:
case DS_NOINC:
askfor(ep, i++, 0, &info);
+ if (ep->last_level == -1)
+ ep->degr_mesg = _("Skipping: new disk can't be dumped in degraded mode");
+ else
+ ep->degr_mesg = _("Skipping: strategy NOINC can't be dumped in degraded mode");
if(dp->skip_full) {
- log_add(L_INFO, _("Ignoring skip_full for %s:%s "
+ log_add(L_INFO, _("Ignoring skip-full for %s:%s "
"because the strategy is NOINC."),
dp->host->hostname, qname);
}
- if(info.command & FORCE_BUMP) {
+ if(ISSET(info.command, FORCE_BUMP)) {
log_add(L_INFO,
_("Ignoring FORCE_BUMP for %s:%s because the strategy is NOINC."),
dp->host->hostname, qname);
one_est_t *dump_est;
dump_est = est_for_level(dp, level);
- if (dump_est->csize <= -1)
+ if (dump_est->level >= 0 && dump_est->csize <= -1)
est_csize(dp, dump_est);
return dump_est->csize;
}
hostp = dp->host;
if(hostp->up == HOST_READY) {
something_started = 1;
+ run_server_host_scripts(EXECUTE_ON_PRE_HOST_ESTIMATE,
+ get_config_name(), hostp);
for(dp1 = hostp->disks; dp1 != NULL; dp1 = dp1->hostnext) {
if (dp1->todo)
- run_server_scripts(EXECUTE_ON_PRE_HOST_ESTIMATE,
- get_config_name(), dp1,
- est(dp1)->estimate[0].level);
- }
- for(dp1 = hostp->disks; dp1 != NULL; dp1 = dp1->hostnext) {
- if (dp1->todo)
- run_server_scripts(EXECUTE_ON_PRE_DLE_ESTIMATE,
+ run_server_dle_scripts(EXECUTE_ON_PRE_DLE_ESTIMATE,
get_config_name(), dp1,
est(dp1)->estimate[0].level);
}
strappend(s, l);
s_len += strlen(l);
amfree(l);
+ amfree(levelstr);
+ amfree(spindlestr);
+ amfree(o);
} else if (strcmp(dp->program,"DUMP") != 0 &&
strcmp(dp->program,"GNUTAR") != 0) {
est(dp)->errstr = newvstrallocf(est(dp)->errstr,
enqueue_disk(&failq, dp);
}
}
+ amfree(b64disk);
+ amfree(b64device);
amfree(qname);
amfree(qdevice);
}
timeout = (time_t)getconf_int(CNF_CTIMEOUT);
}
+ dbprintf(_("send request:\n----\n%s\n----\n\n"), req);
secdrv = security_getdriver(hostp->disks->auth);
if (secdrv == NULL) {
hostp->up = HOST_DONE;
hostp->up = HOST_READY;
if (pkt == NULL) {
- errbuf = vstrallocf(_("Request to %s failed: %s"),
+ if (strcmp(security_geterror(sech), "timeout waiting for REP") == 0) {
+ errbuf = vstrallocf("Some estimate timeout on %s, using server estimate if possible", hostp->hostname);
+ } else {
+ errbuf = vstrallocf(_("Request to %s failed: %s"),
hostp->hostname, security_geterror(sech));
+ }
goto error_return;
}
if (pkt->type == P_NAK) {
}
}
+ dbprintf(_("got reply:\n----\n%s\n----\n\n"), pkt->body);
s = pkt->body;
ch = *s++;
while(ch) {
break;
}
}
- if (i == MAX_LEVELS) {
+ if (i == MAX_LEVELS && level > 0) {
+ /* client always report level 0 for some error */
goto bad_msg; /* this est wasn't requested */
}
est(dp)->got_estimate++;
est(dp)->estimate[1].nsize > (gint64)0) &&
(est(dp)->estimate[2].level == -1 ||
est(dp)->estimate[2].nsize > (gint64)0)))) {
- run_server_scripts(EXECUTE_ON_POST_DLE_ESTIMATE,
+ run_server_dle_scripts(EXECUTE_ON_POST_DLE_ESTIMATE,
get_config_name(), dp,
est(dp)->estimate[0].level);
est(dp)->post_dle = 1;
}
if(hostp->up == HOST_DONE) {
- for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
- if (dp->todo)
- if (pkt->type == P_REP) {
- run_server_scripts(EXECUTE_ON_POST_HOST_ESTIMATE,
- get_config_name(), dp,
- est(dp)->estimate[0].level);
- }
+ if (pkt->type == P_REP) {
+ run_server_host_scripts(EXECUTE_ON_POST_HOST_ESTIMATE,
+ get_config_name(), hostp);
}
}
ep->degr_est = &default_one_est;
if (ep->next_level0 <= 0 || (have_info && ep->last_level == 0
- && (info.command & FORCE_NO_BUMP))) {
+ && (ISSET(info.command, FORCE_NO_BUMP)))) {
if (ep->next_level0 <= 0) {
g_fprintf(stderr,_("(due for level 0) "));
}
}
}
+ if (ep->dump_est->level < 0) {
+ int i;
+ char *q = quote_string("no estimate");
+
+ g_fprintf(stderr,_(" no valid estimate\n"));
+ for(i=0; i<MAX_LEVELS; i++) {
+ if (est(dp)->estimate[i].level >= 0) {
+ g_fprintf(stderr,(" level: %d nsize: %lld csize: %lld\n"),
+ est(dp)->estimate[i].level,
+ (long long)est(dp)->estimate[i].nsize,
+ (long long)est(dp)->estimate[i].csize);
+ }
+ }
+ log_add(L_WARNING, _("%s %s %s 0 %s"), dp->host->hostname, qname,
+ planner_timestamp, q);
+ amfree(q);
+ }
+
g_fprintf(stderr,_(" curr level %d nsize %lld csize %lld "),
ep->dump_est->level, (long long)ep->dump_est->nsize,
(long long)ep->dump_est->csize);
lev0size = est_tape_size(dp, 0);
if(lev0size == (gint64)-1) lev0size = ep->last_lev0size;
- balanced_size += (double)(lev0size / (gint64)runs_per_cycle);
+ if (dp->strategy == DS_NOINC) {
+ balanced_size += (double)lev0size;
+ } else if (dp->dumpcycle == 0) {
+ balanced_size += (double)(lev0size * conf_dumpcycle / (gint64)runs_per_cycle);
+ } else if (dp->dumpcycle != conf_dumpcycle) {
+ balanced_size += (double)(lev0size * (conf_dumpcycle / dp->dumpcycle) / (gint64)runs_per_cycle);
+ } else {
+ balanced_size += (double)(lev0size / (gint64)runs_per_cycle);
+ }
}
g_fprintf(stderr,_("total size %lld total_lev0 %1.0lf balanced-lev0size %1.0lf\n"),
/* if we didn't get an estimate, we can't do an inc */
if (base_est->nsize == (gint64)-1) {
- bump_est = est_for_level(dp, base_est->level + 1);
- if (bump_est->nsize > (gint64)0) /* FORCE_BUMP */
+ bump_est = est_for_level(dp, est(dp)->last_level + 1);
+ if (bump_est->nsize > (gint64)0) { /* FORCE_BUMP */
+ g_fprintf(stderr,_(" picklev: bumping to level %d\n"), bump_est->level);
return bump_est;
+ }
g_fprintf(stderr,_(" picklev: no estimate for level %d, so no incs\n"), base_est->level);
return base_est;
}
for(dp = schedq.head; dp != NULL; dp = ndp) {
int avail_tapes = 1;
- if (dp->tape_splitsize > (gint64)0)
+ if (dp->splitsize > (gint64)0 || dp->allow_split)
avail_tapes = conf_runtapes;
ndp = dp->next; /* remove_disk zaps this */
full_size = est_tape_size(dp, 0);
if (full_size > tapetype_get_length(tape) * (gint64)avail_tapes) {
char *qname = quote_string(dp->name);
- if (conf_runtapes > 1 && dp->tape_splitsize == (gint64)0) {
+ if (conf_runtapes > 1 && dp->splitsize == (gint64)0) {
log_add(L_WARNING, _("disk %s:%s, full dump (%lldKB) will be larger than available tape space"
", you could define a splitsize"),
dp->host->hostname, qname,
if(est(dp)->dump_est->level != 0) continue;
get_info(dp->host->hostname, dp->name, &info);
- if(info.command & FORCE_FULL) {
+ if(ISSET(info.command, FORCE_FULL)) {
nb_forced_level_0 += 1;
preserve = dp;
continue;
int avail_tapes = 1;
nbi = bi->prev;
dp = bi->dp;
- if(dp->tape_splitsize > (gint64)0)
+ if(dp->splitsize > (gint64)0)
avail_tapes = conf_runtapes;
if(bi->deleted) {
}
for(dp = schedq.head; dp != NULL; dp = dp->next) {
- days = est(dp)->next_level0; /* This is > 0 by definition */
+ days = est(dp)->next_level0;
+ if (days < 0) days = 0;
if(days<my_dumpcycle && !dp->skip_full && dp->strategy != DS_NOFULL &&
dp->strategy != DS_INCRONLY) {
sp[days].disks++;