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