]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
Fix cancel crash reported by Stephen Thompson
[bacula/bacula] / bacula / src / dird / ua_run.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2001-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *   Bacula Director -- Run Command
31  *
32  *     Kern Sibbald, December MMI
33  *
34  *   Version $Id$
35  */
36
37 #include "bacula.h"
38 #include "dird.h"
39
40 class run_ctx {
41 public:
42    char *job_name, *level_name, *jid, *store_name, *pool_name;
43    char *where, *fileset_name, *client_name, *bootstrap, *regexwhere;
44    char *restore_client_name, *comment;
45    const char *replace;
46    char *when, *verify_job_name, *catalog_name;
47    char *previous_job_name;
48    char *since;
49    char *plugin_options;
50    const char *verify_list;
51    JOB *job;
52    JOB *verify_job;
53    JOB *previous_job;
54    USTORE *store;
55    CLIENT *client;
56    FILESET *fileset;
57    POOL *pool;
58    CAT *catalog;
59    int Priority;
60    int files;
61    bool cloned;
62    bool mod;
63    int spool_data;
64    bool spool_data_set;
65
66    /* Methods */
67    run_ctx() { memset(this, 0, sizeof(run_ctx)); 
68                store = new USTORE; };
69    ~run_ctx() { delete store; };
70 };
71
72 /* Forward referenced subroutines */
73 static void select_job_level(UAContext *ua, JCR *jcr);
74 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, 
75                 const char *verify_list, char *jid, const char *replace,
76                 char *client_name);
77 static void select_where_regexp(UAContext *ua, JCR *jcr);
78 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc);
79 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc);
80 static int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc);
81
82 /* Imported variables */
83 extern struct s_kw ReplaceOptions[];
84
85 /*
86  * For Backup and Verify Jobs
87  *     run [job=]<job-name> level=<level-name>
88  *
89  * For Restore Jobs
90  *     run <job-name> 
91  *
92  *  Returns: 0 on error
93  *           JobId if OK
94  *
95  */
96 int run_cmd(UAContext *ua, const char *cmd)
97 {
98    JCR *jcr = NULL;
99    run_ctx rc;
100    int status;
101
102    if (!open_client_db(ua)) {
103       return 1;
104    }
105
106    if (!scan_command_line_arguments(ua, rc)) {
107       return 0;
108    }
109
110    if (find_arg(ua, NT_("fdcalled")) > 0) {
111       jcr->file_bsock = dup_bsock(ua->UA_sock);
112       ua->quit = true;
113    }
114
115    /*
116     * Create JCR to run job.  NOTE!!! after this point, free_jcr()
117     *  before returning.
118     */
119    if (!jcr) {
120       jcr = new_jcr(sizeof(JCR), dird_free_jcr);
121       set_jcr_defaults(jcr, rc.job);
122       jcr->unlink_bsr = ua->jcr->unlink_bsr;    /* copy unlink flag from caller */
123       ua->jcr->unlink_bsr = false;
124    }
125    /* Transfer JobIds to new restore Job */
126    if (ua->jcr->JobIds) {
127       jcr->JobIds = ua->jcr->JobIds;
128       ua->jcr->JobIds = NULL;
129    }
130
131 try_again:
132    if (!reset_restore_context(ua, jcr, rc)) {
133       goto bail_out;
134    }
135
136
137    /* Run without prompting? */
138    if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
139       goto start_job;
140    }
141
142    /*
143     * Prompt User to see if all run job parameters are correct, and
144     *   allow him to modify them.
145     */
146    if (!display_job_parameters(ua, jcr, rc.job, rc.verify_list, rc.jid, rc.replace,
147         rc.client_name)) {
148       goto bail_out;
149    }
150
151    if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
152       goto bail_out;
153    }
154
155    if (strncasecmp(ua->cmd, ".mod ", 5) == 0 || 
156        (strncasecmp(ua->cmd, "mod ", 4) == 0 && strlen(ua->cmd) > 6)) {
157       parse_ua_args(ua);
158       rc.mod = true;
159       if (!scan_command_line_arguments(ua, rc)) {
160          return 0;
161       }
162       goto try_again;
163    }
164
165    /* Allow the user to modify the settings */
166    status = modify_job_parameters(ua, jcr, rc);
167    switch (status) {
168    case 0:
169       goto try_again;
170    case 1:
171       break;
172    case -1:
173       goto bail_out;
174    }
175
176
177    if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
178       JobId_t JobId;
179       Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
180
181 start_job:
182       Dmsg3(100, "JobId=%u using pool %s priority=%d\n", (int)jcr->JobId, 
183             jcr->pool->name(), jcr->JobPriority);
184       Dmsg1(900, "Running a job; its spool_data = %d\n", jcr->spool_data);
185       JobId = run_job(jcr);
186       Dmsg4(100, "JobId=%u NewJobId=%d using pool %s priority=%d\n", (int)jcr->JobId, 
187             JobId, jcr->pool->name(), jcr->JobPriority);
188       free_jcr(jcr);                  /* release jcr */
189       if (JobId == 0) {
190          ua->error_msg(_("Job failed.\n"));
191       } else {
192          char ed1[50];
193          ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId, ed1));
194       }
195       return JobId;
196    }
197
198 bail_out:
199    ua->send_msg(_("Job not run.\n"));
200    free_jcr(jcr);
201    return 0;                       /* do not run */
202 }
203
204 int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc)
205 {
206    int i, opt;
207    /*
208     * At user request modify parameters of job to be run.
209     */
210    if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
211       FILE *fd;
212
213       start_prompt(ua, _("Parameters to modify:\n"));
214       add_prompt(ua, _("Level"));            /* 0 */
215       add_prompt(ua, _("Storage"));          /* 1 */
216       add_prompt(ua, _("Job"));              /* 2 */
217       add_prompt(ua, _("FileSet"));          /* 3 */
218       if (jcr->getJobType() == JT_RESTORE) {
219          add_prompt(ua, _("Restore Client"));   /* 4 */
220       } else {
221          add_prompt(ua, _("Client"));        /* 4 */
222       }
223       add_prompt(ua, _("When"));             /* 5 */
224       add_prompt(ua, _("Priority"));         /* 6 */
225       if (jcr->getJobType() == JT_BACKUP ||
226           jcr->getJobType() == JT_COPY ||
227           jcr->getJobType() == JT_MIGRATE ||
228           jcr->getJobType() == JT_VERIFY) {
229          add_prompt(ua, _("Pool"));          /* 7 */
230          if (jcr->getJobType() == JT_VERIFY) {
231             add_prompt(ua, _("Verify Job"));  /* 8 */
232          }
233       } else if (jcr->getJobType() == JT_RESTORE) {
234          add_prompt(ua, _("Bootstrap"));     /* 7 */
235          add_prompt(ua, _("Where"));         /* 8 */
236          add_prompt(ua, _("File Relocation"));/* 9 */    
237          add_prompt(ua, _("Replace"));       /* 10 */
238          add_prompt(ua, _("JobId"));         /* 11 */
239       }
240       if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
241          add_prompt(ua, _("Plugin Options")); /* 12 */
242       }
243       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
244       case 0:
245          /* Level */
246          select_job_level(ua, jcr);
247          goto try_again;
248       case 1:
249          /* Storage */
250          rc.store->store = select_storage_resource(ua);
251          if (rc.store->store) {
252             pm_strcpy(rc.store->store_source, _("user selection"));
253             set_rwstorage(jcr, rc.store);
254             goto try_again;
255          }
256          break;
257       case 2:
258          /* Job */
259          rc.job = select_job_resource(ua);
260          if (rc.job) {
261             jcr->job = rc.job;
262             set_jcr_defaults(jcr, rc.job);
263             goto try_again;
264          }
265          break;
266       case 3:
267          /* FileSet */
268          rc.fileset = select_fileset_resource(ua);
269          if (rc.fileset) {
270             jcr->fileset = rc.fileset;
271             goto try_again;
272          }
273          break;
274       case 4:
275          /* Client */
276          rc.client = select_client_resource(ua);
277          if (rc.client) {
278             jcr->client = rc.client;
279             goto try_again;
280          }
281          break;
282       case 5:
283          /* When */
284          if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
285             break;
286          }
287          if (ua->cmd[0] == 0) {
288             jcr->sched_time = time(NULL);
289          } else {
290             jcr->sched_time = str_to_utime(ua->cmd);
291             if (jcr->sched_time == 0) {
292                ua->send_msg(_("Invalid time, using current time.\n"));
293                jcr->sched_time = time(NULL);
294             }
295          }
296          goto try_again;
297       case 6:
298          /* Priority */
299          if (!get_pint(ua, _("Enter new Priority: "))) {
300             break;
301          }
302          if (ua->pint32_val == 0) {
303             ua->send_msg(_("Priority must be a positive integer.\n"));
304          } else {
305             jcr->JobPriority = ua->pint32_val;
306          }
307          goto try_again;
308       case 7: 
309          /* Pool or Bootstrap depending on JobType */
310          if (jcr->getJobType() == JT_BACKUP ||
311              jcr->getJobType() == JT_COPY ||
312              jcr->getJobType() == JT_MIGRATE ||
313              jcr->getJobType() == JT_VERIFY) {      /* Pool */
314             rc.pool = select_pool_resource(ua);
315             if (rc.pool) {
316                jcr->pool = rc.pool;
317                Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
318                goto try_again;
319             }
320             break;
321          }
322
323          /* Bootstrap */
324          if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
325             break;
326          }
327          if (jcr->RestoreBootstrap) {
328             free(jcr->RestoreBootstrap);
329             jcr->RestoreBootstrap = NULL;
330          }
331          if (ua->cmd[0] != 0) {
332             jcr->RestoreBootstrap = bstrdup(ua->cmd);
333             fd = fopen(jcr->RestoreBootstrap, "rb");
334             if (!fd) {
335                berrno be;
336                ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
337                   jcr->RestoreBootstrap, be.bstrerror());
338                free(jcr->RestoreBootstrap);
339                jcr->RestoreBootstrap = NULL;
340             } else {
341                fclose(fd);
342             }
343          }
344          goto try_again;
345       case 8:
346          /* Verify Job */
347          if (jcr->getJobType() == JT_VERIFY) {
348             rc.verify_job = select_job_resource(ua);
349             if (rc.verify_job) {
350               jcr->verify_job = rc.verify_job;
351             }
352             goto try_again;
353          }
354          /* Where */
355          if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
356             break;
357          }
358          if (jcr->RegexWhere) { /* cannot use regexwhere and where */
359             free(jcr->RegexWhere);
360             jcr->RegexWhere = NULL;
361          }
362          if (jcr->where) {
363             free(jcr->where);
364             jcr->where = NULL;
365          }
366          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
367             ua->cmd[0] = 0;
368          }
369          jcr->where = bstrdup(ua->cmd);
370          goto try_again;
371       case 9: 
372          /* File relocation */
373          select_where_regexp(ua, jcr);
374          goto try_again;
375       case 10:
376          /* Replace */
377          start_prompt(ua, _("Replace:\n"));
378          for (i=0; ReplaceOptions[i].name; i++) {
379             add_prompt(ua, ReplaceOptions[i].name);
380          }
381          opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
382          if (opt >=  0) {
383             rc.replace = ReplaceOptions[opt].name;
384             jcr->replace = ReplaceOptions[opt].token;
385          }
386          goto try_again;
387       case 11:
388          /* JobId */
389          rc.jid = NULL;                  /* force reprompt */
390          jcr->RestoreJobId = 0;
391          if (jcr->RestoreBootstrap) {
392             ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
393          }
394          goto try_again;
395       case 12:        
396          /* Plugin Options */
397          if (!get_cmd(ua, _("Please Plugin Options string: "))) {
398             break;
399          }
400          if (jcr->plugin_options) {
401             free(jcr->plugin_options);
402             jcr->plugin_options = NULL;
403          }
404          jcr->plugin_options = bstrdup(ua->cmd);
405          goto try_again;
406       case -1:                        /* error or cancel */
407          goto bail_out;
408       default:
409          goto try_again;
410       }
411       goto bail_out;
412    }
413    return 1;
414
415 bail_out:
416    return -1;
417
418 try_again:
419    return 0;
420 }
421
422 /*
423  * Reset the restore context. 
424  * This subroutine can be called multiple times, so it
425  *  must keep any prior settings.
426  */
427 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc)
428 {
429    int i;
430
431    jcr->verify_job = rc.verify_job;
432    jcr->previous_job = rc.previous_job;
433    jcr->pool = rc.pool;
434    if (jcr->pool != jcr->job->pool) {
435       pm_strcpy(jcr->pool_source, _("User input"));
436    }
437    set_rwstorage(jcr, rc.store);
438    jcr->client = rc.client;
439    pm_strcpy(jcr->client_name, rc.client->name());
440    jcr->fileset = rc.fileset;
441    jcr->ExpectedFiles = rc.files;
442    if (rc.catalog) {
443       jcr->catalog = rc.catalog;
444       pm_strcpy(jcr->catalog_source, _("User input"));
445    }
446
447    pm_strcpy(jcr->comment, rc.comment);
448
449    if (rc.where) {
450       if (jcr->where) {
451          free(jcr->where);
452       }
453       jcr->where = bstrdup(rc.where);
454       rc.where = NULL;
455    }
456
457    if (rc.regexwhere) {
458       if (jcr->RegexWhere) {
459          free(jcr->RegexWhere);
460       }
461       jcr->RegexWhere = bstrdup(rc.regexwhere);       
462       rc.regexwhere = NULL;
463    }
464
465    if (rc.when) {
466       jcr->sched_time = str_to_utime(rc.when);
467       if (jcr->sched_time == 0) {
468          ua->send_msg(_("Invalid time, using current time.\n"));
469          jcr->sched_time = time(NULL);
470       }
471       rc.when = NULL;
472    }
473
474    if (rc.bootstrap) {
475       if (jcr->RestoreBootstrap) {
476          free(jcr->RestoreBootstrap);
477       }
478       jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
479       rc.bootstrap = NULL;
480    }
481
482    if (rc.plugin_options) {
483       if (jcr->plugin_options) {
484          free(jcr->plugin_options);
485       }
486       jcr->plugin_options = bstrdup(rc.plugin_options);
487       rc.plugin_options = NULL;
488    }
489
490
491    if (rc.replace) {
492       jcr->replace = 0;
493       for (i=0; ReplaceOptions[i].name; i++) {
494          if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
495             jcr->replace = ReplaceOptions[i].token;
496          }
497       }
498       if (!jcr->replace) {
499          ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
500          return false;
501       }
502    } else if (rc.job->replace) {
503       jcr->replace = rc.job->replace;
504    } else {
505       jcr->replace = REPLACE_ALWAYS;
506    }
507    rc.replace = NULL;
508
509    if (rc.Priority) {
510       jcr->JobPriority = rc.Priority;
511       rc.Priority = 0;
512    }
513
514    if (rc.since) {
515       if (!jcr->stime) {
516          jcr->stime = get_pool_memory(PM_MESSAGE);
517       }
518       pm_strcpy(jcr->stime, rc.since);
519       rc.since = NULL;
520    }
521
522    if (rc.cloned) {
523       jcr->cloned = rc.cloned;
524       rc.cloned = false;
525    }
526
527
528    /* If pool changed, update migration write storage */
529    if (jcr->getJobType() == JT_MIGRATE || jcr->getJobType() == JT_COPY ||
530       (jcr->getJobType() == JT_BACKUP && jcr->getJobLevel() == L_VIRTUAL_FULL)) {
531       if (!set_migration_wstorage(jcr, rc.pool)) {
532          return false;
533       }
534    }
535    rc.replace = ReplaceOptions[0].name;
536    for (i=0; ReplaceOptions[i].name; i++) {
537       if (ReplaceOptions[i].token == jcr->replace) {
538          rc.replace = ReplaceOptions[i].name;
539       }
540    }
541    if (rc.level_name) {
542       if (!get_level_from_name(jcr, rc.level_name)) {
543          ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
544          return false;
545       }
546       rc.level_name = NULL;
547    }
548    if (rc.jid) {
549       /* Note, this is also MigrateJobId */
550       jcr->RestoreJobId = str_to_int64(rc.jid);
551       rc.jid = 0;
552    }
553    return true;
554 }
555
556 static void select_where_regexp(UAContext *ua, JCR *jcr)
557 {
558    alist *regs;
559    char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
560    strip_prefix = add_suffix = rwhere = add_prefix = NULL;
561
562 try_again_reg:
563    ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
564                 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
565
566    start_prompt(ua, _("This will replace your current Where value\n"));
567    add_prompt(ua, _("Strip prefix"));                /* 0 */
568    add_prompt(ua, _("Add prefix"));                  /* 1 */
569    add_prompt(ua, _("Add file suffix"));             /* 2 */
570    add_prompt(ua, _("Enter a regexp"));              /* 3 */
571    add_prompt(ua, _("Test filename manipulation"));  /* 4 */
572    add_prompt(ua, _("Use this ?"));                  /* 5 */
573    
574    switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
575    case 0:
576       /* Strip prefix */
577       if (get_cmd(ua, _("Please enter path prefix to strip: "))) {
578          if (strip_prefix) bfree(strip_prefix);
579          strip_prefix = bstrdup(ua->cmd);
580       }
581       
582       goto try_again_reg;
583    case 1:
584       /* Add prefix */
585       if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) {
586          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
587             ua->cmd[0] = 0;
588          }
589
590          if (add_prefix) bfree(add_prefix);
591          add_prefix = bstrdup(ua->cmd);
592       }
593       goto try_again_reg;
594    case 2:
595       /* Add suffix */
596       if (get_cmd(ua, _("Please enter file suffix to add: "))) {
597          if (add_suffix) bfree(add_suffix);
598          add_suffix = bstrdup(ua->cmd);
599       }      
600       goto try_again_reg;
601    case 3:
602       /* Add rwhere */
603       if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
604          if (rwhere) bfree(rwhere);
605          rwhere = bstrdup(ua->cmd);
606       }
607       
608       goto try_again_reg;      
609    case 4:
610       /* Test regexp */ 
611       char *result;
612       char *regexp;
613       
614       if (rwhere && rwhere[0] != '\0') {
615          regs = get_bregexps(rwhere);
616          ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
617       } else {
618          int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
619          regexp = (char *) bmalloc (len * sizeof(char));
620          bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
621          regs = get_bregexps(regexp);
622          ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
623                       NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
624          
625          bfree(regexp);
626       }
627
628       if (!regs) {
629          ua->send_msg(_("Cannot use your regexp\n"));
630          goto try_again_reg;
631       }
632       ua->send_msg(_("Enter a period (.) to stop this test\n"));
633       while (get_cmd(ua, _("Please enter filename to test: "))) {
634          apply_bregexps(ua->cmd, regs, &result);
635          ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
636       }
637       free_bregexps(regs);
638       delete regs;
639       goto try_again_reg;
640
641    case 5:
642       /* OK */
643       break;
644    case -1:                        /* error or cancel */
645       goto bail_out_reg;
646    default:
647       goto try_again_reg;
648    }
649
650    /* replace the existing where */
651    if (jcr->where) {
652       bfree(jcr->where);
653       jcr->where = NULL;
654    }
655
656    /* replace the existing regexwhere */
657    if (jcr->RegexWhere) {
658       bfree(jcr->RegexWhere);
659       jcr->RegexWhere = NULL;
660    }
661
662    if (rwhere) {
663       jcr->RegexWhere = bstrdup(rwhere);
664    } else if (strip_prefix || add_prefix || add_suffix) {
665       int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
666       jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
667       bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
668    }
669
670    regs = get_bregexps(jcr->RegexWhere);
671    if (regs) {
672       free_bregexps(regs);
673       delete regs;
674    } else {
675       if (jcr->RegexWhere) {
676          bfree(jcr->RegexWhere);
677          jcr->RegexWhere = NULL;
678       }
679       ua->send_msg(_("Cannot use your regexp.\n"));
680    }
681
682 bail_out_reg:
683    if (strip_prefix) bfree(strip_prefix);
684    if (add_prefix)   bfree(add_prefix);
685    if (add_suffix)   bfree(add_suffix);
686    if (rwhere)       bfree(rwhere);
687 }
688
689 static void select_job_level(UAContext *ua, JCR *jcr)
690 {
691    if (jcr->getJobType() == JT_BACKUP) {
692       start_prompt(ua, _("Levels:\n"));
693 //    add_prompt(ua, _("Base"));
694       add_prompt(ua, _("Full"));
695       add_prompt(ua, _("Incremental"));
696       add_prompt(ua, _("Differential"));
697       add_prompt(ua, _("Since"));
698       add_prompt(ua, _("VirtualFull"));
699       switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
700 //    case 0:
701 //       jcr->JobLevel = L_BASE;
702 //       break;
703       case 0:
704          jcr->set_JobLevel(L_FULL);
705          break;
706       case 1:
707          jcr->set_JobLevel(L_INCREMENTAL);
708          break;
709       case 2:
710          jcr->set_JobLevel(L_DIFFERENTIAL);
711          break;
712       case 3:
713          jcr->set_JobLevel(L_SINCE);
714          break;
715       case 4:
716          jcr->set_JobLevel(L_VIRTUAL_FULL);
717          break;
718       default:
719          break;
720       }
721    } else if (jcr->getJobType() == JT_VERIFY) {
722       start_prompt(ua, _("Levels:\n"));
723       add_prompt(ua, _("Initialize Catalog"));
724       add_prompt(ua, _("Verify Catalog"));
725       add_prompt(ua, _("Verify Volume to Catalog"));
726       add_prompt(ua, _("Verify Disk to Catalog"));
727       add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
728       switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
729       case 0:
730          jcr->set_JobLevel(L_VERIFY_INIT);
731          break;
732       case 1:
733          jcr->set_JobLevel(L_VERIFY_CATALOG);
734          break;
735       case 2:
736          jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
737          break;
738       case 3:
739          jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
740          break;
741       case 4:
742          jcr->set_JobLevel(L_VERIFY_DATA);
743          break;
744       default:
745          break;
746       }
747    } else {
748       ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
749    }
750    return;
751 }
752
753 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
754    char *jid, const char *replace, char *client_name) 
755 {
756    Dmsg1(800, "JobType=%c\n", jcr->getJobType());
757    switch (jcr->getJobType()) {
758       char ec1[30];
759       char dt[MAX_TIME_LENGTH];
760    case JT_ADMIN:
761       if (ua->api) ua->signal(BNET_RUN_CMD);   
762       ua->send_msg(_("Run %s job\n"
763                      "JobName:  %s\n"
764                      "FileSet:  %s\n"
765                      "Client:   %s\n"
766                      "Storage:  %s\n"
767                      "When:     %s\n"
768                      "Priority: %d\n"),
769                  _("Admin"),
770                  job->name(),
771                  jcr->fileset->name(),
772                  NPRT(jcr->client->name()),
773                  jcr->wstore?jcr->wstore->name():"*None*",
774                  bstrutime(dt, sizeof(dt), jcr->sched_time),
775                  jcr->JobPriority);
776       jcr->set_JobLevel(L_FULL);
777       break;
778    case JT_BACKUP:
779    case JT_VERIFY:
780       if (jcr->getJobType() == JT_BACKUP) {
781          if (ua->api) ua->signal(BNET_RUN_CMD);   
782          ua->send_msg(_("Run %s job\n"
783                         "JobName:  %s\n"
784                         "Level:    %s\n"
785                         "Client:   %s\n"
786                         "FileSet:  %s\n"
787                         "Pool:     %s (From %s)\n"
788                         "Storage:  %s (From %s)\n"
789                         "When:     %s\n"
790                         "Priority: %d\n"
791                         "%s%s%s"),
792                  _("Backup"),
793                  job->name(),
794                  level_to_str(jcr->getJobLevel()),
795                  jcr->client->name(),
796                  jcr->fileset->name(),
797                  NPRT(jcr->pool->name()), jcr->pool_source,
798                  jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
799                  bstrutime(dt, sizeof(dt), jcr->sched_time),
800                  jcr->JobPriority,
801                  jcr->plugin_options?"Plugin Options: ":"",
802                  jcr->plugin_options?jcr->plugin_options:"",
803                  jcr->plugin_options?"\n":"");
804       } else {  /* JT_VERIFY */
805          const char *Name;
806          if (jcr->verify_job) {
807             Name = jcr->verify_job->name();
808          } else {
809             Name = "";
810          }
811          if (!verify_list) {
812             verify_list = job->WriteVerifyList;
813          }
814          if (!verify_list) {
815             verify_list = "";
816          }
817          if (ua->api) ua->signal(BNET_RUN_CMD);   
818          ua->send_msg(_("Run %s job\n"
819                         "JobName:     %s\n"
820                         "Level:       %s\n"
821                         "Client:      %s\n"
822                         "FileSet:     %s\n"
823                         "Pool:        %s (From %s)\n"
824                         "Storage:     %s (From %s)\n"
825                         "Verify Job:  %s\n"
826                         "Verify List: %s\n"
827                         "When:        %s\n"
828                         "Priority:    %d\n"),
829               _("Verify"),
830               job->name(),
831               level_to_str(jcr->getJobLevel()),
832               jcr->client->name(),
833               jcr->fileset->name(),
834               NPRT(jcr->pool->name()), jcr->pool_source,
835               jcr->rstore->name(), jcr->rstore_source,
836               Name,
837               verify_list,
838               bstrutime(dt, sizeof(dt), jcr->sched_time),
839               jcr->JobPriority);
840       }
841       break;
842    case JT_RESTORE:
843       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
844          if (jid) {
845             jcr->RestoreJobId = str_to_int64(jid);
846          } else {
847             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
848                return false;
849             }
850             jcr->RestoreJobId = ua->int64_val;
851          }
852       }
853       jcr->set_JobLevel(L_FULL);      /* default level */
854       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
855       if (jcr->RestoreJobId == 0) {
856          if (ua->api) ua->signal(BNET_RUN_CMD);   
857          /* RegexWhere is take before RestoreWhere */
858          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
859             ua->send_msg(_("Run Restore job\n"
860                         "JobName:         %s\n"
861                         "Bootstrap:       %s\n"
862                         "RegexWhere:      %s\n"
863                         "Replace:         %s\n"
864                         "FileSet:         %s\n"
865                         "Backup Client:   %s\n"
866                         "Restore Client:  %s\n"
867                         "Storage:         %s\n"
868                         "When:            %s\n"
869                         "Catalog:         %s\n"
870                         "Priority:        %d\n"
871                         "Plugin Options:  %s\n"),
872                  job->name(),
873                  NPRT(jcr->RestoreBootstrap), 
874                  jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
875                  replace,
876                  jcr->fileset->name(),
877                  client_name,
878                  jcr->client->name(),
879                  jcr->rstore->name(),
880                  bstrutime(dt, sizeof(dt), jcr->sched_time),
881                  jcr->catalog->name(),
882                  jcr->JobPriority,
883                  NPRT(jcr->plugin_options));
884
885          } else {
886             ua->send_msg(_("Run Restore job\n"
887                         "JobName:         %s\n"
888                         "Bootstrap:       %s\n"
889                         "Where:           %s\n"
890                         "Replace:         %s\n"
891                         "FileSet:         %s\n"
892                         "Backup Client:   %s\n"
893                         "Restore Client:  %s\n"
894                         "Storage:         %s\n"
895                         "When:            %s\n"
896                         "Catalog:         %s\n"
897                         "Priority:        %d\n"
898                         "Plugin Options:  %s\n"),
899                  job->name(),
900                  NPRT(jcr->RestoreBootstrap), 
901                  jcr->where?jcr->where:NPRT(job->RestoreWhere), 
902                  replace,
903                  jcr->fileset->name(),
904                  client_name,
905                  jcr->client->name(),
906                  jcr->rstore->name(),
907                  bstrutime(dt, sizeof(dt), jcr->sched_time),
908                  jcr->catalog->name(),
909                  jcr->JobPriority,
910                  NPRT(jcr->plugin_options));
911          }
912
913       } else {
914          if (ua->api) ua->signal(BNET_RUN_CMD);   
915          ua->send_msg(_("Run Restore job\n"
916                         "JobName:    %s\n"
917                         "Bootstrap:  %s\n"),
918                       job->name(),
919                       NPRT(jcr->RestoreBootstrap));
920                       
921          /* RegexWhere is take before RestoreWhere */
922          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
923             ua->send_msg(_("RegexWhere: %s\n"),
924                          jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
925          } else {
926             ua->send_msg(_("Where:      %s\n"),
927                          jcr->where?jcr->where:NPRT(job->RestoreWhere));
928          }
929
930          ua->send_msg(_("Replace:         %s\n"
931                         "Client:          %s\n"
932                         "Storage:         %s\n"
933                         "JobId:           %s\n"
934                         "When:            %s\n"
935                         "Catalog:         %s\n"
936                         "Priority:        %d\n"
937                         "Plugin Options:  %s\n"),
938               replace,
939               jcr->client->name(),
940               jcr->rstore->name(),
941               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
942               bstrutime(dt, sizeof(dt), jcr->sched_time),
943               jcr->catalog->name(),
944               jcr->JobPriority,
945               NPRT(jcr->plugin_options));
946       }
947       break;
948    case JT_COPY:
949    case JT_MIGRATE:
950       char *prt_type;
951       if (jcr->getJobType() == JT_COPY) {
952          prt_type = _("Run Copy job\n");
953       } else {
954          prt_type = _("Run Migration job\n");
955       }
956       jcr->set_JobLevel(L_FULL);      /* default level */
957       if (ua->api) ua->signal(BNET_RUN_CMD);   
958       ua->send_msg("%s"
959                      "JobName:       %s\n"
960                      "Bootstrap:     %s\n"
961                      "Client:        %s\n"
962                      "FileSet:       %s\n"
963                      "Pool:          %s (From %s)\n"
964                      "Read Storage:  %s (From %s)\n"
965                      "Write Storage: %s (From %s)\n"
966                      "JobId:         %s\n"
967                      "When:          %s\n"
968                      "Catalog:       %s\n"
969                      "Priority:      %d\n",
970            prt_type,
971            job->name(),
972            NPRT(jcr->RestoreBootstrap),
973            jcr->client->name(),
974            jcr->fileset->name(),
975            NPRT(jcr->pool->name()), jcr->pool_source,
976            jcr->rstore->name(), jcr->rstore_source,
977            jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
978            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
979            bstrutime(dt, sizeof(dt), jcr->sched_time),
980            jcr->catalog->name(),
981            jcr->JobPriority);
982       break;
983    default:
984       ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
985       return false;
986    }
987    return true;
988 }
989
990
991 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
992 {
993    bool kw_ok;
994    int i, j;
995    static const char *kw[] = {        /* command line arguments */
996       "job",                          /*  Used in a switch() */
997       "jobid",                        /* 1 */
998       "client",                       /* 2 */
999       "fd",
1000       "fileset",                      /* 4 */
1001       "level",                        /* 5 */
1002       "storage",                      /* 6 */
1003       "sd",                           /* 7 */
1004       "regexwhere",                   /* 8 where string as a bregexp */
1005       "where",                        /* 9 */
1006       "bootstrap",                    /* 10 */
1007       "replace",                      /* 11 */
1008       "when",                         /* 12 */
1009       "priority",                     /* 13 */
1010       "yes",          /* 14  -- if you change this change YES_POS too */
1011       "verifyjob",                    /* 15 */
1012       "files",                        /* 16 number of files to restore */
1013       "catalog",                      /* 17 override catalog */
1014       "since",                        /* 18 since */
1015       "cloned",                       /* 19 cloned */
1016       "verifylist",                   /* 20 verify output list */
1017       "migrationjob",                 /* 21 migration job name */
1018       "pool",                         /* 22 */
1019       "backupclient",                 /* 23 */
1020       "restoreclient",                /* 24 */
1021       "pluginoptions",                /* 25 */
1022       "spooldata",                    /* 26 */
1023       "comment",                      /* 27 */
1024       NULL};
1025
1026 #define YES_POS 14
1027
1028    rc.catalog_name = NULL;
1029    rc.job_name = NULL;
1030    rc.pool_name = NULL;
1031    rc.store_name = NULL;
1032    rc.client_name = NULL;
1033    rc.restore_client_name = NULL;
1034    rc.fileset_name = NULL;
1035    rc.verify_job_name = NULL;
1036    rc.previous_job_name = NULL;
1037    rc.spool_data_set = 0;
1038    rc.comment = NULL;
1039
1040    for (i=1; i<ua->argc; i++) {
1041       Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1042       kw_ok = false;
1043       /* Keep looking until we find a good keyword */
1044       for (j=0; !kw_ok && kw[j]; j++) {
1045          if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1046             /* Note, yes and run have no value, so do not fail */
1047             if (!ua->argv[i] && j != YES_POS /*yes*/) {
1048                ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1049                return false;
1050             }
1051             Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1052             switch (j) {
1053             case 0: /* job */
1054                if (rc.job_name) {
1055                   ua->send_msg(_("Job name specified twice.\n"));
1056                   return false;
1057                }
1058                rc.job_name = ua->argv[i];
1059                kw_ok = true;
1060                break;
1061             case 1: /* JobId */
1062                if (rc.jid && !rc.mod) {
1063                   ua->send_msg(_("JobId specified twice.\n"));
1064                   return false;
1065                }
1066                rc.jid = ua->argv[i];
1067                kw_ok = true;
1068                break;
1069             case 2: /* client */
1070             case 3: /* fd */
1071                if (rc.client_name) {
1072                   ua->send_msg(_("Client specified twice.\n"));
1073                   return false;
1074                }
1075                rc.client_name = ua->argv[i];
1076                kw_ok = true;
1077                break;
1078             case 4: /* fileset */
1079                if (rc.fileset_name) {
1080                   ua->send_msg(_("FileSet specified twice.\n"));
1081                   return false;
1082                }
1083                rc.fileset_name = ua->argv[i];
1084                kw_ok = true;
1085                break;
1086             case 5: /* level */
1087                if (rc.level_name) {
1088                   ua->send_msg(_("Level specified twice.\n"));
1089                   return false;
1090                }
1091                rc.level_name = ua->argv[i];
1092                kw_ok = true;
1093                break;
1094             case 6: /* storage */
1095             case 7: /* sd */
1096                if (rc.store_name) {
1097                   ua->send_msg(_("Storage specified twice.\n"));
1098                   return false;
1099                }
1100                rc.store_name = ua->argv[i];
1101                kw_ok = true;
1102                break;
1103             case 8: /* regexwhere */
1104                 if ((rc.regexwhere || rc.where) && !rc.mod) {
1105                   ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1106                   return false;
1107                }
1108                rc.regexwhere = ua->argv[i];
1109                if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1110                   ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1111                   return false;
1112                }
1113                kw_ok = true;
1114                break;
1115            case 9: /* where */
1116                if ((rc.where || rc.regexwhere) && !rc.mod) {
1117                   ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1118                   return false;
1119                }
1120                rc.where = ua->argv[i];
1121                if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1122                   ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1123                   return false;
1124                }
1125                kw_ok = true;
1126                break;
1127             case 10: /* bootstrap */
1128                if (rc.bootstrap && !rc.mod) {
1129                   ua->send_msg(_("Bootstrap specified twice.\n"));
1130                   return false;
1131                }
1132                rc.bootstrap = ua->argv[i];
1133                kw_ok = true;
1134                break;
1135             case 11: /* replace */
1136                if (rc.replace && !rc.mod) {
1137                   ua->send_msg(_("Replace specified twice.\n"));
1138                   return false;
1139                }
1140                rc.replace = ua->argv[i];
1141                kw_ok = true;
1142                break;
1143             case 12: /* When */
1144                if (rc.when && !rc.mod) {
1145                   ua->send_msg(_("When specified twice.\n"));
1146                   return false;
1147                }
1148                rc.when = ua->argv[i];
1149                kw_ok = true;
1150                break;
1151             case 13:  /* Priority */
1152                if (rc.Priority && !rc.mod) {
1153                   ua->send_msg(_("Priority specified twice.\n"));
1154                   return false;
1155                }
1156                rc.Priority = atoi(ua->argv[i]);
1157                if (rc.Priority <= 0) {
1158                   ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1159                   rc.Priority = 10;
1160                }
1161                kw_ok = true;
1162                break;
1163             case 14: /* yes */
1164                kw_ok = true;
1165                break;
1166             case 15: /* Verify Job */
1167                if (rc.verify_job_name) {
1168                   ua->send_msg(_("Verify Job specified twice.\n"));
1169                   return false;
1170                }
1171                rc.verify_job_name = ua->argv[i];
1172                kw_ok = true;
1173                break;
1174             case 16: /* files */
1175                rc.files = atoi(ua->argv[i]);
1176                kw_ok = true;
1177                break;
1178
1179             case 17: /* catalog */
1180                rc.catalog_name = ua->argv[i];
1181                kw_ok = true;
1182                break;
1183
1184             case 18: /* since */
1185                rc.since = ua->argv[i];
1186                kw_ok = true; 
1187                break;
1188
1189             case 19: /* cloned */
1190                rc. cloned = true;
1191                kw_ok = true;
1192                break;
1193
1194             case 20: /* write verify list output */
1195                rc.verify_list = ua->argv[i];
1196                kw_ok = true;
1197                break;
1198             case 21: /* Migration Job */
1199                if (rc.previous_job_name) {
1200                   ua->send_msg(_("Migration Job specified twice.\n"));
1201                   return false;
1202                }
1203                rc.previous_job_name = ua->argv[i];
1204                kw_ok = true;
1205                break;
1206             case 22: /* pool */
1207                if (rc.pool_name) {
1208                   ua->send_msg(_("Pool specified twice.\n"));
1209                   return false;
1210                }
1211                rc.pool_name = ua->argv[i];
1212                kw_ok = true;
1213                break;
1214             case 23: /* backupclient */
1215                if (rc.client_name) {
1216                   ua->send_msg(_("Client specified twice.\n"));
1217                   return 0;
1218                }
1219                rc.client_name = ua->argv[i];
1220                kw_ok = true;
1221                break;
1222             case 24: /* restoreclient */
1223                if (rc.restore_client_name && !rc.mod) {
1224                   ua->send_msg(_("Restore Client specified twice.\n"));
1225                   return false;
1226                }
1227                rc.restore_client_name = ua->argv[i];
1228                kw_ok = true;
1229                break;
1230             case 25: /* pluginoptions */
1231                ua->send_msg(_("Plugin Options not yet implemented.\n"));
1232                return false;
1233                if (rc.plugin_options) {
1234                   ua->send_msg(_("Plugin Options specified twice.\n"));
1235                   return false;
1236                }
1237                rc.plugin_options = ua->argv[i];
1238                if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1239                   ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1240                   return false;
1241                }
1242                kw_ok = true;
1243                break;
1244             case 26: /* spooldata */
1245                if (rc.spool_data_set) {
1246                   ua->send_msg(_("Spool flag specified twice.\n"));
1247                   return false;
1248                }
1249                if (is_yesno(ua->argv[i], &rc.spool_data)) {
1250                   rc.spool_data_set = 1;
1251                   kw_ok = true;
1252                } else {
1253                   ua->send_msg(_("Invalid spooldata flag.\n"));
1254                }
1255                break;
1256             case 27: /* comment */
1257                rc.comment = ua->argv[i];
1258                kw_ok = true;
1259             default:
1260                break;
1261             }
1262          } /* end strcase compare */
1263       } /* end keyword loop */
1264       /*
1265        * End of keyword for loop -- if not found, we got a bogus keyword
1266        */
1267       if (!kw_ok) {
1268          Dmsg1(800, "%s not found\n", ua->argk[i]);
1269          /*
1270           * Special case for Job Name, it can be the first
1271           * keyword that has no value.
1272           */
1273          if (!rc.job_name && !ua->argv[i]) {
1274             rc.job_name = ua->argk[i];   /* use keyword as job name */
1275             Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1276          } else {
1277             ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1278             return false;
1279          }
1280       }
1281    } /* end argc loop */
1282              
1283    Dmsg0(800, "Done scan.\n");
1284    if (rc.comment) {
1285       if (!is_comment_legal(ua, rc.comment)) {
1286          return false;
1287       }
1288    }
1289    if (rc.catalog_name) {
1290        rc.catalog = GetCatalogResWithName(rc.catalog_name);
1291        if (rc.catalog == NULL) {
1292             ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1293            return false;
1294        }
1295        if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1296           ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1297           return false;
1298        }
1299    }
1300    Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1301
1302    if (rc.job_name) {
1303       /* Find Job */
1304       rc.job = GetJobResWithName(rc.job_name);
1305       if (!rc.job) {
1306          if (*rc.job_name != 0) {
1307             ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1308          }
1309          rc.job = select_job_resource(ua);
1310       } else {
1311          Dmsg1(800, "Found job=%s\n", rc.job_name);
1312       }
1313    } else if (!rc.job) {
1314       ua->send_msg(_("A job name must be specified.\n"));
1315       rc.job = select_job_resource(ua);
1316    }
1317    if (!rc.job) {
1318       return false;
1319    } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1320       ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1321       return false;
1322    }
1323
1324    if (rc.pool_name) {
1325       rc.pool = GetPoolResWithName(rc.pool_name);
1326       if (!rc.pool) {
1327          if (*rc.pool_name != 0) {
1328             ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1329          }
1330          rc.pool = select_pool_resource(ua);
1331       }
1332    } else if (!rc.pool) {
1333       rc.pool = rc.job->pool;             /* use default */
1334    }
1335    if (!rc.pool) {
1336       return false;
1337    } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1338       ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1339       return false;
1340    }
1341    Dmsg1(100, "Using pool %s\n", rc.pool->name());
1342
1343    if (rc.spool_data_set) {
1344       rc.job->spool_data = rc.spool_data;
1345    }
1346    Dmsg1(900, "Spooling data: %s\n", (rc.job->spool_data ? "Yes" : "No"));
1347
1348    if (rc.store_name) {
1349       rc.store->store = GetStoreResWithName(rc.store_name);
1350       pm_strcpy(rc.store->store_source, _("command line"));
1351       if (!rc.store->store) {
1352          if (*rc.store_name != 0) {
1353             ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1354          }
1355          rc.store->store = select_storage_resource(ua);
1356          pm_strcpy(rc.store->store_source, _("user selection"));
1357       }
1358    } else if (!rc.store->store) {
1359       get_job_storage(rc.store, rc.job, NULL);      /* use default */
1360    }
1361    if (!rc.store->store) {
1362       ua->error_msg(_("No storage specified.\n"));
1363       return false;
1364    } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1365       ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1366                rc.store->store->name());
1367       return false;
1368    }
1369    Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1370
1371    if (rc.client_name) {
1372       rc.client = GetClientResWithName(rc.client_name);
1373       if (!rc.client) {
1374          if (*rc.client_name != 0) {
1375             ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1376          }
1377          rc.client = select_client_resource(ua);
1378       }
1379    } else if (!rc.client) {
1380       rc.client = rc.job->client;           /* use default */
1381    }
1382    if (!rc.client) {
1383       return false;
1384    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1385       ua->error_msg(_("No authorization. Client \"%s\".\n"),
1386                rc.client->name());
1387       return false;
1388    }
1389    Dmsg1(800, "Using client=%s\n", rc.client->name());
1390
1391    if (rc.restore_client_name) {
1392       rc.client = GetClientResWithName(rc.restore_client_name);
1393       if (!rc.client) {
1394          if (*rc.restore_client_name != 0) {
1395             ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1396          }
1397          rc.client = select_client_resource(ua);
1398       }
1399    } else if (!rc.client) {
1400       rc.client = rc.job->client;           /* use default */
1401    }
1402    if (!rc.client) {
1403       return false;
1404    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1405       ua->error_msg(_("No authorization. Client \"%s\".\n"),
1406                rc.client->name());
1407       return false;
1408    }
1409    Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1410
1411
1412    if (rc.fileset_name) {
1413       rc.fileset = GetFileSetResWithName(rc.fileset_name);
1414       if (!rc.fileset) {
1415          ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1416          rc.fileset = select_fileset_resource(ua);
1417       }
1418    } else if (!rc.fileset) {
1419       rc.fileset = rc.job->fileset;           /* use default */
1420    }
1421    if (!rc.fileset) {
1422       return false;
1423    } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1424       ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1425                rc.fileset->name());
1426       return false;
1427    }
1428
1429    if (rc.verify_job_name) {
1430       rc.verify_job = GetJobResWithName(rc.verify_job_name);
1431       if (!rc.verify_job) {
1432          ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1433          rc.verify_job = select_job_resource(ua);
1434       }
1435    } else if (!rc.verify_job) {
1436       rc.verify_job = rc.job->verify_job;
1437    }
1438
1439    if (rc.previous_job_name) {
1440       rc.previous_job = GetJobResWithName(rc.previous_job_name);
1441       if (!rc.previous_job) {
1442          ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1443          rc.previous_job = select_job_resource(ua);
1444       }
1445    } else {
1446       rc.previous_job = rc.job->verify_job;
1447    }
1448    return true;
1449 }