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