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