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