]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
11Apr06
[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-2006 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 *previous_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 *previous_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    previous_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 fail */
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 (previous_job_name) {
263                   bsendmsg(ua, _("Migration Job specified twice.\n"));
264                   return 0;
265                }
266                previous_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 (previous_job_name) {
418       previous_job = (JOB *)GetResWithName(R_JOB, previous_job_name);
419       if (!previous_job) {
420          bsendmsg(ua, _("Migration Job \"%s\" not found.\n"), previous_job_name);
421          previous_job = select_job_resource(ua);
422       }
423    } else {
424       previous_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->previous_job = previous_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, NT_("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       /* Note, this is also MigrateJobId */
517       jcr->RestoreJobId = str_to_int64(jid);
518    }
519
520    /* Run without prompting? */
521    if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
522       goto start_job;
523    }
524
525    /*
526     * Prompt User to see if all run job parameters are correct, and
527     *   allow him to modify them.
528     */
529    Dmsg1(800, "JobType=%c\n", jcr->JobType);
530    switch (jcr->JobType) {
531       char ec1[30];
532       char dt[MAX_TIME_LENGTH];
533    case JT_ADMIN:
534          bsendmsg(ua, _("Run %s job\n"
535 "JobName:  %s\n"
536 "FileSet:  %s\n"
537 "Client:   %s\n"
538 "Storage:  %s\n"
539 "When:     %s\n"
540 "Priority: %d\n"),
541                  _("Admin"),
542                  job->hdr.name,
543                  jcr->fileset->hdr.name,
544                  NPRT(jcr->client->hdr.name),
545                  NPRT(jcr->store->hdr.name),
546                  bstrutime(dt, sizeof(dt), jcr->sched_time),
547                  jcr->JobPriority);
548       jcr->JobLevel = L_FULL;
549       break;
550    case JT_BACKUP:
551    case JT_VERIFY:
552       if (jcr->JobType == JT_BACKUP) {
553          bsendmsg(ua, _("Run %s job\n"
554 "JobName:  %s\n"
555 "FileSet:  %s\n"
556 "Level:    %s\n"
557 "Client:   %s\n"
558 "Storage:  %s\n"
559 "Pool:     %s\n"
560 "When:     %s\n"
561 "Priority: %d\n"),
562                  _("Backup"),
563                  job->hdr.name,
564                  jcr->fileset->hdr.name,
565                  level_to_str(jcr->JobLevel),
566                  jcr->client->hdr.name,
567                  jcr->store->hdr.name,
568                  NPRT(jcr->pool->hdr.name),
569                  bstrutime(dt, sizeof(dt), jcr->sched_time),
570                  jcr->JobPriority);
571       } else {  /* JT_VERIFY */
572          const char *Name;
573          if (jcr->verify_job) {
574             Name = jcr->verify_job->hdr.name;
575          } else {
576             Name = "";
577          }
578          if (!verify_list) {
579             verify_list = job->WriteVerifyList;
580          }
581          if (!verify_list) {
582             verify_list = "";
583          }
584          bsendmsg(ua, _("Run %s job\n"
585 "JobName:     %s\n"
586 "FileSet:     %s\n"
587 "Level:       %s\n"
588 "Client:      %s\n"
589 "Storage:     %s\n"
590 "Pool:        %s\n"
591 "Verify Job:  %s\n"
592 "Verify List: %s\n"
593 "When:        %s\n"
594 "Priority:    %d\n"),
595               _("Verify"),
596               job->hdr.name,
597               jcr->fileset->hdr.name,
598               level_to_str(jcr->JobLevel),
599               jcr->client->hdr.name,
600               jcr->store->hdr.name,
601               NPRT(jcr->pool->hdr.name),
602               Name,
603               verify_list,
604               bstrutime(dt, sizeof(dt), jcr->sched_time),
605               jcr->JobPriority);
606       }
607       break;
608    case JT_RESTORE:
609       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
610          if (jid) {
611             jcr->RestoreJobId = str_to_int64(jid);
612          } else {
613             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
614                goto bail_out;
615             }
616             jcr->RestoreJobId = ua->int64_val;
617          }
618       }
619       jcr->JobLevel = L_FULL;      /* default level */
620       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
621       if (jcr->RestoreJobId == 0) {
622          bsendmsg(ua, _("Run Restore job\n"
623                         "JobName:    %s\n"
624                         "Bootstrap:  %s\n"
625                         "Where:      %s\n"
626                         "Replace:    %s\n"
627                         "FileSet:    %s\n"
628                         "Client:     %s\n"
629                         "Storage:    %s\n"
630                         "When:       %s\n"
631                         "Catalog:    %s\n"
632                         "Priority:   %d\n"),
633               job->hdr.name,
634               NPRT(jcr->RestoreBootstrap),
635               jcr->where?jcr->where:NPRT(job->RestoreWhere),
636               replace,
637               jcr->fileset->hdr.name,
638               jcr->client->hdr.name,
639               jcr->store->hdr.name,
640               bstrutime(dt, sizeof(dt), jcr->sched_time),
641               jcr->catalog->hdr.name,
642               jcr->JobPriority);
643       } else {
644          bsendmsg(ua, _("Run Restore job\n"
645                        "JobName:    %s\n"
646                        "Bootstrap:  %s\n"
647                        "Where:      %s\n"
648                        "Replace:    %s\n"
649                        "Client:     %s\n"
650                        "Storage:    %s\n"
651                        "JobId:      %s\n"
652                        "When:       %s\n"
653                        "Catalog:    %s\n"
654                        "Priority:   %d\n"),
655               job->hdr.name,
656               NPRT(jcr->RestoreBootstrap),
657               jcr->where?jcr->where:NPRT(job->RestoreWhere),
658               replace,
659               jcr->client->hdr.name,
660               jcr->store->hdr.name,
661               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
662               bstrutime(dt, sizeof(dt), jcr->sched_time),
663               jcr->catalog->hdr.name,
664               jcr->JobPriority);
665       }
666       break;
667    case JT_MIGRATE:
668       jcr->JobLevel = L_FULL;      /* default level */
669       bsendmsg(ua, _("Run Restore job\n"
670                      "JobName:       %s\n"
671                      "Bootstrap:     %s\n"
672                      "Where:         %s\n"
673                      "Replace:       %s\n"
674                      "FileSet:       %s\n"
675                      "Client:        %s\n"
676                      "Storage:       %s\n"
677                      "JobId:         %s\n"
678                      "When:          %s\n"
679                      "Catalog:       %s\n"
680                      "Priority:      %d\n"),
681            job->hdr.name,
682            NPRT(jcr->RestoreBootstrap),
683            jcr->where?jcr->where:NPRT(job->RestoreWhere),
684            replace,
685            jcr->fileset->hdr.name,
686            jcr->client->hdr.name,
687            jcr->store->hdr.name,
688            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
689            bstrutime(dt, sizeof(dt), jcr->sched_time),
690            jcr->catalog->hdr.name,
691            jcr->JobPriority);
692       break;
693    default:
694       bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
695       goto bail_out;
696    }
697
698    if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
699       goto bail_out;
700    }
701    /*
702     * At user request modify parameters of job to be run.
703     */
704    if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
705       FILE *fd;
706
707       start_prompt(ua, _("Parameters to modify:\n"));
708       add_prompt(ua, _("Level"));            /* 0 */
709       add_prompt(ua, _("Storage"));          /* 1 */
710       add_prompt(ua, _("Job"));              /* 2 */
711       add_prompt(ua, _("FileSet"));          /* 3 */
712       add_prompt(ua, _("Client"));           /* 4 */
713       add_prompt(ua, _("When"));             /* 5 */
714       add_prompt(ua, _("Priority"));         /* 6 */
715       if (jcr->JobType == JT_BACKUP ||
716           jcr->JobType == JT_VERIFY) {
717          add_prompt(ua, _("Pool"));          /* 7 */
718          if (jcr->JobType == JT_VERIFY) {
719             add_prompt(ua, _("Verify Job"));  /* 8 */
720          }
721       } else if (jcr->JobType == JT_RESTORE) {
722          add_prompt(ua, _("Bootstrap"));     /* 7 */
723          add_prompt(ua, _("Where"));         /* 8 */
724          add_prompt(ua, _("Replace"));       /* 9 */
725          add_prompt(ua, _("JobId"));         /* 10 */
726       }
727       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
728       case 0:
729          /* Level */
730          if (jcr->JobType == JT_BACKUP) {
731             start_prompt(ua, _("Levels:\n"));
732             add_prompt(ua, _("Base"));
733             add_prompt(ua, _("Full"));
734             add_prompt(ua, _("Incremental"));
735             add_prompt(ua, _("Differential"));
736             add_prompt(ua, _("Since"));
737             switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
738             case 0:
739                jcr->JobLevel = L_BASE;
740                break;
741             case 1:
742                jcr->JobLevel = L_FULL;
743                break;
744             case 2:
745                jcr->JobLevel = L_INCREMENTAL;
746                break;
747             case 3:
748                jcr->JobLevel = L_DIFFERENTIAL;
749                break;
750             case 4:
751                jcr->JobLevel = L_SINCE;
752                break;
753             default:
754                break;
755             }
756             goto try_again;
757          } else if (jcr->JobType == JT_VERIFY) {
758             start_prompt(ua, _("Levels:\n"));
759             add_prompt(ua, _("Initialize Catalog"));
760             add_prompt(ua, _("Verify Catalog"));
761             add_prompt(ua, _("Verify Volume to Catalog"));
762             add_prompt(ua, _("Verify Disk to Catalog"));
763             add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
764             switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
765             case 0:
766                jcr->JobLevel = L_VERIFY_INIT;
767                break;
768             case 1:
769                jcr->JobLevel = L_VERIFY_CATALOG;
770                break;
771             case 2:
772                jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
773                break;
774             case 3:
775                jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
776                break;
777             case 4:
778                jcr->JobLevel = L_VERIFY_DATA;
779                break;
780             default:
781                break;
782             }
783             goto try_again;
784          } else {
785             bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
786          }
787          goto try_again;
788       case 1:
789          /* Storage */
790          store = select_storage_resource(ua);
791          if (store) {
792             set_storage(jcr, store);
793             goto try_again;
794          }
795          break;
796       case 2:
797          /* Job */
798          job = select_job_resource(ua);
799          if (job) {
800             jcr->job = job;
801             set_jcr_defaults(jcr, job);
802             goto try_again;
803          }
804          break;
805       case 3:
806          /* FileSet */
807          fileset = select_fileset_resource(ua);
808          if (fileset) {
809             jcr->fileset = fileset;
810             goto try_again;
811          }
812          break;
813       case 4:
814          /* Client */
815          client = select_client_resource(ua);
816          if (client) {
817             jcr->client = client;
818             goto try_again;
819          }
820          break;
821       case 5:
822          /* When */
823          if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
824             break;
825          }
826          if (ua->cmd[0] == 0) {
827             jcr->sched_time = time(NULL);
828          } else {
829             jcr->sched_time = str_to_utime(ua->cmd);
830             if (jcr->sched_time == 0) {
831                bsendmsg(ua, _("Invalid time, using current time.\n"));
832                jcr->sched_time = time(NULL);
833             }
834          }
835          goto try_again;
836       case 6:
837          /* Priority */
838          if (!get_pint(ua, _("Enter new Priority: "))) {
839             break;
840          }
841          if (ua->pint32_val == 0) {
842             bsendmsg(ua, _("Priority must be a positive integer.\n"));
843          } else {
844             jcr->JobPriority = ua->pint32_val;
845          }
846          goto try_again;
847       case 7:
848          /* Pool or Bootstrap depending on JobType */
849          if (jcr->JobType == JT_BACKUP ||
850              jcr->JobType == JT_VERIFY) {      /* Pool */
851             pool = select_pool_resource(ua);
852             if (pool) {
853                jcr->pool = pool;
854                goto try_again;
855             }
856             break;
857          }
858
859          /* Bootstrap */
860          if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
861             break;
862          }
863          if (jcr->RestoreBootstrap) {
864             free(jcr->RestoreBootstrap);
865             jcr->RestoreBootstrap = NULL;
866          }
867          if (ua->cmd[0] != 0) {
868             jcr->RestoreBootstrap = bstrdup(ua->cmd);
869             fd = fopen(jcr->RestoreBootstrap, "r");
870             if (!fd) {
871                bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
872                   jcr->RestoreBootstrap, strerror(errno));
873                free(jcr->RestoreBootstrap);
874                jcr->RestoreBootstrap = NULL;
875             } else {
876                fclose(fd);
877             }
878          }
879          goto try_again;
880       case 8:
881          /* Verify Job */
882          if (jcr->JobType == JT_VERIFY) {
883             verify_job = select_job_resource(ua);
884             if (verify_job) {
885               jcr->verify_job = verify_job;
886             }
887             goto try_again;
888          }
889          /* Where */
890          if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
891             break;
892          }
893          if (jcr->where) {
894             free(jcr->where);
895             jcr->where = NULL;
896          }
897          if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
898             ua->cmd[0] = 0;
899          }
900          jcr->where = bstrdup(ua->cmd);
901          goto try_again;
902       case 9:
903          /* Replace */
904          start_prompt(ua, _("Replace:\n"));
905          for (i=0; ReplaceOptions[i].name; i++) {
906             add_prompt(ua, ReplaceOptions[i].name);
907          }
908          opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
909          if (opt >=  0) {
910             jcr->replace = ReplaceOptions[opt].token;
911          }
912          goto try_again;
913       case 10:
914          /* JobId */
915          jid = NULL;                  /* force reprompt */
916          jcr->RestoreJobId = 0;
917          if (jcr->RestoreBootstrap) {
918             bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
919          }
920          goto try_again;
921       case -1:                        /* error or cancel */
922          goto bail_out;
923       default:
924          goto try_again;
925       }
926       goto bail_out;
927    }
928
929    if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
930       JobId_t JobId;
931       Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
932 start_job:
933       JobId = run_job(jcr);
934       free_jcr(jcr);                  /* release jcr */
935       if (JobId == 0) {
936          bsendmsg(ua, _("Job failed.\n"));
937       } else {
938          char ed1[50];
939          bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
940       }
941       return JobId;
942    }
943
944 bail_out:
945    bsendmsg(ua, _("Job not run.\n"));
946    free_jcr(jcr);
947    return 0;                       /* do not run */
948 }