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