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