static bool bvfs_parse_arg_version(UAContext *ua, char **client, DBId_t *fnid, bool *versions, bool *copies) { *fnid = 0; *client = NULL; *versions = false; *copies = false; for (int i = 1; i < ua->argc; i++) { if (bstrcasecmp(ua->argk[i], NT_("fnid")) || bstrcasecmp(ua->argk[i], NT_("filenameid"))) { if (is_a_number(ua->argv[i])) { *fnid = str_to_int64(ua->argv[i]); } } if (bstrcasecmp(ua->argk[i], NT_("client"))) { *client = ua->argv[i]; } if (copies && bstrcasecmp(ua->argk[i], NT_("copies"))) { *copies = true; } if (versions && bstrcasecmp(ua->argk[i], NT_("versions"))) { *versions = true; } } return (*client && *fnid > 0); }
const char *volume_status_to_str(const char *status) { int pos; const char *vs[] = { NT_("Append"), _("Append"), NT_("Archive"), _("Archive"), NT_("Disabled"), _("Disabled"), NT_("Full"), _("Full"), NT_("Used"), _("Used"), NT_("Cleaning"), _("Cleaning"), NT_("Purged"), _("Purged"), NT_("Recycle"), _("Recycle"), NT_("Read-Only"), _("Read-Only"), NT_("Error"), _("Error"), NULL, NULL}; if (status) { for (pos = 0 ; vs[pos] ; pos += 2) { if (bstrcmp(vs[pos], status)) { return vs[pos+1]; } } } return _("Invalid volume status"); }
/* * This gets the client name from which the backup was made */ static int get_client_name(UAContext *ua, RESTORE_CTX *rx) { int i; CLIENT_DBR cr; /* * If no client name specified yet, get it now */ if (!rx->ClientName) { /* * Try command line argument */ i = find_arg_with_value(ua, NT_("client")); if (i < 0) { i = find_arg_with_value(ua, NT_("backupclient")); } if (i >= 0) { if (!is_name_valid(ua->argv[i], &ua->errmsg)) { ua->error_msg("%s argument: %s", ua->argk[i], ua->errmsg); return 0; } rx->ClientName = bstrdup(ua->argv[i]); return 1; } memset(&cr, 0, sizeof(cr)); if (!get_client_dbr(ua, &cr)) { return 0; } rx->ClientName = bstrdup(cr.Name); } return 1; }
bool configure_cmd(UAContext *ua, const char *cmd) { bool result = false; if (!(my_config->is_using_config_include_dir())) { ua->warning_msg(_( "It seems that the configuration is not adapted to the include directory structure. " "This means, that the configure command may not work as expected. " "Your configuration changes may not survive a reload/restart. " "Please see %s for details.\n"), MANUAL_CONFIG_DIR_URL); } if (ua->argc < 3) { ua->error_msg(_("usage:\n" " configure add <resourcetype> <key1>=<value1> ...\n" " configure export client=<clientname>\n")); return false; } if (bstrcasecmp(ua->argk[1], NT_("add"))) { result = configure_add(ua, 2); } else if (bstrcasecmp(ua->argk[1], NT_("export"))) { result = configure_export(ua); } else { ua->error_msg(_("invalid subcommand %s.\n"), ua->argk[1]); return false; } return result; }
/* * We get the number of drives in the changer from the SD */ int get_num_drives_from_SD(UAContext *ua) { STORE *store = ua->jcr->wstore; char dev_name[MAX_NAME_LENGTH]; BSOCK *sd; int drives = 0; if (!(sd=open_sd_bsock(ua))) { return 0; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* Ask for autochanger number of slots */ sd->fsend(NT_("autochanger drives %s\n"), dev_name); while (sd->recv() >= 0) { if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) { break; } else { ua->send_msg("%s", sd->msg); } } close_sd_bsock(ua); // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives); return drives; }
static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive) { STORE *store = ua->jcr->wstore; BSOCK *sd; char dev_name[MAX_NAME_LENGTH]; char *VolName = NULL; int rtn_slot; if (!(sd=open_sd_bsock(ua))) { ua->error_msg(_("Could not open SD socket.\n")); return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* Ask for autochanger list of volumes */ sd->fsend(NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive); Dmsg1(100, "Sent: %s", sd->msg); /* Get Volume name in this Slot */ while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); Dmsg1(100, "Got: %s", sd->msg); if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) { VolName = (char *)malloc(sd->msglen); if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) { break; } free(VolName); VolName = NULL; } } close_sd_bsock(ua); Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName)); return VolName; }
static bool bvfs_parse_arg(UAContext *ua, DBId_t *pathid, char **path, char **jobid, int *limit, int *offset) { *pathid = 0; *limit = 2000; *offset = 0; *path = NULL; *jobid = NULL; for (int i = 1; i < ua->argc; i++) { if (bstrcasecmp(ua->argk[i], NT_("pathid"))) { if (is_a_number(ua->argv[i])) { *pathid = str_to_int64(ua->argv[i]); } } if (bstrcasecmp(ua->argk[i], NT_("path"))) { *path = ua->argv[i]; } if (bstrcasecmp(ua->argk[i], NT_("jobid"))) { if (is_a_number_list(ua->argv[i])) { *jobid = ua->argv[i]; } } if (bstrcasecmp(ua->argk[i], NT_("limit"))) { if (is_a_number(ua->argv[i])) { *limit = str_to_int64(ua->argv[i]); } } if (bstrcasecmp(ua->argk[i], NT_("offset"))) { if (is_a_number(ua->argv[i])) { *offset = str_to_int64(ua->argv[i]); } } } if (!((*pathid || *path) && *jobid)) { return false; } if (!open_client_db(ua, true)) { return false; } return true; }
/* Modify the RecyclePool of a Volume */ void update_vol_recyclepool(UAContext *ua, char *val, MEDIA_DBR *mr) { POOL_DBR pr; POOL_MEM query(PM_MESSAGE); char ed1[50], ed2[50], *poolname; if(val && *val) { /* update volume recyclepool="Scratch" */ /* If a pool name is given, look up the PoolId */ memset(&pr, 0, sizeof(pr)); bstrncpy(pr.Name, val, sizeof(pr.Name)); if (!get_pool_dbr(ua, &pr, NT_("recyclepool"))) { return; } /* pool = select_pool_resource(ua); */ mr->RecyclePoolId = pr.PoolId; /* get the PoolId */ poolname = pr.Name; } else { /* update volume recyclepool="" */ /* If no pool name is given, set the PoolId to 0 (the default) */ mr->RecyclePoolId = 0; poolname = _("*None*"); } db_lock(ua->db); Mmsg(query, "UPDATE Media SET RecyclePoolId=%s WHERE MediaId=%s", edit_int64(mr->RecyclePoolId, ed1), edit_int64(mr->MediaId, ed2)); if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_("New RecyclePool is: %s\n"), poolname); } db_unlock(ua->db); }
//-------------------------------------------------------- // constuct a Green's submatrix //-------------------------------------------------------- void ChargeRegulatorMethodFeedback::set_influence_matrix(void) { // construct control-influence matrix bar{G}^-1: ds{p} = G{p,m}^-1 dphi{m} // if (nInfluenceNodes_ < nControlNodes_) throw ATC_Error(" least square not implmented "); if (nInfluenceNodes_ > nControlNodes_) throw ATC_Error(" solve not possible "); DENS_MAT G(nInfluenceNodes_,nControlNodes_); DENS_VEC G_I; set<int>::const_iterator itr,itr2,itr3; const Array<int> & nmap = atc_->fe_engine()->fe_mesh()->global_to_unique_map(); int i = 0; for (itr = influenceNodes_.begin(); itr != influenceNodes_.end(); itr++) { poissonSolver_->greens_function(*itr, G_I); int j = 0; for (itr2 = controlNodes_.begin(); itr2 != controlNodes_.end(); itr2++) { int jnode = nmap(*itr2); G(i,j++) = G_I(jnode); } i++; } invG_ = inv(G); // construct the prolong-restrict projector N N^T for influence nodes only InterscaleManager & interscaleManager(atc_->interscale_manager()); const SPAR_MAT & N_Ia = (boundary_) ? (interscaleManager.per_atom_sparse_matrix("InterpolantGhost"))->quantity(): (interscaleManager.per_atom_sparse_matrix("Interpolant"))->quantity(); NT_.reset(nInfluenceAtoms_,nInfluenceNodes_); DENS_MAT NNT(nInfluenceNodes_,nInfluenceNodes_); int k = 0; for (itr3 = influenceAtoms_.begin(); itr3 != influenceAtoms_.end(); itr3++) { int katom = *itr3; int i = 0; for (itr = influenceNodes_.begin(); itr != influenceNodes_.end(); itr++) { int Inode = *itr; int j = 0; NT_(k,i) = N_Ia(katom,Inode); for (itr2 = influenceNodes_.begin(); itr2 != influenceNodes_.end(); itr2++) { int Jnode = *itr2; NNT(i,j++) += N_Ia(katom,Inode)*N_Ia(katom,Jnode); } i++; } k++; } // swap contributions across processors DENS_MAT localNNT = NNT; int count = NNT.nRows()*NNT.nCols(); lammpsInterface_->allsum(localNNT.ptr(),NNT.ptr(),count); invNNT_ = inv(NNT); // total influence matrix if (nInfluenceAtoms_ > 0) { NTinvNNTinvG_ = NT_*invNNT_*invG_; } }
/* * Turn auto display of console messages on/off */ int autodisplay_cmd(UAContext *ua, const char *cmd) { static const char *kw[] = { NT_("on"), NT_("off"), NULL}; switch (find_arg_keyword(ua, kw)) { case 0: ua->auto_display_messages = true; break; case 1: ua->auto_display_messages = false; break; default: ua->error_msg(_("ON or OFF keyword missing.\n")); break; } return 1; }
/* * Turn GUI mode on/off */ int gui_cmd(UAContext *ua, const char *cmd) { static const char *kw[] = { NT_("on"), NT_("off"), NULL}; switch (find_arg_keyword(ua, kw)) { case 0: ua->jcr->gui = ua->gui = true; break; case 1: ua->jcr->gui = ua->gui = false; break; default: ua->error_msg(_("ON or OFF keyword missing.\n")); break; } return 1; }
/* * This gets the client name from which the backup was made */ static bool get_client_name(UAContext *ua, RESTORE_CTX *rx) { int i; CLIENT_DBR cr; memset(&cr, 0, sizeof(cr)); /* * If no client name specified yet, get it now */ if (!rx->ClientName) { /* * Try command line argument */ i = find_arg_with_value(ua, NT_("client")); if (i < 0) { i = find_arg_with_value(ua, NT_("backupclient")); } if (i >= 0) { if (!is_name_valid(ua->argv[i], ua->errmsg)) { ua->error_msg("%s argument: %s", ua->argk[i], ua->errmsg); return false; } bstrncpy(cr.Name, ua->argv[i], sizeof(cr.Name)); if (!db_get_client_record(ua->jcr, ua->db, &cr)) { ua->error_msg("invalid %s argument: %s\n", ua->argk[i], ua->argv[i]); return false; } rx->ClientName = bstrdup(ua->argv[i]); return true; } if (!get_client_dbr(ua, &cr)) { return false; } rx->ClientName = bstrdup(cr.Name); } return true; }
/* * Update long term statistics */ static bool update_stats(UAContext *ua) { int i = find_arg_with_value(ua, NT_("days")); utime_t since=0; if (i >= 0) { since = atoi(ua->argv[i]) * 24*60*60; } int nb = db_update_stats(ua->jcr, ua->db, since); ua->info_msg(_("Updating %i job(s).\n"), nb); return true; }
/* * Execute a command from the UA */ bool do_a_dot_command(UAContext *ua) { int i; int len; bool ok = false; bool found = false; BSOCK *user = ua->UA_sock; Dmsg1(1400, "Dot command: %s\n", user->msg); if (ua->argc == 0) { return false; } len = strlen(ua->argk[0]); if (len == 1) { if (ua->api) user->signal(BNET_CMD_BEGIN); if (ua->api) user->signal(BNET_CMD_OK); return true; /* no op */ } for (i=0; i<comsize; i++) { /* search for command */ if (bstrncasecmp(ua->argk[0], _(commands[i].key), len)) { /* Check if this command is authorized in RunScript */ if (ua->runscript && !commands[i].use_in_rs) { ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]); break; } bool gui = ua->gui; /* Check if command permitted, but "quit" is always OK */ if (!bstrcmp(ua->argk[0], NT_(".quit")) && !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) { break; } Dmsg1(100, "Cmd: %s\n", ua->cmd); ua->gui = true; if (ua->api) user->signal(BNET_CMD_BEGIN); ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */ if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED); ua->gui = gui; found = true; break; } } if (!found) { ua->error_msg("%s%s", ua->argk[0], _(": is an invalid command.\n")); ok = false; } return ok; }
/* * Get a catalog resource from prompt list */ CATRES *get_catalog_resource(UAContext *ua) { CATRES *catalog = NULL; char name[MAX_NAME_LENGTH]; for (int i = 1; i < ua->argc; i++) { if (bstrcasecmp(ua->argk[i], NT_("catalog")) && ua->argv[i]) { if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) { catalog = (CATRES *)GetResWithName(R_CATALOG, ua->argv[i]); break; } } } if (ua->gui && !catalog) { LockRes(); catalog = (CATRES *)GetNextRes(R_CATALOG, NULL); UnlockRes(); if (!catalog) { ua->error_msg(_("Could not find a Catalog resource\n")); return NULL; } else if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) { ua->error_msg(_("You must specify a \"use <catalog-name>\" command before continuing.\n")); return NULL; } return catalog; } if (!catalog) { start_prompt(ua, _("The defined Catalog resources are:\n")); LockRes(); foreach_res(catalog, R_CATALOG) { if (acl_access_ok(ua, Catalog_ACL, catalog->name())) { add_prompt(ua, catalog->name()); } } UnlockRes(); if (do_prompt(ua, _("Catalog"), _("Select Catalog resource"), name, sizeof(name)) < 0) { return NULL; } catalog = (CATRES *)GetResWithName(R_CATALOG, name); }
/* * This is where we pick up a client name to restore to. */ static int get_restore_client_name(UAContext *ua, RESTORE_CTX &rx) { /* Start with same name as backup client */ bstrncpy(rx.RestoreClientName, rx.ClientName, sizeof(rx.RestoreClientName)); /* try command line argument */ int i = find_arg_with_value(ua, NT_("restoreclient")); if (i >= 0) { if (!is_name_valid(ua->argv[i], &ua->errmsg)) { ua->error_msg("%s argument: %s", ua->argk[i], ua->errmsg); return 0; } bstrncpy(rx.RestoreClientName, ua->argv[i], sizeof(rx.RestoreClientName)); return 1; } return 1; }
static void update_volstatus(UAContext *ua, const char *val, MEDIA_DBR *mr) { POOL_MEM query(PM_MESSAGE); const char *kw[] = { NT_("Append"), NT_("Archive"), NT_("Disabled"), NT_("Full"), NT_("Used"), NT_("Cleaning"), NT_("Recycle"), NT_("Read-Only"), NT_("Error"), NULL }; bool found = false; int i; for (i = 0; kw[i]; i++) { if (bstrcasecmp(val, kw[i])) { found = true; break; } } if (!found) { ua->error_msg(_("Invalid VolStatus specified: %s\n"), val); } else { char ed1[50]; bstrncpy(mr->VolStatus, kw[i], sizeof(mr->VolStatus)); Mmsg(query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%s", mr->VolStatus, edit_int64(mr->MediaId,ed1)); if (!db_sql_query(ua->db, query.c_str())) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_("New Volume status is: %s\n"), mr->VolStatus); } } }
/* * We get the volume name from the SD */ char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive) { BSOCK *sd; STORERES *store = ua->jcr->res.wstore; char dev_name[MAX_NAME_LENGTH]; char *VolName = NULL; int rtn_slot; if (!(sd = open_sd_bsock(ua))) { ua->error_msg(_("Could not open SD socket.\n")); return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* * Ask storage daemon to read the label of the volume in a * specific slot of the autochanger using the drive number given. * This could change the loaded volume in the drive. */ sd->fsend(readlabelcmd, dev_name, Slot, drive); Dmsg1(100, "Sent: %s", sd->msg); /* * Get Volume name in this Slot */ while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); Dmsg1(100, "Got: %s", sd->msg); if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) { VolName = (char *)malloc(sd->msglen); if (sscanf(sd->msg, readlabelresponse, VolName, &rtn_slot) == 2) { break; } free(VolName); VolName = NULL; } } close_sd_bsock(ua); Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName)); return VolName; }
/* * This is where we pick up a client name to restore to. */ static int get_restore_client_name(UAContext *ua, RESTORE_CTX &rx) { int i; /* * Try command line argument */ i = find_arg_with_value(ua, NT_("restoreclient")); if (i >= 0) { if (!is_name_valid(ua->argv[i], &ua->errmsg)) { ua->error_msg("%s argument: %s", ua->argk[i], ua->errmsg); return 0; } rx.RestoreClientName = bstrdup(ua->argv[i]); return 1; } rx.RestoreClientName = bstrdup(rx.ClientName); return 1; }
static inline bool configure_export(UAContext *ua) { bool result = false; int i; i = find_arg_with_value(ua, NT_("client")); if (i < 0) { configure_export_usage(ua); return false; } if (!ua->GetClientResWithName(ua->argv[i])) { configure_export_usage(ua); return false; } ua->send->object_start("configure"); result = configure_create_fd_resource(ua, ua->argv[i]); ua->send->object_end("configure"); return result; }
static bool ask_for_fileregex(UAContext *ua, RESTORE_CTX *rx) { if (find_arg(ua, NT_("all")) >= 0) { /* if user enters all on command line */ return true; /* select everything */ } ua->send_msg(_("\n\nFor one or more of the JobIds selected, no files were found,\n" "so file selection is not possible.\n" "Most likely your retention policy pruned the files.\n")); if (get_yesno(ua, _("\nDo you want to restore all the files? (yes|no): "))) { if (ua->pint32_val == 1) return true; while (get_cmd(ua, _("\nRegexp matching files to restore? (empty to abort): "))) { if (ua->cmd[0] == '\0') { break; } else { regex_t *fileregex_re = NULL; int rc; char errmsg[500] = ""; fileregex_re = (regex_t *)bmalloc(sizeof(regex_t)); rc = regcomp(fileregex_re, ua->cmd, REG_EXTENDED|REG_NOSUB); if (rc != 0) { regerror(rc, fileregex_re, errmsg, sizeof(errmsg)); } regfree(fileregex_re); free(fileregex_re); if (*errmsg) { ua->send_msg(_("Regex compile error: %s\n"), errmsg); } else { rx->bsr->fileregex = bstrdup(ua->cmd); return true; } } } } return false; }
/* * This is where we pick up a client name to restore to. */ static bool get_restore_client_name(UAContext *ua, RESTORE_CTX &rx) { int i; /* * Try command line argument */ i = find_arg_with_value(ua, NT_("restoreclient")); if (i >= 0) { if (!is_name_valid(ua->argv[i], ua->errmsg)) { ua->error_msg("%s argument: %s", ua->argk[i], ua->errmsg); return false; } if (!GetClientResWithName(ua->argv[i])) { ua->error_msg("invalid %s argument: %s\n", ua->argk[i], ua->argv[i]); return false; } rx.RestoreClientName = bstrdup(ua->argv[i]); return true; } rx.RestoreClientName = bstrdup(rx.ClientName); return true; }
/* * Confirm a retention period */ bool confirm_retention(UAContext *ua, utime_t *ret, const char *msg) { bool retval; char ed1[100]; int yes_in_arg; yes_in_arg = find_arg(ua, NT_("yes")); for ( ;; ) { ua->info_msg(_("The current %s retention period is: %s\n"), msg, edit_utime(*ret, ed1, sizeof(ed1))); if (yes_in_arg != -1) { return true; } if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) { return false; } if (bstrcasecmp(ua->cmd, _("mod"))) { if (!get_cmd(ua, _("Enter new retention period: "))) { return false; } if (!duration_to_utime(ua->cmd, ret)) { ua->error_msg(_("Invalid period.\n")); continue; } continue; } if (is_yesno(ua->cmd, &retval)) { return retval; } } return true; }
*val_size = *val_len + 1; return 1; } struct s_built_in_vars { const char *var_name; int code; int (*func)(JCR *jcr, int code, const char **val_ptr, int *val_len, int *val_size); }; /* * Table of build in variables */ static struct s_built_in_vars built_in_vars[] = { { NT_("Year"), 1, date_item }, { NT_("Month"), 2, date_item }, { NT_("Day"), 3, date_item }, { NT_("Hour"), 4, date_item }, { NT_("Minute"), 5, date_item }, { NT_("Second"), 6, date_item }, { NT_("WeekDay"), 7, date_item }, { NT_("Job"), 1, job_item }, { NT_("Dir"), 2, job_item }, { NT_("Level"), 3, job_item }, { NT_("Type"), 4, job_item }, { NT_("JobId"), 5, job_item }, { NT_("Client"), 6, job_item }, { NT_("NumVols"), 7, job_item }, { NT_("Pool"), 8, job_item }, { NT_("Storage"), 9, job_item },
/* * Prune records from database * * prune files (from) client=xxx [pool=yyy] * prune jobs (from) client=xxx [pool=yyy] * prune volume=xxx * prune stats */ int prunecmd(UAContext *ua, const char *cmd) { CLIENTRES *client; POOLRES *pool; POOL_DBR pr; MEDIA_DBR mr; utime_t retention; int kw; static const char *keywords[] = { NT_("Files"), NT_("Jobs"), NT_("Volume"), NT_("Stats"), NULL}; if (!open_client_db(ua)) { return false; } /* First search args */ kw = find_arg_keyword(ua, keywords); if (kw < 0 || kw > 3) { /* no args, so ask user */ kw = do_keyword_prompt(ua, _("Choose item to prune"), keywords); } switch (kw) { case 0: /* prune files */ if (!(client = get_client_resource(ua))) { return false; } if (find_arg_with_value(ua, "pool") >= 0) { pool = get_pool_resource(ua); } else { pool = NULL; } /* Pool File Retention takes precedence over client File Retention */ if (pool && pool->FileRetention > 0) { if (!confirm_retention(ua, &pool->FileRetention, "File")) { return false; } } else if (!confirm_retention(ua, &client->FileRetention, "File")) { return false; } prune_files(ua, client, pool); return true; case 1: /* prune jobs */ if (!(client = get_client_resource(ua))) { return false; } if (find_arg_with_value(ua, "pool") >= 0) { pool = get_pool_resource(ua); } else { pool = NULL; } /* Pool Job Retention takes precedence over client Job Retention */ if (pool && pool->JobRetention > 0) { if (!confirm_retention(ua, &pool->JobRetention, "Job")) { return false; } } else if (!confirm_retention(ua, &client->JobRetention, "Job")) { return false; } /* ****FIXME**** allow user to select JobType */ prune_jobs(ua, client, pool, JT_BACKUP); return 1; case 2: /* prune volume */ if (!select_pool_and_media_dbr(ua, &pr, &mr)) { return false; } if (mr.Enabled == 2) { ua->error_msg(_("Cannot prune Volume \"%s\" because it is archived.\n"), mr.VolumeName); return false; } if (!confirm_retention(ua, &mr.VolRetention, "Volume")) { return false; } prune_volume(ua, &mr); return true; case 3: /* prune stats */ if (!director->stats_retention) { return false; } retention = director->stats_retention; if (!confirm_retention(ua, &retention, "Statistics")) { return false; } prune_stats(ua, retention); return true; default: break; } return true; }
s_woy, /* week of year w00 - w53 */ s_last, /* last week of month */ s_modulo /* every nth monthday/week */ }; struct s_keyw { const char *name; /* keyword */ enum e_state state; /* parser state */ int code; /* state value */ }; /* * Keywords understood by parser */ static struct s_keyw keyw[] = { { NT_("on"), s_none, 0 }, { NT_("at"), s_at, 0 }, { NT_("last"), s_last, 0 }, { NT_("sun"), s_wday, 0 }, { NT_("mon"), s_wday, 1 }, { NT_("tue"), s_wday, 2 }, { NT_("wed"), s_wday, 3 }, { NT_("thu"), s_wday, 4 }, { NT_("fri"), s_wday, 5 }, { NT_("sat"), s_wday, 6 }, { NT_("jan"), s_month, 0 }, { NT_("feb"), s_month, 1 }, { NT_("mar"), s_month, 2 }, { NT_("apr"), s_month, 3 }, { NT_("may"), s_month, 4 }, { NT_("jun"), s_month, 5 },
/* * Restore files */ bool restore_cmd(UAContext *ua, const char *cmd) { RESTORE_CTX rx; /* restore context */ POOL_MEM buf; JOBRES *job; int i; JCR *jcr = ua->jcr; char *escaped_bsr_name = NULL; char *escaped_where_name = NULL; char *strip_prefix, *add_prefix, *add_suffix, *regexp; strip_prefix = add_prefix = add_suffix = regexp = NULL; memset(&rx, 0, sizeof(rx)); rx.path = get_pool_memory(PM_FNAME); rx.fname = get_pool_memory(PM_FNAME); rx.JobIds = get_pool_memory(PM_FNAME); rx.JobIds[0] = 0; rx.BaseJobIds = get_pool_memory(PM_FNAME); rx.query = get_pool_memory(PM_FNAME); rx.bsr = new_bsr(); i = find_arg_with_value(ua, "comment"); if (i >= 0) { rx.comment = ua->argv[i]; if (!is_comment_legal(ua, rx.comment)) { goto bail_out; } } i = find_arg_with_value(ua, "backupformat"); if (i >= 0) { rx.backup_format = ua->argv[i]; } i = find_arg_with_value(ua, "where"); if (i >= 0) { rx.where = ua->argv[i]; } i = find_arg_with_value(ua, "replace"); if (i >= 0) { rx.replace = ua->argv[i]; } i = find_arg_with_value(ua, "pluginoptions"); if (i >= 0) { rx.plugin_options = ua->argv[i]; } i = find_arg_with_value(ua, "strip_prefix"); if (i >= 0) { strip_prefix = ua->argv[i]; } i = find_arg_with_value(ua, "add_prefix"); if (i >= 0) { add_prefix = ua->argv[i]; } i = find_arg_with_value(ua, "add_suffix"); if (i >= 0) { add_suffix = ua->argv[i]; } i = find_arg_with_value(ua, "regexwhere"); if (i >= 0) { rx.RegexWhere = ua->argv[i]; } if (strip_prefix || add_suffix || add_prefix) { int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix); regexp = (char *)bmalloc(len * sizeof(char)); bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix); rx.RegexWhere = regexp; } /* TODO: add acl for regexwhere ? */ if (rx.RegexWhere) { if (!acl_access_ok(ua, Where_ACL, rx.RegexWhere, true)) { ua->error_msg(_("\"RegexWhere\" specification not authorized.\n")); goto bail_out; } } if (rx.where) { if (!acl_access_ok(ua, Where_ACL, rx.where, true)) { ua->error_msg(_("\"where\" specification not authorized.\n")); goto bail_out; } } if (!open_client_db(ua, true)) { goto bail_out; } /* Ensure there is at least one Restore Job */ LockRes(); foreach_res(job, R_JOB) { if (job->JobType == JT_RESTORE) { if (!rx.restore_job) { rx.restore_job = job; } rx.restore_jobs++; } } UnlockRes(); if (!rx.restore_jobs) { ua->error_msg(_( "No Restore Job Resource found in bareos-dir.conf.\n" "You must create at least one before running this command.\n")); goto bail_out; } /* * Request user to select JobIds or files by various different methods * last 20 jobs, where File saved, most recent backup, ... * In the end, a list of files are pumped into * add_findex() */ switch (user_select_jobids_or_files(ua, &rx)) { case 0: /* error */ goto bail_out; case 1: /* selected by jobid */ get_and_display_basejobs(ua, &rx); if (!build_directory_tree(ua, &rx)) { ua->send_msg(_("Restore not done.\n")); goto bail_out; } break; case 2: /* selected by filename, no tree needed */ break; } if (rx.bsr->JobId) { char ed1[50]; if (!complete_bsr(ua, rx.bsr)) { /* find Vol, SessId, SessTime from JobIds */ ua->error_msg(_("Unable to construct a valid BSR. Cannot continue.\n")); goto bail_out; } if (!(rx.selected_files = write_bsr_file(ua, rx))) { ua->warning_msg(_("No files selected to be restored.\n")); goto bail_out; } display_bsr_info(ua, rx); /* display vols needed, etc */ if (rx.selected_files==1) { ua->info_msg(_("\n1 file selected to be restored.\n\n")); } else { ua->info_msg(_("\n%s files selected to be restored.\n\n"), edit_uint64_with_commas(rx.selected_files, ed1)); } } else { ua->warning_msg(_("No files selected to be restored.\n")); goto bail_out; } if (rx.restore_jobs == 1) { job = rx.restore_job; } else { job = get_restore_job(ua); } if (!job) { goto bail_out; } if (!get_client_name(ua, &rx)) { goto bail_out; } if (!rx.ClientName) { ua->error_msg(_("No Client resource found!\n")); goto bail_out; } if (!get_restore_client_name(ua, rx)) { goto bail_out; } escaped_bsr_name = escape_filename(jcr->RestoreBootstrap); Mmsg(ua->cmd, "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" " bootstrap=\"%s\" files=%u catalog=\"%s\"", job->name(), rx.ClientName, rx.RestoreClientName, rx.store?rx.store->name():"", escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, rx.selected_files, ua->catalog->name()); /* * Build run command */ if (rx.backup_format) { Mmsg(buf, " backupformat=%s", rx.backup_format); pm_strcat(ua->cmd, buf); } pm_strcpy(buf, ""); if (rx.RegexWhere) { escaped_where_name = escape_filename(rx.RegexWhere); Mmsg(buf, " regexwhere=\"%s\"", escaped_where_name ? escaped_where_name : rx.RegexWhere); } else if (rx.where) { escaped_where_name = escape_filename(rx.where); Mmsg(buf," where=\"%s\"", escaped_where_name ? escaped_where_name : rx.where); } pm_strcat(ua->cmd, buf); if (rx.replace) { Mmsg(buf, " replace=%s", rx.replace); pm_strcat(ua->cmd, buf); } if (rx.plugin_options) { Mmsg(buf, " pluginoptions=%s", rx.plugin_options); pm_strcat(ua->cmd, buf); } if (rx.comment) { Mmsg(buf, " comment=\"%s\"", rx.comment); pm_strcat(ua->cmd, buf); } if (escaped_bsr_name != NULL) { bfree(escaped_bsr_name); } if (escaped_where_name != NULL) { bfree(escaped_where_name); } if (regexp) { bfree(regexp); } if (find_arg(ua, NT_("yes")) > 0) { pm_strcat(ua->cmd, " yes"); /* pass it on to the run command */ } Dmsg1(200, "Submitting: %s\n", ua->cmd); /* * Transfer jobids to jcr to for picking up restore objects */ jcr->JobIds = rx.JobIds; rx.JobIds = NULL; parse_ua_args(ua); run_cmd(ua, ua->cmd); free_rx(&rx); garbage_collect_memory(); /* release unused memory */ return true; bail_out: if (escaped_bsr_name != NULL) { bfree(escaped_bsr_name); } if (escaped_where_name != NULL) { bfree(escaped_where_name); } if (regexp) { bfree(regexp); } free_rx(&rx); garbage_collect_memory(); /* release unused memory */ return false; }
/* * The first step in the restore process is for the user to * select a list of JobIds from which he will subsequently * select which files are to be restored. * * Returns: 2 if filename list made * 1 if jobid list made * 0 on error */ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx) { char *p; char date[MAX_TIME_LENGTH]; bool have_date = false; /* Include current second if using current time */ utime_t now = time(NULL) + 1; JobId_t JobId; JOB_DBR jr = { (JobId_t)-1 }; bool done = false; int i, j; const char *list[] = { _("List last 20 Jobs run"), _("List Jobs where a given File is saved"), _("Enter list of comma separated JobIds to select"), _("Enter SQL list command"), _("Select the most recent backup for a client"), _("Select backup for a client before a specified time"), _("Enter a list of files to restore"), _("Enter a list of files to restore before a specified time"), _("Find the JobIds of the most recent backup for a client"), _("Find the JobIds for a backup for a client before a specified time"), _("Enter a list of directories to restore for found JobIds"), _("Select full restore to a specified Job date"), _("Cancel"), NULL }; const char *kw[] = { /* * These keywords are handled in a for loop */ "jobid", /* 0 */ "current", /* 1 */ "before", /* 2 */ "file", /* 3 */ "directory", /* 4 */ "select", /* 5 */ "pool", /* 6 */ "all", /* 7 */ /* * The keyword below are handled by individual arg lookups */ "client", /* 8 */ "storage", /* 9 */ "fileset", /* 10 */ "where", /* 11 */ "yes", /* 12 */ "bootstrap", /* 13 */ "done", /* 14 */ "strip_prefix", /* 15 */ "add_prefix", /* 16 */ "add_suffix", /* 17 */ "regexwhere", /* 18 */ "restoreclient", /* 19 */ "copies", /* 20 */ "comment", /* 21 */ "restorejob", /* 22 */ "replace", /* 23 */ "pluginoptions", /* 24 */ NULL }; rx->JobIds[0] = 0; for (i = 1; i<ua->argc; i++) { /* loop through arguments */ bool found_kw = false; for (j = 0; kw[j]; j++) { /* loop through keywords */ if (bstrcasecmp(kw[j], ua->argk[i])) { found_kw = true; break; } } if (!found_kw) { ua->error_msg(_("Unknown keyword: %s\n"), ua->argk[i]); return 0; } /* Found keyword in kw[] list, process it */ switch (j) { case 0: /* jobid */ if (!has_value(ua, i)) { return 0; } if (*rx->JobIds != 0) { pm_strcat(rx->JobIds, ","); } pm_strcat(rx->JobIds, ua->argv[i]); done = true; break; case 1: /* current */ /* * Note, we add one second here just to include any job * that may have finished within the current second, * which happens a lot in scripting small jobs. */ bstrutime(date, sizeof(date), now); have_date = true; break; case 2: /* before */ if (have_date || !has_value(ua, i)) { return 0; } if (str_to_utime(ua->argv[i]) == 0) { ua->error_msg(_("Improper date format: %s\n"), ua->argv[i]); return 0; } bstrncpy(date, ua->argv[i], sizeof(date)); have_date = true; break; case 3: /* file */ case 4: /* dir */ if (!has_value(ua, i)) { return 0; } if (!have_date) { bstrutime(date, sizeof(date), now); } if (!get_client_name(ua, rx)) { return 0; } pm_strcpy(ua->cmd, ua->argv[i]); insert_one_file_or_dir(ua, rx, date, j==4); return 2; case 5: /* select */ if (!have_date) { bstrutime(date, sizeof(date), now); } if (!select_backups_before_date(ua, rx, date)) { return 0; } done = true; break; case 6: /* pool specified */ if (!has_value(ua, i)) { return 0; } rx->pool = (POOLRES *)GetResWithName(R_POOL, ua->argv[i]); if (!rx->pool) { ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]); return 0; } if (!acl_access_ok(ua, Pool_ACL, ua->argv[i], true)) { rx->pool = NULL; ua->error_msg(_("Error: Pool resource \"%s\" access not allowed.\n"), ua->argv[i]); return 0; } break; case 7: /* all specified */ rx->all = true; break; default: /* * All keywords 7 or greater are ignored or handled by a select prompt */ break; } } if (!done) { ua->send_msg(_("\nFirst you select one or more JobIds that contain files\n" "to be restored. You will be presented several methods\n" "of specifying the JobIds. Then you will be allowed to\n" "select which files from those JobIds are to be restored.\n\n")); } /* If choice not already made above, prompt */ for ( ; !done; ) { char *fname; int len; bool gui_save; db_list_ctx jobids; start_prompt(ua, _("To select the JobIds, you have the following choices:\n")); for (int i=0; list[i]; i++) { add_prompt(ua, list[i]); } done = true; switch (do_prompt(ua, "", _("Select item: "), NULL, 0)) { case -1: /* error or cancel */ return 0; case 0: /* list last 20 Jobs run */ if (!acl_access_ok(ua, Command_ACL, NT_("sqlquery"), true)) { ua->error_msg(_("SQL query not authorized.\n")); return 0; } gui_save = ua->jcr->gui; ua->jcr->gui = true; db_list_sql_query(ua->jcr, ua->db, uar_list_jobs, ua->send, HORZ_LIST, true); ua->jcr->gui = gui_save; done = false; break; case 1: /* list where a file is saved */ if (!get_client_name(ua, rx)) { return 0; } if (!get_cmd(ua, _("Enter Filename (no path):"))) { return 0; } len = strlen(ua->cmd); fname = (char *)malloc(len * 2 + 1); db_escape_string(ua->jcr, ua->db, fname, ua->cmd, len); Mmsg(rx->query, uar_file[db_get_type_index(ua->db)], rx->ClientName, fname); free(fname); gui_save = ua->jcr->gui; ua->jcr->gui = true; db_list_sql_query(ua->jcr, ua->db, rx->query, ua->send, HORZ_LIST, true); ua->jcr->gui = gui_save; done = false; break; case 2: /* enter a list of JobIds */ if (!get_cmd(ua, _("Enter JobId(s), comma separated, to restore: "))) { return 0; } pm_strcpy(rx->JobIds, ua->cmd); break; case 3: /* Enter an SQL list command */ if (!acl_access_ok(ua, Command_ACL, NT_("sqlquery"), true)) { ua->error_msg(_("SQL query not authorized.\n")); return 0; } if (!get_cmd(ua, _("Enter SQL list command: "))) { return 0; } gui_save = ua->jcr->gui; ua->jcr->gui = true; db_list_sql_query(ua->jcr, ua->db, ua->cmd, ua->send, HORZ_LIST, true); ua->jcr->gui = gui_save; done = false; break; case 4: /* Select the most recent backups */ if (!have_date) { bstrutime(date, sizeof(date), now); } if (!select_backups_before_date(ua, rx, date)) { return 0; } break; case 5: /* select backup at specified time */ if (!have_date) { if (!get_date(ua, date, sizeof(date))) { return 0; } } if (!select_backups_before_date(ua, rx, date)) { return 0; } break; case 6: /* Enter files */ if (!have_date) { bstrutime(date, sizeof(date), now); } if (!get_client_name(ua, rx)) { return 0; } ua->send_msg(_("Enter file names with paths, or < to enter a filename\n" "containing a list of file names with paths, and terminate\n" "them with a blank line.\n")); for ( ;; ) { if (!get_cmd(ua, _("Enter full filename: "))) { return 0; } len = strlen(ua->cmd); if (len == 0) { break; } insert_one_file_or_dir(ua, rx, date, false); } return 2; case 7: /* enter files backed up before specified time */ if (!have_date) { if (!get_date(ua, date, sizeof(date))) { return 0; } } if (!get_client_name(ua, rx)) { return 0; } ua->send_msg(_("Enter file names with paths, or < to enter a filename\n" "containing a list of file names with paths, and terminate\n" "them with a blank line.\n")); for ( ;; ) { if (!get_cmd(ua, _("Enter full filename: "))) { return 0; } len = strlen(ua->cmd); if (len == 0) { break; } insert_one_file_or_dir(ua, rx, date, false); } return 2; case 8: /* Find JobIds for current backup */ if (!have_date) { bstrutime(date, sizeof(date), now); } if (!select_backups_before_date(ua, rx, date)) { return 0; } done = false; break; case 9: /* Find JobIds for give date */ if (!have_date) { if (!get_date(ua, date, sizeof(date))) { return 0; } } if (!select_backups_before_date(ua, rx, date)) { return 0; } done = false; break; case 10: /* Enter directories */ if (*rx->JobIds != 0) { ua->send_msg(_("You have already selected the following JobIds: %s\n"), rx->JobIds); } else if (get_cmd(ua, _("Enter JobId(s), comma separated, to restore: "))) { if (*rx->JobIds != 0 && *ua->cmd) { pm_strcat(rx->JobIds, ","); } pm_strcat(rx->JobIds, ua->cmd); } if (*rx->JobIds == 0 || *rx->JobIds == '.') { *rx->JobIds = 0; return 0; /* nothing entered, return */ } if (!have_date) { bstrutime(date, sizeof(date), now); } if (!get_client_name(ua, rx)) { return 0; } ua->send_msg(_("Enter full directory names or start the name\n" "with a < to indicate it is a filename containing a list\n" "of directories and terminate them with a blank line.\n")); for ( ;; ) { if (!get_cmd(ua, _("Enter directory name: "))) { return 0; } len = strlen(ua->cmd); if (len == 0) { break; } /* Add trailing slash to end of directory names */ if (ua->cmd[0] != '<' && !IsPathSeparator(ua->cmd[len-1])) { strcat(ua->cmd, "/"); } insert_one_file_or_dir(ua, rx, date, true); } return 2; case 11: /* Choose a jobid and select jobs */ if (!get_cmd(ua, _("Enter JobId to get the state to restore: ")) || !is_an_integer(ua->cmd)) { return 0; } memset(&jr, 0, sizeof(jr)); jr.JobId = str_to_int64(ua->cmd); if (!db_get_job_record(ua->jcr, ua->db, &jr)) { ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"), ua->cmd, db_strerror(ua->db)); return 0; } ua->send_msg(_("Selecting jobs to build the Full state at %s\n"), jr.cStartTime); jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */ if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &jobids)) { return 0; } pm_strcpy(rx->JobIds, jobids.list); Dmsg1(30, "Item 12: jobids = %s\n", rx->JobIds); break; case 12: /* Cancel or quit */ return 0; } } memset(&jr, 0, sizeof(jr)); POOLMEM *JobIds = get_pool_memory(PM_FNAME); *JobIds = 0; rx->TotalFiles = 0; /* * Find total number of files to be restored, and filter the JobId * list to contain only ones permitted by the ACL conditions. */ for (p=rx->JobIds; ; ) { char ed1[50]; int status = get_next_jobid_from_list(&p, &JobId); if (status < 0) { ua->error_msg(_("Invalid JobId in list.\n")); free_pool_memory(JobIds); return 0; } if (status == 0) { break; } if (jr.JobId == JobId) { continue; /* duplicate of last JobId */ } memset(&jr, 0, sizeof(jr)); jr.JobId = JobId; if (!db_get_job_record(ua->jcr, ua->db, &jr)) { ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"), edit_int64(JobId, ed1), db_strerror(ua->db)); free_pool_memory(JobIds); return 0; } if (!acl_access_ok(ua, Job_ACL, jr.Name, true)) { ua->error_msg(_("Access to JobId=%s (Job \"%s\") not authorized. Not selected.\n"), edit_int64(JobId, ed1), jr.Name); continue; } if (*JobIds != 0) { pm_strcat(JobIds, ","); } pm_strcat(JobIds, edit_int64(JobId, ed1)); rx->TotalFiles += jr.JobFiles; } free_pool_memory(rx->JobIds); rx->JobIds = JobIds; /* Set ACL filtered list */ if (*rx->JobIds == 0) { ua->warning_msg(_("No Jobs selected.\n")); return 0; } if (strchr(rx->JobIds,',')) { ua->info_msg(_("You have selected the following JobIds: %s\n"), rx->JobIds); } else { ua->info_msg(_("You have selected the following JobId: %s\n"), rx->JobIds); } return true; }
int run_scripts(JCR *jcr, alist *runscripts, const char *label, alist *allowed_script_dirs) { RUNSCRIPT *script; bool runit; int when; Dmsg2(200, "runscript: running all RUNSCRIPT object (%s) JobStatus=%c\n", label, jcr->JobStatus); if (strstr(label, NT_("Before"))) { when = SCRIPT_Before; } else if (bstrcmp(label, NT_("ClientAfterVSS"))) { when = SCRIPT_AfterVSS; } else { when = SCRIPT_After; } if (runscripts == NULL) { Dmsg0(100, "runscript: WARNING RUNSCRIPTS list is NULL\n"); return 0; } foreach_alist(script, runscripts) { Dmsg2(200, "runscript: try to run %s:%s\n", NPRT(script->target), NPRT(script->command)); runit = false; if ((script->when & SCRIPT_Before) && (when & SCRIPT_Before)) { if ((script->on_success && (jcr->JobStatus == JS_Running || jcr->JobStatus == JS_Created)) || (script->on_failure && (job_canceled(jcr) || jcr->JobStatus == JS_Differences))) { Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n", script->command, script->on_success, script->on_failure, jcr->JobStatus ); runit = true; } } if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) { if ((script->on_success && (jcr->JobStatus == JS_Blocked)) || (script->on_failure && job_canceled(jcr))) { Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n", script->command, script->on_success, script->on_failure, jcr->JobStatus ); runit = true; } } if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) { if ((script->on_success && (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) || (script->on_failure && (job_canceled(jcr) || jcr->JobStatus == JS_Differences))) { Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n", script->command, script->on_success, script->on_failure, jcr->JobStatus ); runit = true; } } if (!script->is_local()) { runit = false; } /* * We execute it */ if (runit) { if (!script_dir_allowed(jcr, script, allowed_script_dirs)) { Dmsg1(200, "runscript: Not running script %s because its not in one of the allowed scripts dirs\n", script->command); Jmsg(jcr, M_ERROR, 0, _("Runscript: run %s \"%s\" could not execute, " "not in one of the allowed scripts dirs\n"), label, script->command); jcr->setJobStatus(JS_ErrorTerminated); goto bail_out; } script->run(jcr, label); } }
/* * Update a Job record -- allows you to change the * date fields in a Job record. This helps when * providing migration from other vendors. */ static bool update_job(UAContext *ua) { int i; char ed1[50], ed2[50]; POOL_MEM cmd(PM_MESSAGE); JOB_DBR jr; CLIENT_DBR cr; utime_t StartTime; char *client_name = NULL; char *start_time = NULL; const char *kw[] = { NT_("starttime"), /* 0 */ NT_("client"), /* 1 */ NULL }; Dmsg1(200, "cmd=%s\n", ua->cmd); i = find_arg_with_value(ua, NT_("jobid")); if (i < 0) { ua->error_msg(_("Expect JobId keyword, not found.\n")); return false; } memset(&jr, 0, sizeof(jr)); memset(&cr, 0, sizeof(cr)); jr.JobId = str_to_int64(ua->argv[i]); if (!db_get_job_record(ua->jcr, ua->db, &jr)) { ua->error_msg("%s", db_strerror(ua->db)); return false; } for (i=0; kw[i]; i++) { int j; if ((j=find_arg_with_value(ua, kw[i])) >= 0) { switch (i) { case 0: /* start time */ start_time = ua->argv[j]; break; case 1: /* Client name */ client_name = ua->argv[j]; break; } } } if (!client_name && !start_time) { ua->error_msg(_("Neither Client nor StartTime specified.\n")); return 0; } if (client_name) { if (!get_client_dbr(ua, &cr)) { return false; } jr.ClientId = cr.ClientId; } if (start_time) { utime_t delta_start; StartTime = str_to_utime(start_time); if (StartTime == 0) { ua->error_msg(_("Improper date format: %s\n"), ua->argv[i]); return false; } delta_start = StartTime - jr.StartTime; Dmsg3(200, "ST=%lld jr.ST=%lld delta=%lld\n", StartTime, (utime_t)jr.StartTime, delta_start); jr.StartTime = (time_t)StartTime; jr.SchedTime += (time_t)delta_start; jr.EndTime += (time_t)delta_start; jr.JobTDate += delta_start; /* Convert to DB times */ bstrutime(jr.cStartTime, sizeof(jr.cStartTime), jr.StartTime); bstrutime(jr.cSchedTime, sizeof(jr.cSchedTime), jr.SchedTime); bstrutime(jr.cEndTime, sizeof(jr.cEndTime), jr.EndTime); } Mmsg(cmd, "UPDATE Job SET ClientId=%s,StartTime='%s',SchedTime='%s'," "EndTime='%s',JobTDate=%s WHERE JobId=%s", edit_int64(jr.ClientId, ed1), jr.cStartTime, jr.cSchedTime, jr.cEndTime, edit_uint64(jr.JobTDate, ed1), edit_int64(jr.JobId, ed2)); if (!db_sql_query(ua->db, cmd.c_str(), NULL, NULL)) { ua->error_msg("%s", db_strerror(ua->db)); return false; } return true; }