]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
ebl fix segfault in migration job when storage is not defined
[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                if (!acl_access_ok(ua, Where_ACL, where)) {
189                   bsendmsg(ua, _("Forbidden \"where\" specified.\n"));
190                   return 0;
191                }
192                kw_ok = true;
193                break;
194             case 10: /* bootstrap */
195                if (bootstrap) {
196                   bsendmsg(ua, _("Bootstrap specified twice.\n"));
197                   return 0;
198                }
199                bootstrap = ua->argv[i];
200                kw_ok = true;
201                break;
202             case 11: /* replace */
203                if (replace) {
204                   bsendmsg(ua, _("Replace specified twice.\n"));
205                   return 0;
206                }
207                replace = ua->argv[i];
208                kw_ok = true;
209                break;
210             case 12: /* When */
211                if (when) {
212                   bsendmsg(ua, _("When specified twice.\n"));
213                   return 0;
214                }
215                when = ua->argv[i];
216                kw_ok = true;
217                break;
218             case 13:  /* Priority */
219                if (Priority) {
220                   bsendmsg(ua, _("Priority specified twice.\n"));
221                   return 0;
222                }
223                Priority = atoi(ua->argv[i]);
224                if (Priority <= 0) {
225                   bsendmsg(ua, _("Priority must be positive nonzero setting it to 10.\n"));
226                   Priority = 10;
227                }
228                kw_ok = true;
229                break;
230             case 14: /* yes */
231                kw_ok = true;
232                break;
233             case 15: /* Verify Job */
234                if (verify_job_name) {
235                   bsendmsg(ua, _("Verify Job specified twice.\n"));
236                   return 0;
237                }
238                verify_job_name = ua->argv[i];
239                kw_ok = true;
240                break;
241             case 16: /* files */
242                files = atoi(ua->argv[i]);
243                kw_ok = true;
244                break;
245
246             case 17: /* catalog */
247                catalog_name = ua->argv[i];
248                kw_ok = true;
249                break;
250
251             case 18: /* since */
252                since = ua->argv[i];
253                kw_ok = true; 
254                break;
255
256             case 19: /* cloned */
257                cloned = true;
258                kw_ok = true;
259                break;
260
261             case 20: /* write verify list output */
262                verify_list = ua->argv[i];
263                kw_ok = true;
264                break;
265             case 21: /* Migration Job */
266                if (previous_job_name) {
267                   bsendmsg(ua, _("Migration Job specified twice.\n"));
268                   return 0;
269                }
270                previous_job_name = ua->argv[i];
271                kw_ok = true;
272                break;
273
274
275             default:
276                break;
277             }
278          } /* end strcase compare */
279       } /* end keyword loop */
280       /*
281        * End of keyword for loop -- if not found, we got a bogus keyword
282        */
283       if (!kw_ok) {
284          Dmsg1(800, "%s not found\n", ua->argk[i]);
285          /*
286           * Special case for Job Name, it can be the first
287           * keyword that has no value.
288           */
289          if (!job_name && !ua->argv[i]) {
290             job_name = ua->argk[i];   /* use keyword as job name */
291             Dmsg1(800, "Set jobname=%s\n", job_name);
292          } else {
293             bsendmsg(ua, _("Invalid keyword: %s\n"), ua->argk[i]);
294             return 0;
295          }
296       }
297    } /* end argc loop */
298              
299    Dmsg0(800, "Done scan.\n");
300
301    CAT *catalog = NULL;
302    if (catalog_name != NULL) {
303        catalog = (CAT *)GetResWithName(R_CATALOG, catalog_name);
304        if (catalog == NULL) {
305             bsendmsg(ua, _("Catalog \"%s\" not found\n"), catalog_name);
306            return 0;
307        }
308    }
309    Dmsg1(800, "Using catalog=%s\n", NPRT(catalog_name));
310
311    if (job_name) {
312       /* Find Job */
313       job = (JOB *)GetResWithName(R_JOB, job_name);
314       if (!job) {
315          if (*job_name != 0) {
316             bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
317          }
318          job = select_job_resource(ua);
319       } else {
320          Dmsg1(800, "Found job=%s\n", job_name);
321       }
322    } else {
323       bsendmsg(ua, _("A job name must be specified.\n"));
324       job = select_job_resource(ua);
325    }
326    if (!job) {
327       return 0;
328    } else if (!acl_access_ok(ua, Job_ACL, job->name())) {
329       bsendmsg(ua, _("No authorization. Job \"%s\".\n"),
330          job->name());
331       return 0;
332    }
333
334    if (store_name) {
335       store = (STORE *)GetResWithName(R_STORAGE, store_name);
336       if (!store) {
337          if (*store_name != 0) {
338             bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
339          }
340          store = select_storage_resource(ua);
341       }
342    } else if (job->storage) {
343       store = (STORE *)job->storage->first();           /* use default */
344    }
345    if (!store) {
346       return 1;
347    } else if (!acl_access_ok(ua, Storage_ACL, store->name())) {
348       bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
349                store->name());
350       return 0;
351    }
352    Dmsg1(800, "Using storage=%s\n", store->name());
353
354    if (pool_name) {
355       pool = (POOL *)GetResWithName(R_POOL, pool_name);
356       if (!pool) {
357          if (*pool_name != 0) {
358             bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
359          }
360          pool = select_pool_resource(ua);
361       }
362    } else {
363       pool = job->pool;             /* use default */
364    }
365    if (!pool) {
366       return 0;
367    } else if (!acl_access_ok(ua, Pool_ACL, pool->name())) {
368       bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
369                pool->name());
370       return 0;
371    }
372    Dmsg1(800, "Using pool\n", pool->name());
373
374    if (client_name) {
375       client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
376       if (!client) {
377          if (*client_name != 0) {
378             bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
379          }
380          client = select_client_resource(ua);
381       }
382    } else {
383       client = job->client;           /* use default */
384    }
385    if (!client) {
386       return 0;
387    } else if (!acl_access_ok(ua, Client_ACL, client->name())) {
388       bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
389                client->name());
390       return 0;
391    }
392    Dmsg1(800, "Using client=%s\n", client->name());
393
394    if (fileset_name) {
395       fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
396       if (!fileset) {
397          bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
398          fileset = select_fileset_resource(ua);
399       }
400    } else {
401       fileset = job->fileset;           /* use default */
402    }
403    if (!fileset) {
404       return 0;
405    } else if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
406       bsendmsg(ua, _("No authorization. FileSet \"%s\".\n"),
407                fileset->name());
408       return 0;
409    }
410
411    if (verify_job_name) {
412       verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
413       if (!verify_job) {
414          bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
415          verify_job = select_job_resource(ua);
416       }
417    } else {
418       verify_job = job->verify_job;
419    }
420
421    if (previous_job_name) {
422       previous_job = (JOB *)GetResWithName(R_JOB, previous_job_name);
423       if (!previous_job) {
424          bsendmsg(ua, _("Migration Job \"%s\" not found.\n"), previous_job_name);
425          previous_job = select_job_resource(ua);
426       }
427    } else {
428       previous_job = job->verify_job;
429    }
430
431
432    /*
433     * Create JCR to run job.  NOTE!!! after this point, free_jcr()
434     *  before returning.
435     */
436    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
437    set_jcr_defaults(jcr, job);
438
439    jcr->verify_job = verify_job;
440    jcr->previous_job = previous_job;
441    set_rwstorage(jcr, store);
442    jcr->client = client;
443    jcr->fileset = fileset;
444    jcr->pool = pool;
445    jcr->ExpectedFiles = files;
446    if (catalog != NULL) {
447       jcr->catalog = catalog;
448    }
449    if (where) {
450       if (jcr->where) {
451          free(jcr->where);
452       }
453       jcr->where = bstrdup(where);
454    }
455
456    if (when) {
457       jcr->sched_time = str_to_utime(when);
458       if (jcr->sched_time == 0) {
459          bsendmsg(ua, _("Invalid time, using current time.\n"));
460          jcr->sched_time = time(NULL);
461       }
462    }
463
464    if (bootstrap) {
465       if (jcr->RestoreBootstrap) {
466          free(jcr->RestoreBootstrap);
467       }
468       jcr->RestoreBootstrap = bstrdup(bootstrap);
469    }
470
471    if (replace) {
472       jcr->replace = 0;
473       for (i=0; ReplaceOptions[i].name; i++) {
474          if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
475             jcr->replace = ReplaceOptions[i].token;
476          }
477       }
478       if (!jcr->replace) {
479          bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
480          goto bail_out;
481       }
482    } else if (job->replace) {
483       jcr->replace = job->replace;
484    } else {
485       jcr->replace = REPLACE_ALWAYS;
486    }
487
488    if (Priority) {
489       jcr->JobPriority = Priority;
490    }
491
492    if (since) {
493       if (!jcr->stime) {
494          jcr->stime = get_pool_memory(PM_MESSAGE);
495       }
496       pm_strcpy(jcr->stime, since);
497    }
498
499    jcr->cloned = cloned;
500
501    if (find_arg(ua, NT_("fdcalled")) > 0) {
502       jcr->file_bsock = dup_bsock(ua->UA_sock);
503       ua->quit = true;
504    }
505
506 try_again:
507    replace = ReplaceOptions[0].name;
508    for (i=0; ReplaceOptions[i].name; i++) {
509       if (ReplaceOptions[i].token == jcr->replace) {
510          replace = ReplaceOptions[i].name;
511       }
512    }
513    if (level_name) {
514       if (!get_level_from_name(jcr, level_name)) {
515          bsendmsg(ua, _("Level %s not valid.\n"), level_name);
516          goto bail_out;
517       }
518    }
519    if (jid) {
520       /* Note, this is also MigrateJobId */
521       jcr->RestoreJobId = str_to_int64(jid);
522    }
523
524    /* Run without prompting? */
525    if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
526       goto start_job;
527    }
528
529    /*
530     * Prompt User to see if all run job parameters are correct, and
531     *   allow him to modify them.
532     */
533    Dmsg1(800, "JobType=%c\n", jcr->JobType);
534    switch (jcr->JobType) {
535       char ec1[30];
536       char dt[MAX_TIME_LENGTH];
537    case JT_ADMIN:
538          bsendmsg(ua, _("Run %s job\n"
539 "JobName:  %s\n"
540 "FileSet:  %s\n"
541 "Client:   %s\n"
542 "Storage:  %s\n"
543 "When:     %s\n"
544 "Priority: %d\n"),
545                  _("Admin"),
546                  job->name(),
547                  jcr->fileset->name(),
548                  NPRT(jcr->client->name()),
549                  NPRT(jcr->wstore->name()),
550                  bstrutime(dt, sizeof(dt), jcr->sched_time),
551                  jcr->JobPriority);
552       jcr->JobLevel = L_FULL;
553       break;
554    case JT_BACKUP:
555    case JT_VERIFY:
556       if (jcr->JobType == JT_BACKUP) {
557          bsendmsg(ua, _("Run %s job\n"
558 "JobName:  %s\n"
559 "FileSet:  %s\n"
560 "Level:    %s\n"
561 "Client:   %s\n"
562 "Storage:  %s\n"
563 "Pool:     %s\n"
564 "When:     %s\n"
565 "Priority: %d\n"),
566                  _("Backup"),
567                  job->name(),
568                  jcr->fileset->name(),
569                  level_to_str(jcr->JobLevel),
570                  jcr->client->name(),
571                  jcr->wstore->name(),
572                  NPRT(jcr->pool->name()),
573                  bstrutime(dt, sizeof(dt), jcr->sched_time),
574                  jcr->JobPriority);
575       } else {  /* JT_VERIFY */
576          const char *Name;
577          if (jcr->verify_job) {
578             Name = jcr->verify_job->name();
579          } else {
580             Name = "";
581          }
582          if (!verify_list) {
583             verify_list = job->WriteVerifyList;
584          }
585          if (!verify_list) {
586             verify_list = "";
587          }
588          bsendmsg(ua, _("Run %s job\n"
589 "JobName:     %s\n"
590 "FileSet:     %s\n"
591 "Level:       %s\n"
592 "Client:      %s\n"
593 "Storage:     %s\n"
594 "Pool:        %s\n"
595 "Verify Job:  %s\n"
596 "Verify List: %s\n"
597 "When:        %s\n"
598 "Priority:    %d\n"),
599               _("Verify"),
600               job->name(),
601               jcr->fileset->name(),
602               level_to_str(jcr->JobLevel),
603               jcr->client->name(),
604               jcr->rstore->name(),
605               NPRT(jcr->pool->name()),
606               Name,
607               verify_list,
608               bstrutime(dt, sizeof(dt), jcr->sched_time),
609               jcr->JobPriority);
610       }
611       break;
612    case JT_RESTORE:
613       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
614          if (jid) {
615             jcr->RestoreJobId = str_to_int64(jid);
616          } else {
617             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
618                goto bail_out;
619             }
620             jcr->RestoreJobId = ua->int64_val;
621          }
622       }
623       jcr->JobLevel = L_FULL;      /* default level */
624       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
625       if (jcr->RestoreJobId == 0) {
626          bsendmsg(ua, _("Run Restore job\n"
627                         "JobName:    %s\n"
628                         "Bootstrap:  %s\n"
629                         "Where:      %s\n"
630                         "Replace:    %s\n"
631                         "FileSet:    %s\n"
632                         "Client:     %s\n"
633                         "Storage:    %s\n"
634                         "When:       %s\n"
635                         "Catalog:    %s\n"
636                         "Priority:   %d\n"),
637               job->name(),
638               NPRT(jcr->RestoreBootstrap),
639               jcr->where?jcr->where:NPRT(job->RestoreWhere),
640               replace,
641               jcr->fileset->name(),
642               jcr->client->name(),
643               jcr->rstore->name(),
644               bstrutime(dt, sizeof(dt), jcr->sched_time),
645               jcr->catalog->name(),
646               jcr->JobPriority);
647       } else {
648          bsendmsg(ua, _("Run Restore job\n"
649                        "JobName:    %s\n"
650                        "Bootstrap:  %s\n"
651                        "Where:      %s\n"
652                        "Replace:    %s\n"
653                        "Client:     %s\n"
654                        "Storage:    %s\n"
655                        "JobId:      %s\n"
656                        "When:       %s\n"
657                        "Catalog:    %s\n"
658                        "Priority:   %d\n"),
659               job->name(),
660               NPRT(jcr->RestoreBootstrap),
661               jcr->where?jcr->where:NPRT(job->RestoreWhere),
662               replace,
663               jcr->client->name(),
664               jcr->rstore->name(),
665               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
666               bstrutime(dt, sizeof(dt), jcr->sched_time),
667               jcr->catalog->name(),
668               jcr->JobPriority);
669       }
670       break;
671    case JT_MIGRATE:
672       jcr->JobLevel = L_FULL;      /* default level */
673       bsendmsg(ua, _("Run Migration job\n"
674                      "JobName:       %s\n"
675                      "Bootstrap:     %s\n"
676                      "FileSet:       %s\n"
677                      "Client:        %s\n"
678                      "Storage:       %s\n"
679                      "JobId:         %s\n"
680                      "When:          %s\n"
681                      "Catalog:       %s\n"
682                      "Priority:      %d\n"),
683            job->name(),
684            NPRT(jcr->RestoreBootstrap),
685            jcr->fileset->name(),
686            jcr->client->name(),
687            jcr->wstore->name(),
688            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
689            bstrutime(dt, sizeof(dt), jcr->sched_time),
690            jcr->catalog->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_rwstorage(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, "rb");
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 #if 0  
935       bsendmsg(ua, "<job director=\"console\" time=\"%u\" status=\"%c\" type=\"%c\" "
936               "jobid=\"%u\" job=\"%s\" level=\"%c\" finished=\"false\" priority=\"%u\"/>\n",
937                time(NULL), jcr->JobStatus, jcr->JobType, jcr->JobId,
938               jcr->Job, jcr->JobLevel, jcr->JobPriority);
939 #endif
940       free_jcr(jcr);                  /* release jcr */
941       if (JobId == 0) {
942          bsendmsg(ua, _("Job failed.\n"));
943       } else {
944          char ed1[50];
945          bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
946       }
947       return JobId;
948    }
949
950 bail_out:
951    bsendmsg(ua, _("Job not run.\n"));
952    free_jcr(jcr);
953    return 0;                       /* do not run */
954 }