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