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