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