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