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