]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
Fix bug #1751 Make duplicate checking somewhat less naiv.
[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    int ignoreduplicatecheck;
65    bool ignoreduplicatecheck_set;
66
67    /* Methods */
68    run_ctx() { memset(this, 0, sizeof(run_ctx)); 
69                store = new USTORE; };
70    ~run_ctx() { delete store; };
71 };
72
73 /* Forward referenced subroutines */
74 static void select_job_level(UAContext *ua, JCR *jcr);
75 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, 
76                 const char *verify_list, char *jid, const char *replace,
77                 char *client_name);
78 static void select_where_regexp(UAContext *ua, JCR *jcr);
79 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc);
80 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc);
81 static int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc);
82
83 /* Imported variables */
84 extern struct s_kw ReplaceOptions[];
85
86 /*
87  * For Backup and Verify Jobs
88  *     run [job=]<job-name> level=<level-name>
89  *
90  * For Restore Jobs
91  *     run <job-name> 
92  *
93  *  Returns: 0 on error
94  *           JobId if OK
95  *
96  */
97 int run_cmd(UAContext *ua, const char *cmd)
98 {
99    JCR *jcr = NULL;
100    run_ctx rc;
101    int status;
102
103    if (!open_client_db(ua)) {
104       return 1;
105    }
106
107    if (!scan_command_line_arguments(ua, rc)) {
108       return 0;
109    }
110
111    if (find_arg(ua, NT_("fdcalled")) > 0) {
112       jcr->file_bsock = dup_bsock(ua->UA_sock);
113       ua->quit = true;
114    }
115
116    /*
117     * Create JCR to run job.  NOTE!!! after this point, free_jcr()
118     *  before returning.
119     */
120    if (!jcr) {
121       jcr = new_jcr(sizeof(JCR), dird_free_jcr);
122       set_jcr_defaults(jcr, rc.job);
123       jcr->unlink_bsr = ua->jcr->unlink_bsr;    /* copy unlink flag from caller */
124       ua->jcr->unlink_bsr = false;
125    }
126    /* Transfer JobIds to new restore Job */
127    if (ua->jcr->JobIds) {
128       jcr->JobIds = ua->jcr->JobIds;
129       ua->jcr->JobIds = NULL;
130    }
131
132 try_again:
133    if (!reset_restore_context(ua, jcr, rc)) {
134       goto bail_out;
135    }
136
137
138    /* Run without prompting? */
139    if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
140       goto start_job;
141    }
142
143    /*
144     * Prompt User to see if all run job parameters are correct, and
145     *   allow him to modify them.
146     */
147    if (!display_job_parameters(ua, jcr, rc.job, rc.verify_list, rc.jid, rc.replace,
148         rc.client_name)) {
149       goto bail_out;
150    }
151
152    if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
153       goto bail_out;
154    }
155
156    if (strncasecmp(ua->cmd, ".mod ", 5) == 0 || 
157        (strncasecmp(ua->cmd, "mod ", 4) == 0 && strlen(ua->cmd) > 6)) {
158       parse_ua_args(ua);
159       rc.mod = true;
160       if (!scan_command_line_arguments(ua, rc)) {
161          return 0;
162       }
163       goto try_again;
164    }
165
166    /* Allow the user to modify the settings */
167    status = modify_job_parameters(ua, jcr, rc);
168    switch (status) {
169    case 0:
170       goto try_again;
171    case 1:
172       break;
173    case -1:
174       goto bail_out;
175    }
176
177
178    if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
179       JobId_t JobId;
180       Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
181
182 start_job:
183       Dmsg3(100, "JobId=%u using pool %s priority=%d\n", (int)jcr->JobId, 
184             jcr->pool->name(), jcr->JobPriority);
185       Dmsg1(900, "Running a job; its spool_data = %d\n", jcr->spool_data);
186       JobId = run_job(jcr);
187       Dmsg4(100, "JobId=%u NewJobId=%d using pool %s priority=%d\n", (int)jcr->JobId, 
188             JobId, jcr->pool->name(), jcr->JobPriority);
189       free_jcr(jcr);                  /* release jcr */
190       if (JobId == 0) {
191          ua->error_msg(_("Job failed.\n"));
192       } else {
193          char ed1[50];
194          ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId, ed1));
195       }
196       return JobId;
197    }
198
199 bail_out:
200    ua->send_msg(_("Job not run.\n"));
201    free_jcr(jcr);
202    return 0;                       /* do not run */
203 }
204
205 int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc)
206 {
207    int i, opt;
208    /*
209     * At user request modify parameters of job to be run.
210     */
211    if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
212       FILE *fd;
213
214       start_prompt(ua, _("Parameters to modify:\n"));
215       add_prompt(ua, _("Level"));            /* 0 */
216       add_prompt(ua, _("Storage"));          /* 1 */
217       add_prompt(ua, _("Job"));              /* 2 */
218       add_prompt(ua, _("FileSet"));          /* 3 */
219       if (jcr->getJobType() == JT_RESTORE) {
220          add_prompt(ua, _("Restore Client"));   /* 4 */
221       } else {
222          add_prompt(ua, _("Client"));        /* 4 */
223       }
224       add_prompt(ua, _("When"));             /* 5 */
225       add_prompt(ua, _("Priority"));         /* 6 */
226       if (jcr->getJobType() == JT_BACKUP ||
227           jcr->getJobType() == JT_COPY ||
228           jcr->getJobType() == JT_MIGRATE ||
229           jcr->getJobType() == JT_VERIFY) {
230          add_prompt(ua, _("Pool"));          /* 7 */
231          if (jcr->getJobType() == JT_VERIFY) {
232             add_prompt(ua, _("Verify Job"));  /* 8 */
233          }
234       } else if (jcr->getJobType() == JT_RESTORE) {
235          add_prompt(ua, _("Bootstrap"));     /* 7 */
236          add_prompt(ua, _("Where"));         /* 8 */
237          add_prompt(ua, _("File Relocation"));/* 9 */    
238          add_prompt(ua, _("Replace"));       /* 10 */
239          add_prompt(ua, _("JobId"));         /* 11 */
240       }
241       if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
242          add_prompt(ua, _("Plugin Options")); /* 12 */
243       }
244       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
245       case 0:
246          /* Level */
247          select_job_level(ua, jcr);
248          goto try_again;
249       case 1:
250          /* Storage */
251          rc.store->store = select_storage_resource(ua);
252          if (rc.store->store) {
253             pm_strcpy(rc.store->store_source, _("user selection"));
254             set_rwstorage(jcr, rc.store);
255             goto try_again;
256          }
257          break;
258       case 2:
259          /* Job */
260          rc.job = select_job_resource(ua);
261          if (rc.job) {
262             jcr->job = rc.job;
263             set_jcr_defaults(jcr, rc.job);
264             goto try_again;
265          }
266          break;
267       case 3:
268          /* FileSet */
269          rc.fileset = select_fileset_resource(ua);
270          if (rc.fileset) {
271             jcr->fileset = rc.fileset;
272             goto try_again;
273          }
274          break;
275       case 4:
276          /* Client */
277          rc.client = select_client_resource(ua);
278          if (rc.client) {
279             jcr->client = rc.client;
280             goto try_again;
281          }
282          break;
283       case 5:
284          /* When */
285          if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
286             break;
287          }
288          if (ua->cmd[0] == 0) {
289             jcr->sched_time = time(NULL);
290          } else {
291             jcr->sched_time = str_to_utime(ua->cmd);
292             if (jcr->sched_time == 0) {
293                ua->send_msg(_("Invalid time, using current time.\n"));
294                jcr->sched_time = time(NULL);
295             }
296          }
297          goto try_again;
298       case 6:
299          /* Priority */
300          if (!get_pint(ua, _("Enter new Priority: "))) {
301             break;
302          }
303          if (ua->pint32_val == 0) {
304             ua->send_msg(_("Priority must be a positive integer.\n"));
305          } else {
306             jcr->JobPriority = ua->pint32_val;
307          }
308          goto try_again;
309       case 7: 
310          /* Pool or Bootstrap depending on JobType */
311          if (jcr->getJobType() == JT_BACKUP ||
312              jcr->getJobType() == JT_COPY ||
313              jcr->getJobType() == JT_MIGRATE ||
314              jcr->getJobType() == JT_VERIFY) {      /* Pool */
315             rc.pool = select_pool_resource(ua);
316             if (rc.pool) {
317                jcr->pool = rc.pool;
318                Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
319                goto try_again;
320             }
321             break;
322          }
323
324          /* Bootstrap */
325          if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
326             break;
327          }
328          if (jcr->RestoreBootstrap) {
329             free(jcr->RestoreBootstrap);
330             jcr->RestoreBootstrap = NULL;
331          }
332          if (ua->cmd[0] != 0) {
333             jcr->RestoreBootstrap = bstrdup(ua->cmd);
334             fd = fopen(jcr->RestoreBootstrap, "rb");
335             if (!fd) {
336                berrno be;
337                ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
338                   jcr->RestoreBootstrap, be.bstrerror());
339                free(jcr->RestoreBootstrap);
340                jcr->RestoreBootstrap = NULL;
341             } else {
342                fclose(fd);
343             }
344          }
345          goto try_again;
346       case 8:
347          /* Verify Job */
348          if (jcr->getJobType() == JT_VERIFY) {
349             rc.verify_job = select_job_resource(ua);
350             if (rc.verify_job) {
351               jcr->verify_job = rc.verify_job;
352             }
353             goto try_again;
354          }
355          /* Where */
356          if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
357             break;
358          }
359          if (jcr->RegexWhere) { /* cannot use regexwhere and where */
360             free(jcr->RegexWhere);
361             jcr->RegexWhere = NULL;
362          }
363          if (jcr->where) {
364             free(jcr->where);
365             jcr->where = NULL;
366          }
367          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
368             ua->cmd[0] = 0;
369          }
370          jcr->where = bstrdup(ua->cmd);
371          goto try_again;
372       case 9: 
373          /* File relocation */
374          select_where_regexp(ua, jcr);
375          goto try_again;
376       case 10:
377          /* Replace */
378          start_prompt(ua, _("Replace:\n"));
379          for (i=0; ReplaceOptions[i].name; i++) {
380             add_prompt(ua, ReplaceOptions[i].name);
381          }
382          opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
383          if (opt >=  0) {
384             rc.replace = ReplaceOptions[opt].name;
385             jcr->replace = ReplaceOptions[opt].token;
386          }
387          goto try_again;
388       case 11:
389          /* JobId */
390          rc.jid = NULL;                  /* force reprompt */
391          jcr->RestoreJobId = 0;
392          if (jcr->RestoreBootstrap) {
393             ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
394          }
395          goto try_again;
396       case 12:        
397          /* Plugin Options */
398          if (!get_cmd(ua, _("Please Plugin Options string: "))) {
399             break;
400          }
401          if (jcr->plugin_options) {
402             free(jcr->plugin_options);
403             jcr->plugin_options = NULL;
404          }
405          jcr->plugin_options = bstrdup(ua->cmd);
406          goto try_again;
407       case -1:                        /* error or cancel */
408          goto bail_out;
409       default:
410          goto try_again;
411       }
412       goto bail_out;
413    }
414    return 1;
415
416 bail_out:
417    return -1;
418
419 try_again:
420    return 0;
421 }
422
423 /*
424  * Reset the restore context. 
425  * This subroutine can be called multiple times, so it
426  *  must keep any prior settings.
427  */
428 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc)
429 {
430    int i;
431
432    jcr->verify_job = rc.verify_job;
433    jcr->previous_job = rc.previous_job;
434    jcr->pool = rc.pool;
435    if (jcr->pool != jcr->job->pool) {
436       pm_strcpy(jcr->pool_source, _("User input"));
437    }
438    set_rwstorage(jcr, rc.store);
439    jcr->client = rc.client;
440    pm_strcpy(jcr->client_name, rc.client->name());
441    jcr->fileset = rc.fileset;
442    jcr->ExpectedFiles = rc.files;
443    if (rc.catalog) {
444       jcr->catalog = rc.catalog;
445       pm_strcpy(jcr->catalog_source, _("User input"));
446    }
447
448    pm_strcpy(jcr->comment, rc.comment);
449
450    if (rc.where) {
451       if (jcr->where) {
452          free(jcr->where);
453       }
454       jcr->where = bstrdup(rc.where);
455       rc.where = NULL;
456    }
457
458    if (rc.regexwhere) {
459       if (jcr->RegexWhere) {
460          free(jcr->RegexWhere);
461       }
462       jcr->RegexWhere = bstrdup(rc.regexwhere);       
463       rc.regexwhere = NULL;
464    }
465
466    if (rc.when) {
467       jcr->sched_time = str_to_utime(rc.when);
468       if (jcr->sched_time == 0) {
469          ua->send_msg(_("Invalid time, using current time.\n"));
470          jcr->sched_time = time(NULL);
471       }
472       rc.when = NULL;
473    }
474
475    if (rc.bootstrap) {
476       if (jcr->RestoreBootstrap) {
477          free(jcr->RestoreBootstrap);
478       }
479       jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
480       rc.bootstrap = NULL;
481    }
482
483    if (rc.plugin_options) {
484       if (jcr->plugin_options) {
485          free(jcr->plugin_options);
486       }
487       jcr->plugin_options = bstrdup(rc.plugin_options);
488       rc.plugin_options = NULL;
489    }
490
491    if (rc.replace) {
492       jcr->replace = 0;
493       for (i=0; ReplaceOptions[i].name; i++) {
494          if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
495             jcr->replace = ReplaceOptions[i].token;
496          }
497       }
498       if (!jcr->replace) {
499          ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
500          return false;
501       }
502    } else if (rc.job->replace) {
503       jcr->replace = rc.job->replace;
504    } else {
505       jcr->replace = REPLACE_ALWAYS;
506    }
507    rc.replace = NULL;
508
509    if (rc.Priority) {
510       jcr->JobPriority = rc.Priority;
511       rc.Priority = 0;
512    }
513
514    if (rc.since) {
515       if (!jcr->stime) {
516          jcr->stime = get_pool_memory(PM_MESSAGE);
517       }
518       pm_strcpy(jcr->stime, rc.since);
519       rc.since = NULL;
520    }
521
522    if (rc.cloned) {
523       jcr->cloned = rc.cloned;
524       rc.cloned = false;
525    }
526
527    /* If pool changed, update migration write storage */
528    if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
529       (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(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->setJobLevel(L_FULL);
704          break;
705       case 1:
706          jcr->setJobLevel(L_INCREMENTAL);
707          break;
708       case 2:
709          jcr->setJobLevel(L_DIFFERENTIAL);
710          break;
711       case 3:
712          jcr->setJobLevel(L_SINCE);
713          break;
714       case 4:
715          jcr->setJobLevel(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->setJobLevel(L_VERIFY_INIT);
730          break;
731       case 1:
732          jcr->setJobLevel(L_VERIFY_CATALOG);
733          break;
734       case 2:
735          jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
736          break;
737       case 3:
738          jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
739          break;
740       case 4:
741          jcr->setJobLevel(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 Admin 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                  job->name(),
786                  jcr->fileset->name(),
787                  NPRT(jcr->client->name()),
788                  jcr->wstore?jcr->wstore->name():"*None*",
789                  bstrutime(dt, sizeof(dt), jcr->sched_time),
790                  jcr->JobPriority);
791       }
792       jcr->setJobLevel(L_FULL);
793       break;
794    case JT_BACKUP:
795    case JT_VERIFY:
796       if (jcr->getJobType() == JT_BACKUP) {
797          if (ua->api) {
798             ua->signal(BNET_RUN_CMD);   
799             ua->send_msg("Type: Backup\n"
800                         "Title: Run Backup Job\n"
801                         "JobName:  %s\n"
802                         "Level:    %s\n"
803                         "Client:   %s\n"
804                         "FileSet:  %s\n"
805                         "Pool:     %s\n"
806                         "Storage:  %s\n"
807                         "When:     %s\n"
808                         "Priority: %d\n"
809                         "%s%s%s",
810                  job->name(),
811                  level_to_str(jcr->getJobLevel()),
812                  jcr->client->name(),
813                  jcr->fileset->name(),
814                  NPRT(jcr->pool->name()),
815                  jcr->wstore?jcr->wstore->name():"*None*",
816                  bstrutime(dt, sizeof(dt), jcr->sched_time),
817                  jcr->JobPriority,
818                  jcr->plugin_options?"Plugin Options: ":"",
819                  jcr->plugin_options?jcr->plugin_options:"",
820                  jcr->plugin_options?"\n":"");
821          } else {
822             ua->send_msg(_("Run Backup job\n"
823                         "JobName:  %s\n"
824                         "Level:    %s\n"
825                         "Client:   %s\n"
826                         "FileSet:  %s\n"
827                         "Pool:     %s (From %s)\n"
828                         "Storage:  %s (From %s)\n"
829                         "When:     %s\n"
830                         "Priority: %d\n"
831                         "%s%s%s"),
832                  job->name(),
833                  level_to_str(jcr->getJobLevel()),
834                  jcr->client->name(),
835                  jcr->fileset->name(),
836                  NPRT(jcr->pool->name()), jcr->pool_source,
837                  jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
838                  bstrutime(dt, sizeof(dt), jcr->sched_time),
839                  jcr->JobPriority,
840                  jcr->plugin_options?"Plugin Options: ":"",
841                  jcr->plugin_options?jcr->plugin_options:"",
842                  jcr->plugin_options?"\n":"");
843          }
844       } else {  /* JT_VERIFY */
845          JOB_DBR jr;
846          const char *Name;
847          if (jcr->verify_job) {
848             Name = jcr->verify_job->name();
849          } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
850             memset(&jr, 0, sizeof(jr));
851             jr.JobId = jcr->RestoreJobId;
852             if (!db_get_job_record(jcr, ua->db, &jr)) {
853                ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
854                     db_strerror(ua->db));
855                return false;
856             }
857             Name = jr.Job;
858          } else {
859             Name = "";
860          }
861          if (!verify_list) {
862             verify_list = job->WriteVerifyList;
863          }
864          if (!verify_list) {
865             verify_list = "";
866          }
867          if (ua->api) {
868             ua->signal(BNET_RUN_CMD);   
869             ua->send_msg("Type: Verify\n"
870                         "Title: Run Verify Job\n"
871                         "JobName:     %s\n"
872                         "Level:       %s\n"
873                         "Client:      %s\n"
874                         "FileSet:     %s\n"
875                         "Pool:        %s (From %s)\n"
876                         "Storage:     %s (From %s)\n"
877                         "Verify Job:  %s\n"
878                         "Verify List: %s\n"
879                         "When:        %s\n"
880                         "Priority:    %d\n",
881               job->name(),
882               level_to_str(jcr->getJobLevel()),
883               jcr->client->name(),
884               jcr->fileset->name(),
885               NPRT(jcr->pool->name()), jcr->pool_source,
886               jcr->rstore->name(), jcr->rstore_source,
887               Name,
888               verify_list,
889               bstrutime(dt, sizeof(dt), jcr->sched_time),
890               jcr->JobPriority);
891          } else {
892             ua->send_msg(_("Run Verify Job\n"
893                         "JobName:     %s\n"
894                         "Level:       %s\n"
895                         "Client:      %s\n"
896                         "FileSet:     %s\n"
897                         "Pool:        %s (From %s)\n"
898                         "Storage:     %s (From %s)\n"
899                         "Verify Job:  %s\n"
900                         "Verify List: %s\n"
901                         "When:        %s\n"
902                         "Priority:    %d\n"),
903               job->name(),
904               level_to_str(jcr->getJobLevel()),
905               jcr->client->name(),
906               jcr->fileset->name(),
907               NPRT(jcr->pool->name()), jcr->pool_source,
908               jcr->rstore->name(), jcr->rstore_source,
909               Name,
910               verify_list,
911               bstrutime(dt, sizeof(dt), jcr->sched_time),
912               jcr->JobPriority);
913          }
914       }
915       break;
916    case JT_RESTORE:
917       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
918          if (jid) {
919             jcr->RestoreJobId = str_to_int64(jid);
920          } else {
921             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
922                return false;
923             }
924             jcr->RestoreJobId = ua->int64_val;
925          }
926       }
927       jcr->setJobLevel(L_FULL);      /* default level */
928       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
929       if (jcr->RestoreJobId == 0) {
930          /* RegexWhere is take before RestoreWhere */
931          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
932             if (ua->api) {
933                ua->signal(BNET_RUN_CMD);   
934                ua->send_msg("Type: Restore\n"
935                         "Title: Run Restore Job\n"
936                         "JobName:         %s\n"
937                         "Bootstrap:       %s\n"
938                         "RegexWhere:      %s\n"
939                         "Replace:         %s\n"
940                         "FileSet:         %s\n"
941                         "Backup Client:   %s\n"
942                         "Restore Client:  %s\n"
943                         "Storage:         %s\n"
944                         "When:            %s\n"
945                         "Catalog:         %s\n"
946                         "Priority:        %d\n"
947                         "Plugin Options:  %s\n",
948                  job->name(),
949                  NPRT(jcr->RestoreBootstrap), 
950                  jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
951                  replace,
952                  jcr->fileset->name(),
953                  client_name,
954                  jcr->client->name(),
955                  jcr->rstore->name(),
956                  bstrutime(dt, sizeof(dt), jcr->sched_time),
957                  jcr->catalog->name(),
958                  jcr->JobPriority,
959                  NPRT(jcr->plugin_options));
960             } else {
961                ua->send_msg(_("Run Restore job\n"
962                         "JobName:         %s\n"
963                         "Bootstrap:       %s\n"
964                         "RegexWhere:      %s\n"
965                         "Replace:         %s\n"
966                         "FileSet:         %s\n"
967                         "Backup Client:   %s\n"
968                         "Restore Client:  %s\n"
969                         "Storage:         %s\n"
970                         "When:            %s\n"
971                         "Catalog:         %s\n"
972                         "Priority:        %d\n"
973                         "Plugin Options:  %s\n"),
974                  job->name(),
975                  NPRT(jcr->RestoreBootstrap), 
976                  jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
977                  replace,
978                  jcr->fileset->name(),
979                  client_name,
980                  jcr->client->name(),
981                  jcr->rstore->name(),
982                  bstrutime(dt, sizeof(dt), jcr->sched_time),
983                  jcr->catalog->name(),
984                  jcr->JobPriority,
985                  NPRT(jcr->plugin_options));
986             }
987          } else {
988             if (ua->api) {
989                ua->signal(BNET_RUN_CMD);   
990                ua->send_msg("Type: Restore\n"
991                         "Title: Run Restore job\n"
992                         "JobName:         %s\n"
993                         "Bootstrap:       %s\n"
994                         "Where:           %s\n"
995                         "Replace:         %s\n"
996                         "FileSet:         %s\n"
997                         "Backup Client:   %s\n"
998                         "Restore Client:  %s\n"
999                         "Storage:         %s\n"
1000                         "When:            %s\n"
1001                         "Catalog:         %s\n"
1002                         "Priority:        %d\n"
1003                         "Plugin Options:  %s\n",
1004                  job->name(),
1005                  NPRT(jcr->RestoreBootstrap), 
1006                  jcr->where?jcr->where:NPRT(job->RestoreWhere), 
1007                  replace,
1008                  jcr->fileset->name(),
1009                  client_name,
1010                  jcr->client->name(),
1011                  jcr->rstore->name(),
1012                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1013                  jcr->catalog->name(),
1014                  jcr->JobPriority,
1015                  NPRT(jcr->plugin_options));
1016             } else {
1017                ua->send_msg(_("Run Restore job\n"
1018                         "JobName:         %s\n"
1019                         "Bootstrap:       %s\n"
1020                         "Where:           %s\n"
1021                         "Replace:         %s\n"
1022                         "FileSet:         %s\n"
1023                         "Backup Client:   %s\n"
1024                         "Restore Client:  %s\n"
1025                         "Storage:         %s\n"
1026                         "When:            %s\n"
1027                         "Catalog:         %s\n"
1028                         "Priority:        %d\n"
1029                         "Plugin Options:  %s\n"),
1030                  job->name(),
1031                  NPRT(jcr->RestoreBootstrap), 
1032                  jcr->where?jcr->where:NPRT(job->RestoreWhere), 
1033                  replace,
1034                  jcr->fileset->name(),
1035                  client_name,
1036                  jcr->client->name(),
1037                  jcr->rstore->name(),
1038                  bstrutime(dt, sizeof(dt), jcr->sched_time),
1039                  jcr->catalog->name(),
1040                  jcr->JobPriority,
1041                  NPRT(jcr->plugin_options));
1042             }
1043          }
1044
1045       } else {
1046          /* ***FIXME*** This needs to be fixed for bat */
1047          if (ua->api) ua->signal(BNET_RUN_CMD);   
1048          ua->send_msg(_("Run Restore job\n"
1049                         "JobName:    %s\n"
1050                         "Bootstrap:  %s\n"),
1051                       job->name(),
1052                       NPRT(jcr->RestoreBootstrap));
1053                       
1054          /* RegexWhere is take before RestoreWhere */
1055          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1056             ua->send_msg(_("RegexWhere: %s\n"),
1057                          jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
1058          } else {
1059             ua->send_msg(_("Where:      %s\n"),
1060                          jcr->where?jcr->where:NPRT(job->RestoreWhere));
1061          }
1062
1063          ua->send_msg(_("Replace:         %s\n"
1064                         "Client:          %s\n"
1065                         "Storage:         %s\n"
1066                         "JobId:           %s\n"
1067                         "When:            %s\n"
1068                         "Catalog:         %s\n"
1069                         "Priority:        %d\n"
1070                         "Plugin Options:  %s\n"),
1071               replace,
1072               jcr->client->name(),
1073               jcr->rstore->name(),
1074               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
1075               bstrutime(dt, sizeof(dt), jcr->sched_time),
1076               jcr->catalog->name(),
1077               jcr->JobPriority,
1078               NPRT(jcr->plugin_options));
1079       }
1080       break;
1081    case JT_COPY:
1082    case JT_MIGRATE:
1083       char *prt_type;
1084       jcr->setJobLevel(L_FULL);      /* default level */
1085       if (ua->api) {
1086          ua->signal(BNET_RUN_CMD);
1087          if (jcr->getJobType() == JT_COPY) {
1088             prt_type = (char *)"Type: Copy\nTitle: Run Copy Job\n";
1089          } else {
1090             prt_type = (char *)"Type: Migration\nTitle: Run Migration Job\n";
1091          }
1092          ua->send_msg("%s"
1093                      "JobName:       %s\n"
1094                      "Bootstrap:     %s\n"
1095                      "Client:        %s\n"
1096                      "FileSet:       %s\n"
1097                      "Pool:          %s\n"
1098                      "Read Storage:  %s\n"
1099                      "Write Storage: %s\n"
1100                      "JobId:         %s\n"
1101                      "When:          %s\n"
1102                      "Catalog:       %s\n"
1103                      "Priority:      %d\n",
1104            prt_type,
1105            job->name(),
1106            NPRT(jcr->RestoreBootstrap),
1107            jcr->client->name(),
1108            jcr->fileset->name(),
1109            NPRT(jcr->pool->name()),
1110            jcr->rstore->name(),
1111            jcr->wstore?jcr->wstore->name():"*None*",
1112            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1113            bstrutime(dt, sizeof(dt), jcr->sched_time),
1114            jcr->catalog->name(),
1115            jcr->JobPriority);
1116       } else {
1117          if (jcr->getJobType() == JT_COPY) {
1118             prt_type = _("Run Copy job\n");
1119          } else {
1120             prt_type = _("Run Migration job\n");
1121          }
1122          ua->send_msg("%s"
1123                      "JobName:       %s\n"
1124                      "Bootstrap:     %s\n"
1125                      "Client:        %s\n"
1126                      "FileSet:       %s\n"
1127                      "Pool:          %s (From %s)\n"
1128                      "Read Storage:  %s (From %s)\n"
1129                      "Write Storage: %s (From %s)\n"
1130                      "JobId:         %s\n"
1131                      "When:          %s\n"
1132                      "Catalog:       %s\n"
1133                      "Priority:      %d\n",
1134            prt_type,
1135            job->name(),
1136            NPRT(jcr->RestoreBootstrap),
1137            jcr->client->name(),
1138            jcr->fileset->name(),
1139            NPRT(jcr->pool->name()), jcr->pool_source,
1140            jcr->rstore->name(), jcr->rstore_source,
1141            jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1142            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1143            bstrutime(dt, sizeof(dt), jcr->sched_time),
1144            jcr->catalog->name(),
1145            jcr->JobPriority);
1146       }
1147       break;
1148    default:
1149       ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1150       return false;
1151    }
1152    return true;
1153 }
1154
1155
1156 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
1157 {
1158    bool kw_ok;
1159    int i, j;
1160    static const char *kw[] = {        /* command line arguments */
1161       "job",                          /*  Used in a switch() */
1162       "jobid",                        /* 1 */
1163       "client",                       /* 2 */
1164       "fd",                           /* 3 */
1165       "fileset",                      /* 4 */
1166       "level",                        /* 5 */
1167       "storage",                      /* 6 */
1168       "sd",                           /* 7 */
1169       "regexwhere",                   /* 8 where string as a bregexp */
1170       "where",                        /* 9 */
1171       "bootstrap",                    /* 10 */
1172       "replace",                      /* 11 */
1173       "when",                         /* 12 */
1174       "priority",                     /* 13 */
1175       "yes",                          /* 14  -- if you change this change YES_POS too */
1176       "verifyjob",                    /* 15 */
1177       "files",                        /* 16 number of files to restore */
1178       "catalog",                      /* 17 override catalog */
1179       "since",                        /* 18 since */
1180       "cloned",                       /* 19 cloned */
1181       "verifylist",                   /* 20 verify output list */
1182       "migrationjob",                 /* 21 migration job name */
1183       "pool",                         /* 22 */
1184       "backupclient",                 /* 23 */
1185       "restoreclient",                /* 24 */
1186       "pluginoptions",                /* 25 */
1187       "spooldata",                    /* 26 */
1188       "comment",                      /* 27 */
1189       "ignoreduplicatecheck",         /* 28 */
1190       NULL
1191    };
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 = false;
1205    rc.ignoreduplicatecheck = false;
1206    rc.comment = NULL;
1207
1208    for (i=1; i<ua->argc; i++) {
1209       Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1210       kw_ok = false;
1211       /* Keep looking until we find a good keyword */
1212       for (j=0; !kw_ok && kw[j]; j++) {
1213          if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1214             /* Note, yes and run have no value, so do not fail */
1215             if (!ua->argv[i] && j != YES_POS /*yes*/) {
1216                ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1217                return false;
1218             }
1219             Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1220             switch (j) {
1221             case 0: /* job */
1222                if (rc.job_name) {
1223                   ua->send_msg(_("Job name specified twice.\n"));
1224                   return false;
1225                }
1226                rc.job_name = ua->argv[i];
1227                kw_ok = true;
1228                break;
1229             case 1: /* JobId */
1230                if (rc.jid && !rc.mod) {
1231                   ua->send_msg(_("JobId specified twice.\n"));
1232                   return false;
1233                }
1234                rc.jid = ua->argv[i];
1235                kw_ok = true;
1236                break;
1237             case 2: /* client */
1238             case 3: /* fd */
1239                if (rc.client_name) {
1240                   ua->send_msg(_("Client specified twice.\n"));
1241                   return false;
1242                }
1243                rc.client_name = ua->argv[i];
1244                kw_ok = true;
1245                break;
1246             case 4: /* fileset */
1247                if (rc.fileset_name) {
1248                   ua->send_msg(_("FileSet specified twice.\n"));
1249                   return false;
1250                }
1251                rc.fileset_name = ua->argv[i];
1252                kw_ok = true;
1253                break;
1254             case 5: /* level */
1255                if (rc.level_name) {
1256                   ua->send_msg(_("Level specified twice.\n"));
1257                   return false;
1258                }
1259                rc.level_name = ua->argv[i];
1260                kw_ok = true;
1261                break;
1262             case 6: /* storage */
1263             case 7: /* sd */
1264                if (rc.store_name) {
1265                   ua->send_msg(_("Storage specified twice.\n"));
1266                   return false;
1267                }
1268                rc.store_name = ua->argv[i];
1269                kw_ok = true;
1270                break;
1271             case 8: /* regexwhere */
1272                 if ((rc.regexwhere || rc.where) && !rc.mod) {
1273                   ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1274                   return false;
1275                }
1276                rc.regexwhere = ua->argv[i];
1277                if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1278                   ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1279                   return false;
1280                }
1281                kw_ok = true;
1282                break;
1283            case 9: /* where */
1284                if ((rc.where || rc.regexwhere) && !rc.mod) {
1285                   ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1286                   return false;
1287                }
1288                rc.where = ua->argv[i];
1289                if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1290                   ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1291                   return false;
1292                }
1293                kw_ok = true;
1294                break;
1295             case 10: /* bootstrap */
1296                if (rc.bootstrap && !rc.mod) {
1297                   ua->send_msg(_("Bootstrap specified twice.\n"));
1298                   return false;
1299                }
1300                rc.bootstrap = ua->argv[i];
1301                kw_ok = true;
1302                break;
1303             case 11: /* replace */
1304                if (rc.replace && !rc.mod) {
1305                   ua->send_msg(_("Replace specified twice.\n"));
1306                   return false;
1307                }
1308                rc.replace = ua->argv[i];
1309                kw_ok = true;
1310                break;
1311             case 12: /* When */
1312                if (rc.when && !rc.mod) {
1313                   ua->send_msg(_("When specified twice.\n"));
1314                   return false;
1315                }
1316                rc.when = ua->argv[i];
1317                kw_ok = true;
1318                break;
1319             case 13:  /* Priority */
1320                if (rc.Priority && !rc.mod) {
1321                   ua->send_msg(_("Priority specified twice.\n"));
1322                   return false;
1323                }
1324                rc.Priority = atoi(ua->argv[i]);
1325                if (rc.Priority <= 0) {
1326                   ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1327                   rc.Priority = 10;
1328                }
1329                kw_ok = true;
1330                break;
1331             case 14: /* yes */
1332                kw_ok = true;
1333                break;
1334             case 15: /* Verify Job */
1335                if (rc.verify_job_name) {
1336                   ua->send_msg(_("Verify Job specified twice.\n"));
1337                   return false;
1338                }
1339                rc.verify_job_name = ua->argv[i];
1340                kw_ok = true;
1341                break;
1342             case 16: /* files */
1343                rc.files = atoi(ua->argv[i]);
1344                kw_ok = true;
1345                break;
1346             case 17: /* catalog */
1347                rc.catalog_name = ua->argv[i];
1348                kw_ok = true;
1349                break;
1350             case 18: /* since */
1351                rc.since = ua->argv[i];
1352                kw_ok = true; 
1353                break;
1354             case 19: /* cloned */
1355                rc. cloned = true;
1356                kw_ok = true;
1357                break;
1358             case 20: /* write verify list output */
1359                rc.verify_list = ua->argv[i];
1360                kw_ok = true;
1361                break;
1362             case 21: /* Migration Job */
1363                if (rc.previous_job_name) {
1364                   ua->send_msg(_("Migration Job specified twice.\n"));
1365                   return false;
1366                }
1367                rc.previous_job_name = ua->argv[i];
1368                kw_ok = true;
1369                break;
1370             case 22: /* pool */
1371                if (rc.pool_name) {
1372                   ua->send_msg(_("Pool specified twice.\n"));
1373                   return false;
1374                }
1375                rc.pool_name = ua->argv[i];
1376                kw_ok = true;
1377                break;
1378             case 23: /* backupclient */
1379                if (rc.client_name) {
1380                   ua->send_msg(_("Client specified twice.\n"));
1381                   return 0;
1382                }
1383                rc.client_name = ua->argv[i];
1384                kw_ok = true;
1385                break;
1386             case 24: /* restoreclient */
1387                if (rc.restore_client_name && !rc.mod) {
1388                   ua->send_msg(_("Restore Client specified twice.\n"));
1389                   return false;
1390                }
1391                rc.restore_client_name = ua->argv[i];
1392                kw_ok = true;
1393                break;
1394             case 25: /* pluginoptions */
1395                ua->send_msg(_("Plugin Options not yet implemented.\n"));
1396                return false;
1397                if (rc.plugin_options) {
1398                   ua->send_msg(_("Plugin Options specified twice.\n"));
1399                   return false;
1400                }
1401                rc.plugin_options = ua->argv[i];
1402                if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1403                   ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1404                   return false;
1405                }
1406                kw_ok = true;
1407                break;
1408             case 26: /* spooldata */
1409                if (rc.spool_data_set) {
1410                   ua->send_msg(_("Spool flag specified twice.\n"));
1411                   return false;
1412                }
1413                if (is_yesno(ua->argv[i], &rc.spool_data)) {
1414                   rc.spool_data_set = true;
1415                   kw_ok = true;
1416                } else {
1417                   ua->send_msg(_("Invalid spooldata flag.\n"));
1418                }
1419                break;
1420             case 27: /* comment */
1421                rc.comment = ua->argv[i];
1422                kw_ok = true;
1423                break;
1424             case 28: /* ignoreduplicatecheck */
1425                if (rc.ignoreduplicatecheck_set) {
1426                   ua->send_msg(_("IgnoreDuplicateCheck flag specified twice.\n"));
1427                   return false;
1428                }
1429                if (is_yesno(ua->argv[i], &rc.ignoreduplicatecheck)) {
1430                   rc.ignoreduplicatecheck_set = true;
1431                   kw_ok = true;
1432                } else {
1433                   ua->send_msg(_("Invalid ignoreduplicatecheck flag.\n"));
1434                }
1435                break;
1436             default:
1437                break;
1438             }
1439          } /* end strcase compare */
1440       } /* end keyword loop */
1441       /*
1442        * End of keyword for loop -- if not found, we got a bogus keyword
1443        */
1444       if (!kw_ok) {
1445          Dmsg1(800, "%s not found\n", ua->argk[i]);
1446          /*
1447           * Special case for Job Name, it can be the first
1448           * keyword that has no value.
1449           */
1450          if (!rc.job_name && !ua->argv[i]) {
1451             rc.job_name = ua->argk[i];   /* use keyword as job name */
1452             Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1453          } else {
1454             ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1455             return false;
1456          }
1457       }
1458    } /* end argc loop */
1459              
1460    Dmsg0(800, "Done scan.\n");
1461    if (rc.comment) {
1462       if (!is_comment_legal(ua, rc.comment)) {
1463          return false;
1464       }
1465    }
1466    if (rc.catalog_name) {
1467        rc.catalog = GetCatalogResWithName(rc.catalog_name);
1468        if (rc.catalog == NULL) {
1469             ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1470            return false;
1471        }
1472        if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1473           ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1474           return false;
1475        }
1476    }
1477    Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1478
1479    if (rc.job_name) {
1480       /* Find Job */
1481       rc.job = GetJobResWithName(rc.job_name);
1482       if (!rc.job) {
1483          if (*rc.job_name != 0) {
1484             ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1485          }
1486          rc.job = select_job_resource(ua);
1487       } else {
1488          Dmsg1(800, "Found job=%s\n", rc.job_name);
1489       }
1490    } else if (!rc.job) {
1491       ua->send_msg(_("A job name must be specified.\n"));
1492       rc.job = select_job_resource(ua);
1493    }
1494    if (!rc.job) {
1495       return false;
1496    } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1497       ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1498       return false;
1499    }
1500
1501    if (rc.pool_name) {
1502       rc.pool = GetPoolResWithName(rc.pool_name);
1503       if (!rc.pool) {
1504          if (*rc.pool_name != 0) {
1505             ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1506          }
1507          rc.pool = select_pool_resource(ua);
1508       }
1509    } else if (!rc.pool) {
1510       rc.pool = rc.job->pool;             /* use default */
1511    }
1512    if (!rc.pool) {
1513       return false;
1514    } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1515       ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1516       return false;
1517    }
1518    Dmsg1(100, "Using pool %s\n", rc.pool->name());
1519
1520    if (rc.spool_data_set) {
1521       rc.job->spool_data = rc.spool_data;
1522    }
1523    Dmsg1(900, "Spooling data: %s\n", (rc.job->spool_data ? "Yes" : "No"));
1524
1525    if (rc.ignoreduplicatecheck) {
1526       rc.job->IgnoreDuplicateJobChecking = rc.ignoreduplicatecheck;
1527    }
1528    Dmsg1(900, "Ignore Duplicate Job Check: %s\n", (rc.job->IgnoreDuplicateJobChecking ? "Yes" : "No"));
1529
1530    if (rc.store_name) {
1531       rc.store->store = GetStoreResWithName(rc.store_name);
1532       pm_strcpy(rc.store->store_source, _("command line"));
1533       if (!rc.store->store) {
1534          if (*rc.store_name != 0) {
1535             ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1536          }
1537          rc.store->store = select_storage_resource(ua);
1538          pm_strcpy(rc.store->store_source, _("user selection"));
1539       }
1540    } else if (!rc.store->store) {
1541       get_job_storage(rc.store, rc.job, NULL);      /* use default */
1542    }
1543    if (!rc.store->store) {
1544       ua->error_msg(_("No storage specified.\n"));
1545       return false;
1546    } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1547       ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1548                rc.store->store->name());
1549       return false;
1550    }
1551    Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1552
1553    if (rc.client_name) {
1554       rc.client = GetClientResWithName(rc.client_name);
1555       if (!rc.client) {
1556          if (*rc.client_name != 0) {
1557             ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1558          }
1559          rc.client = select_client_resource(ua);
1560       }
1561    } else if (!rc.client) {
1562       rc.client = rc.job->client;           /* use default */
1563    }
1564    if (!rc.client) {
1565       return false;
1566    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1567       ua->error_msg(_("No authorization. Client \"%s\".\n"),
1568                rc.client->name());
1569       return false;
1570    }
1571    Dmsg1(800, "Using client=%s\n", rc.client->name());
1572
1573    if (rc.restore_client_name) {
1574       rc.client = GetClientResWithName(rc.restore_client_name);
1575       if (!rc.client) {
1576          if (*rc.restore_client_name != 0) {
1577             ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1578          }
1579          rc.client = select_client_resource(ua);
1580       }
1581    } else if (!rc.client) {
1582       rc.client = rc.job->client;           /* use default */
1583    }
1584    if (!rc.client) {
1585       return false;
1586    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1587       ua->error_msg(_("No authorization. Client \"%s\".\n"),
1588                rc.client->name());
1589       return false;
1590    }
1591    Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1592
1593    if (rc.fileset_name) {
1594       rc.fileset = GetFileSetResWithName(rc.fileset_name);
1595       if (!rc.fileset) {
1596          ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1597          rc.fileset = select_fileset_resource(ua);
1598       }
1599    } else if (!rc.fileset) {
1600       rc.fileset = rc.job->fileset;           /* use default */
1601    }
1602    if (!rc.fileset) {
1603       return false;
1604    } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1605       ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1606                rc.fileset->name());
1607       return false;
1608    }
1609
1610    if (rc.verify_job_name) {
1611       rc.verify_job = GetJobResWithName(rc.verify_job_name);
1612       if (!rc.verify_job) {
1613          ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1614          rc.verify_job = select_job_resource(ua);
1615       }
1616    } else if (!rc.verify_job) {
1617       rc.verify_job = rc.job->verify_job;
1618    }
1619
1620    if (rc.previous_job_name) {
1621       rc.previous_job = GetJobResWithName(rc.previous_job_name);
1622       if (!rc.previous_job) {
1623          ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1624          rc.previous_job = select_job_resource(ua);
1625       }
1626    } else {
1627       rc.previous_job = rc.job->verify_job;
1628    }
1629    return true;
1630 }