]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
kes Add code in catreq.c to reject volumes not marked Enabled.
[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 /* 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    jcr->fileset = fileset;
471    jcr->ExpectedFiles = files;
472    if (catalog != NULL) {
473       jcr->catalog = catalog;
474    }
475    if (where) {
476       if (jcr->where) {
477          free(jcr->where);
478       }
479       jcr->where = bstrdup(where);
480    }
481
482    if (when) {
483       jcr->sched_time = str_to_utime(when);
484       if (jcr->sched_time == 0) {
485          bsendmsg(ua, _("Invalid time, using current time.\n"));
486          jcr->sched_time = time(NULL);
487       }
488    }
489
490    if (bootstrap) {
491       if (jcr->RestoreBootstrap) {
492          free(jcr->RestoreBootstrap);
493       }
494       jcr->RestoreBootstrap = bstrdup(bootstrap);
495    }
496
497    if (replace) {
498       jcr->replace = 0;
499       for (i=0; ReplaceOptions[i].name; i++) {
500          if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
501             jcr->replace = ReplaceOptions[i].token;
502          }
503       }
504       if (!jcr->replace) {
505          bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
506          goto bail_out;
507       }
508    } else if (job->replace) {
509       jcr->replace = job->replace;
510    } else {
511       jcr->replace = REPLACE_ALWAYS;
512    }
513
514    if (Priority) {
515       jcr->JobPriority = Priority;
516    }
517
518    if (since) {
519       if (!jcr->stime) {
520          jcr->stime = get_pool_memory(PM_MESSAGE);
521       }
522       pm_strcpy(jcr->stime, since);
523    }
524
525    jcr->cloned = cloned;
526
527    if (find_arg(ua, NT_("fdcalled")) > 0) {
528       jcr->file_bsock = dup_bsock(ua->UA_sock);
529       ua->quit = true;
530    }
531
532 try_again:
533    /* If pool changed, update migration write storage */
534    if (jcr->JobType == JT_MIGRATE) {
535       if (!set_migration_wstorage(jcr, pool)) {
536          goto bail_out;
537       }
538    }
539    replace = ReplaceOptions[0].name;
540    for (i=0; ReplaceOptions[i].name; i++) {
541       if (ReplaceOptions[i].token == jcr->replace) {
542          replace = ReplaceOptions[i].name;
543       }
544    }
545    if (level_name) {
546       if (!get_level_from_name(jcr, level_name)) {
547          bsendmsg(ua, _("Level %s not valid.\n"), level_name);
548          goto bail_out;
549       }
550    }
551    if (jid) {
552       /* Note, this is also MigrateJobId */
553       jcr->RestoreJobId = str_to_int64(jid);
554    }
555
556    /* Run without prompting? */
557    if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
558       goto start_job;
559    }
560
561    /*
562     * Prompt User to see if all run job parameters are correct, and
563     *   allow him to modify them.
564     */
565    if (!display_job_parameters(ua, jcr, job, verify_list, jid, replace)) {
566       goto bail_out;
567    }
568
569    if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
570       goto bail_out;
571    }
572
573    /*
574     * At user request modify parameters of job to be run.
575     */
576    if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
577       FILE *fd;
578
579       start_prompt(ua, _("Parameters to modify:\n"));
580       add_prompt(ua, _("Level"));            /* 0 */
581       add_prompt(ua, _("Storage"));          /* 1 */
582       add_prompt(ua, _("Job"));              /* 2 */
583       add_prompt(ua, _("FileSet"));          /* 3 */
584       add_prompt(ua, _("Client"));           /* 4 */
585       add_prompt(ua, _("When"));             /* 5 */
586       add_prompt(ua, _("Priority"));         /* 6 */
587       if (jcr->JobType == JT_BACKUP ||
588           jcr->JobType == JT_MIGRATE ||
589           jcr->JobType == JT_VERIFY) {
590          add_prompt(ua, _("Pool"));          /* 7 */
591          if (jcr->JobType == JT_VERIFY) {
592             add_prompt(ua, _("Verify Job"));  /* 8 */
593          }
594       } else if (jcr->JobType == JT_RESTORE) {
595          add_prompt(ua, _("Bootstrap"));     /* 7 */
596          add_prompt(ua, _("Where"));         /* 8 */
597          add_prompt(ua, _("Replace"));       /* 9 */
598          add_prompt(ua, _("JobId"));         /* 10 */
599       }
600       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
601       case 0:
602          /* Level */
603          select_job_level(ua, jcr);
604          goto try_again;
605       case 1:
606          /* Storage */
607          store.store = select_storage_resource(ua);
608          if (store.store) {
609             pm_strcpy(store.store_source, _("user selection"));
610             set_rwstorage(jcr, &store);
611             goto try_again;
612          }
613          break;
614       case 2:
615          /* Job */
616          job = select_job_resource(ua);
617          if (job) {
618             jcr->job = job;
619             set_jcr_defaults(jcr, job);
620             goto try_again;
621          }
622          break;
623       case 3:
624          /* FileSet */
625          fileset = select_fileset_resource(ua);
626          if (fileset) {
627             jcr->fileset = fileset;
628             goto try_again;
629          }
630          break;
631       case 4:
632          /* Client */
633          client = select_client_resource(ua);
634          if (client) {
635             jcr->client = client;
636             goto try_again;
637          }
638          break;
639       case 5:
640          /* When */
641          if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
642             break;
643          }
644          if (ua->cmd[0] == 0) {
645             jcr->sched_time = time(NULL);
646          } else {
647             jcr->sched_time = str_to_utime(ua->cmd);
648             if (jcr->sched_time == 0) {
649                bsendmsg(ua, _("Invalid time, using current time.\n"));
650                jcr->sched_time = time(NULL);
651             }
652          }
653          goto try_again;
654       case 6:
655          /* Priority */
656          if (!get_pint(ua, _("Enter new Priority: "))) {
657             break;
658          }
659          if (ua->pint32_val == 0) {
660             bsendmsg(ua, _("Priority must be a positive integer.\n"));
661          } else {
662             jcr->JobPriority = ua->pint32_val;
663          }
664          goto try_again;
665       case 7:
666          /* Pool or Bootstrap depending on JobType */
667          if (jcr->JobType == JT_BACKUP ||
668              jcr->JobType == JT_MIGRATE ||
669              jcr->JobType == JT_VERIFY) {      /* Pool */
670             pool = select_pool_resource(ua);
671             if (pool) {
672                jcr->pool = pool;
673                Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
674                goto try_again;
675             }
676             break;
677          }
678
679          /* Bootstrap */
680          if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
681             break;
682          }
683          if (jcr->RestoreBootstrap) {
684             free(jcr->RestoreBootstrap);
685             jcr->RestoreBootstrap = NULL;
686          }
687          if (ua->cmd[0] != 0) {
688             jcr->RestoreBootstrap = bstrdup(ua->cmd);
689             fd = fopen(jcr->RestoreBootstrap, "rb");
690             if (!fd) {
691                bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
692                   jcr->RestoreBootstrap, strerror(errno));
693                free(jcr->RestoreBootstrap);
694                jcr->RestoreBootstrap = NULL;
695             } else {
696                fclose(fd);
697             }
698          }
699          goto try_again;
700       case 8:
701          /* Verify Job */
702          if (jcr->JobType == JT_VERIFY) {
703             verify_job = select_job_resource(ua);
704             if (verify_job) {
705               jcr->verify_job = verify_job;
706             }
707             goto try_again;
708          }
709          /* Where */
710          if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
711             break;
712          }
713          if (jcr->where) {
714             free(jcr->where);
715             jcr->where = NULL;
716          }
717          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
718             ua->cmd[0] = 0;
719          }
720          jcr->where = bstrdup(ua->cmd);
721          goto try_again;
722       case 9:
723          /* Replace */
724          start_prompt(ua, _("Replace:\n"));
725          for (i=0; ReplaceOptions[i].name; i++) {
726             add_prompt(ua, ReplaceOptions[i].name);
727          }
728          opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
729          if (opt >=  0) {
730             jcr->replace = ReplaceOptions[opt].token;
731          }
732          goto try_again;
733       case 10:
734          /* JobId */
735          jid = NULL;                  /* force reprompt */
736          jcr->RestoreJobId = 0;
737          if (jcr->RestoreBootstrap) {
738             bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
739          }
740          goto try_again;
741       case -1:                        /* error or cancel */
742          goto bail_out;
743       default:
744          goto try_again;
745       }
746       goto bail_out;
747    }
748
749    if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
750       JobId_t JobId;
751       Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
752 start_job:
753       Dmsg1(100, "Using pool %s\n", jcr->pool->name());
754       JobId = run_job(jcr);
755 #if 0  
756       bsendmsg(ua, "<job director=\"console\" time=\"%u\" status=\"%c\" type=\"%c\" "
757               "jobid=\"%u\" job=\"%s\" level=\"%c\" finished=\"false\" priority=\"%u\"/>\n",
758                time(NULL), jcr->JobStatus, jcr->JobType, jcr->JobId,
759               jcr->Job, jcr->JobLevel, jcr->JobPriority);
760 #endif
761       free_jcr(jcr);                  /* release jcr */
762       if (JobId == 0) {
763          bsendmsg(ua, _("Job failed.\n"));
764       } else {
765          char ed1[50];
766          bsendmsg(ua, _("Job queued. JobId=%s\n"), edit_int64(JobId,ed1));
767       }
768       return JobId;
769    }
770
771 bail_out:
772    bsendmsg(ua, _("Job not run.\n"));
773    free_jcr(jcr);
774    return 0;                       /* do not run */
775 }
776
777 static void select_job_level(UAContext *ua, JCR *jcr)
778 {
779    if (jcr->JobType == JT_BACKUP) {
780       start_prompt(ua, _("Levels:\n"));
781       add_prompt(ua, _("Base"));
782       add_prompt(ua, _("Full"));
783       add_prompt(ua, _("Incremental"));
784       add_prompt(ua, _("Differential"));
785       add_prompt(ua, _("Since"));
786       switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
787       case 0:
788          jcr->JobLevel = L_BASE;
789          break;
790       case 1:
791          jcr->JobLevel = L_FULL;
792          break;
793       case 2:
794          jcr->JobLevel = L_INCREMENTAL;
795          break;
796       case 3:
797          jcr->JobLevel = L_DIFFERENTIAL;
798          break;
799       case 4:
800          jcr->JobLevel = L_SINCE;
801          break;
802       default:
803          break;
804       }
805    } else if (jcr->JobType == JT_VERIFY) {
806       start_prompt(ua, _("Levels:\n"));
807       add_prompt(ua, _("Initialize Catalog"));
808       add_prompt(ua, _("Verify Catalog"));
809       add_prompt(ua, _("Verify Volume to Catalog"));
810       add_prompt(ua, _("Verify Disk to Catalog"));
811       add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
812       switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
813       case 0:
814          jcr->JobLevel = L_VERIFY_INIT;
815          break;
816       case 1:
817          jcr->JobLevel = L_VERIFY_CATALOG;
818          break;
819       case 2:
820          jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
821          break;
822       case 3:
823          jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
824          break;
825       case 4:
826          jcr->JobLevel = L_VERIFY_DATA;
827          break;
828       default:
829          break;
830       }
831    } else {
832       bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
833    }
834    return;
835 }
836
837 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *verify_list,
838    char *jid, const char *replace) 
839 {
840    Dmsg1(800, "JobType=%c\n", jcr->JobType);
841    switch (jcr->JobType) {
842       char ec1[30];
843       char dt[MAX_TIME_LENGTH];
844    case JT_ADMIN:
845          bsendmsg(ua, _("Run %s job\n"
846                         "JobName:  %s\n"
847                         "FileSet:  %s\n"
848                         "Client:   %s\n"
849                         "Storage:  %s\n"
850                         "When:     %s\n"
851                         "Priority: %d\n"),
852                  _("Admin"),
853                  job->name(),
854                  jcr->fileset->name(),
855                  NPRT(jcr->client->name()),
856                  jcr->wstore?jcr->wstore->name():"*None*",
857                  bstrutime(dt, sizeof(dt), jcr->sched_time),
858                  jcr->JobPriority);
859       jcr->JobLevel = L_FULL;
860       break;
861    case JT_BACKUP:
862    case JT_VERIFY:
863       if (jcr->JobType == JT_BACKUP) {
864          bsendmsg(ua, _("Run %s job\n"
865                         "JobName:  %s\n"
866                         "Level:    %s\n"
867                         "Client:   %s\n"
868                         "FileSet:  %s\n"
869                         "Pool:     %s (From %s)\n"
870                         "Storage:  %s (From %s)\n"
871                         "When:     %s\n"
872                         "Priority: %d\n"),
873                  _("Backup"),
874                  job->name(),
875                  level_to_str(jcr->JobLevel),
876                  jcr->client->name(),
877                  jcr->fileset->name(),
878                  NPRT(jcr->pool->name()), jcr->pool_source,
879                  jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
880                  bstrutime(dt, sizeof(dt), jcr->sched_time),
881                  jcr->JobPriority);
882       } else {  /* JT_VERIFY */
883          const char *Name;
884          if (jcr->verify_job) {
885             Name = jcr->verify_job->name();
886          } else {
887             Name = "";
888          }
889          if (!verify_list) {
890             verify_list = job->WriteVerifyList;
891          }
892          if (!verify_list) {
893             verify_list = "";
894          }
895          bsendmsg(ua, _("Run %s job\n"
896                         "JobName:     %s\n"
897                         "Level:       %s\n"
898                         "Client:      %s\n"
899                         "FileSet:     %s\n"
900                         "Pool:        %s (From %s)\n"
901                         "Storage:     %s (From %s)\n"
902                         "Verify Job:  %s\n"
903                         "Verify List: %s\n"
904                         "When:        %s\n"
905                         "Priority:    %d\n"),
906               _("Verify"),
907               job->name(),
908               level_to_str(jcr->JobLevel),
909               jcr->client->name(),
910               jcr->fileset->name(),
911               NPRT(jcr->pool->name()), jcr->pool_source,
912               jcr->rstore->name(), jcr->rstore_source,
913               Name,
914               verify_list,
915               bstrutime(dt, sizeof(dt), jcr->sched_time),
916               jcr->JobPriority);
917       }
918       break;
919    case JT_RESTORE:
920       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
921          if (jid) {
922             jcr->RestoreJobId = str_to_int64(jid);
923          } else {
924             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
925                return false;
926             }
927             jcr->RestoreJobId = ua->int64_val;
928          }
929       }
930       jcr->JobLevel = L_FULL;      /* default level */
931       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
932       if (jcr->RestoreJobId == 0) {
933          bsendmsg(ua, _("Run Restore job\n"
934                         "JobName:    %s\n"
935                         "Bootstrap:  %s\n"
936                         "Where:      %s\n"
937                         "Replace:    %s\n"
938                         "FileSet:    %s\n"
939                         "Client:     %s\n"
940                         "Storage:    %s\n"
941                         "When:       %s\n"
942                         "Catalog:    %s\n"
943                         "Priority:   %d\n"),
944               job->name(),
945               NPRT(jcr->RestoreBootstrap),
946               jcr->where?jcr->where:NPRT(job->RestoreWhere),
947               replace,
948               jcr->fileset->name(),
949               jcr->client->name(),
950               jcr->rstore->name(),
951               bstrutime(dt, sizeof(dt), jcr->sched_time),
952               jcr->catalog->name(),
953               jcr->JobPriority);
954       } else {
955          bsendmsg(ua, _("Run Restore job\n"
956                        "JobName:    %s\n"
957                        "Bootstrap:  %s\n"
958                        "Where:      %s\n"
959                        "Replace:    %s\n"
960                        "Client:     %s\n"
961                        "Storage:    %s\n"
962                        "JobId:      %s\n"
963                        "When:       %s\n"
964                        "Catalog:    %s\n"
965                        "Priority:   %d\n"),
966               job->name(),
967               NPRT(jcr->RestoreBootstrap),
968               jcr->where?jcr->where:NPRT(job->RestoreWhere),
969               replace,
970               jcr->client->name(),
971               jcr->rstore->name(),
972               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
973               bstrutime(dt, sizeof(dt), jcr->sched_time),
974               jcr->catalog->name(),
975               jcr->JobPriority);
976       }
977       break;
978    case JT_MIGRATE:
979       jcr->JobLevel = L_FULL;      /* default level */
980       bsendmsg(ua, _("Run Migration job\n"
981                      "JobName:       %s\n"
982                      "Bootstrap:     %s\n"
983                      "Client:        %s\n"
984                      "FileSet:       %s\n"
985                      "Pool:          %s (From %s)\n"
986                      "Read Storage:  %s (From %s)\n"
987                      "Write Storage: %s (From %s)\n"
988                      "JobId:         %s\n"
989                      "When:          %s\n"
990                      "Catalog:       %s\n"
991                      "Priority:      %d\n"),
992            job->name(),
993            NPRT(jcr->RestoreBootstrap),
994            jcr->client->name(),
995            jcr->fileset->name(),
996            NPRT(jcr->pool->name()), jcr->pool_source,
997            jcr->rstore->name(), jcr->rstore_source,
998            jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
999            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1000            bstrutime(dt, sizeof(dt), jcr->sched_time),
1001            jcr->catalog->name(),
1002            jcr->JobPriority);
1003       break;
1004    default:
1005       bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
1006       return false;
1007    }
1008    return true;
1009 }