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