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