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