]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
Remove debug code
[bacula/bacula] / bacula / src / dird / ua_run.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2001-2007 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 two of the GNU 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 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 John Walker.
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  *   Version $Id$
35  */
36
37 #include "bacula.h"
38 #include "dird.h"
39
40 class run_ctx {
41 public:
42    char *job_name, *level_name, *jid, *store_name, *pool_name;
43    char *where, *fileset_name, *client_name, *bootstrap, *regexwhere;
44    char *restore_client_name;
45    const char *replace;
46    char *when, *verify_job_name, *catalog_name;
47    char *previous_job_name;
48    char *since;
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
63    /* Methods */
64    run_ctx() { memset(this, 0, sizeof(run_ctx)); 
65                store = new USTORE; };
66    ~run_ctx() { delete store; };
67 };
68
69 /* Forward referenced subroutines */
70 static void select_job_level(UAContext *ua, JCR *jcr);
71 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, 
72                 const char *verify_list, char *jid, const char *replace,
73                 char *client_name);
74 static void select_where_regexp(UAContext *ua, JCR *jcr);
75 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc);
76
77 /* Imported variables */
78 extern struct s_kw ReplaceOptions[];
79
80 /*
81  * For Backup and Verify Jobs
82  *     run [job=]<job-name> level=<level-name>
83  *
84  * For Restore Jobs
85  *     run <job-name> 
86  *
87  *  Returns: 0 on error
88  *           JobId if OK
89  *
90  */
91 int run_cmd(UAContext *ua, const char *cmd)
92 {
93    JCR *jcr = NULL;
94    run_ctx rc;
95    int i, opt;
96
97    if (!open_client_db(ua)) {
98       return 1;
99    }
100
101    if (!scan_command_line_arguments(ua, rc)) {
102       return 0;
103    }
104
105    if (find_arg(ua, NT_("fdcalled")) > 0) {
106       jcr->file_bsock = dup_bsock(ua->UA_sock);
107       ua->quit = true;
108    }
109
110 try_again:
111    /*
112     * Create JCR to run job.  NOTE!!! after this point, free_jcr()
113     *  before returning.
114     */
115    if (!jcr) {
116       jcr = new_jcr(sizeof(JCR), dird_free_jcr);
117       set_jcr_defaults(jcr, rc.job);
118       jcr->unlink_bsr = ua->jcr->unlink_bsr;    /* copy unlink flag from caller */
119       ua->jcr->unlink_bsr = false;
120    }
121
122    jcr->verify_job = rc.verify_job;
123    jcr->previous_job = rc.previous_job;
124    jcr->pool = rc.pool;
125    set_rwstorage(jcr, rc.store);
126    jcr->client = rc.client;
127    pm_strcpy(jcr->client_name, rc.client->name());
128    jcr->fileset = rc.fileset;
129    jcr->ExpectedFiles = rc.files;
130    if (rc.catalog) {
131       jcr->catalog = rc.catalog;
132    }
133    if (rc.where) {
134       if (jcr->where) {
135          free(jcr->where);
136       }
137       jcr->where = bstrdup(rc.where);
138       rc.where = NULL;
139    }
140
141    if (rc.regexwhere) {
142       if (jcr->RegexWhere) {
143          free(jcr->RegexWhere);
144       }
145       jcr->RegexWhere = bstrdup(rc.regexwhere);       
146       rc.regexwhere = NULL;
147    }
148
149    if (rc.when) {
150       jcr->sched_time = str_to_utime(rc.when);
151       if (jcr->sched_time == 0) {
152          ua->send_msg(_("Invalid time, using current time.\n"));
153          jcr->sched_time = time(NULL);
154       }
155       rc.when = NULL;
156    }
157
158    if (rc.bootstrap) {
159       if (jcr->RestoreBootstrap) {
160          free(jcr->RestoreBootstrap);
161       }
162       jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
163       rc.bootstrap = NULL;
164    }
165
166    if (rc.replace) {
167       jcr->replace = 0;
168       for (i=0; ReplaceOptions[i].name; i++) {
169          if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
170             jcr->replace = ReplaceOptions[i].token;
171          }
172       }
173       if (!jcr->replace) {
174          ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
175          goto bail_out;
176       }
177    } else if (rc.job->replace) {
178       jcr->replace = rc.job->replace;
179    } else {
180       jcr->replace = REPLACE_ALWAYS;
181    }
182    rc.replace = NULL;
183
184    if (rc.Priority) {
185       jcr->JobPriority = rc.Priority;
186       rc.Priority = 0;
187    }
188
189    if (rc.since) {
190       if (!jcr->stime) {
191          jcr->stime = get_pool_memory(PM_MESSAGE);
192       }
193       pm_strcpy(jcr->stime, rc.since);
194       rc.since = NULL;
195    }
196
197    if (rc.cloned) {
198       jcr->cloned = rc.cloned;
199       rc.cloned = false;
200    }
201
202
203    /* If pool changed, update migration write storage */
204    if (jcr->JobType == JT_MIGRATE) {
205       if (!set_migration_wstorage(jcr, rc.pool)) {
206          goto bail_out;
207       }
208    }
209    rc.replace = ReplaceOptions[0].name;
210    for (i=0; ReplaceOptions[i].name; i++) {
211       if (ReplaceOptions[i].token == jcr->replace) {
212          rc.replace = ReplaceOptions[i].name;
213       }
214    }
215    if (rc.level_name) {
216       if (!get_level_from_name(jcr, rc.level_name)) {
217          ua->send_msg(_("Level %s not valid.\n"), rc.level_name);
218          goto bail_out;
219       }
220       rc.level_name = NULL;
221    }
222    if (rc.jid) {
223       /* Note, this is also MigrateJobId */
224       jcr->RestoreJobId = str_to_int64(rc.jid);
225       rc.jid = 0;
226    }
227
228    /* Run without prompting? */
229    if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
230       goto start_job;
231    }
232
233    /*
234     * Prompt User to see if all run job parameters are correct, and
235     *   allow him to modify them.
236     */
237    if (!display_job_parameters(ua, jcr, rc.job, rc.verify_list, rc.jid, rc.replace,
238         rc.client_name)) {
239       goto bail_out;
240    }
241
242    if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
243       goto bail_out;
244    }
245
246    if (strncasecmp(ua->cmd, ".mod ", 5) == 0 || 
247        (strncasecmp(ua->cmd, "mod ", 4) == 0 && strlen(ua->cmd) > 6)) {
248       parse_ua_args(ua);
249       rc.mod = true;
250       if (!scan_command_line_arguments(ua, rc)) {
251          return 0;
252       }
253       goto try_again;
254    }
255
256    /*
257     * At user request modify parameters of job to be run.
258     */
259    if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
260       FILE *fd;
261
262       start_prompt(ua, _("Parameters to modify:\n"));
263       add_prompt(ua, _("Level"));            /* 0 */
264       add_prompt(ua, _("Storage"));          /* 1 */
265       add_prompt(ua, _("Job"));              /* 2 */
266       add_prompt(ua, _("FileSet"));          /* 3 */
267       if (jcr->JobType == JT_RESTORE) {
268          add_prompt(ua, _("Restore Client"));   /* 4 */
269       } else {
270          add_prompt(ua, _("Client"));        /* 4 */
271       }
272       add_prompt(ua, _("When"));             /* 5 */
273       add_prompt(ua, _("Priority"));         /* 6 */
274       if (jcr->JobType == JT_BACKUP ||
275           jcr->JobType == JT_MIGRATE ||
276           jcr->JobType == JT_VERIFY) {
277          add_prompt(ua, _("Pool"));          /* 7 */
278          if (jcr->JobType == JT_VERIFY) {
279             add_prompt(ua, _("Verify Job"));  /* 8 */
280          }
281       } else if (jcr->JobType == JT_RESTORE) {
282          add_prompt(ua, _("Bootstrap"));     /* 7 */
283          add_prompt(ua, _("Where"));         /* 8 */
284          add_prompt(ua, _("File Relocation"));/* 9 */    
285          add_prompt(ua, _("Replace"));       /* 10 */
286          add_prompt(ua, _("JobId"));         /* 11 */
287       }
288       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
289       case 0:
290          /* Level */
291          select_job_level(ua, jcr);
292          goto try_again;
293       case 1:
294          /* Storage */
295          rc.store->store = select_storage_resource(ua);
296          if (rc.store->store) {
297             pm_strcpy(rc.store->store_source, _("user selection"));
298             set_rwstorage(jcr, rc.store);
299             goto try_again;
300          }
301          break;
302       case 2:
303          /* Job */
304          rc.job = select_job_resource(ua);
305          if (rc.job) {
306             jcr->job = rc.job;
307             set_jcr_defaults(jcr, rc.job);
308             goto try_again;
309          }
310          break;
311       case 3:
312          /* FileSet */
313          rc.fileset = select_fileset_resource(ua);
314          if (rc.fileset) {
315             jcr->fileset = rc.fileset;
316             goto try_again;
317          }
318          break;
319       case 4:
320          /* Client */
321          rc.client = select_client_resource(ua);
322          if (rc.client) {
323             jcr->client = rc.client;
324             goto try_again;
325          }
326          break;
327       case 5:
328          /* When */
329          if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
330             break;
331          }
332          if (ua->cmd[0] == 0) {
333             jcr->sched_time = time(NULL);
334          } else {
335             jcr->sched_time = str_to_utime(ua->cmd);
336             if (jcr->sched_time == 0) {
337                ua->send_msg(_("Invalid time, using current time.\n"));
338                jcr->sched_time = time(NULL);
339             }
340          }
341          goto try_again;
342       case 6:
343          /* Priority */
344          if (!get_pint(ua, _("Enter new Priority: "))) {
345             break;
346          }
347          if (ua->pint32_val == 0) {
348             ua->send_msg(_("Priority must be a positive integer.\n"));
349          } else {
350             jcr->JobPriority = ua->pint32_val;
351          }
352          goto try_again;
353       case 7:
354          /* Pool or Bootstrap depending on JobType */
355          if (jcr->JobType == JT_BACKUP ||
356              jcr->JobType == JT_MIGRATE ||
357              jcr->JobType == JT_VERIFY) {      /* Pool */
358             rc.pool = select_pool_resource(ua);
359             if (rc.pool) {
360                jcr->pool = rc.pool;
361                Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
362                goto try_again;
363             }
364             break;
365          }
366
367          /* Bootstrap */
368          if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
369             break;
370          }
371          if (jcr->RestoreBootstrap) {
372             free(jcr->RestoreBootstrap);
373             jcr->RestoreBootstrap = NULL;
374          }
375          if (ua->cmd[0] != 0) {
376             jcr->RestoreBootstrap = bstrdup(ua->cmd);
377             fd = fopen(jcr->RestoreBootstrap, "rb");
378             if (!fd) {
379                ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
380                   jcr->RestoreBootstrap, strerror(errno));
381                free(jcr->RestoreBootstrap);
382                jcr->RestoreBootstrap = NULL;
383             } else {
384                fclose(fd);
385             }
386          }
387          goto try_again;
388       case 8:
389          /* Verify Job */
390          if (jcr->JobType == JT_VERIFY) {
391             rc.verify_job = select_job_resource(ua);
392             if (rc.verify_job) {
393               jcr->verify_job = rc.verify_job;
394             }
395             goto try_again;
396          }
397          /* Where */
398          if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
399             break;
400          }
401          if (jcr->RegexWhere) { /* cannot use regexwhere and where */
402             free(jcr->RegexWhere);
403             jcr->RegexWhere = NULL;
404          }
405          if (jcr->where) {
406             free(jcr->where);
407             jcr->where = NULL;
408          }
409          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
410             ua->cmd[0] = 0;
411          }
412          jcr->where = bstrdup(ua->cmd);
413          goto try_again;
414       case 9: 
415          /* File relocation */
416          select_where_regexp(ua, jcr);
417          goto try_again;
418       case 10:
419          /* Replace */
420          start_prompt(ua, _("Replace:\n"));
421          for (i=0; ReplaceOptions[i].name; i++) {
422             add_prompt(ua, ReplaceOptions[i].name);
423          }
424          opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
425          if (opt >=  0) {
426             jcr->replace = ReplaceOptions[opt].token;
427          }
428          goto try_again;
429       case 11:
430          /* JobId */
431          rc.jid = NULL;                  /* force reprompt */
432          jcr->RestoreJobId = 0;
433          if (jcr->RestoreBootstrap) {
434             ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
435          }
436          goto try_again;
437       case -1:                        /* error or cancel */
438          goto bail_out;
439       default:
440          goto try_again;
441       }
442       goto bail_out;
443    }
444
445    if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
446       JobId_t JobId;
447       Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
448
449 start_job:
450       Dmsg1(100, "Using pool %s\n", jcr->pool->name());
451       JobId = run_job(jcr);
452       free_jcr(jcr);                  /* release jcr */
453       if (JobId == 0) {
454          ua->error_msg(_("Job failed.\n"));
455       } else {
456          char ed1[50];
457          ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId, ed1));
458       }
459       return JobId;
460    }
461
462 bail_out:
463    ua->send_msg(_("Job not run.\n"));
464    free_jcr(jcr);
465    return 0;                       /* do not run */
466 }
467
468 static void select_where_regexp(UAContext *ua, JCR *jcr)
469 {
470    alist *regs;
471    char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
472    strip_prefix = add_suffix = rwhere = add_prefix = NULL;
473
474 try_again_reg:
475    ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
476                 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
477
478    start_prompt(ua, _("This will replace your current Where value\n"));
479    add_prompt(ua, _("Strip prefix"));                /* 0 */
480    add_prompt(ua, _("Add prefix"));                  /* 1 */
481    add_prompt(ua, _("Add file suffix"));             /* 2 */
482    add_prompt(ua, _("Enter a regexp"));              /* 3 */
483    add_prompt(ua, _("Test filename manipulation"));  /* 4 */
484    add_prompt(ua, _("Use this ?"));                  /* 5 */
485    
486    switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
487    case 0:
488       /* Strip prefix */
489       if (get_cmd(ua, _("Please enter path prefix to strip: "))) {
490          if (strip_prefix) bfree(strip_prefix);
491          strip_prefix = bstrdup(ua->cmd);
492       }
493       
494       goto try_again_reg;
495    case 1:
496       /* Add prefix */
497       if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) {
498          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
499             ua->cmd[0] = 0;
500          }
501
502          if (add_prefix) bfree(add_prefix);
503          add_prefix = bstrdup(ua->cmd);
504       }
505       goto try_again_reg;
506    case 2:
507       /* Add suffix */
508       if (get_cmd(ua, _("Please enter file suffix to add: "))) {
509          if (add_suffix) bfree(add_suffix);
510          add_suffix = bstrdup(ua->cmd);
511       }      
512       goto try_again_reg;
513    case 3:
514       /* Add rwhere */
515       if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
516          if (rwhere) bfree(rwhere);
517          rwhere = bstrdup(ua->cmd);
518       }
519       
520       goto try_again_reg;      
521    case 4:
522       /* Test regexp */ 
523       char *result;
524       char *regexp;
525       
526       if (rwhere && rwhere[0] != '\0') {
527          regs = get_bregexps(rwhere);
528          ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
529       } else {
530          int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
531          regexp = (char *) bmalloc (len * sizeof(char));
532          bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
533          regs = get_bregexps(regexp);
534          ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
535                       NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
536          
537          bfree(regexp);
538       }
539
540       if (!regs) {
541          ua->send_msg(_("Cannot use your regexp\n"));
542          goto try_again_reg;
543       }
544
545       while (get_cmd(ua, _("Please enter filename to test: "))) {
546          apply_bregexps(ua->cmd, regs, &result);
547          ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
548       }
549       free_bregexps(regs);
550       delete regs;
551       goto try_again_reg;
552
553    case 5:
554       /* OK */
555       break;
556    case -1:                        /* error or cancel */
557       goto bail_out_reg;
558    default:
559       goto try_again_reg;
560    }
561
562    /* replace the existing where */
563    if (jcr->where) {
564       bfree(jcr->where);
565       jcr->where = NULL;
566    }
567
568    /* replace the existing regexwhere */
569    if (jcr->RegexWhere) {
570       bfree(jcr->RegexWhere);
571       jcr->RegexWhere = NULL;
572    }
573
574    if (rwhere) {
575       jcr->RegexWhere = bstrdup(rwhere);
576    } else if (strip_prefix || add_prefix || add_suffix) {
577       int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
578       jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
579       bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
580    }
581
582    regs = get_bregexps(jcr->RegexWhere);
583    if (regs) {
584       free_bregexps(regs);
585       delete regs;
586    } else {
587       if (jcr->RegexWhere) {
588          bfree(jcr->RegexWhere);
589          jcr->RegexWhere = NULL;
590       }
591       ua->send_msg(_("Cannot use your regexp.\n"));
592    }
593
594 bail_out_reg:
595    if (strip_prefix) bfree(strip_prefix);
596    if (add_prefix)   bfree(add_prefix);
597    if (add_suffix)   bfree(add_suffix);
598    if (rwhere)       bfree(rwhere);
599 }
600
601 static void select_job_level(UAContext *ua, JCR *jcr)
602 {
603    if (jcr->JobType == JT_BACKUP) {
604       start_prompt(ua, _("Levels:\n"));
605       add_prompt(ua, _("Base"));
606       add_prompt(ua, _("Full"));
607       add_prompt(ua, _("Incremental"));
608       add_prompt(ua, _("Differential"));
609       add_prompt(ua, _("Since"));
610       switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
611       case 0:
612          jcr->JobLevel = L_BASE;
613          break;
614       case 1:
615          jcr->JobLevel = L_FULL;
616          break;
617       case 2:
618          jcr->JobLevel = L_INCREMENTAL;
619          break;
620       case 3:
621          jcr->JobLevel = L_DIFFERENTIAL;
622          break;
623       case 4:
624          jcr->JobLevel = L_SINCE;
625          break;
626       default:
627          break;
628       }
629    } else if (jcr->JobType == JT_VERIFY) {
630       start_prompt(ua, _("Levels:\n"));
631       add_prompt(ua, _("Initialize Catalog"));
632       add_prompt(ua, _("Verify Catalog"));
633       add_prompt(ua, _("Verify Volume to Catalog"));
634       add_prompt(ua, _("Verify Disk to Catalog"));
635       add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
636       switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
637       case 0:
638          jcr->JobLevel = L_VERIFY_INIT;
639          break;
640       case 1:
641          jcr->JobLevel = L_VERIFY_CATALOG;
642          break;
643       case 2:
644          jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
645          break;
646       case 3:
647          jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
648          break;
649       case 4:
650          jcr->JobLevel = L_VERIFY_DATA;
651          break;
652       default:
653          break;
654       }
655    } else {
656       ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
657    }
658    return;
659 }
660
661 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
662    char *jid, const char *replace, char *client_name) 
663 {
664    Dmsg1(800, "JobType=%c\n", jcr->JobType);
665    switch (jcr->JobType) {
666       char ec1[30];
667       char dt[MAX_TIME_LENGTH];
668    case JT_ADMIN:
669       if (ua->api) ua->signal(BNET_RUN_CMD);   
670       ua->send_msg(_("Run %s job\n"
671                      "JobName:  %s\n"
672                      "FileSet:  %s\n"
673                      "Client:   %s\n"
674                      "Storage:  %s\n"
675                      "When:     %s\n"
676                      "Priority: %d\n"),
677                  _("Admin"),
678                  job->name(),
679                  jcr->fileset->name(),
680                  NPRT(jcr->client->name()),
681                  jcr->wstore?jcr->wstore->name():"*None*",
682                  bstrutime(dt, sizeof(dt), jcr->sched_time),
683                  jcr->JobPriority);
684       jcr->JobLevel = L_FULL;
685       break;
686    case JT_BACKUP:
687    case JT_VERIFY:
688       if (jcr->JobType == JT_BACKUP) {
689          if (ua->api) ua->signal(BNET_RUN_CMD);   
690          ua->send_msg(_("Run %s job\n"
691                         "JobName:  %s\n"
692                         "Level:    %s\n"
693                         "Client:   %s\n"
694                         "FileSet:  %s\n"
695                         "Pool:     %s (From %s)\n"
696                         "Storage:  %s (From %s)\n"
697                         "When:     %s\n"
698                         "Priority: %d\n"),
699                  _("Backup"),
700                  job->name(),
701                  level_to_str(jcr->JobLevel),
702                  jcr->client->name(),
703                  jcr->fileset->name(),
704                  NPRT(jcr->pool->name()), jcr->pool_source,
705                  jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
706                  bstrutime(dt, sizeof(dt), jcr->sched_time),
707                  jcr->JobPriority);
708       } else {  /* JT_VERIFY */
709          const char *Name;
710          if (jcr->verify_job) {
711             Name = jcr->verify_job->name();
712          } else {
713             Name = "";
714          }
715          if (!verify_list) {
716             verify_list = job->WriteVerifyList;
717          }
718          if (!verify_list) {
719             verify_list = "";
720          }
721          if (ua->api) ua->signal(BNET_RUN_CMD);   
722          ua->send_msg(_("Run %s job\n"
723                         "JobName:     %s\n"
724                         "Level:       %s\n"
725                         "Client:      %s\n"
726                         "FileSet:     %s\n"
727                         "Pool:        %s (From %s)\n"
728                         "Storage:     %s (From %s)\n"
729                         "Verify Job:  %s\n"
730                         "Verify List: %s\n"
731                         "When:        %s\n"
732                         "Priority:    %d\n"),
733               _("Verify"),
734               job->name(),
735               level_to_str(jcr->JobLevel),
736               jcr->client->name(),
737               jcr->fileset->name(),
738               NPRT(jcr->pool->name()), jcr->pool_source,
739               jcr->rstore->name(), jcr->rstore_source,
740               Name,
741               verify_list,
742               bstrutime(dt, sizeof(dt), jcr->sched_time),
743               jcr->JobPriority);
744       }
745       break;
746    case JT_RESTORE:
747       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
748          if (jid) {
749             jcr->RestoreJobId = str_to_int64(jid);
750          } else {
751             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
752                return false;
753             }
754             jcr->RestoreJobId = ua->int64_val;
755          }
756       }
757       jcr->JobLevel = L_FULL;      /* default level */
758       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
759       if (jcr->RestoreJobId == 0) {
760          if (ua->api) ua->signal(BNET_RUN_CMD);   
761          /* RegexWhere is take before RestoreWhere */
762          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
763             ua->send_msg(_("Run Restore job\n"
764                         "JobName:        f%s\n"
765                         "Bootstrap:       %s\n"
766                         "RegexWhere:      %s\n"
767                         "Replace:         %s\n"
768                         "FileSet:         %s\n"
769                         "Backup Client:   %s\n"
770                         "Restore Client:  %s\n"
771                         "Storage:         %s\n"
772                         "When:            %s\n"
773                         "Catalog:         %s\n"
774                         "Priority:        %d\n"),
775                  job->name(),
776                  NPRT(jcr->RestoreBootstrap), 
777                  jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
778                  replace,
779                  jcr->fileset->name(),
780                  client_name,
781                  jcr->client->name(),
782                  jcr->rstore->name(),
783                  bstrutime(dt, sizeof(dt), jcr->sched_time),
784                  jcr->catalog->name(),
785                  jcr->JobPriority);
786
787          } else {
788             ua->send_msg(_("Run Restore job\n"
789                         "JobName:         %s\n"
790                         "Bootstrap:       %s\n"
791                         "Where:           %s\n"
792                         "Replace:         %s\n"
793                         "FileSet:         %s\n"
794                         "Backup Client:   %s\n"
795                         "Restore Client:  %s\n"
796                         "Storage:         %s\n"
797                         "When:            %s\n"
798                         "Catalog:         %s\n"
799                         "Priority:        %d\n"),
800                  job->name(),
801                  NPRT(jcr->RestoreBootstrap), 
802                  jcr->where?jcr->where:NPRT(job->RestoreWhere), 
803                  replace,
804                  jcr->fileset->name(),
805                  client_name,
806                  jcr->client->name(),
807                  jcr->rstore->name(),
808                  bstrutime(dt, sizeof(dt), jcr->sched_time),
809                  jcr->catalog->name(),
810                  jcr->JobPriority);
811          }
812
813       } else {
814          if (ua->api) ua->signal(BNET_RUN_CMD);   
815          ua->send_msg(_("Run Restore job\n"
816                         "JobName:    %s\n"
817                         "Bootstrap:  %s\n"),
818                       job->name(),
819                       NPRT(jcr->RestoreBootstrap));
820                       
821          /* RegexWhere is take before RestoreWhere */
822          if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
823             ua->send_msg(_("RegexWhere: %s\n"),
824                          jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
825          } else {
826             ua->send_msg(_("Where:      %s\n"),
827                          jcr->where?jcr->where:NPRT(job->RestoreWhere));
828          }
829
830          ua->send_msg(_("Replace:    %s\n"
831                         "Client:     %s\n"
832                         "Storage:    %s\n"
833                         "JobId:      %s\n"
834                         "When:       %s\n"
835                         "Catalog:    %s\n"
836                         "Priority:   %d\n"),
837               replace,
838               jcr->client->name(),
839               jcr->rstore->name(),
840               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
841               bstrutime(dt, sizeof(dt), jcr->sched_time),
842               jcr->catalog->name(),
843               jcr->JobPriority);
844       }
845       break;
846    case JT_MIGRATE:
847       jcr->JobLevel = L_FULL;      /* default level */
848       if (ua->api) ua->signal(BNET_RUN_CMD);   
849       ua->send_msg(_("Run Migration job\n"
850                      "JobName:       %s\n"
851                      "Bootstrap:     %s\n"
852                      "Client:        %s\n"
853                      "FileSet:       %s\n"
854                      "Pool:          %s (From %s)\n"
855                      "Read Storage:  %s (From %s)\n"
856                      "Write Storage: %s (From %s)\n"
857                      "JobId:         %s\n"
858                      "When:          %s\n"
859                      "Catalog:       %s\n"
860                      "Priority:      %d\n"),
861            job->name(),
862            NPRT(jcr->RestoreBootstrap),
863            jcr->client->name(),
864            jcr->fileset->name(),
865            NPRT(jcr->pool->name()), jcr->pool_source,
866            jcr->rstore->name(), jcr->rstore_source,
867            jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
868            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
869            bstrutime(dt, sizeof(dt), jcr->sched_time),
870            jcr->catalog->name(),
871            jcr->JobPriority);
872       break;
873    default:
874       ua->error_msg(_("Unknown Job Type=%d\n"), jcr->JobType);
875       return false;
876    }
877    return true;
878 }
879
880
881 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
882 {
883    bool kw_ok;
884    int i, j;
885    static const char *kw[] = {        /* command line arguments */
886       "job",                          /*  Used in a switch() */
887       "jobid",                        /* 1 */
888       "client",                       /* 2 */
889       "fd",
890       "fileset",                      /* 4 */
891       "level",                        /* 5 */
892       "storage",                      /* 6 */
893       "sd",                           /* 7 */
894       "regexwhere",                   /* 8 where string as a bregexp */
895       "where",                        /* 9 */
896       "bootstrap",                    /* 10 */
897       "replace",                      /* 11 */
898       "when",                         /* 12 */
899       "priority",                     /* 13 */
900       "yes",          /* 14  -- if you change this change YES_POS too */
901       "verifyjob",                    /* 15 */
902       "files",                        /* 16 number of files to restore */
903       "catalog",                      /* 17 override catalog */
904       "since",                        /* 18 since */
905       "cloned",                       /* 19 cloned */
906       "verifylist",                   /* 20 verify output list */
907       "migrationjob",                 /* 21 migration job name */
908       "pool",                         /* 22 */
909       "backupclient",                 /* 23 */
910       "restoreclient",                /* 24 */
911       NULL};
912
913 #define YES_POS 14
914
915    rc.catalog_name = NULL;
916    rc.job_name = NULL;
917    rc.pool_name = NULL;
918    rc.store_name = NULL;
919    rc.client_name = NULL;
920    rc.restore_client_name = NULL;
921    rc.fileset_name = NULL;
922    rc.verify_job_name = NULL;
923    rc.previous_job_name = NULL;
924
925
926    for (i=1; i<ua->argc; i++) {
927       Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
928       kw_ok = false;
929       /* Keep looking until we find a good keyword */
930       for (j=0; !kw_ok && kw[j]; j++) {
931          if (strcasecmp(ua->argk[i], kw[j]) == 0) {
932             /* Note, yes and run have no value, so do not fail */
933             if (!ua->argv[i] && j != YES_POS /*yes*/) {
934                ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
935                return false;
936             }
937             Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
938             switch (j) {
939             case 0: /* job */
940                if (rc.job_name) {
941                   ua->send_msg(_("Job name specified twice.\n"));
942                   return false;
943                }
944                rc.job_name = ua->argv[i];
945                kw_ok = true;
946                break;
947             case 1: /* JobId */
948                if (rc.jid && !rc.mod) {
949                   ua->send_msg(_("JobId specified twice.\n"));
950                   return false;
951                }
952                rc.jid = ua->argv[i];
953                kw_ok = true;
954                break;
955             case 2: /* client */
956             case 3: /* fd */
957                if (rc.client_name) {
958                   ua->send_msg(_("Client specified twice.\n"));
959                   return false;
960                }
961                rc.client_name = ua->argv[i];
962                kw_ok = true;
963                break;
964             case 4: /* fileset */
965                if (rc.fileset_name) {
966                   ua->send_msg(_("FileSet specified twice.\n"));
967                   return false;
968                }
969                rc.fileset_name = ua->argv[i];
970                kw_ok = true;
971                break;
972             case 5: /* level */
973                if (rc.level_name) {
974                   ua->send_msg(_("Level specified twice.\n"));
975                   return false;
976                }
977                rc.level_name = ua->argv[i];
978                kw_ok = true;
979                break;
980             case 6: /* storage */
981             case 7: /* sd */
982                if (rc.store_name) {
983                   ua->send_msg(_("Storage specified twice.\n"));
984                   return false;
985                }
986                rc.store_name = ua->argv[i];
987                kw_ok = true;
988                break;
989             case 8: /* regexwhere */
990                 if ((rc.regexwhere || rc.where) && !rc.mod) {
991                   ua->send_msg(_("RegexWhere or Where specified twice.\n"));
992                   return false;
993                }
994                rc.regexwhere = ua->argv[i];
995                if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
996                   ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
997                   return false;
998                }
999                kw_ok = true;
1000                break;
1001            case 9: /* where */
1002                if ((rc.where || rc.regexwhere) && !rc.mod) {
1003                   ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1004                   return false;
1005                }
1006                rc.where = ua->argv[i];
1007                if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1008                   ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1009                   return false;
1010                }
1011                kw_ok = true;
1012                break;
1013             case 10: /* bootstrap */
1014                if (rc.bootstrap && !rc.mod) {
1015                   ua->send_msg(_("Bootstrap specified twice.\n"));
1016                   return false;
1017                }
1018                rc.bootstrap = ua->argv[i];
1019                kw_ok = true;
1020                break;
1021             case 11: /* replace */
1022                if (rc.replace && !rc.mod) {
1023                   ua->send_msg(_("Replace specified twice.\n"));
1024                   return false;
1025                }
1026                rc.replace = ua->argv[i];
1027                kw_ok = true;
1028                break;
1029             case 12: /* When */
1030                if (rc.when && !rc.mod) {
1031                   ua->send_msg(_("When specified twice.\n"));
1032                   return false;
1033                }
1034                rc.when = ua->argv[i];
1035                kw_ok = true;
1036                break;
1037             case 13:  /* Priority */
1038                if (rc.Priority && !rc.mod) {
1039                   ua->send_msg(_("Priority specified twice.\n"));
1040                   return false;
1041                }
1042                rc.Priority = atoi(ua->argv[i]);
1043                if (rc.Priority <= 0) {
1044                   ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1045                   rc.Priority = 10;
1046                }
1047                kw_ok = true;
1048                break;
1049             case 14: /* yes */
1050                kw_ok = true;
1051                break;
1052             case 15: /* Verify Job */
1053                if (rc.verify_job_name) {
1054                   ua->send_msg(_("Verify Job specified twice.\n"));
1055                   return false;
1056                }
1057                rc.verify_job_name = ua->argv[i];
1058                kw_ok = true;
1059                break;
1060             case 16: /* files */
1061                rc.files = atoi(ua->argv[i]);
1062                kw_ok = true;
1063                break;
1064
1065             case 17: /* catalog */
1066                rc.catalog_name = ua->argv[i];
1067                kw_ok = true;
1068                break;
1069
1070             case 18: /* since */
1071                rc.since = ua->argv[i];
1072                kw_ok = true; 
1073                break;
1074
1075             case 19: /* cloned */
1076                rc. cloned = true;
1077                kw_ok = true;
1078                break;
1079
1080             case 20: /* write verify list output */
1081                rc.verify_list = ua->argv[i];
1082                kw_ok = true;
1083                break;
1084             case 21: /* Migration Job */
1085                if (rc.previous_job_name) {
1086                   ua->send_msg(_("Migration Job specified twice.\n"));
1087                   return false;
1088                }
1089                rc.previous_job_name = ua->argv[i];
1090                kw_ok = true;
1091                break;
1092             case 22: /* pool */
1093                if (rc.pool_name) {
1094                   ua->send_msg(_("Pool specified twice.\n"));
1095                   return false;
1096                }
1097                rc.pool_name = ua->argv[i];
1098                kw_ok = true;
1099                break;
1100             case 23: /* backupclient */
1101                if (rc.client_name) {
1102                   ua->send_msg(_("Client specified twice.\n"));
1103                   return 0;
1104                }
1105                rc.client_name = ua->argv[i];
1106                kw_ok = true;
1107                break;
1108             case 24: /* restoreclient */
1109                if (rc.restore_client_name && !rc.mod) {
1110                   ua->send_msg(_("Restore Client specified twice.\n"));
1111                   return false;
1112                }
1113                rc.restore_client_name = ua->argv[i];
1114                kw_ok = true;
1115                break;
1116             default:
1117                break;
1118             }
1119          } /* end strcase compare */
1120       } /* end keyword loop */
1121       /*
1122        * End of keyword for loop -- if not found, we got a bogus keyword
1123        */
1124       if (!kw_ok) {
1125          Dmsg1(800, "%s not found\n", ua->argk[i]);
1126          /*
1127           * Special case for Job Name, it can be the first
1128           * keyword that has no value.
1129           */
1130          if (!rc.job_name && !ua->argv[i]) {
1131             rc.job_name = ua->argk[i];   /* use keyword as job name */
1132             Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1133          } else {
1134             ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1135             return false;
1136          }
1137       }
1138    } /* end argc loop */
1139              
1140    Dmsg0(800, "Done scan.\n");
1141
1142    if (rc.catalog_name) {
1143        rc.catalog = GetCatalogResWithName(rc.catalog_name);
1144        if (rc.catalog == NULL) {
1145             ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1146            return false;
1147        }
1148        if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1149           ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1150           return false;
1151        }
1152    }
1153    Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1154
1155    if (rc.job_name) {
1156       /* Find Job */
1157       rc.job = GetJobResWithName(rc.job_name);
1158       if (!rc.job) {
1159          if (*rc.job_name != 0) {
1160             ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1161          }
1162          rc.job = select_job_resource(ua);
1163       } else {
1164          Dmsg1(800, "Found job=%s\n", rc.job_name);
1165       }
1166    } else if (!rc.job) {
1167       ua->send_msg(_("A job name must be specified.\n"));
1168       rc.job = select_job_resource(ua);
1169    }
1170    if (!rc.job) {
1171       return false;
1172    } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1173       ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1174       return false;
1175    }
1176
1177    if (rc.pool_name) {
1178       rc.pool = GetPoolResWithName(rc.pool_name);
1179       if (!rc.pool) {
1180          if (*rc.pool_name != 0) {
1181             ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1182          }
1183          rc.pool = select_pool_resource(ua);
1184       }
1185    } else if (!rc.pool) {
1186       rc.pool = rc.job->pool;             /* use default */
1187    }
1188    if (!rc.pool) {
1189       return false;
1190    } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1191       ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1192       return false;
1193    }
1194    Dmsg1(100, "Using pool %s\n", rc.pool->name());
1195
1196    if (rc.store_name) {
1197       rc.store->store = GetStoreResWithName(rc.store_name);
1198       pm_strcpy(rc.store->store_source, _("command line"));
1199       if (!rc.store->store) {
1200          if (*rc.store_name != 0) {
1201             ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1202          }
1203          rc.store->store = select_storage_resource(ua);
1204          pm_strcpy(rc.store->store_source, _("user selection"));
1205       }
1206    } else if (!rc.store->store) {
1207       get_job_storage(rc.store, rc.job, NULL);      /* use default */
1208    }
1209    if (!rc.store->store) {
1210       ua->error_msg(_("No storage specified.\n"));
1211       return false;
1212    } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1213       ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1214                rc.store->store->name());
1215       return false;
1216    }
1217    Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1218
1219    if (rc.client_name) {
1220       rc.client = GetClientResWithName(rc.client_name);
1221       if (!rc.client) {
1222          if (*rc.client_name != 0) {
1223             ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1224          }
1225          rc.client = select_client_resource(ua);
1226       }
1227    } else if (!rc.client) {
1228       rc.client = rc.job->client;           /* use default */
1229    }
1230    if (!rc.client) {
1231       return false;
1232    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1233       ua->error_msg(_("No authorization. Client \"%s\".\n"),
1234                rc.client->name());
1235       return false;
1236    }
1237    Dmsg1(800, "Using client=%s\n", rc.client->name());
1238
1239    if (rc.restore_client_name) {
1240       rc.client = GetClientResWithName(rc.restore_client_name);
1241       if (!rc.client) {
1242          if (*rc.restore_client_name != 0) {
1243             ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1244          }
1245          rc.client = select_client_resource(ua);
1246       }
1247    } else if (!rc.client) {
1248       rc.client = rc.job->client;           /* use default */
1249    }
1250    if (!rc.client) {
1251       return false;
1252    } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1253       ua->error_msg(_("No authorization. Client \"%s\".\n"),
1254                rc.client->name());
1255       return false;
1256    }
1257    Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1258
1259
1260    if (rc.fileset_name) {
1261       rc.fileset = GetFileSetResWithName(rc.fileset_name);
1262       if (!rc.fileset) {
1263          ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1264          rc.fileset = select_fileset_resource(ua);
1265       }
1266    } else if (!rc.fileset) {
1267       rc.fileset = rc.job->fileset;           /* use default */
1268    }
1269    if (!rc.fileset) {
1270       return false;
1271    } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1272       ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1273                rc.fileset->name());
1274       return false;
1275    }
1276
1277    if (rc.verify_job_name) {
1278       rc.verify_job = GetJobResWithName(rc.verify_job_name);
1279       if (!rc.verify_job) {
1280          ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1281          rc.verify_job = select_job_resource(ua);
1282       }
1283    } else if (!rc.verify_job) {
1284       rc.verify_job = rc.job->verify_job;
1285    }
1286
1287    if (rc.previous_job_name) {
1288       rc.previous_job = GetJobResWithName(rc.previous_job_name);
1289       if (!rc.previous_job) {
1290          ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1291          rc.previous_job = select_job_resource(ua);
1292       }
1293    } else {
1294       rc.previous_job = rc.job->verify_job;
1295    }
1296    return true;
1297 }