]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
7dde36effb7a2df143539faac616d6c332335ecf
[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 three of the GNU Affero 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 Affero 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;
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    if (rc.where) {
442       if (jcr->where) {
443          free(jcr->where);
444       }
445       jcr->where = bstrdup(rc.where);
446       rc.where = NULL;
447    }
448
449    if (rc.regexwhere) {
450       if (jcr->RegexWhere) {
451          free(jcr->RegexWhere);
452       }
453       jcr->RegexWhere = bstrdup(rc.regexwhere);       
454       rc.regexwhere = NULL;
455    }
456
457    if (rc.when) {
458       jcr->sched_time = str_to_utime(rc.when);
459       if (jcr->sched_time == 0) {
460          ua->send_msg(_("Invalid time, using current time.\n"));
461          jcr->sched_time = time(NULL);
462       }
463       rc.when = NULL;
464    }
465
466    if (rc.bootstrap) {
467       if (jcr->RestoreBootstrap) {
468          free(jcr->RestoreBootstrap);
469       }
470       jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
471       rc.bootstrap = NULL;
472    }
473
474    if (rc.plugin_options) {
475       if (jcr->plugin_options) {
476          free(jcr->plugin_options);
477       }
478       jcr->plugin_options = bstrdup(rc.plugin_options);
479       rc.plugin_options = NULL;
480    }
481
482
483    if (rc.replace) {
484       jcr->replace = 0;
485       for (i=0; ReplaceOptions[i].name; i++) {
486          if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
487             jcr->replace = ReplaceOptions[i].token;
488          }
489       }
490       if (!jcr->replace) {
491          ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
492          return false;
493       }
494    } else if (rc.job->replace) {
495       jcr->replace = rc.job->replace;
496    } else {
497       jcr->replace = REPLACE_ALWAYS;
498    }
499    rc.replace = NULL;
500
501    if (rc.Priority) {
502       jcr->JobPriority = rc.Priority;
503       rc.Priority = 0;
504    }
505
506    if (rc.since) {
507       if (!jcr->stime) {
508          jcr->stime = get_pool_memory(PM_MESSAGE);
509       }
510       pm_strcpy(jcr->stime, rc.since);
511       rc.since = NULL;
512    }
513
514    if (rc.cloned) {
515       jcr->cloned = rc.cloned;
516       rc.cloned = false;
517    }
518
519
520    /* If pool changed, update migration write storage */
521    if (jcr->getJobType() == JT_MIGRATE || jcr->getJobType() == JT_COPY ||
522       (jcr->getJobType() == JT_BACKUP && jcr->getJobLevel() == L_VIRTUAL_FULL)) {
523       if (!set_migration_wstorage(jcr, rc.pool)) {
524          return false;
525       }
526    }
527    rc.replace = ReplaceOptions[0].name;
528    for (i=0; ReplaceOptions[i].name; i++) {
529       if (ReplaceOptions[i].token == jcr->replace) {
530          rc.replace = ReplaceOptions[i].name;
531       }
532    }
533    if (rc.level_name) {
534       if (!get_level_from_name(jcr, rc.level_name)) {
535          ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
536          return false;
537       }
538       rc.level_name = NULL;
539    }
540    if (rc.jid) {
541       /* Note, this is also MigrateJobId */
542       jcr->RestoreJobId = str_to_int64(rc.jid);
543       rc.jid = 0;
544    }
545    return true;
546 }
547
548 static void select_where_regexp(UAContext *ua, JCR *jcr)
549 {
550    alist *regs;
551    char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
552    strip_prefix = add_suffix = rwhere = add_prefix = NULL;
553
554 try_again_reg:
555    ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
556                 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
557
558    start_prompt(ua, _("This will replace your current Where value\n"));
559    add_prompt(ua, _("Strip prefix"));                /* 0 */
560    add_prompt(ua, _("Add prefix"));                  /* 1 */
561    add_prompt(ua, _("Add file suffix"));             /* 2 */
562    add_prompt(ua, _("Enter a regexp"));              /* 3 */
563    add_prompt(ua, _("Test filename manipulation"));  /* 4 */
564    add_prompt(ua, _("Use this ?"));                  /* 5 */
565    
566    switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
567    case 0:
568       /* Strip prefix */
569       if (get_cmd(ua, _("Please enter path prefix to strip: "))) {
570          if (strip_prefix) bfree(strip_prefix);
571          strip_prefix = bstrdup(ua->cmd);
572       }
573       
574       goto try_again_reg;
575    case 1:
576       /* Add prefix */
577       if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) {
578          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
579             ua->cmd[0] = 0;
580          }
581
582          if (add_prefix) bfree(add_prefix);
583          add_prefix = bstrdup(ua->cmd);
584       }
585       goto try_again_reg;
586    case 2:
587       /* Add suffix */
588       if (get_cmd(ua, _("Please enter file suffix to add: "))) {
589          if (add_suffix) bfree(add_suffix);
590          add_suffix = bstrdup(ua->cmd);
591       }      
592       goto try_again_reg;
593    case 3:
594       /* Add rwhere */
595       if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
596          if (rwhere) bfree(rwhere);
597          rwhere = bstrdup(ua->cmd);
598       }
599       
600       goto try_again_reg;      
601    case 4:
602       /* Test regexp */ 
603       char *result;
604       char *regexp;
605       
606       if (rwhere && rwhere[0] != '\0') {
607          regs = get_bregexps(rwhere);
608          ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
609       } else {
610          int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
611          regexp = (char *) bmalloc (len * sizeof(char));
612          bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
613          regs = get_bregexps(regexp);
614          ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
615                       NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
616          
617          bfree(regexp);
618       }
619
620       if (!regs) {
621          ua->send_msg(_("Cannot use your regexp\n"));
622          goto try_again_reg;
623       }
624       ua->send_msg(_("Enter a period (.) to stop this test\n"));
625       while (get_cmd(ua, _("Please enter filename to test: "))) {
626          apply_bregexps(ua->cmd, regs, &result);
627          ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
628       }
629       free_bregexps(regs);
630       delete regs;
631       goto try_again_reg;
632
633    case 5:
634       /* OK */
635       break;
636    case -1:                        /* error or cancel */
637       goto bail_out_reg;
638    default:
639       goto try_again_reg;
640    }
641
642    /* replace the existing where */
643    if (jcr->where) {
644       bfree(jcr->where);
645       jcr->where = NULL;
646    }
647
648    /* replace the existing regexwhere */
649    if (jcr->RegexWhere) {
650       bfree(jcr->RegexWhere);
651       jcr->RegexWhere = NULL;
652    }
653
654    if (rwhere) {
655       jcr->RegexWhere = bstrdup(rwhere);
656    } else if (strip_prefix || add_prefix || add_suffix) {
657       int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
658       jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
659       bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
660    }
661
662    regs = get_bregexps(jcr->RegexWhere);
663    if (regs) {
664       free_bregexps(regs);
665       delete regs;
666    } else {
667       if (jcr->RegexWhere) {
668          bfree(jcr->RegexWhere);
669          jcr->RegexWhere = NULL;
670       }
671       ua->send_msg(_("Cannot use your regexp.\n"));
672    }
673
674 bail_out_reg:
675    if (strip_prefix) bfree(strip_prefix);
676    if (add_prefix)   bfree(add_prefix);
677    if (add_suffix)   bfree(add_suffix);
678    if (rwhere)       bfree(rwhere);
679 }
680
681 static void select_job_level(UAContext *ua, JCR *jcr)
682 {
683    if (jcr->getJobType() == JT_BACKUP) {
684       start_prompt(ua, _("Levels:\n"));
685 //    add_prompt(ua, _("Base"));
686       add_prompt(ua, _("Full"));
687       add_prompt(ua, _("Incremental"));
688       add_prompt(ua, _("Differential"));
689       add_prompt(ua, _("Since"));
690       add_prompt(ua, _("VirtualFull"));
691       switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
692 //    case 0:
693 //       jcr->JobLevel = L_BASE;
694 //       break;
695       case 0:
696          jcr->set_JobLevel(L_FULL);
697          break;
698       case 1:
699          jcr->set_JobLevel(L_INCREMENTAL);
700          break;
701       case 2:
702          jcr->set_JobLevel(L_DIFFERENTIAL);
703          break;
704       case 3:
705          jcr->set_JobLevel(L_SINCE);
706          break;
707       case 4:
708          jcr->set_JobLevel(L_VIRTUAL_FULL);
709          break;
710       default:
711          break;
712       }
713    } else if (jcr->getJobType() == JT_VERIFY) {
714       start_prompt(ua, _("Levels:\n"));
715       add_prompt(ua, _("Initialize Catalog"));
716       add_prompt(ua, _("Verify Catalog"));
717       add_prompt(ua, _("Verify Volume to Catalog"));
718       add_prompt(ua, _("Verify Disk to Catalog"));
719       add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
720       switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
721       case 0:
722          jcr->set_JobLevel(L_VERIFY_INIT);
723          break;
724       case 1:
725          jcr->set_JobLevel(L_VERIFY_CATALOG);
726          break;
727       case 2:
728          jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
729          break;
730       case 3:
731          jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
732          break;
733       case 4:
734          jcr->set_JobLevel(L_VERIFY_DATA);
735          break;
736       default:
737          break;
738       }
739    } else {
740       ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
741    }
742    return;
743 }
744
745 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
746    char *jid, const char *replace, char *client_name) 
747 {
748    Dmsg1(800, "JobType=%c\n", jcr->getJobType());
749    switch (jcr->getJobType()) {
750       char ec1[30];
751       char dt[MAX_TIME_LENGTH];
752    case JT_ADMIN:
753       if (ua->api) ua->signal(BNET_RUN_CMD);   
754       ua->send_msg(_("Run %s job\n"
755                      "JobName:  %s\n"
756                      "FileSet:  %s\n"
757                      "Client:   %s\n"
758                      "Storage:  %s\n"
759                      "When:     %s\n"
760                      "Priority: %d\n"),
761                  _("Admin"),
762                  job->name(),
763                  jcr->fileset->name(),
764                  NPRT(jcr->client->name()),
765                  jcr->wstore?jcr->wstore->name():"*None*",
766                  bstrutime(dt, sizeof(dt), jcr->sched_time),
767                  jcr->JobPriority);
768       jcr->set_JobLevel(L_FULL);
769       break;
770    case JT_BACKUP:
771    case JT_VERIFY:
772       if (jcr->getJobType() == JT_BACKUP) {
773          if (ua->api) ua->signal(BNET_RUN_CMD);   
774          ua->send_msg(_("Run %s job\n"
775                         "JobName:  %s\n"
776                         "Level:    %s\n"
777                         "Client:   %s\n"
778                         "FileSet:  %s\n"
779                         "Pool:     %s (From %s)\n"
780                         "Storage:  %s (From %s)\n"
781                         "When:     %s\n"
782                         "Priority: %d\n"
783                         "%s%s%s"),
784                  _("Backup"),
785                  job->name(),
786                  level_to_str(jcr->getJobLevel()),
787                  jcr->client->name(),
788                  jcr->fileset->name(),
789                  NPRT(jcr->pool->name()), jcr->pool_source,
790                  jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
791                  bstrutime(dt, sizeof(dt), jcr->sched_time),
792                  jcr->JobPriority,
793                  jcr->plugin_options?"Plugin Options: ":"",
794                  jcr->plugin_options?jcr->plugin_options:"",
795                  jcr->plugin_options?"\n":"");
796       } else {  /* JT_VERIFY */
797          const char *Name;
798          if (jcr->verify_job) {
799             Name = jcr->verify_job->name();
800          } else {
801             Name = "";
802          }
803          if (!verify_list) {
804             verify_list = job->WriteVerifyList;
805          }
806          if (!verify_list) {
807             verify_list = "";
808          }
809          if (ua->api) ua->signal(BNET_RUN_CMD);   
810          ua->send_msg(_("Run %s job\n"
811                         "JobName:     %s\n"
812                         "Level:       %s\n"
813                         "Client:      %s\n"
814                         "FileSet:     %s\n"
815                         "Pool:        %s (From %s)\n"
816                         "Storage:     %s (From %s)\n"
817                         "Verify Job:  %s\n"
818                         "Verify List: %s\n"
819                         "When:        %s\n"
820                         "Priority:    %d\n"),
821               _("Verify"),
822               job->name(),
823               level_to_str(jcr->getJobLevel()),
824               jcr->client->name(),
825               jcr->fileset->name(),
826               NPRT(jcr->pool->name()), jcr->pool_source,
827               jcr->rstore->name(), jcr->rstore_source,
828               Name,
829               verify_list,
830               bstrutime(dt, sizeof(dt), jcr->sched_time),
831               jcr->JobPriority);
832       }
833       break;
834    case JT_RESTORE:
835       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
836          if (jid) {
837             jcr->RestoreJobId = str_to_int64(jid);
838          } else {
839             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
840                return false;
841             }
842             jcr->RestoreJobId = ua->int64_val;
843          }
844       }
845       jcr->set_JobLevel(L_FULL);      /* default level */
846       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
847       if (jcr->RestoreJobId == 0) {
848          if (ua->api) ua->signal(BNET_RUN_CMD);   
849          /* RegexWhere is take before RestoreWhere */
850          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
851             ua->send_msg(_("Run Restore job\n"
852                         "JobName:         %s\n"
853                         "Bootstrap:       %s\n"
854                         "RegexWhere:      %s\n"
855                         "Replace:         %s\n"
856                         "FileSet:         %s\n"
857                         "Backup Client:   %s\n"
858                         "Restore Client:  %s\n"
859                         "Storage:         %s\n"
860                         "When:            %s\n"
861                         "Catalog:         %s\n"
862                         "Priority:        %d\n"
863                         "Plugin Options:  %s\n"),
864                  job->name(),
865                  NPRT(jcr->RestoreBootstrap), 
866                  jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
867                  replace,
868                  jcr->fileset->name(),
869                  client_name,
870                  jcr->client->name(),
871                  jcr->rstore->name(),
872                  bstrutime(dt, sizeof(dt), jcr->sched_time),
873                  jcr->catalog->name(),
874                  jcr->JobPriority,
875                  NPRT(jcr->plugin_options));
876
877          } else {
878             ua->send_msg(_("Run Restore job\n"
879                         "JobName:         %s\n"
880                         "Bootstrap:       %s\n"
881                         "Where:           %s\n"
882                         "Replace:         %s\n"
883                         "FileSet:         %s\n"
884                         "Backup Client:   %s\n"
885                         "Restore Client:  %s\n"
886                         "Storage:         %s\n"
887                         "When:            %s\n"
888                         "Catalog:         %s\n"
889                         "Priority:        %d\n"
890                         "Plugin Options:  %s\n"),
891                  job->name(),
892                  NPRT(jcr->RestoreBootstrap), 
893                  jcr->where?jcr->where:NPRT(job->RestoreWhere), 
894                  replace,
895                  jcr->fileset->name(),
896                  client_name,
897                  jcr->client->name(),
898                  jcr->rstore->name(),
899                  bstrutime(dt, sizeof(dt), jcr->sched_time),
900                  jcr->catalog->name(),
901                  jcr->JobPriority,
902                  NPRT(jcr->plugin_options));
903          }
904
905       } else {
906          if (ua->api) ua->signal(BNET_RUN_CMD);   
907          ua->send_msg(_("Run Restore job\n"
908                         "JobName:    %s\n"
909                         "Bootstrap:  %s\n"),
910                       job->name(),
911                       NPRT(jcr->RestoreBootstrap));
912                       
913          /* RegexWhere is take before RestoreWhere */
914          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
915             ua->send_msg(_("RegexWhere: %s\n"),
916                          jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
917          } else {
918             ua->send_msg(_("Where:      %s\n"),
919                          jcr->where?jcr->where:NPRT(job->RestoreWhere));
920          }
921
922          ua->send_msg(_("Replace:         %s\n"
923                         "Client:          %s\n"
924                         "Storage:         %s\n"
925                         "JobId:           %s\n"
926                         "When:            %s\n"
927                         "Catalog:         %s\n"
928                         "Priority:        %d\n"
929                         "Plugin Options:  %s\n"),
930               replace,
931               jcr->client->name(),
932               jcr->rstore->name(),
933               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
934               bstrutime(dt, sizeof(dt), jcr->sched_time),
935               jcr->catalog->name(),
936               jcr->JobPriority,
937               NPRT(jcr->plugin_options));
938       }
939       break;
940    case JT_COPY:
941    case JT_MIGRATE:
942       const char *prt_type;
943       if (jcr->getJobType() == JT_COPY) {
944          prt_type = _("Run Copy job\n");
945       } else {
946          prt_type = _("Run Migration job\n");
947       }
948       jcr->set_JobLevel(L_FULL);      /* default level */
949       if (ua->api) ua->signal(BNET_RUN_CMD);   
950       ua->send_msg("%s"
951                      "JobName:       %s\n"
952                      "Bootstrap:     %s\n"
953                      "Client:        %s\n"
954                      "FileSet:       %s\n"
955                      "Pool:          %s (From %s)\n"
956                      "Read Storage:  %s (From %s)\n"
957                      "Write Storage: %s (From %s)\n"
958                      "JobId:         %s\n"
959                      "When:          %s\n"
960                      "Catalog:       %s\n"
961                      "Priority:      %d\n",
962            prt_type,
963            job->name(),
964            NPRT(jcr->RestoreBootstrap),
965            jcr->client->name(),
966            jcr->fileset->name(),
967            NPRT(jcr->pool->name()), jcr->pool_source,
968            jcr->rstore->name(), jcr->rstore_source,
969            jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
970            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
971            bstrutime(dt, sizeof(dt), jcr->sched_time),
972            jcr->catalog->name(),
973            jcr->JobPriority);
974       break;
975    default:
976       ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
977       return false;
978    }
979    return true;
980 }
981
982
983 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
984 {
985    bool kw_ok;
986    int i, j;
987    static const char *kw[] = {        /* command line arguments */
988       "job",                          /*  Used in a switch() */
989       "jobid",                        /* 1 */
990       "client",                       /* 2 */
991       "fd",
992       "fileset",                      /* 4 */
993       "level",                        /* 5 */
994       "storage",                      /* 6 */
995       "sd",                           /* 7 */
996       "regexwhere",                   /* 8 where string as a bregexp */
997       "where",                        /* 9 */
998       "bootstrap",                    /* 10 */
999       "replace",                      /* 11 */
1000       "when",                         /* 12 */
1001       "priority",                     /* 13 */
1002       "yes",          /* 14  -- if you change this change YES_POS too */
1003       "verifyjob",                    /* 15 */
1004       "files",                        /* 16 number of files to restore */
1005       "catalog",                      /* 17 override catalog */
1006       "since",                        /* 18 since */
1007       "cloned",                       /* 19 cloned */
1008       "verifylist",                   /* 20 verify output list */
1009       "migrationjob",                 /* 21 migration job name */
1010       "pool",                         /* 22 */
1011       "backupclient",                 /* 23 */
1012       "restoreclient",                /* 24 */
1013       "pluginoptions",                /* 25 */
1014       "spooldata",                    /* 26 */
1015       NULL};
1016
1017 #define YES_POS 14
1018
1019    rc.catalog_name = NULL;
1020    rc.job_name = NULL;
1021    rc.pool_name = NULL;
1022    rc.store_name = NULL;
1023    rc.client_name = NULL;
1024    rc.restore_client_name = NULL;
1025    rc.fileset_name = NULL;
1026    rc.verify_job_name = NULL;
1027    rc.previous_job_name = NULL;
1028    rc.spool_data_set = 0;
1029
1030
1031    for (i=1; i<ua->argc; i++) {
1032       Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1033       kw_ok = false;
1034       /* Keep looking until we find a good keyword */
1035       for (j=0; !kw_ok && kw[j]; j++) {
1036          if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1037             /* Note, yes and run have no value, so do not fail */
1038             if (!ua->argv[i] && j != YES_POS /*yes*/) {
1039                ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1040                return false;
1041             }
1042             Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1043             switch (j) {
1044             case 0: /* job */
1045                if (rc.job_name) {
1046                   ua->send_msg(_("Job name specified twice.\n"));
1047                   return false;
1048                }
1049                rc.job_name = ua->argv[i];
1050                kw_ok = true;
1051                break;
1052             case 1: /* JobId */
1053                if (rc.jid && !rc.mod) {
1054                   ua->send_msg(_("JobId specified twice.\n"));
1055                   return false;
1056                }
1057                rc.jid = ua->argv[i];
1058                kw_ok = true;
1059                break;
1060             case 2: /* client */
1061             case 3: /* fd */
1062                if (rc.client_name) {
1063                   ua->send_msg(_("Client specified twice.\n"));
1064                   return false;
1065                }
1066                rc.client_name = ua->argv[i];
1067                kw_ok = true;
1068                break;
1069             case 4: /* fileset */
1070                if (rc.fileset_name) {
1071                   ua->send_msg(_("FileSet specified twice.\n"));
1072                   return false;
1073                }
1074                rc.fileset_name = ua->argv[i];
1075                kw_ok = true;
1076                break;
1077             case 5: /* level */
1078                if (rc.level_name) {
1079                   ua->send_msg(_("Level specified twice.\n"));
1080                   return false;
1081                }
1082                rc.level_name = ua->argv[i];
1083                kw_ok = true;
1084                break;
1085             case 6: /* storage */
1086             case 7: /* sd */
1087                if (rc.store_name) {
1088                   ua->send_msg(_("Storage specified twice.\n"));
1089                   return false;
1090                }
1091                rc.store_name = ua->argv[i];
1092                kw_ok = true;
1093                break;
1094             case 8: /* regexwhere */
1095                 if ((rc.regexwhere || rc.where) && !rc.mod) {
1096                   ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1097                   return false;
1098                }
1099                rc.regexwhere = ua->argv[i];
1100                if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1101                   ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1102                   return false;
1103                }
1104                kw_ok = true;
1105                break;
1106            case 9: /* where */
1107                if ((rc.where || rc.regexwhere) && !rc.mod) {
1108                   ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1109                   return false;
1110                }
1111                rc.where = ua->argv[i];
1112                if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1113                   ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1114                   return false;
1115                }
1116                kw_ok = true;
1117                break;
1118             case 10: /* bootstrap */
1119                if (rc.bootstrap && !rc.mod) {
1120                   ua->send_msg(_("Bootstrap specified twice.\n"));
1121                   return false;
1122                }
1123                rc.bootstrap = ua->argv[i];
1124                kw_ok = true;
1125                break;
1126             case 11: /* replace */
1127                if (rc.replace && !rc.mod) {
1128                   ua->send_msg(_("Replace specified twice.\n"));
1129                   return false;
1130                }
1131                rc.replace = ua->argv[i];
1132                kw_ok = true;
1133                break;
1134             case 12: /* When */
1135                if (rc.when && !rc.mod) {
1136                   ua->send_msg(_("When specified twice.\n"));
1137                   return false;
1138                }
1139                rc.when = ua->argv[i];
1140                kw_ok = true;
1141                break;
1142             case 13:  /* Priority */
1143                if (rc.Priority && !rc.mod) {
1144                   ua->send_msg(_("Priority specified twice.\n"));
1145                   return false;
1146                }
1147                rc.Priority = atoi(ua->argv[i]);
1148                if (rc.Priority <= 0) {
1149                   ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1150                   rc.Priority = 10;
1151                }
1152                kw_ok = true;
1153                break;
1154             case 14: /* yes */
1155                kw_ok = true;
1156                break;
1157             case 15: /* Verify Job */
1158                if (rc.verify_job_name) {
1159                   ua->send_msg(_("Verify Job specified twice.\n"));
1160                   return false;
1161                }
1162                rc.verify_job_name = ua->argv[i];
1163                kw_ok = true;
1164                break;
1165             case 16: /* files */
1166                rc.files = atoi(ua->argv[i]);
1167                kw_ok = true;
1168                break;
1169
1170             case 17: /* catalog */
1171                rc.catalog_name = ua->argv[i];
1172                kw_ok = true;
1173                break;
1174
1175             case 18: /* since */
1176                rc.since = ua->argv[i];
1177                kw_ok = true; 
1178                break;
1179
1180             case 19: /* cloned */
1181                rc. cloned = true;
1182                kw_ok = true;
1183                break;
1184
1185             case 20: /* write verify list output */
1186                rc.verify_list = ua->argv[i];
1187                kw_ok = true;
1188                break;
1189             case 21: /* Migration Job */
1190                if (rc.previous_job_name) {
1191                   ua->send_msg(_("Migration Job specified twice.\n"));
1192                   return false;
1193                }
1194                rc.previous_job_name = ua->argv[i];
1195                kw_ok = true;
1196                break;
1197             case 22: /* pool */
1198                if (rc.pool_name) {
1199                   ua->send_msg(_("Pool specified twice.\n"));
1200                   return false;
1201                }
1202                rc.pool_name = ua->argv[i];
1203                kw_ok = true;
1204                break;
1205             case 23: /* backupclient */
1206                if (rc.client_name) {
1207                   ua->send_msg(_("Client specified twice.\n"));
1208                   return 0;
1209                }
1210                rc.client_name = ua->argv[i];
1211                kw_ok = true;
1212                break;
1213             case 24: /* restoreclient */
1214                if (rc.restore_client_name && !rc.mod) {
1215                   ua->send_msg(_("Restore Client specified twice.\n"));
1216                   return false;
1217                }
1218                rc.restore_client_name = ua->argv[i];
1219                kw_ok = true;
1220                break;
1221             case 25: /* pluginoptions */
1222                ua->send_msg(_("Plugin Options not yet implemented.\n"));
1223                return false;
1224                if (rc.plugin_options) {
1225                   ua->send_msg(_("Plugin Options specified twice.\n"));
1226                   return false;
1227                }
1228                rc.plugin_options = ua->argv[i];
1229                if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1230                   ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1231                   return false;
1232                }
1233                kw_ok = true;
1234                break;
1235             case 26: /* spooldata */
1236                if (rc.spool_data_set) {
1237                   ua->send_msg(_("Spool flag specified twice.\n"));
1238                   return false;
1239                }
1240                if (is_yesno(ua->argv[i], &rc.spool_data)) {
1241                   rc.spool_data_set = 1;
1242                   kw_ok = true;
1243                } else {
1244                   ua->send_msg(_("Invalid spooldata flag.\n"));
1245                }
1246                break;
1247             default:
1248                break;
1249             }
1250          } /* end strcase compare */
1251       } /* end keyword loop */
1252       /*
1253        * End of keyword for loop -- if not found, we got a bogus keyword
1254        */
1255       if (!kw_ok) {
1256          Dmsg1(800, "%s not found\n", ua->argk[i]);
1257          /*
1258           * Special case for Job Name, it can be the first
1259           * keyword that has no value.
1260           */
1261          if (!rc.job_name && !ua->argv[i]) {
1262             rc.job_name = ua->argk[i];   /* use keyword as job name */
1263             Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1264          } else {
1265             ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1266             return false;
1267          }
1268       }
1269    } /* end argc loop */
1270              
1271    Dmsg0(800, "Done scan.\n");
1272
1273    if (rc.catalog_name) {
1274        rc.catalog = GetCatalogResWithName(rc.catalog_name);
1275        if (rc.catalog == NULL) {
1276             ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1277            return false;
1278        }
1279        if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1280           ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1281           return false;
1282        }
1283    }
1284    Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1285
1286    if (rc.job_name) {
1287       /* Find Job */
1288       rc.job = GetJobResWithName(rc.job_name);
1289       if (!rc.job) {
1290          if (*rc.job_name != 0) {
1291             ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1292          }
1293          rc.job = select_job_resource(ua);
1294       } else {
1295          Dmsg1(800, "Found job=%s\n", rc.job_name);
1296       }
1297    } else if (!rc.job) {
1298       ua->send_msg(_("A job name must be specified.\n"));
1299       rc.job = select_job_resource(ua);
1300    }
1301    if (!rc.job) {
1302       return false;
1303    } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1304       ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1305       return false;
1306    }
1307
1308    if (rc.pool_name) {
1309       rc.pool = GetPoolResWithName(rc.pool_name);
1310       if (!rc.pool) {
1311          if (*rc.pool_name != 0) {
1312             ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1313          }
1314          rc.pool = select_pool_resource(ua);
1315       }
1316    } else if (!rc.pool) {
1317       rc.pool = rc.job->pool;             /* use default */
1318    }
1319    if (!rc.pool) {
1320       return false;
1321    } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1322       ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1323       return false;
1324    }
1325    Dmsg1(100, "Using pool %s\n", rc.pool->name());
1326
1327    if (rc.spool_data_set) {
1328       rc.job->spool_data = rc.spool_data;
1329    }
1330    Dmsg1(900, "Spooling data: %s\n", (rc.job->spool_data ? "Yes" : "No"));
1331
1332    if (rc.store_name) {
1333       rc.store->store = GetStoreResWithName(rc.store_name);
1334       pm_strcpy(rc.store->store_source, _("command line"));
1335       if (!rc.store->store) {
1336          if (*rc.store_name != 0) {
1337             ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1338          }
1339          rc.store->store = select_storage_resource(ua);
1340          pm_strcpy(rc.store->store_source, _("user selection"));
1341       }
1342    } else if (!rc.store->store) {
1343       get_job_storage(rc.store, rc.job, NULL);      /* use default */
1344    }
1345    if (!rc.store->store) {
1346       ua->error_msg(_("No storage specified.\n"));
1347       return false;
1348    } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1349       ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1350                rc.store->store->name());
1351       return false;
1352    }
1353    Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1354
1355    if (rc.client_name) {
1356       rc.client = GetClientResWithName(rc.client_name);
1357       if (!rc.client) {
1358          if (*rc.client_name != 0) {
1359             ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1360          }
1361          rc.client = select_client_resource(ua);
1362       }
1363    } else if (!rc.client) {
1364       rc.client = rc.job->client;           /* use default */
1365    }
1366    if (!rc.client) {
1367       return false;
1368    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1369       ua->error_msg(_("No authorization. Client \"%s\".\n"),
1370                rc.client->name());
1371       return false;
1372    }
1373    Dmsg1(800, "Using client=%s\n", rc.client->name());
1374
1375    if (rc.restore_client_name) {
1376       rc.client = GetClientResWithName(rc.restore_client_name);
1377       if (!rc.client) {
1378          if (*rc.restore_client_name != 0) {
1379             ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1380          }
1381          rc.client = select_client_resource(ua);
1382       }
1383    } else if (!rc.client) {
1384       rc.client = rc.job->client;           /* use default */
1385    }
1386    if (!rc.client) {
1387       return false;
1388    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1389       ua->error_msg(_("No authorization. Client \"%s\".\n"),
1390                rc.client->name());
1391       return false;
1392    }
1393    Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1394
1395
1396    if (rc.fileset_name) {
1397       rc.fileset = GetFileSetResWithName(rc.fileset_name);
1398       if (!rc.fileset) {
1399          ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1400          rc.fileset = select_fileset_resource(ua);
1401       }
1402    } else if (!rc.fileset) {
1403       rc.fileset = rc.job->fileset;           /* use default */
1404    }
1405    if (!rc.fileset) {
1406       return false;
1407    } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1408       ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1409                rc.fileset->name());
1410       return false;
1411    }
1412
1413    if (rc.verify_job_name) {
1414       rc.verify_job = GetJobResWithName(rc.verify_job_name);
1415       if (!rc.verify_job) {
1416          ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1417          rc.verify_job = select_job_resource(ua);
1418       }
1419    } else if (!rc.verify_job) {
1420       rc.verify_job = rc.job->verify_job;
1421    }
1422
1423    if (rc.previous_job_name) {
1424       rc.previous_job = GetJobResWithName(rc.previous_job_name);
1425       if (!rc.previous_job) {
1426          ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1427          rc.previous_job = select_job_resource(ua);
1428       }
1429    } else {
1430       rc.previous_job = rc.job->verify_job;
1431    }
1432    return true;
1433 }