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