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