]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
Backport from BEE
[bacula/bacula] / bacula / src / dird / ua_run.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2001-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *
18  *   Bacula Director -- Run Command
19  *
20  *     Kern Sibbald, December MMI
21  *
22  */
23
24 #include "bacula.h"
25 #include "dird.h"
26
27 const char *get_command(int index);
28
29 class run_ctx {
30 public:
31    char *job_name, *level_name, *jid, *store_name, *pool_name;
32    char *where, *fileset_name, *client_name, *bootstrap, *regexwhere;
33    char *restore_client_name, *comment, *media_type, *next_pool_name;
34    const char *replace;
35    char *when, *verify_job_name, *catalog_name;
36    char *previous_job_name;
37    char *since;
38    char *plugin_options;
39    const char *verify_list;
40    JOB *job;
41    JOB *verify_job;
42    JOB *previous_job;
43    JOB_DBR jr;
44    USTORE *store;
45    CLIENT *client;
46    FILESET *fileset;
47    POOL *pool;
48    POOL *next_pool;
49    CAT *catalog;
50    JobId_t JobId;
51    alist *JobIds;
52    int Priority;
53    int files;
54    bool cloned;
55    bool mod;
56    bool restart;
57    bool done;
58    bool alljobid;
59    int spool_data;
60    bool spool_data_set;
61    int accurate;
62    bool accurate_set;
63    int ignoreduplicatecheck;
64    bool ignoreduplicatecheck_set;
65    /* Methods */
66    run_ctx() { memset(this, 0, sizeof(run_ctx));
67                store = new USTORE; };
68    ~run_ctx() { delete store; };
69 };
70
71 /* Forward referenced subroutines */
72 static void select_job_level(UAContext *ua, JCR *jcr);
73 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job,
74                 const char *verify_list, char *jid, const char *replace,
75                 char *client_name);
76 static void select_where_regexp(UAContext *ua, JCR *jcr);
77 static bool scan_run_command_line_arguments(UAContext *ua, run_ctx &rc);
78 static bool set_run_context_in_jcr(UAContext *ua, JCR *jcr, run_ctx &rc);
79 static int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc);
80 static JobId_t start_job(UAContext *ua, JCR *jcr, run_ctx &rc);
81
82 /* Imported variables */
83 extern struct s_kw ReplaceOptions[];
84
85 /*
86  * For Backup and Verify Jobs
87  *     run [job=]<job-name> level=<level-name>
88  *
89  * For Restore Jobs
90  *     run <job-name>
91  *
92  *  Returns: 0 on error
93  *           JobId if OK
94  *
95  */
96 int run_cmd(UAContext *ua, const char *cmd)
97 {
98    JCR *jcr = NULL;
99    run_ctx rc;
100    int status;
101
102    if (!open_client_db(ua)) {
103       goto bail_out;
104    }
105
106    if (!scan_run_command_line_arguments(ua, rc)) {
107       goto bail_out;
108    }
109
110    if (find_arg(ua, NT_("fdcalled")) > 0) {
111       jcr->file_bsock = dup_bsock(ua->UA_sock);
112       ua->quit = true;
113    }
114
115    for ( ;; ) {
116       /*
117        * Create JCR to run job.  NOTE!!! after this point, free_jcr()
118        *  before returning.
119        */
120       if (!jcr) {
121          jcr = new_jcr(sizeof(JCR), dird_free_jcr);
122          set_jcr_defaults(jcr, rc.job);
123          jcr->unlink_bsr = ua->jcr->unlink_bsr;    /* copy unlink flag from caller */
124          ua->jcr->unlink_bsr = false;
125       }
126       /* Transfer JobIds to new restore Job */
127       if (ua->jcr->JobIds) {
128          jcr->JobIds = ua->jcr->JobIds;
129          ua->jcr->JobIds = NULL;
130       }
131       if (!set_run_context_in_jcr(ua, jcr, rc)) {
132          break; /* error get out of while loop */
133       }
134
135
136       /* Run without prompting? */
137       if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
138          return start_job(ua, jcr, rc);
139       }
140
141       /*
142        * Prompt User to see if all run job parameters are correct, and
143        *   allow him to modify them.
144        */
145       if (!display_job_parameters(ua, jcr, rc.job, rc.verify_list, rc.jid, rc.replace,
146            rc.client_name)) {
147          break; /* error get out of while loop */
148       }
149
150       if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
151          break; /* error get out of while loop */
152       }
153
154       if (strncasecmp(ua->cmd, ".mod ", 5) == 0 ||
155           (strncasecmp(ua->cmd, "mod ", 4) == 0 && strlen(ua->cmd) > 6)) {
156          parse_ua_args(ua);
157          rc.mod = true;
158          if (!scan_run_command_line_arguments(ua, rc)) {
159             break; /* error get out of while loop */
160          }
161          continue;   /* another round with while loop */
162       }
163
164       /* Allow the user to modify the settings */
165       status = modify_job_parameters(ua, jcr, rc);
166       if (status == 0) {
167          continue;   /* another round with while loop */
168       }
169       if (status == -1) { /* error */
170          break; /* error get out of while loop */
171       }
172
173       if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
174          return start_job(ua, jcr, rc);
175       }
176       if (strncasecmp(ua->cmd, _("no"), strlen(ua->cmd)) == 0) {
177          break; /* get out of while loop */
178       }
179       ua->send_msg(_("\nBad response: %s. You must answer yes, mod, or no.\n\n"), ua->cmd);
180    }
181
182 bail_out:
183    ua->send_msg(_("Job not run.\n"));
184    if (jcr) {
185       free_jcr(jcr);
186    }
187    return 0;                       /* do not run */
188 }
189
190 static JobId_t start_job(UAContext *ua, JCR *jcr, run_ctx &rc)
191 {
192    JobId_t JobId;
193
194    Dmsg1(100, "Starting JobId=%d\n", rc.jr.JobId);
195    JobId = run_job(jcr);
196    Dmsg4(100, "JobId=%u NewJobId=%d pool=%s priority=%d\n", (int)jcr->JobId,
197          JobId, jcr->pool->name(), jcr->JobPriority);
198    free_jcr(jcr);                  /* release jcr */
199    if (JobId == 0) {
200       ua->error_msg(_("Job failed.\n"));
201    } else {
202       char ed1[50];
203       ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId, ed1));
204    }
205    return JobId;
206 }
207
208 /*
209  * If no job_name defined in the run context, ask
210  *  the user for it.
211  * Then put the job resource in the run context and
212  *  check the access rights.
213  */
214 static bool get_job(UAContext *ua, run_ctx &rc)
215 {
216    if (rc.job_name) {
217       /* Find Job */
218       rc.job = GetJobResWithName(rc.job_name);
219       if (!rc.job) {
220          if (*rc.job_name != 0) {
221             ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
222          }
223          rc.job = select_job_resource(ua);
224       } else {
225          Dmsg1(100, "Found job=%s\n", rc.job_name);
226       }
227    } else if (!rc.job) {
228       ua->send_msg(_("A job name must be specified.\n"));
229       rc.job = select_job_resource(ua);
230    }
231    if (!rc.job) {
232       return false;
233    } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
234       ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
235       return false;
236    }
237    return true;
238 }
239
240 /*
241  * If no pool_name defined in the run context, ask
242  *  the user for it.
243  * Then put the pool resource in the run context and
244  *  check the access rights.
245  */
246 static bool get_pool(UAContext *ua, run_ctx &rc)
247 {
248    if (rc.pool_name) {
249       rc.pool = GetPoolResWithName(rc.pool_name);
250       if (!rc.pool) {
251          if (*rc.pool_name != 0) {
252             ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
253          }
254          rc.pool = select_pool_resource(ua);
255       }
256    } else if (!rc.pool) {
257       rc.pool = rc.job->pool;             /* use default */
258    }
259    if (!rc.pool) {
260       return false;
261    } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
262       ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
263       return false;
264    }
265    Dmsg1(100, "Using Pool=%s\n", rc.pool->name());
266    return true;
267 }
268
269 static bool get_next_pool(UAContext *ua, run_ctx &rc)
270 {
271    if (rc.next_pool_name) {
272       Dmsg1(100, "Have next pool override=%s\n", rc.next_pool_name);
273       rc.next_pool = GetPoolResWithName(rc.next_pool_name);
274       if (!rc.next_pool) {
275          if (*rc.next_pool_name != 0) {
276             ua->warning_msg(_("NextPool \"%s\" not found.\n"), rc.next_pool_name);
277          }
278          rc.next_pool = select_pool_resource(ua);
279       }
280    }
281    if (!rc.next_pool) {
282       rc.next_pool = rc.pool->NextPool;      /* use default */
283    }
284    if (rc.next_pool && !acl_access_ok(ua, Pool_ACL, rc.next_pool->name())) {
285       ua->error_msg(_("No authorization. NextPool \"%s\".\n"), rc.next_pool->name());
286       return false;
287    }
288    if (rc.next_pool) {
289       Dmsg1(100, "Using NextPool=%s\n", NPRT(rc.next_pool->name()));
290    }
291    return true;
292 }
293
294
295 /*
296  * Fill in client data according to what is setup
297  *  in the run context, and make sure the user
298  *  has authorized access to it.
299  */
300 static bool get_client(UAContext *ua, run_ctx &rc)
301 {
302    if (rc.client_name) {
303       rc.client = GetClientResWithName(rc.client_name);
304       if (!rc.client) {
305          if (*rc.client_name != 0) {
306             ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
307          }
308          rc.client = select_client_resource(ua);
309       }
310    } else if (!rc.client) {
311       rc.client = rc.job->client;           /* use default */
312    }
313    if (!rc.client) {
314       return false;
315    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
316       ua->error_msg(_("No authorization. Client \"%s\".\n"),
317                rc.client->name());
318       return false;
319    }
320    Dmsg1(800, "Using client=%s\n", rc.client->name());
321
322    if (rc.restore_client_name) {
323       rc.client = GetClientResWithName(rc.restore_client_name);
324       if (!rc.client) {
325          if (*rc.restore_client_name != 0) {
326             ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
327          }
328          rc.client = select_client_resource(ua);
329       }
330    } else if (!rc.client) {
331       rc.client = rc.job->client;           /* use default */
332    }
333    if (!rc.client) {
334       return false;
335    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
336       ua->error_msg(_("No authorization. Client \"%s\".\n"),
337                rc.client->name());
338       return false;
339    }
340    Dmsg1(800, "Using restore client=%s\n", rc.client->name());
341    return true;
342 }
343
344
345 /*
346  * Fill in fileset data according to what is setup
347  *  in the run context, and make sure the user
348  *  has authorized access to it.
349  */
350 static bool get_fileset(UAContext *ua, run_ctx &rc)
351 {
352    if (rc.fileset_name) {
353       rc.fileset = GetFileSetResWithName(rc.fileset_name);
354       if (!rc.fileset) {
355          ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
356          rc.fileset = select_fileset_resource(ua);
357       }
358    } else if (!rc.fileset) {
359       rc.fileset = rc.job->fileset;           /* use default */
360    }
361    if (!rc.fileset) {
362       return false;
363    } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
364       ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
365                rc.fileset->name());
366       return false;
367    }
368    return true;
369 }
370
371 /*
372  * Fill in storage data according to what is setup
373  *  in the run context, and make sure the user
374  *  has authorized access to it.
375  */
376 static bool get_storage(UAContext *ua, run_ctx &rc)
377 {
378    if (rc.store_name) {
379       rc.store->store = GetStoreResWithName(rc.store_name);
380       pm_strcpy(rc.store->store_source, _("command line"));
381       if (!rc.store->store) {
382          if (*rc.store_name != 0) {
383             ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
384          }
385          rc.store->store = select_storage_resource(ua);
386          pm_strcpy(rc.store->store_source, _("user selection"));
387       }
388    } else if (!rc.store->store) {
389       get_job_storage(rc.store, rc.job, NULL);      /* use default */
390    }
391    if (!rc.store->store) {
392       ua->error_msg(_("No storage specified.\n"));
393       return false;
394    } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
395       ua->error_msg(_("No authorization. Storage \"%s\".\n"),
396                rc.store->store->name());
397       return false;
398    }
399    Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
400    return true;
401 }
402
403 /*
404  * Get and pass back a list of Jobids in rc.jid
405  */
406 static bool get_jobid_list(UAContext *ua, sellist &sl, run_ctx &rc)
407 {
408    int i, JobId;
409    JOB_DBR jr;
410    char *pJobId;
411    bool found = false;
412
413    memset(&jr, 0, sizeof(jr));
414    rc.jid = NULL;
415    /* See if any JobId is specified */
416    if ((i=find_arg(ua, "jobid")) >= 0) {
417       rc.jid = ua->argv[i];
418       if (!rc.jid) {
419          ua->send_msg(_("No JobId specified.\n"));
420          return false;
421       }
422       if (sl.set_string(ua->argv[i], true) < 0 && sl.get_errmsg()) {
423          ua->send_msg("%s", sl.get_errmsg());
424          return false;
425       }
426       return true;
427    }
428
429    /* No JobId list give, so see if he specified a Job */
430    if ((i=find_arg(ua, "job")) >= 0) {
431       rc.job_name = ua->argv[i];
432       if (!get_job(ua, rc)) {
433          ua->send_msg(_("Invalid or no Job name specified.\n"));
434          return false;
435       }
436    }
437    jr.limit = 100;  /* max 100 records */
438    if (rc.job_name) {
439       bstrncpy(jr.Name, rc.job_name, sizeof(jr.Name));
440    } else {
441       jr.Name[0] = 0;
442    }
443    jr.JobStatus = rc.jr.JobStatus;
444    Dmsg2(100, "JobStatus=%d JobName=%s\n", jr.JobStatus, jr.Name);
445    /* rc.JobIds is alist of all records found and printed */
446    rc.JobIds = db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, INCOMPLETE_JOBS);
447    if (!rc.JobIds || rc.JobIds->size()==0 ||
448        !get_selection_list(ua, sl, _("Enter the JobId list to select: "), false)) {
449       return false;
450    }
451    Dmsg1(100, "list=%s\n", sl.get_list());
452    /*
453     * Make sure each item entered is in the JobIds list
454     */
455    while ( (JobId = sl.next()) > 0) {
456       foreach_alist(pJobId, rc.JobIds) {
457          if (JobId == str_to_int64(pJobId)) {
458             pJobId[0] = 0;
459             found = true;
460             break;
461          }
462       }
463       if (!found) {
464          ua->error_msg(_("JobId=%d entered is not in the list.\n"), JobId);
465          return false;
466       }
467    }
468    sl.begin();         /* reset to walk list again */
469    rc.done = false;
470    return true;
471 }
472
473 static bool get_jobid_from_list(UAContext *ua, sellist &sl, run_ctx &rc)
474 {
475    int JobId;
476
477    if (rc.done) {
478       return false;
479    }
480    if ((JobId = sl.next()) < 0) {
481       Dmsg1(100, "sl.next()=%d\n", JobId);
482       rc.done = true;
483       return false;
484    }
485    rc.jr.JobId = rc.JobId = JobId;
486    Dmsg1(100, "Next JobId=%d\n", rc.JobId);
487    if (!db_get_job_record(ua->jcr, ua->db, &rc.jr)) {
488       ua->error_msg(_("Could not get job record for selected JobId=%d. ERR=%s"),
489                     rc.JobId, db_strerror(ua->db));
490       return false;
491    }
492    Dmsg3(100, "Job=%s JobId=%d JobStatus=%c\n", rc.jr.Name, rc.jr.JobId,
493          rc.jr.JobStatus);
494    rc.job_name = rc.jr.Name;
495    if (!get_job(ua, rc)) {
496       return false;
497    }
498    if (!get_pool(ua, rc)) {
499       return false;
500    }
501    get_job_storage(rc.store, rc.job, NULL);
502    rc.client_name = rc.job->client->hdr.name;
503    if (!get_client(ua, rc)) {
504       return false;
505    }
506    if (!get_fileset(ua, rc)) {
507       return false;
508    }
509    if (!get_storage(ua, rc)) {
510       return false;
511    }
512    return true;
513 }
514
515 /*
516  * Restart Canceled or Failed
517  *
518  *  Returns: 0 on error
519  *           JobId if OK
520  *
521  */
522 int restart_cmd(UAContext *ua, const char *cmd)
523 {
524    JCR *jcr = NULL;
525    run_ctx rc;
526    sellist sl;
527    int i, j;
528    bool got_kw = false;
529    struct s_js {
530       const char *status_name;
531       int32_t job_status;
532    };
533    struct s_js kw[] = {
534       {"Canceled",   JS_Canceled},
535       {"Failed",     JS_FatalError},
536       {"All",        0},
537       {NULL,         0}
538    };
539
540    if (!open_client_db(ua)) {
541       return 0;
542    }
543
544    rc.jr.JobStatus = 0;
545    for (i=1; i<ua->argc; i++) {
546       for (j=0; kw[j].status_name; j++) {
547          if (strcasecmp(ua->argk[i], kw[j].status_name) == 0) {
548             rc.jr.JobStatus = kw[j].job_status;
549             got_kw = true;
550             break;
551          }
552       }
553    }
554    if (!got_kw) {  /* Must prompt user */
555       start_prompt(ua, _("You have the following choices:\n"));
556       for (i=0; kw[i].status_name; i++) {
557          add_prompt(ua, kw[i].status_name);
558       }
559       i = do_prompt(ua, NULL, _("Select termination code: "), NULL, 0);
560       if (i < 0) {
561          return 0;
562       }
563       rc.jr.JobStatus = kw[i].job_status;
564    }
565
566    /* type now has what job termination code we want to look at */
567    Dmsg1(100, "Termination code=%c\n", rc.jr.JobStatus);
568
569    /* Get a list of JobIds to restore */
570    if (!get_jobid_list(ua, sl, rc)) {
571       if (rc.JobIds) {
572          rc.JobIds->destroy();
573       }
574       return false;
575    }
576    Dmsg1(100, "list=%s\n", sl.get_list());
577
578    while (get_jobid_from_list(ua, sl, rc)) {
579       /*
580        * Create JCR to run job.  NOTE!!! after this point, free_jcr()
581        *  before returning.
582        */
583       if (!jcr) {
584          jcr = new_jcr(sizeof(JCR), dird_free_jcr);
585          set_jcr_defaults(jcr, rc.job);
586          jcr->unlink_bsr = ua->jcr->unlink_bsr;    /* copy unlink flag from caller */
587          ua->jcr->unlink_bsr = false;
588       }
589
590       if (!set_run_context_in_jcr(ua, jcr, rc)) {
591          break;
592       }
593       start_job(ua, jcr, rc);
594       jcr = NULL;
595    }
596
597    if (jcr) {
598       free_jcr(jcr);
599    }
600    if (rc.JobIds) {
601       rc.JobIds->destroy();
602    }
603    return 0;                       /* do not run */
604 }
605
606
607 int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc)
608 {
609    int i, opt;
610
611    /*
612     * At user request modify parameters of job to be run.
613     */
614    if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0){
615       FILE *fd;
616
617       start_prompt(ua, _("Parameters to modify:\n"));
618       add_prompt(ua, _("Level"));            /* 0 */
619       add_prompt(ua, _("Storage"));          /* 1 */
620       add_prompt(ua, _("Job"));              /* 2 */
621       add_prompt(ua, _("FileSet"));          /* 3 */
622       if (jcr->getJobType() == JT_RESTORE) {
623          add_prompt(ua, _("Restore Client"));   /* 4 */
624       } else {
625          add_prompt(ua, _("Client"));        /* 4 */
626       }
627       add_prompt(ua, _("When"));             /* 5 */
628       add_prompt(ua, _("Priority"));         /* 6 */
629       if (jcr->getJobType() == JT_BACKUP ||
630           jcr->getJobType() == JT_COPY ||
631           jcr->getJobType() == JT_MIGRATE ||
632           jcr->getJobType() == JT_VERIFY) {
633          add_prompt(ua, _("Pool"));          /* 7 */
634          if ((jcr->getJobType() == JT_BACKUP &&   /* Virtual full */
635               jcr->is_JobLevel(L_VIRTUAL_FULL)) ||
636              jcr->getJobType() == JT_COPY ||
637              jcr->getJobType() == JT_MIGRATE) {
638             add_prompt(ua, _("NextPool"));          /* 8 */
639          } else if (jcr->getJobType() == JT_VERIFY) {
640             add_prompt(ua, _("Verify Job"));  /* 8 */
641          }
642       } else if (jcr->getJobType() == JT_RESTORE) {
643          add_prompt(ua, _("Bootstrap"));     /* 7 */
644          add_prompt(ua, _("Where"));         /* 8 */
645          add_prompt(ua, _("File Relocation"));/* 9 */
646          add_prompt(ua, _("Replace"));       /* 10 */
647          add_prompt(ua, _("JobId"));         /* 11 */
648       }
649       if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
650          add_prompt(ua, _("Plugin Options")); /* 12 */
651       }
652       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
653       case 0:
654          /* Level */
655          select_job_level(ua, jcr);
656          goto try_again;
657       case 1:
658          /* Storage */
659          rc.store->store = select_storage_resource(ua);
660          if (rc.store->store) {
661             pm_strcpy(rc.store->store_source, _("user selection"));
662             set_rwstorage(jcr, rc.store);
663             goto try_again;
664          }
665          break;
666       case 2:
667          /* Job */
668          rc.job = select_job_resource(ua);
669          if (rc.job) {
670             jcr->job = rc.job;
671             set_jcr_defaults(jcr, rc.job);
672             goto try_again;
673          }
674          break;
675       case 3:
676          /* FileSet */
677          rc.fileset = select_fileset_resource(ua);
678          if (rc.fileset) {
679             jcr->fileset = rc.fileset;
680             goto try_again;
681          }
682          break;
683       case 4:
684          /* Client */
685          rc.client = select_client_resource(ua);
686          if (rc.client) {
687             jcr->client = rc.client;
688             goto try_again;
689          }
690          break;
691       case 5:
692          /* When */
693          if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
694             break;
695          }
696          if (ua->cmd[0] == 0) {
697             jcr->sched_time = time(NULL);
698          } else {
699             jcr->sched_time = str_to_utime(ua->cmd);
700             if (jcr->sched_time == 0) {
701                ua->send_msg(_("Invalid time, using current time.\n"));
702                jcr->sched_time = time(NULL);
703             }
704          }
705          goto try_again;
706       case 6:
707          /* Priority */
708          if (!get_pint(ua, _("Enter new Priority: "))) {
709             break;
710          }
711          if (ua->pint32_val == 0) {
712             ua->send_msg(_("Priority must be a positive integer.\n"));
713          } else {
714             jcr->JobPriority = ua->pint32_val;
715          }
716          goto try_again;
717       case 7:
718          /* Pool or Bootstrap depending on JobType */
719          if (jcr->getJobType() == JT_BACKUP ||
720              jcr->getJobType() == JT_COPY ||
721              jcr->getJobType() == JT_MIGRATE ||
722              jcr->getJobType() == JT_VERIFY) {      /* Pool */
723             rc.pool = select_pool_resource(ua);
724             if (rc.pool) {
725                jcr->pool = rc.pool;
726                Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
727                goto try_again;
728             }
729             break;
730          }
731
732          /* Bootstrap */
733          if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
734             break;
735          }
736          if (jcr->RestoreBootstrap) {
737             free(jcr->RestoreBootstrap);
738             jcr->RestoreBootstrap = NULL;
739          }
740          if (ua->cmd[0] != 0) {
741             jcr->RestoreBootstrap = bstrdup(ua->cmd);
742             fd = fopen(jcr->RestoreBootstrap, "rb");
743             if (!fd) {
744                berrno be;
745                ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
746                   jcr->RestoreBootstrap, be.bstrerror());
747                free(jcr->RestoreBootstrap);
748                jcr->RestoreBootstrap = NULL;
749             } else {
750                fclose(fd);
751             }
752          }
753          goto try_again;
754       case 8:
755          /* Specify Next Pool */
756          if ((jcr->getJobType() == JT_BACKUP &&   /* Virtual full */
757               jcr->is_JobLevel(L_VIRTUAL_FULL)) ||
758              jcr->getJobType() == JT_COPY ||
759              jcr->getJobType() == JT_MIGRATE) {
760             rc.next_pool = select_pool_resource(ua);
761             if (rc.next_pool) {
762                jcr->next_pool = rc.next_pool;
763                pm_strcpy(jcr->next_pool_source, _("Command input"));
764                goto try_again;
765             }
766          }
767          /* Verify Job */
768          if (jcr->getJobType() == JT_VERIFY) {
769             rc.verify_job = select_job_resource(ua);
770             if (rc.verify_job) {
771               jcr->verify_job = rc.verify_job;
772             }
773             goto try_again;
774          }
775          /* Where */
776          if (!get_cmd(ua, _("Please enter the full path prefix for restore (/ for none): "))) {
777             break;
778          }
779          if (jcr->RegexWhere) { /* cannot use regexwhere and where */
780             free(jcr->RegexWhere);
781             jcr->RegexWhere = NULL;
782          }
783          if (jcr->where) {
784             free(jcr->where);
785             jcr->where = NULL;
786          }
787          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
788             ua->cmd[0] = 0;
789          }
790          jcr->where = bstrdup(ua->cmd);
791          goto try_again;
792       case 9:
793          /* File relocation */
794          select_where_regexp(ua, jcr);
795          goto try_again;
796       case 10:
797          /* Replace */
798          start_prompt(ua, _("Replace:\n"));
799          for (i=0; ReplaceOptions[i].name; i++) {
800             add_prompt(ua, ReplaceOptions[i].name);
801          }
802          opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
803          if (opt >=  0) {
804             rc.replace = ReplaceOptions[opt].name;
805             jcr->replace = ReplaceOptions[opt].token;
806          }
807          goto try_again;
808       case 11:
809          /* JobId */
810          rc.jid = NULL;                  /* force reprompt */
811          jcr->RestoreJobId = 0;
812          if (jcr->RestoreBootstrap) {
813             ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
814          }
815          goto try_again;
816       case 12:
817          goto try_again;
818       case -1:                        /* error or cancel */
819          goto bail_out;
820       default:
821          goto try_again;
822       }
823       goto bail_out;
824    }
825    return 1;
826
827 bail_out:
828    return -1;
829 try_again:
830    return 0;
831 }
832
833 /*
834  * Put the run context that we have at this point into the JCR.
835  * That allows us to re-ask for the run context.
836  * This subroutine can be called multiple times, so it
837  *  must keep any prior settings.
838  */
839 static bool set_run_context_in_jcr(UAContext *ua, JCR *jcr, run_ctx &rc)
840 {
841    int i;
842
843    jcr->verify_job = rc.verify_job;
844    jcr->previous_job = rc.previous_job;
845    jcr->pool = rc.pool;
846    jcr->next_pool = rc.next_pool;
847    if (rc.pool_name) {
848       pm_strcpy(jcr->pool_source, _("Command input"));
849    } else if (jcr->pool != jcr->job->pool) {
850       pm_strcpy(jcr->pool_source, _("User input"));
851    }
852    if (rc.next_pool_name) {
853       pm_strcpy(jcr->next_pool_source, _("Command input"));
854    } else if (jcr->next_pool != jcr->pool->NextPool) {
855       pm_strcpy(jcr->next_pool_source, _("User input"));
856    }
857
858    set_rwstorage(jcr, rc.store);
859    jcr->client = rc.client;
860    pm_strcpy(jcr->client_name, rc.client->name());
861    if (rc.media_type) {
862       if (!jcr->media_type) {
863          jcr->media_type = get_pool_memory(PM_NAME);
864       }
865       pm_strcpy(jcr->media_type, rc.media_type);
866    }
867    jcr->fileset = rc.fileset;
868    jcr->ExpectedFiles = rc.files;
869    if (rc.catalog) {
870       jcr->catalog = rc.catalog;
871       pm_strcpy(jcr->catalog_source, _("User input"));
872    }
873
874    pm_strcpy(jcr->comment, rc.comment);
875
876    if (rc.where) {
877       if (jcr->where) {
878          free(jcr->where);
879       }
880       jcr->where = bstrdup(rc.where);
881       rc.where = NULL;
882    }
883
884    if (rc.regexwhere) {
885       if (jcr->RegexWhere) {
886          free(jcr->RegexWhere);
887       }
888       jcr->RegexWhere = bstrdup(rc.regexwhere);
889       rc.regexwhere = NULL;
890    }
891
892    if (rc.when) {
893       jcr->sched_time = str_to_utime(rc.when);
894       if (jcr->sched_time == 0) {
895          ua->send_msg(_("Invalid time, using current time.\n"));
896          jcr->sched_time = time(NULL);
897       }
898       rc.when = NULL;
899    }
900
901    if (rc.bootstrap) {
902       if (jcr->RestoreBootstrap) {
903          free(jcr->RestoreBootstrap);
904       }
905       jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
906       rc.bootstrap = NULL;
907    }
908
909    if (rc.plugin_options) {
910       if (jcr->plugin_options) {
911          free(jcr->plugin_options);
912       }
913       jcr->plugin_options = bstrdup(rc.plugin_options);
914       rc.plugin_options = NULL;
915    }
916
917    if (rc.replace) {
918       jcr->replace = 0;
919       for (i=0; ReplaceOptions[i].name; i++) {
920          if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
921             jcr->replace = ReplaceOptions[i].token;
922          }
923       }
924       if (!jcr->replace) {
925          ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
926          return false;
927       }
928    } else if (rc.job->replace) {
929       jcr->replace = rc.job->replace;
930    } else {
931       jcr->replace = REPLACE_ALWAYS;
932    }
933    rc.replace = NULL;
934
935    if (rc.Priority) {
936       jcr->JobPriority = rc.Priority;
937       rc.Priority = 0;
938    }
939
940    if (rc.since) {
941       if (!jcr->stime) {
942          jcr->stime = get_pool_memory(PM_MESSAGE);
943       }
944       pm_strcpy(jcr->stime, rc.since);
945       rc.since = NULL;
946    }
947
948    if (rc.cloned) {
949       jcr->cloned = rc.cloned;
950       rc.cloned = false;
951    }
952
953    /* If pool changed, update migration write storage */
954    if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
955       (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL))) {
956       if (!set_mac_wstorage(ua, jcr, rc.pool, rc.next_pool,
957             _("Storage from NextPool override"))) {
958          return false;
959       }
960    }
961    rc.replace = ReplaceOptions[0].name;
962    for (i=0; ReplaceOptions[i].name; i++) {
963       if (ReplaceOptions[i].token == (int)jcr->replace) {
964          rc.replace = ReplaceOptions[i].name;
965       }
966    }
967    if (rc.level_name) {
968       if (!get_level_from_name(jcr, rc.level_name)) {
969          ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
970          return false;
971       }
972       rc.level_name = NULL;
973    }
974    if (rc.jid) {
975       /* Note, this is also MigrateJobId and a VerifyJobId */
976       jcr->RestoreJobId = str_to_int64(rc.jid);
977
978       /* Copy also this parameter for VirtualFull in jcr->JobIds */
979       if (!jcr->JobIds) {
980          jcr->JobIds = get_pool_memory(PM_FNAME);
981       }
982       pm_strcpy(jcr->JobIds, rc.jid);
983       jcr->use_all_JobIds = rc.alljobid; /* if we found the "alljobid=" kw */
984       rc.alljobid = false;
985       rc.jid = 0;
986    }
987
988    /* Some options are not available through the menu
989     * TODO: Add an advanced menu?
990     */
991    if (rc.spool_data_set) {
992       jcr->spool_data = rc.spool_data;
993    }
994
995    if (rc.accurate_set) {
996       jcr->accurate = rc.accurate;
997    }
998
999    /* Used by migration jobs that can have the same name,
1000     * but can run at the same time
1001     */
1002    if (rc.ignoreduplicatecheck_set) {
1003       jcr->IgnoreDuplicateJobChecking = rc.ignoreduplicatecheck;
1004    }
1005
1006    return true;
1007 }
1008
1009 static void select_where_regexp(UAContext *ua, JCR *jcr)
1010 {
1011    alist *regs;
1012    char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
1013    strip_prefix = add_suffix = rwhere = add_prefix = NULL;
1014
1015 try_again_reg:
1016    ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
1017                 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
1018
1019    start_prompt(ua, _("This will replace your current Where value\n"));
1020    add_prompt(ua, _("Strip prefix"));                /* 0 */
1021    add_prompt(ua, _("Add prefix"));                  /* 1 */
1022    add_prompt(ua, _("Add file suffix"));             /* 2 */
1023    add_prompt(ua, _("Enter a regexp"));              /* 3 */
1024    add_prompt(ua, _("Test filename manipulation"));  /* 4 */
1025    add_prompt(ua, _("Use this ?"));                  /* 5 */
1026
1027    switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
1028    case 0:
1029       /* Strip prefix */
1030       if (get_cmd(ua, _("Please enter the path prefix to strip: "))) {
1031          if (strip_prefix) bfree(strip_prefix);
1032          strip_prefix = bstrdup(ua->cmd);
1033       }
1034
1035       goto try_again_reg;
1036    case 1:
1037       /* Add prefix */
1038       if (get_cmd(ua, _("Please enter the path prefix to add (/ for none): "))) {
1039          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
1040             ua->cmd[0] = 0;
1041          }
1042
1043          if (add_prefix) bfree(add_prefix);
1044          add_prefix = bstrdup(ua->cmd);
1045       }
1046       goto try_again_reg;
1047    case 2:
1048       /* Add suffix */
1049       if (get_cmd(ua, _("Please enter the file suffix to add: "))) {
1050          if (add_suffix) bfree(add_suffix);
1051          add_suffix = bstrdup(ua->cmd);
1052       }
1053       goto try_again_reg;
1054    case 3:
1055       /* Add rwhere */
1056       if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
1057          if (rwhere) bfree(rwhere);
1058          rwhere = bstrdup(ua->cmd);
1059       }
1060
1061       goto try_again_reg;
1062    case 4:
1063       /* Test regexp */
1064       char *result;
1065       char *regexp;
1066
1067       if (rwhere && rwhere[0] != '\0') {
1068          regs = get_bregexps(rwhere);
1069          ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
1070       } else {
1071          int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
1072          regexp = (char *) bmalloc (len * sizeof(char));
1073          bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
1074          regs = get_bregexps(regexp);
1075          ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
1076                       NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
1077
1078          bfree(regexp);
1079       }
1080
1081       if (!regs) {
1082          ua->send_msg(_("Cannot use your regexp\n"));
1083          goto try_again_reg;
1084       }
1085       ua->send_msg(_("Enter a period (.) to stop this test\n"));
1086       while (get_cmd(ua, _("Please enter filename to test: "))) {
1087          apply_bregexps(ua->cmd, regs, &result);
1088          ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
1089       }
1090       free_bregexps(regs);
1091       delete regs;
1092       goto try_again_reg;
1093
1094    case 5:
1095       /* OK */
1096       break;
1097    case -1:                        /* error or cancel */
1098       goto bail_out_reg;
1099    default:
1100       goto try_again_reg;
1101    }
1102
1103    /* replace the existing where */
1104    if (jcr->where) {
1105       bfree(jcr->where);
1106       jcr->where = NULL;
1107    }
1108
1109    /* replace the existing regexwhere */
1110    if (jcr->RegexWhere) {
1111       bfree(jcr->RegexWhere);
1112       jcr->RegexWhere = NULL;
1113    }
1114
1115    if (rwhere) {
1116       jcr->RegexWhere = bstrdup(rwhere);
1117    } else if (strip_prefix || add_prefix || add_suffix) {
1118       int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
1119       jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
1120       bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
1121    }
1122
1123    regs = get_bregexps(jcr->RegexWhere);
1124    if (regs) {
1125       free_bregexps(regs);
1126       delete regs;
1127    } else {
1128       if (jcr->RegexWhere) {
1129          bfree(jcr->RegexWhere);
1130          jcr->RegexWhere = NULL;
1131       }
1132       ua->send_msg(_("Cannot use your regexp.\n"));
1133    }
1134
1135 bail_out_reg:
1136    if (strip_prefix) bfree(strip_prefix);
1137    if (add_prefix)   bfree(add_prefix);
1138    if (add_suffix)   bfree(add_suffix);
1139    if (rwhere)       bfree(rwhere);
1140 }
1141
1142 static void select_job_level(UAContext *ua, JCR *jcr)
1143 {
1144    if (jcr->getJobType() == JT_BACKUP) {
1145       start_prompt(ua, _("Levels:\n"));
1146 //    add_prompt(ua, _("Base"));
1147       add_prompt(ua, _("Full"));
1148       add_prompt(ua, _("Incremental"));
1149       add_prompt(ua, _("Differential"));
1150       add_prompt(ua, _("Since"));
1151       add_prompt(ua, _("VirtualFull"));
1152       switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
1153 //    case 0:
1154 //       jcr->JobLevel = L_BASE;
1155 //       break;
1156       case 0:
1157          jcr->setJobLevel(L_FULL);
1158          break;
1159       case 1:
1160          jcr->setJobLevel(L_INCREMENTAL);
1161          break;
1162       case 2:
1163          jcr->setJobLevel(L_DIFFERENTIAL);
1164          break;
1165       case 3:
1166          jcr->setJobLevel(L_SINCE);
1167          break;
1168       case 4:
1169          jcr->setJobLevel(L_VIRTUAL_FULL);
1170          break;
1171       default:
1172          break;
1173       }
1174    } else if (jcr->getJobType() == JT_VERIFY) {
1175       start_prompt(ua, _("Levels:\n"));
1176       add_prompt(ua, _("Initialize Catalog"));
1177       add_prompt(ua, _("Verify Catalog"));
1178       add_prompt(ua, _("Verify Volume to Catalog"));
1179       add_prompt(ua, _("Verify Disk to Catalog"));
1180       add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
1181       switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
1182       case 0:
1183          jcr->setJobLevel(L_VERIFY_INIT);
1184          break;
1185       case 1:
1186          jcr->setJobLevel(L_VERIFY_CATALOG);
1187          break;
1188       case 2:
1189          jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1190          break;
1191       case 3:
1192          jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
1193          break;
1194       case 4:
1195          jcr->setJobLevel(L_VERIFY_DATA);
1196          break;
1197       default:
1198          break;
1199       }
1200    } else {
1201       ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
1202    }
1203    return;
1204 }
1205
1206 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
1207    char *jid, const char *replace, char *client_name)
1208 {
1209    char ec1[30];
1210    char dt[MAX_TIME_LENGTH];
1211
1212    Dmsg1(800, "JobType=%c\n", jcr->getJobType());
1213    switch (jcr->getJobType()) {
1214    case JT_ADMIN:
1215       if (ua->api) {
1216          ua->signal(BNET_RUN_CMD);
1217          ua->send_msg("Type: Admin\n"
1218                      "Title: Run Admin Job\n"
1219                      "JobName:  %s\n"
1220                      "FileSet:  %s\n"
1221                      "Client:   %s\n"
1222                      "Storage:  %s\n"
1223                      "When:     %s\n"
1224                      "Priority: %d\n",
1225                  job->name(),
1226                  jcr->fileset->name(),
1227                  NPRT(jcr->client->name()),
1228                  jcr->wstore?jcr->wstore->name():"*None*",
1229                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1230                  jcr->JobPriority);
1231       } else {
1232          ua->send_msg(_("Run Admin Job\n"
1233                      "JobName:  %s\n"
1234                      "FileSet:  %s\n"
1235                      "Client:   %s\n"
1236                      "Storage:  %s\n"
1237                      "When:     %s\n"
1238                      "Priority: %d\n"),
1239                  job->name(),
1240                  jcr->fileset->name(),
1241                  NPRT(jcr->client->name()),
1242                  jcr->wstore?jcr->wstore->name():"*None*",
1243                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1244                  jcr->JobPriority);
1245       }
1246       jcr->setJobLevel(L_FULL);
1247       break;
1248    case JT_BACKUP:
1249    case JT_VERIFY:
1250       char next_pool[MAX_NAME_LENGTH + 50];
1251       next_pool[0] = 0;
1252       if (jcr->getJobType() == JT_BACKUP) {
1253          if (ua->api) {
1254             ua->signal(BNET_RUN_CMD);
1255             if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
1256                bsnprintf(next_pool, sizeof(next_pool), "NextPool: %s\n",
1257                   jcr->next_pool ? jcr->next_pool->name() : "*None*");
1258             }
1259             ua->send_msg("Type: Backup\n"
1260                         "Title: Run Backup Job\n"
1261                         "JobName:  %s\n"
1262                         "Level:    %s\n"
1263                         "Client:   %s\n"
1264                         "FileSet:  %s\n"
1265                         "Pool:     %s\n"
1266                         "%s"
1267                         "Storage:  %s\n"
1268                         "When:     %s\n"
1269                         "Priority: %d\n",
1270                  job->name(),
1271                  level_to_str(jcr->getJobLevel()),
1272                  jcr->client->name(),
1273                  jcr->fileset->name(),
1274                  NPRT(jcr->pool->name()),
1275                  next_pool,
1276                  jcr->wstore?jcr->wstore->name():"*None*",
1277                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1278                  jcr->JobPriority);
1279          } else {
1280             if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
1281                bsnprintf(next_pool, sizeof(next_pool),
1282                   "NextPool: %s (From %s)\n",
1283                   jcr->next_pool ? jcr->next_pool->name() : "*None*",
1284                   jcr->next_pool_source);
1285             }
1286             ua->send_msg(_("Run Backup job\n"
1287                         "JobName:  %s\n"
1288                         "Level:    %s\n"
1289                         "Client:   %s\n"
1290                         "FileSet:  %s\n"
1291                         "Pool:     %s (From %s)\n"
1292                         "%s"
1293                         "Storage:  %s (From %s)\n"
1294                         "When:     %s\n"
1295                         "Priority: %d\n"),
1296                  job->name(),
1297                  level_to_str(jcr->getJobLevel()),
1298                  jcr->client->name(),
1299                  jcr->fileset->name(),
1300                  NPRT(jcr->pool->name()), jcr->pool_source,
1301                  next_pool,
1302                  jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1303                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1304                  jcr->JobPriority);
1305          }
1306       } else {  /* JT_VERIFY */
1307          JOB_DBR jr;
1308          const char *Name;
1309          if (jcr->verify_job) {
1310             Name = jcr->verify_job->name();
1311          } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
1312             memset(&jr, 0, sizeof(jr));
1313             jr.JobId = jcr->RestoreJobId;
1314             if (!db_get_job_record(jcr, ua->db, &jr)) {
1315                ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
1316                     db_strerror(ua->db));
1317                return false;
1318             }
1319             Name = jr.Job;
1320          } else {
1321             Name = "";
1322          }
1323          if (!verify_list) {
1324             verify_list = job->WriteVerifyList;
1325          }
1326          if (!verify_list) {
1327             verify_list = "";
1328          }
1329          if (ua->api) {
1330             ua->signal(BNET_RUN_CMD);
1331             ua->send_msg("Type: Verify\n"
1332                         "Title: Run Verify Job\n"
1333                         "JobName:     %s\n"
1334                         "Level:       %s\n"
1335                         "Client:      %s\n"
1336                         "FileSet:     %s\n"
1337                         "Pool:        %s (From %s)\n"
1338                         "Storage:     %s (From %s)\n"
1339                         "Verify Job:  %s\n"
1340                         "Verify List: %s\n"
1341                         "When:        %s\n"
1342                         "Priority:    %d\n",
1343               job->name(),
1344               level_to_str(jcr->getJobLevel()),
1345               jcr->client->name(),
1346               jcr->fileset->name(),
1347               NPRT(jcr->pool->name()), jcr->pool_source,
1348               jcr->rstore->name(), jcr->rstore_source,
1349               Name,
1350               verify_list,
1351               bstrutime(dt, sizeof(dt), jcr->sched_time),
1352               jcr->JobPriority);
1353          } else {
1354             ua->send_msg(_("Run Verify Job\n"
1355                         "JobName:     %s\n"
1356                         "Level:       %s\n"
1357                         "Client:      %s\n"
1358                         "FileSet:     %s\n"
1359                         "Pool:        %s (From %s)\n"
1360                         "Storage:     %s (From %s)\n"
1361                         "Verify Job:  %s\n"
1362                         "Verify List: %s\n"
1363                         "When:        %s\n"
1364                         "Priority:    %d\n"),
1365               job->name(),
1366               level_to_str(jcr->getJobLevel()),
1367               jcr->client->name(),
1368               jcr->fileset->name(),
1369               NPRT(jcr->pool->name()), jcr->pool_source,
1370               jcr->rstore->name(), jcr->rstore_source,
1371               Name,
1372               verify_list,
1373               bstrutime(dt, sizeof(dt), jcr->sched_time),
1374               jcr->JobPriority);
1375          }
1376       }
1377       break;
1378    case JT_RESTORE:
1379       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
1380          if (jid) {
1381             jcr->RestoreJobId = str_to_int64(jid);
1382          } else {
1383             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
1384                return false;
1385             }
1386             jcr->RestoreJobId = ua->int64_val;
1387          }
1388       }
1389       jcr->setJobLevel(L_FULL);      /* default level */
1390       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
1391       if (jcr->RestoreJobId == 0) {
1392          /* RegexWhere is take before RestoreWhere */
1393          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1394             if (ua->api) {
1395                ua->signal(BNET_RUN_CMD);
1396                ua->send_msg("Type: Restore\n"
1397                         "Title: Run Restore Job\n"
1398                         "JobName:         %s\n"
1399                         "Bootstrap:       %s\n"
1400                         "RegexWhere:      %s\n"
1401                         "Replace:         %s\n"
1402                         "FileSet:         %s\n"
1403                         "Backup Client:   %s\n"
1404                         "Restore Client:  %s\n"
1405                         "Storage:         %s\n"
1406                         "When:            %s\n"
1407                         "Catalog:         %s\n"
1408                         "Priority:        %d\n",
1409                  job->name(),
1410                  NPRT(jcr->RestoreBootstrap),
1411                  jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
1412                  replace,
1413                  jcr->fileset->name(),
1414                  client_name,
1415                  jcr->client->name(),
1416                  jcr->rstore->name(),
1417                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1418                  jcr->catalog->name(),
1419                  jcr->JobPriority);
1420             } else {
1421                ua->send_msg(_("Run Restore job\n"
1422                         "JobName:         %s\n"
1423                         "Bootstrap:       %s\n"
1424                         "RegexWhere:      %s\n"
1425                         "Replace:         %s\n"
1426                         "FileSet:         %s\n"
1427                         "Backup Client:   %s\n"
1428                         "Restore Client:  %s\n"
1429                         "Storage:         %s\n"
1430                         "When:            %s\n"
1431                         "Catalog:         %s\n"
1432                         "Priority:        %d\n"),
1433                  job->name(),
1434                  NPRT(jcr->RestoreBootstrap),
1435                  jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
1436                  replace,
1437                  jcr->fileset->name(),
1438                  client_name,
1439                  jcr->client->name(),
1440                  jcr->rstore->name(),
1441                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1442                  jcr->catalog->name(),
1443                  jcr->JobPriority);
1444             }
1445          } else {
1446             if (ua->api) {
1447                ua->signal(BNET_RUN_CMD);
1448                ua->send_msg("Type: Restore\n"
1449                         "Title: Run Restore job\n"
1450                         "JobName:         %s\n"
1451                         "Bootstrap:       %s\n"
1452                         "Where:           %s\n"
1453                         "Replace:         %s\n"
1454                         "FileSet:         %s\n"
1455                         "Backup Client:   %s\n"
1456                         "Restore Client:  %s\n"
1457                         "Storage:         %s\n"
1458                         "When:            %s\n"
1459                         "Catalog:         %s\n"
1460                         "Priority:        %d\n",
1461                  job->name(),
1462                  NPRT(jcr->RestoreBootstrap),
1463                  jcr->where?jcr->where:NPRT(job->RestoreWhere),
1464                  replace,
1465                  jcr->fileset->name(),
1466                  client_name,
1467                  jcr->client->name(),
1468                  jcr->rstore->name(),
1469                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1470                  jcr->catalog->name(),
1471                  jcr->JobPriority);
1472             } else {
1473                ua->send_msg(_("Run Restore job\n"
1474                         "JobName:         %s\n"
1475                         "Bootstrap:       %s\n"
1476                         "Where:           %s\n"
1477                         "Replace:         %s\n"
1478                         "FileSet:         %s\n"
1479                         "Backup Client:   %s\n"
1480                         "Restore Client:  %s\n"
1481                         "Storage:         %s\n"
1482                         "When:            %s\n"
1483                         "Catalog:         %s\n"
1484                         "Priority:        %d\n"),
1485                  job->name(),
1486                  NPRT(jcr->RestoreBootstrap),
1487                  jcr->where?jcr->where:NPRT(job->RestoreWhere),
1488                  replace,
1489                  jcr->fileset->name(),
1490                  client_name,
1491                  jcr->client->name(),
1492                  jcr->rstore->name(),
1493                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1494                  jcr->catalog->name(),
1495                  jcr->JobPriority);
1496             }
1497          }
1498
1499       } else {
1500          /* ***FIXME*** This needs to be fixed for bat */
1501          if (ua->api) ua->signal(BNET_RUN_CMD);
1502          ua->send_msg(_("Run Restore job\n"
1503                         "JobName:    %s\n"
1504                         "Bootstrap:  %s\n"),
1505                       job->name(),
1506                       NPRT(jcr->RestoreBootstrap));
1507
1508          /* RegexWhere is take before RestoreWhere */
1509          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1510             ua->send_msg(_("RegexWhere: %s\n"),
1511                          jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
1512          } else {
1513             ua->send_msg(_("Where:      %s\n"),
1514                          jcr->where?jcr->where:NPRT(job->RestoreWhere));
1515          }
1516
1517          ua->send_msg(_("Replace:         %s\n"
1518                         "Client:          %s\n"
1519                         "Storage:         %s\n"
1520                         "JobId:           %s\n"
1521                         "When:            %s\n"
1522                         "Catalog:         %s\n"
1523                         "Priority:        %d\n"),
1524               replace,
1525               jcr->client->name(),
1526               jcr->rstore->name(),
1527               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
1528               bstrutime(dt, sizeof(dt), jcr->sched_time),
1529               jcr->catalog->name(),
1530               jcr->JobPriority);
1531        }
1532       break;
1533    case JT_COPY:
1534    case JT_MIGRATE:
1535       char *prt_type;
1536       jcr->setJobLevel(L_FULL);      /* default level */
1537       if (ua->api) {
1538          ua->signal(BNET_RUN_CMD);
1539          if (jcr->getJobType() == JT_COPY) {
1540             prt_type = (char *)"Type: Copy\nTitle: Run Copy Job\n";
1541          } else {
1542             prt_type = (char *)"Type: Migration\nTitle: Run Migration Job\n";
1543          }
1544          ua->send_msg("%s"
1545                      "JobName:       %s\n"
1546                      "Bootstrap:     %s\n"
1547                      "Client:        %s\n"
1548                      "FileSet:       %s\n"
1549                      "Pool:          %s\n"
1550                      "NextPool:      %s\n"
1551                      "Read Storage:  %s\n"
1552                      "Write Storage: %s\n"
1553                      "JobId:         %s\n"
1554                      "When:          %s\n"
1555                      "Catalog:       %s\n"
1556                      "Priority:      %d\n",
1557            prt_type,
1558            job->name(),
1559            NPRT(jcr->RestoreBootstrap),
1560            jcr->client->name(),
1561            jcr->fileset->name(),
1562            NPRT(jcr->pool->name()),
1563            jcr->next_pool?jcr->next_pool->name():"*None*",
1564            jcr->rstore->name(),
1565            jcr->wstore?jcr->wstore->name():"*None*",
1566            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1567            bstrutime(dt, sizeof(dt), jcr->sched_time),
1568            jcr->catalog->name(),
1569            jcr->JobPriority);
1570       } else {
1571          if (jcr->getJobType() == JT_COPY) {
1572             prt_type = _("Run Copy job\n");
1573          } else {
1574             prt_type = _("Run Migration job\n");
1575          }
1576          ua->send_msg("%s"
1577                      "JobName:       %s\n"
1578                      "Bootstrap:     %s\n"
1579                      "Client:        %s\n"
1580                      "FileSet:       %s\n"
1581                      "Pool:          %s (From %s)\n"
1582                      "NextPool:      %s (From %s)\n"
1583                      "Read Storage:  %s (From %s)\n"
1584                      "Write Storage: %s (From %s)\n"
1585                      "JobId:         %s\n"
1586                      "When:          %s\n"
1587                      "Catalog:       %s\n"
1588                      "Priority:      %d\n",
1589            prt_type,
1590            job->name(),
1591            NPRT(jcr->RestoreBootstrap),
1592            jcr->client->name(),
1593            jcr->fileset->name(),
1594            NPRT(jcr->pool->name()), jcr->pool_source,
1595            jcr->next_pool?jcr->next_pool->name():"*None*",
1596                NPRT(jcr->next_pool_source),
1597            jcr->rstore->name(), jcr->rstore_source,
1598            jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1599            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1600            bstrutime(dt, sizeof(dt), jcr->sched_time),
1601            jcr->catalog->name(),
1602            jcr->JobPriority);
1603       }
1604       break;
1605    default:
1606       ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1607       return false;
1608    }
1609    return true;
1610 }
1611
1612
1613 static bool scan_run_command_line_arguments(UAContext *ua, run_ctx &rc)
1614 {
1615    bool kw_ok;
1616    int i, j;
1617    static const char *kw[] = {        /* command line arguments */
1618       "alljobid",                     /* 0 Used in a switch() */
1619       "jobid",                        /* 1 */
1620       "client",                       /* 2 */
1621       "fd",                           /* 3 */
1622       "fileset",                      /* 4 */
1623       "level",                        /* 5 */
1624       "storage",                      /* 6 */
1625       "sd",                           /* 7 */
1626       "regexwhere",                   /* 8 where string as a bregexp */
1627       "where",                        /* 9 */
1628       "bootstrap",                    /* 10 */
1629       "replace",                      /* 11 */
1630       "when",                         /* 12 */
1631       "priority",                     /* 13 */
1632       "yes",                          /* 14  -- if you change this change YES_POS too */
1633       "verifyjob",                    /* 15 */
1634       "files",                        /* 16 number of files to restore */
1635       "catalog",                      /* 17 override catalog */
1636       "since",                        /* 18 since */
1637       "cloned",                       /* 19 cloned */
1638       "verifylist",                   /* 20 verify output list */
1639       "migrationjob",                 /* 21 migration job name */
1640       "pool",                         /* 22 */
1641       "backupclient",                 /* 23 */
1642       "restoreclient",                /* 24 */
1643       "pluginoptions",                /* 25 */
1644       "spooldata",                    /* 26 */
1645       "comment",                      /* 27 */
1646       "ignoreduplicatecheck",         /* 28 */
1647       "accurate",                     /* 29 */
1648       "job",                          /* 30 */
1649       "mediatype",                    /* 31 */
1650       "nextpool",                     /* 32 override next pool name */
1651       NULL
1652    };
1653
1654 #define YES_POS 14
1655
1656    rc.catalog_name = NULL;
1657    rc.job_name = NULL;
1658    rc.pool_name = NULL;
1659    rc.next_pool_name = NULL;
1660    rc.store_name = NULL;
1661    rc.client_name = NULL;
1662    rc.media_type = NULL;
1663    rc.restore_client_name = NULL;
1664    rc.fileset_name = NULL;
1665    rc.verify_job_name = NULL;
1666    rc.previous_job_name = NULL;
1667    rc.accurate_set = false;
1668    rc.spool_data_set = false;
1669    rc.ignoreduplicatecheck = false;
1670    rc.comment = NULL;
1671
1672    for (i=1; i<ua->argc; i++) {
1673       Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1674       kw_ok = false;
1675       /* Keep looking until we find a good keyword */
1676       for (j=0; !kw_ok && kw[j]; j++) {
1677          if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1678             /* Note, yes and run have no value, so do not fail */
1679             if (!ua->argv[i] && j != YES_POS /*yes*/) {
1680                ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1681                return false;
1682             }
1683             Dmsg2(800, "Got j=%d keyword=%s\n", j, NPRT(kw[j]));
1684             switch (j) {
1685             case 0: /* alljobid */
1686                rc.alljobid = true;
1687                /* Fall through wanted */
1688             case 1:  /* JobId */
1689                if (rc.jid && !rc.mod) {
1690                   ua->send_msg(_("JobId specified twice.\n"));
1691                   return false;
1692                }
1693                rc.jid = ua->argv[i];
1694                kw_ok = true;
1695                break;
1696             case 2: /* client */
1697             case 3: /* fd */
1698                if (rc.client_name) {
1699                   ua->send_msg(_("Client specified twice.\n"));
1700                   return false;
1701                }
1702                rc.client_name = ua->argv[i];
1703                kw_ok = true;
1704                break;
1705             case 4: /* fileset */
1706                if (rc.fileset_name) {
1707                   ua->send_msg(_("FileSet specified twice.\n"));
1708                   return false;
1709                }
1710                rc.fileset_name = ua->argv[i];
1711                kw_ok = true;
1712                break;
1713             case 5: /* level */
1714                if (rc.level_name) {
1715                   ua->send_msg(_("Level specified twice.\n"));
1716                   return false;
1717                }
1718                rc.level_name = ua->argv[i];
1719                kw_ok = true;
1720                break;
1721             case 6: /* storage */
1722             case 7: /* sd */
1723                if (rc.store_name) {
1724                   ua->send_msg(_("Storage specified twice.\n"));
1725                   return false;
1726                }
1727                rc.store_name = ua->argv[i];
1728                kw_ok = true;
1729                break;
1730             case 8: /* regexwhere */
1731                 if ((rc.regexwhere || rc.where) && !rc.mod) {
1732                   ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1733                   return false;
1734                }
1735                rc.regexwhere = ua->argv[i];
1736                if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1737                   ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1738                   return false;
1739                }
1740                kw_ok = true;
1741                break;
1742            case 9: /* where */
1743                if ((rc.where || rc.regexwhere) && !rc.mod) {
1744                   ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1745                   return false;
1746                }
1747                rc.where = ua->argv[i];
1748                if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1749                   ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1750                   return false;
1751                }
1752                kw_ok = true;
1753                break;
1754             case 10: /* bootstrap */
1755                if (rc.bootstrap && !rc.mod) {
1756                   ua->send_msg(_("Bootstrap specified twice.\n"));
1757                   return false;
1758                }
1759                rc.bootstrap = ua->argv[i];
1760                kw_ok = true;
1761                break;
1762             case 11: /* replace */
1763                if (rc.replace && !rc.mod) {
1764                   ua->send_msg(_("Replace specified twice.\n"));
1765                   return false;
1766                }
1767                rc.replace = ua->argv[i];
1768                kw_ok = true;
1769                break;
1770             case 12: /* When */
1771                if (rc.when && !rc.mod) {
1772                   ua->send_msg(_("When specified twice.\n"));
1773                   return false;
1774                }
1775                rc.when = ua->argv[i];
1776                kw_ok = true;
1777                break;
1778             case 13:  /* Priority */
1779                if (rc.Priority && !rc.mod) {
1780                   ua->send_msg(_("Priority specified twice.\n"));
1781                   return false;
1782                }
1783                rc.Priority = atoi(ua->argv[i]);
1784                if (rc.Priority <= 0) {
1785                   ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1786                   rc.Priority = 10;
1787                }
1788                kw_ok = true;
1789                break;
1790             case 14: /* yes */
1791                kw_ok = true;
1792                break;
1793             case 15: /* Verify Job */
1794                if (rc.verify_job_name) {
1795                   ua->send_msg(_("Verify Job specified twice.\n"));
1796                   return false;
1797                }
1798                rc.verify_job_name = ua->argv[i];
1799                kw_ok = true;
1800                break;
1801             case 16: /* files */
1802                rc.files = atoi(ua->argv[i]);
1803                kw_ok = true;
1804                break;
1805             case 17: /* catalog */
1806                rc.catalog_name = ua->argv[i];
1807                kw_ok = true;
1808                break;
1809             case 18: /* since */
1810                rc.since = ua->argv[i];
1811                kw_ok = true;
1812                break;
1813             case 19: /* cloned */
1814                rc. cloned = true;
1815                kw_ok = true;
1816                break;
1817             case 20: /* write verify list output */
1818                rc.verify_list = ua->argv[i];
1819                kw_ok = true;
1820                break;
1821             case 21: /* Migration Job */
1822                if (rc.previous_job_name) {
1823                   ua->send_msg(_("Migration Job specified twice.\n"));
1824                   return false;
1825                }
1826                rc.previous_job_name = ua->argv[i];
1827                kw_ok = true;
1828                break;
1829             case 22: /* pool */
1830                if (rc.pool_name) {
1831                   ua->send_msg(_("Pool specified twice.\n"));
1832                   return false;
1833                }
1834                rc.pool_name = ua->argv[i];
1835                kw_ok = true;
1836                break;
1837             case 23: /* backupclient */
1838                if (rc.client_name) {
1839                   ua->send_msg(_("Client specified twice.\n"));
1840                   return 0;
1841                }
1842                rc.client_name = ua->argv[i];
1843                kw_ok = true;
1844                break;
1845             case 24: /* restoreclient */
1846                if (rc.restore_client_name && !rc.mod) {
1847                   ua->send_msg(_("Restore Client specified twice.\n"));
1848                   return false;
1849                }
1850                rc.restore_client_name = ua->argv[i];
1851                kw_ok = true;
1852                break;
1853             case 25: /* pluginoptions */
1854                ua->send_msg(_("Plugin Options not yet implemented.\n"));
1855                return false;
1856                if (rc.plugin_options) {
1857                   ua->send_msg(_("Plugin Options specified twice.\n"));
1858                   return false;
1859                }
1860                rc.plugin_options = ua->argv[i];
1861                if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1862                   ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1863                   return false;
1864                }
1865                kw_ok = true;
1866                break;
1867             case 26: /* spooldata */
1868                if (rc.spool_data_set) {
1869                   ua->send_msg(_("Spool flag specified twice.\n"));
1870                   return false;
1871                }
1872                if (is_yesno(ua->argv[i], &rc.spool_data)) {
1873                   rc.spool_data_set = true;
1874                   kw_ok = true;
1875                } else {
1876                   ua->send_msg(_("Invalid spooldata flag.\n"));
1877                }
1878                break;
1879             case 27: /* comment */
1880                rc.comment = ua->argv[i];
1881                kw_ok = true;
1882                break;
1883             case 28: /* ignoreduplicatecheck */
1884                if (rc.ignoreduplicatecheck_set) {
1885                   ua->send_msg(_("IgnoreDuplicateCheck flag specified twice.\n"));
1886                   return false;
1887                }
1888                if (is_yesno(ua->argv[i], &rc.ignoreduplicatecheck)) {
1889                   rc.ignoreduplicatecheck_set = true;
1890                   kw_ok = true;
1891                } else {
1892                   ua->send_msg(_("Invalid ignoreduplicatecheck flag.\n"));
1893                }
1894                break;
1895             case 29: /* accurate */
1896                if (rc.accurate_set) {
1897                   ua->send_msg(_("Accurate flag specified twice.\n"));
1898                   return false;
1899                }
1900                if (is_yesno(ua->argv[i], &rc.accurate)) {
1901                   rc.accurate_set = true;
1902                   kw_ok = true;
1903                } else {
1904                   ua->send_msg(_("Invalid accurate flag.\n"));
1905                }
1906                break;
1907             case 30: /* job */
1908                if (rc.job_name) {
1909                   ua->send_msg(_("Job name specified twice.\n"));
1910                   return false;
1911                }
1912                rc.job_name = ua->argv[i];
1913                kw_ok = true;
1914                break;
1915             case 31: /* mediatype */
1916                if (rc.media_type) {
1917                   ua->send_msg(_("Media Type specified twice.\n"));
1918                   return false;
1919                }
1920                rc.media_type = ua->argv[i];
1921                kw_ok = true;
1922                break;
1923             case 32: /* Next Pool */
1924                if (rc.next_pool_name) {
1925                   ua->send_msg(_("NextPool specified twice.\n"));
1926                   return false;
1927                }
1928                rc.next_pool_name = ua->argv[i];
1929                kw_ok = true;
1930                break;
1931             default:
1932                break;
1933             }
1934          } /* end strcase compare */
1935       } /* end keyword loop */
1936
1937       /*
1938        * End of keyword for loop -- if not found, we got a bogus keyword
1939        */
1940       if (!kw_ok) {
1941          Dmsg1(800, "%s not found\n", ua->argk[i]);
1942          /*
1943           * Special case for Job Name, it can be the first
1944           * keyword that has no value.
1945           */
1946          if (!rc.job_name && !ua->argv[i]) {
1947             rc.job_name = ua->argk[i];   /* use keyword as job name */
1948             Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1949          } else {
1950             ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1951             return false;
1952          }
1953       }
1954    } /* end argc loop */
1955
1956    Dmsg0(800, "Done scan.\n");
1957    if (rc.comment) {
1958       if (!is_comment_legal(ua, rc.comment)) {
1959          return false;
1960       }
1961    }
1962    if (rc.catalog_name) {
1963        rc.catalog = GetCatalogResWithName(rc.catalog_name);
1964        if (rc.catalog == NULL) {
1965             ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1966            return false;
1967        }
1968        if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1969           ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1970           return false;
1971        }
1972    }
1973    Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1974
1975    if (!get_job(ua, rc)) {
1976       return false;
1977    }
1978
1979    if (!get_pool(ua, rc)) {
1980       return false;
1981    }
1982
1983    if (!get_next_pool(ua, rc)) {
1984       return false;
1985    }
1986
1987    if (!get_storage(ua, rc)) {
1988       return false;
1989    }
1990
1991
1992    if (!get_client(ua, rc)) {
1993       return false;
1994    }
1995
1996    if (!get_fileset(ua, rc)) {
1997       return false;
1998    }
1999
2000    if (rc.verify_job_name) {
2001       rc.verify_job = GetJobResWithName(rc.verify_job_name);
2002       if (!rc.verify_job) {
2003          ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
2004          rc.verify_job = select_job_resource(ua);
2005       }
2006    } else if (!rc.verify_job) {
2007       rc.verify_job = rc.job->verify_job;
2008    }
2009
2010    if (rc.previous_job_name) {
2011       rc.previous_job = GetJobResWithName(rc.previous_job_name);
2012       if (!rc.previous_job) {
2013          ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
2014          rc.previous_job = select_job_resource(ua);
2015       }
2016    } else {
2017       rc.previous_job = rc.job->verify_job;
2018    }
2019    return true;
2020 }