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