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