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