]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
- Start implementing Verify list output.
[bacula/bacula] / bacula / src / dird / ua_run.c
1 /*
2  *
3  *   Bacula Director -- Run Command
4  *
5  *     Kern Sibbald, December MMI
6  *
7  *   Version $Id$
8  */
9 /*
10    Copyright (C) 2001-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"
25 #include "dird.h"
26
27 /* Imported subroutines */
28
29 /* Imported variables */
30 extern struct s_kw ReplaceOptions[];
31
32 /*
33  * For Backup and Verify Jobs
34  *     run [job=]<job-name> level=<level-name>
35  *
36  * For Restore Jobs
37  *     run <job-name> jobid=nn
38  *
39  *  Returns: 0 on error
40  *           JobId if OK
41  *
42  */
43 int run_cmd(UAContext *ua, const char *cmd)
44 {
45    JCR *jcr;
46    char *job_name, *level_name, *jid, *store_name, *pool_name;
47    char *where, *fileset_name, *client_name, *bootstrap;
48    const char *replace;
49    char *when, *verify_job_name, *catalog_name;
50    char *since = NULL;
51    char *verify_list;
52    bool cloned = false;
53    int Priority = 0;
54    int i, j, opt, files = 0;
55    bool kw_ok;
56    JOB *job = NULL;
57    JOB *verify_job = NULL;
58    STORE *store = NULL;
59    CLIENT *client = NULL;
60    FILESET *fileset = NULL;
61    POOL *pool = NULL;
62    static const char *kw[] = {        /* command line arguments */
63       "job",                          /*  Used in a switch() */
64       "jobid",                        /* 1 */
65       "client",                       /* 2 */
66       "fd",
67       "fileset",                      /* 4 */
68       "level",                        /* 5 */
69       "storage",                      /* 6 */
70       "sd",                           /* 7 */
71       "pool",                         /* 8 */
72       "where",                        /* 9 */
73       "bootstrap",                    /* 10 */
74       "replace",                      /* 11 */
75       "when",                         /* 12 */
76       "priority",                     /* 13 */
77       "yes",          /* 14  -- if you change this change YES_POS too */
78       "verifyjob",                    /* 15 */
79       "files",                        /* 16 number of files to restore */
80       "catalog",                      /* 17 override catalog */
81       "since",                        /* 18 since */
82       "cloned",                       /* 19 cloned */
83       "verifylist",                   /* 20 verify output list */
84       NULL};
85
86 #define YES_POS 14
87
88    if (!open_db(ua)) {
89       return 1;
90    }
91
92    job_name = NULL;
93    level_name = NULL;
94    jid = NULL;
95    store_name = NULL;
96    pool_name = NULL;
97    where = NULL;
98    when = NULL;
99    client_name = NULL;
100    fileset_name = NULL;
101    bootstrap = NULL;
102    replace = NULL;
103    verify_job_name = NULL;
104    catalog_name = NULL;
105    verify_list = NULL;
106
107    for (i=1; i<ua->argc; i++) {
108       Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
109       kw_ok = false;
110       /* Keep looking until we find a good keyword */
111       for (j=0; !kw_ok && kw[j]; j++) {
112          if (strcasecmp(ua->argk[i], _(kw[j])) == 0) {
113             /* Note, yes and run have no value, so do not err */
114             if (!ua->argv[i] && j != YES_POS /*yes*/) {
115                bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]);
116                return 1;
117             }
118             Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
119             switch (j) {
120             case 0: /* job */
121                if (job_name) {
122                   bsendmsg(ua, _("Job name specified twice.\n"));
123                   return 0;
124                }
125                job_name = ua->argv[i];
126                kw_ok = true;
127                break;
128             case 1: /* JobId */
129                if (jid) {
130                   bsendmsg(ua, _("JobId specified twice.\n"));
131                   return 0;
132                }
133                jid = ua->argv[i];
134                kw_ok = true;
135                break;
136             case 2: /* client */
137             case 3: /* fd */
138                if (client_name) {
139                   bsendmsg(ua, _("Client specified twice.\n"));
140                   return 0;
141                }
142                client_name = ua->argv[i];
143                kw_ok = true;
144                break;
145             case 4: /* fileset */
146                if (fileset_name) {
147                   bsendmsg(ua, _("FileSet specified twice.\n"));
148                   return 0;
149                }
150                fileset_name = ua->argv[i];
151                kw_ok = true;
152                break;
153             case 5: /* level */
154                if (level_name) {
155                   bsendmsg(ua, _("Level specified twice.\n"));
156                   return 0;
157                }
158                level_name = ua->argv[i];
159                kw_ok = true;
160                break;
161             case 6: /* storage */
162             case 7: /* sd */
163                if (store_name) {
164                   bsendmsg(ua, _("Storage specified twice.\n"));
165                   return 0;
166                }
167                store_name = ua->argv[i];
168                kw_ok = true;
169                break;
170             case 8: /* pool */
171                if (pool_name) {
172                   bsendmsg(ua, _("Pool specified twice.\n"));
173                   return 0;
174                }
175                pool_name = ua->argv[i];
176                kw_ok = true;
177                break;
178             case 9: /* where */
179                if (where) {
180                   bsendmsg(ua, _("Where specified twice.\n"));
181                   return 0;
182                }
183                where = ua->argv[i];
184                kw_ok = true;
185                break;
186             case 10: /* bootstrap */
187                if (bootstrap) {
188                   bsendmsg(ua, _("Bootstrap specified twice.\n"));
189                   return 0;
190                }
191                bootstrap = ua->argv[i];
192                kw_ok = true;
193                break;
194             case 11: /* replace */
195                if (replace) {
196                   bsendmsg(ua, _("Replace specified twice.\n"));
197                   return 0;
198                }
199                replace = ua->argv[i];
200                kw_ok = true;
201                break;
202             case 12: /* When */
203                if (when) {
204                   bsendmsg(ua, _("When specified twice.\n"));
205                   return 0;
206                }
207                when = ua->argv[i];
208                kw_ok = true;
209                break;
210             case 13:  /* Priority */
211                if (Priority) {
212                   bsendmsg(ua, _("Priority specified twice.\n"));
213                   return 0;
214                }
215                Priority = atoi(ua->argv[i]);
216                if (Priority <= 0) {
217                   bsendmsg(ua, _("Priority must be positive nonzero setting it to 10.\n"));
218                   Priority = 10;
219                }
220                kw_ok = true;
221                break;
222             case 14: /* yes */
223                kw_ok = true;
224                break;
225             case 15: /* Verify Job */
226                if (verify_job_name) {
227                   bsendmsg(ua, _("Verify Job specified twice.\n"));
228                   return 0;
229                }
230                verify_job_name = ua->argv[i];
231                kw_ok = true;
232                break;
233             case 16: /* files */
234                files = atoi(ua->argv[i]);
235                kw_ok = true;
236                break;
237
238             case 17: /* catalog */
239                catalog_name = ua->argv[i];
240                kw_ok = true;
241                break;
242
243             case 18: /* since */
244                since = ua->argv[i];
245                kw_ok = true; 
246                break;
247
248             case 19: /* cloned */
249                cloned = true;
250                kw_ok = true;
251                break;
252
253             case 20: /* write verify list output */
254                verify_list = ua->argv[i];
255                kw_ok = true;
256                break;
257
258             default:
259                break;
260             }
261          } /* end strcase compare */
262       } /* end keyword loop */
263       /*
264        * End of keyword for loop -- if not found, we got a bogus keyword
265        */
266       if (!kw_ok) {
267          Dmsg1(800, "%s not found\n", ua->argk[i]);
268          /*
269           * Special case for Job Name, it can be the first
270           * keyword that has no value.
271           */
272          if (!job_name && !ua->argv[i]) {
273             job_name = ua->argk[i];   /* use keyword as job name */
274             Dmsg1(800, "Set jobname=%s\n", job_name);
275          } else {
276             bsendmsg(ua, _("Invalid keyword: %s\n"), ua->argk[i]);
277             return 0;
278          }
279       }
280    } /* end argc loop */
281              
282    Dmsg0(800, "Done scan.\n");
283
284    CAT *catalog = NULL;
285    if (catalog_name != NULL) {
286        catalog = (CAT *)GetResWithName(R_CATALOG, catalog_name);
287        if (catalog == NULL) {
288             bsendmsg(ua, _("Catalog \"%s\" not found\n"), catalog_name);
289            return 0;
290        }
291    }
292    Dmsg1(800, "Using catalog=%s\n", NPRT(catalog_name));
293
294    if (job_name) {
295       /* Find Job */
296       job = (JOB *)GetResWithName(R_JOB, job_name);
297       if (!job) {
298          if (*job_name != 0) {
299             bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
300          }
301          job = select_job_resource(ua);
302       } else {
303          Dmsg1(800, "Found job=%s\n", job_name);
304       }
305    } else {
306       bsendmsg(ua, _("A job name must be specified.\n"));
307       job = select_job_resource(ua);
308    }
309    if (!job) {
310       return 0;
311    } else if (!acl_access_ok(ua, Job_ACL, job->hdr.name)) {
312       bsendmsg(ua, _("No authorization. Job \"%s\".\n"),
313          job->hdr.name);
314       return 0;
315    }
316
317    if (store_name) {
318       store = (STORE *)GetResWithName(R_STORAGE, store_name);
319       if (!store) {
320          if (*store_name != 0) {
321             bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
322          }
323          store = select_storage_resource(ua);
324       }
325    } else {
326       store = (STORE *)job->storage->first();           /* use default */
327    }
328    if (!store) {
329       return 1;
330    } else if (!acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
331       bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
332                store->hdr.name);
333       return 0;
334    }
335    Dmsg1(800, "Using storage=%s\n", store->hdr.name);
336
337    if (pool_name) {
338       pool = (POOL *)GetResWithName(R_POOL, pool_name);
339       if (!pool) {
340          if (*pool_name != 0) {
341             bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
342          }
343          pool = select_pool_resource(ua);
344       }
345    } else {
346       pool = job->pool;             /* use default */
347    }
348    if (!pool) {
349       return 0;
350    } else if (!acl_access_ok(ua, Pool_ACL, pool->hdr.name)) {
351       bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
352                pool->hdr.name);
353       return 0;
354    }
355    Dmsg1(800, "Using pool\n", pool->hdr.name);
356
357    if (client_name) {
358       client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
359       if (!client) {
360          if (*client_name != 0) {
361             bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
362          }
363          client = select_client_resource(ua);
364       }
365    } else {
366       client = job->client;           /* use default */
367    }
368    if (!client) {
369       return 0;
370    } else if (!acl_access_ok(ua, Client_ACL, client->hdr.name)) {
371       bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
372                client->hdr.name);
373       return 0;
374    }
375    Dmsg1(800, "Using client=%s\n", client->hdr.name);
376
377    if (fileset_name) {
378       fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
379       if (!fileset) {
380          bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
381          fileset = select_fileset_resource(ua);
382       }
383    } else {
384       fileset = job->fileset;           /* use default */
385    }
386    if (!fileset) {
387       return 0;
388    } else if (!acl_access_ok(ua, FileSet_ACL, fileset->hdr.name)) {
389       bsendmsg(ua, _("No authorization. FileSet \"%s\".\n"),
390                fileset->hdr.name);
391       return 0;
392    }
393
394    if (verify_job_name) {
395       verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
396       if (!verify_job) {
397          bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
398          verify_job = select_job_resource(ua);
399       }
400    } else {
401       verify_job = job->verify_job;
402    }
403
404    /*
405     * Create JCR to run job.  NOTE!!! after this point, free_jcr()
406     *  before returning.
407     */
408    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
409    set_jcr_defaults(jcr, job);
410
411    jcr->verify_job = verify_job;
412    set_storage(jcr, store);
413    jcr->client = client;
414    jcr->fileset = fileset;
415    jcr->pool = pool;
416    jcr->ExpectedFiles = files;
417    if (catalog != NULL) {
418       jcr->catalog = catalog;
419    }
420    if (where) {
421       if (jcr->where) {
422          free(jcr->where);
423       }
424       jcr->where = bstrdup(where);
425    }
426
427    if (when) {
428       jcr->sched_time = str_to_utime(when);
429       if (jcr->sched_time == 0) {
430          bsendmsg(ua, _("Invalid time, using current time.\n"));
431          jcr->sched_time = time(NULL);
432       }
433    }
434
435    if (bootstrap) {
436       if (jcr->RestoreBootstrap) {
437          free(jcr->RestoreBootstrap);
438       }
439       jcr->RestoreBootstrap = bstrdup(bootstrap);
440    }
441
442    if (replace) {
443       jcr->replace = 0;
444       for (i=0; ReplaceOptions[i].name; i++) {
445          if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
446             jcr->replace = ReplaceOptions[i].token;
447          }
448       }
449       if (!jcr->replace) {
450          bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
451          goto bail_out;
452       }
453    } else if (job->replace) {
454       jcr->replace = job->replace;
455    } else {
456       jcr->replace = REPLACE_ALWAYS;
457    }
458
459    if (Priority) {
460       jcr->JobPriority = Priority;
461    }
462
463    if (since) {
464       if (!jcr->stime) {
465          jcr->stime = get_pool_memory(PM_MESSAGE);
466       }
467       pm_strcpy(jcr->stime, since);
468    }
469
470    jcr->cloned = cloned;
471
472    if (find_arg(ua, N_("fdcalled")) > 0) {
473       jcr->file_bsock = dup_bsock(ua->UA_sock);
474       ua->quit = true;
475    }
476
477 try_again:
478    replace = ReplaceOptions[0].name;
479    for (i=0; ReplaceOptions[i].name; i++) {
480       if (ReplaceOptions[i].token == jcr->replace) {
481          replace = ReplaceOptions[i].name;
482       }
483    }
484    if (level_name) {
485       if (!get_level_from_name(jcr, level_name)) {
486          bsendmsg(ua, _("Level %s not valid.\n"), level_name);
487          goto bail_out;
488       }
489    }
490    if (jid) {
491       jcr->RestoreJobId = str_to_int64(jid);
492    }
493
494    /* Run without prompting? */
495    if (ua->batch || find_arg(ua, N_("yes")) > 0) {
496       goto start_job;
497    }
498
499    /*
500     * Prompt User to see if all run job parameters are correct, and
501     *   allow him to modify them.
502     */
503    Dmsg1(800, "JobType=%c\n", jcr->JobType);
504    switch (jcr->JobType) {
505       char ec1[30];
506       char dt[MAX_TIME_LENGTH];
507    case JT_ADMIN:
508          bsendmsg(ua, _("Run %s job\n"
509 "JobName:  %s\n"
510 "FileSet:  %s\n"
511 "Client:   %s\n"
512 "Storage:  %s\n"
513 "When:     %s\n"
514 "Priority: %d\n"),
515                  _("Admin"),
516                  job->hdr.name,
517                  jcr->fileset->hdr.name,
518                  NPRT(jcr->client->hdr.name),
519                  NPRT(jcr->store->hdr.name),
520                  bstrutime(dt, sizeof(dt), jcr->sched_time),
521                  jcr->JobPriority);
522       jcr->JobLevel = L_FULL;
523       break;
524    case JT_BACKUP:
525    case JT_VERIFY:
526       if (jcr->JobType == JT_BACKUP) {
527          bsendmsg(ua, _("Run %s job\n"
528 "JobName:  %s\n"
529 "FileSet:  %s\n"
530 "Level:    %s\n"
531 "Client:   %s\n"
532 "Storage:  %s\n"
533 "Pool:     %s\n"
534 "When:     %s\n"
535 "Priority: %d\n"),
536                  _("Backup"),
537                  job->hdr.name,
538                  jcr->fileset->hdr.name,
539                  level_to_str(jcr->JobLevel),
540                  jcr->client->hdr.name,
541                  jcr->store->hdr.name,
542                  NPRT(jcr->pool->hdr.name),
543                  bstrutime(dt, sizeof(dt), jcr->sched_time),
544                  jcr->JobPriority);
545       } else {  /* JT_VERIFY */
546          const char *Name;
547          if (jcr->verify_job) {
548             Name = jcr->verify_job->hdr.name;
549          } else {
550             Name = "";
551          }
552          if (!verify_list) {
553             verify_list = job->WriteVerifyList;
554          }
555          if (!verify_list) {
556             verify_list = "";
557          }
558          bsendmsg(ua, _("Run %s job\n"
559 "JobName:     %s\n"
560 "FileSet:     %s\n"
561 "Level:       %s\n"
562 "Client:      %s\n"
563 "Storage:     %s\n"
564 "Pool:        %s\n"
565 "Verify Job:  %s\n"
566 "Verify List: %s\n"
567 "When:        %s\n"
568 "Priority:    %d\n"),
569               _("Verify"),
570               job->hdr.name,
571               jcr->fileset->hdr.name,
572               level_to_str(jcr->JobLevel),
573               jcr->client->hdr.name,
574               jcr->store->hdr.name,
575               NPRT(jcr->pool->hdr.name),
576               Name,
577               verify_list,
578               bstrutime(dt, sizeof(dt), jcr->sched_time),
579               jcr->JobPriority);
580       }
581       break;
582    case JT_RESTORE:
583       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
584          if (jid) {
585             jcr->RestoreJobId = str_to_int64(jid);
586          } else {
587             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
588                goto bail_out;
589             }
590             jcr->RestoreJobId = ua->int64_val;
591          }
592       }
593       jcr->JobLevel = L_FULL;      /* default level */
594       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
595       if (jcr->RestoreJobId == 0) {
596          bsendmsg(ua, _("Run Restore job\n"
597                         "JobName:    %s\n"
598                         "Bootstrap:  %s\n"
599                         "Where:      %s\n"
600                         "Replace:    %s\n"
601                         "FileSet:    %s\n"
602                         "Client:     %s\n"
603                         "Storage:    %s\n"
604                         "When:       %s\n"
605                         "Catalog:    %s\n"
606                         "Priority:   %d\n"),
607               job->hdr.name,
608               NPRT(jcr->RestoreBootstrap),
609               jcr->where?jcr->where:NPRT(job->RestoreWhere),
610               replace,
611               jcr->fileset->hdr.name,
612               jcr->client->hdr.name,
613               jcr->store->hdr.name,
614               bstrutime(dt, sizeof(dt), jcr->sched_time),
615               jcr->catalog->hdr.name,
616               jcr->JobPriority);
617       } else {
618          bsendmsg(ua, _("Run Restore job\n"
619                        "JobName:    %s\n"
620                        "Bootstrap:  %s\n"
621                        "Where:      %s\n"
622                        "Replace:    %s\n"
623                        "Client:     %s\n"
624                        "Storage:    %s\n"
625                        "JobId:      %s\n"
626                        "When:       %s\n"
627                        "Catalog:    %s\n"
628                        "Priority:   %d\n"),
629               job->hdr.name,
630               NPRT(jcr->RestoreBootstrap),
631               jcr->where?jcr->where:NPRT(job->RestoreWhere),
632               replace,
633               jcr->client->hdr.name,
634               jcr->store->hdr.name,
635               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
636               bstrutime(dt, sizeof(dt), jcr->sched_time),
637               jcr->catalog->hdr.name,
638               jcr->JobPriority);
639       }
640       break;
641    default:
642       bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
643       goto bail_out;
644    }
645
646    if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
647       goto bail_out;
648    }
649    /*
650     * At user request modify parameters of job to be run.
651     */
652    if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
653       FILE *fd;
654
655       start_prompt(ua, _("Parameters to modify:\n"));
656       add_prompt(ua, _("Level"));            /* 0 */
657       add_prompt(ua, _("Storage"));          /* 1 */
658       add_prompt(ua, _("Job"));              /* 2 */
659       add_prompt(ua, _("FileSet"));          /* 3 */
660       add_prompt(ua, _("Client"));           /* 4 */
661       add_prompt(ua, _("When"));             /* 5 */
662       add_prompt(ua, _("Priority"));         /* 6 */
663       if (jcr->JobType == JT_BACKUP ||
664           jcr->JobType == JT_VERIFY) {
665          add_prompt(ua, _("Pool"));          /* 7 */
666          if (jcr->JobType == JT_VERIFY) {
667             add_prompt(ua, _("Verify Job"));  /* 8 */
668          }
669       } else if (jcr->JobType == JT_RESTORE) {
670          add_prompt(ua, _("Bootstrap"));     /* 7 */
671          add_prompt(ua, _("Where"));         /* 8 */
672          add_prompt(ua, _("Replace"));       /* 9 */
673          add_prompt(ua, _("JobId"));         /* 10 */
674       }
675       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
676       case 0:
677          /* Level */
678          if (jcr->JobType == JT_BACKUP) {
679             start_prompt(ua, _("Levels:\n"));
680             add_prompt(ua, _("Base"));
681             add_prompt(ua, _("Full"));
682             add_prompt(ua, _("Incremental"));
683             add_prompt(ua, _("Differential"));
684             add_prompt(ua, _("Since"));
685             switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
686             case 0:
687                jcr->JobLevel = L_BASE;
688                break;
689             case 1:
690                jcr->JobLevel = L_FULL;
691                break;
692             case 2:
693                jcr->JobLevel = L_INCREMENTAL;
694                break;
695             case 3:
696                jcr->JobLevel = L_DIFFERENTIAL;
697                break;
698             case 4:
699                jcr->JobLevel = L_SINCE;
700                break;
701             default:
702                break;
703             }
704             goto try_again;
705          } else if (jcr->JobType == JT_VERIFY) {
706             start_prompt(ua, _("Levels:\n"));
707             add_prompt(ua, _("Initialize Catalog"));
708             add_prompt(ua, _("Verify Catalog"));
709             add_prompt(ua, _("Verify Volume to Catalog"));
710             add_prompt(ua, _("Verify Disk to Catalog"));
711             add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
712             switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
713             case 0:
714                jcr->JobLevel = L_VERIFY_INIT;
715                break;
716             case 1:
717                jcr->JobLevel = L_VERIFY_CATALOG;
718                break;
719             case 2:
720                jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
721                break;
722             case 3:
723                jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
724                break;
725             case 4:
726                jcr->JobLevel = L_VERIFY_DATA;
727                break;
728             default:
729                break;
730             }
731             goto try_again;
732          } else {
733             bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
734          }
735          goto try_again;
736       case 1:
737          /* Storage */
738          store = select_storage_resource(ua);
739          if (store) {
740             set_storage(jcr, store);
741             goto try_again;
742          }
743          break;
744       case 2:
745          /* Job */
746          job = select_job_resource(ua);
747          if (job) {
748             jcr->job = job;
749             set_jcr_defaults(jcr, job);
750             goto try_again;
751          }
752          break;
753       case 3:
754          /* FileSet */
755          fileset = select_fileset_resource(ua);
756          if (fileset) {
757             jcr->fileset = fileset;
758             goto try_again;
759          }
760          break;
761       case 4:
762          /* Client */
763          client = select_client_resource(ua);
764          if (client) {
765             jcr->client = client;
766             goto try_again;
767          }
768          break;
769       case 5:
770          /* When */
771          if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
772             break;
773          }
774          if (ua->cmd[0] == 0) {
775             jcr->sched_time = time(NULL);
776          } else {
777             jcr->sched_time = str_to_utime(ua->cmd);
778             if (jcr->sched_time == 0) {
779                bsendmsg(ua, _("Invalid time, using current time.\n"));
780                jcr->sched_time = time(NULL);
781             }
782          }
783          goto try_again;
784       case 6:
785          /* Priority */
786          if (!get_pint(ua, _("Enter new Priority: "))) {
787             break;
788          }
789          if (ua->pint32_val == 0) {
790             bsendmsg(ua, _("Priority must be a positive integer.\n"));
791          } else {
792             jcr->JobPriority = ua->pint32_val;
793          }
794          goto try_again;
795       case 7:
796          /* Pool or Bootstrap depending on JobType */
797          if (jcr->JobType == JT_BACKUP ||
798              jcr->JobType == JT_VERIFY) {      /* Pool */
799             pool = select_pool_resource(ua);
800             if (pool) {
801                jcr->pool = pool;
802                goto try_again;
803             }
804             break;
805          }
806
807          /* Bootstrap */
808          if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
809             break;
810          }
811          if (jcr->RestoreBootstrap) {
812             free(jcr->RestoreBootstrap);
813             jcr->RestoreBootstrap = NULL;
814          }
815          if (ua->cmd[0] != 0) {
816             jcr->RestoreBootstrap = bstrdup(ua->cmd);
817             fd = fopen(jcr->RestoreBootstrap, "r");
818             if (!fd) {
819                bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
820                   jcr->RestoreBootstrap, strerror(errno));
821                free(jcr->RestoreBootstrap);
822                jcr->RestoreBootstrap = NULL;
823             } else {
824                fclose(fd);
825             }
826          }
827          goto try_again;
828       case 8:
829          /* Verify Job */
830          if (jcr->JobType == JT_VERIFY) {
831             verify_job = select_job_resource(ua);
832             if (verify_job) {
833               jcr->verify_job = verify_job;
834             }
835             goto try_again;
836          }
837          /* Where */
838          if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
839             break;
840          }
841          if (jcr->where) {
842             free(jcr->where);
843             jcr->where = NULL;
844          }
845          if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
846             ua->cmd[0] = 0;
847          }
848          jcr->where = bstrdup(ua->cmd);
849          goto try_again;
850       case 9:
851          /* Replace */
852          start_prompt(ua, _("Replace:\n"));
853          for (i=0; ReplaceOptions[i].name; i++) {
854             add_prompt(ua, ReplaceOptions[i].name);
855          }
856          opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
857          if (opt >=  0) {
858             jcr->replace = ReplaceOptions[opt].token;
859          }
860          goto try_again;
861       case 10:
862          /* JobId */
863          jid = NULL;                  /* force reprompt */
864          jcr->RestoreJobId = 0;
865          if (jcr->RestoreBootstrap) {
866             bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
867          }
868          goto try_again;
869       case -1:                        /* error or cancel */
870          goto bail_out;
871       default:
872          goto try_again;
873       }
874       goto bail_out;
875    }
876
877    if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
878       JobId_t JobId;
879       Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
880 start_job:
881       JobId = run_job(jcr);
882       free_jcr(jcr);                  /* release jcr */
883       if (JobId == 0) {
884          bsendmsg(ua, _("Job failed.\n"));
885       } else {
886          char ed1[50];
887          bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
888       }
889       return JobId;
890    }
891
892 bail_out:
893    bsendmsg(ua, _("Job not run.\n"));
894    free_jcr(jcr);
895    return 0;                       /* do not run */
896 }