]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
kes Extend new GUI API.
[bacula/bacula] / bacula / src / dird / ua_run.c
1 /*
2  *
3  *   Bacula Director -- Run Command
4  *
5  *     Kern Sibbald, December MMI
6  *
7  *   Version $Id$
8  */
9 /*
10    Bacula® - The Network Backup Solution
11
12    Copyright (C) 2001-2007 Free Software Foundation Europe e.V.
13
14    The main author of Bacula is Kern Sibbald, with contributions from
15    many others, a complete list can be found in the file AUTHORS.
16    This program is Free Software; you can redistribute it and/or
17    modify it under the terms of version two of the GNU General Public
18    License as published by the Free Software Foundation plus additions
19    that are listed in the file LICENSE.
20
21    This program is distributed in the hope that it will be useful, but
22    WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24    General Public License for more details.
25
26    You should have received a copy of the GNU General Public License
27    along with this program; if not, write to the Free Software
28    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29    02110-1301, USA.
30
31    Bacula® is a registered trademark of John Walker.
32    The licensor of Bacula is the Free Software Foundation Europe
33    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34    Switzerland, email:ftf@fsfeurope.org.
35 */
36
37 #include "bacula.h"
38 #include "dird.h"
39
40 /* Forward referenced subroutines */
41 static void select_job_level(UAContext *ua, JCR *jcr);
42 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *verify_list, 
43    char *jid, const char *replace);
44
45
46 /* Imported variables */
47 extern struct s_kw ReplaceOptions[];
48
49 /*
50  * For Backup and Verify Jobs
51  *     run [job=]<job-name> level=<level-name>
52  *
53  * For Restore Jobs
54  *     run <job-name> 
55  *
56  *  Returns: 0 on error
57  *           JobId if OK
58  *
59  */
60 int run_cmd(UAContext *ua, const char *cmd)
61 {
62    JCR *jcr;
63    char *job_name, *level_name, *jid, *store_name, *pool_name;
64    char *where, *fileset_name, *client_name, *bootstrap;
65    const char *replace;
66    char *when, *verify_job_name, *catalog_name;
67    char *previous_job_name;
68    char *since = NULL;
69    char *verify_list;
70    bool cloned = false;
71    int Priority = 0;
72    int i, j, opt, files = 0;
73    bool kw_ok;
74    JOB *job = NULL;
75    JOB *verify_job = NULL;
76    JOB *previous_job = NULL;
77    USTORE store;
78    CLIENT *client = NULL;
79    FILESET *fileset = NULL;
80    POOL *pool = NULL;
81    static const char *kw[] = {        /* command line arguments */
82       "job",                          /*  Used in a switch() */
83       "jobid",                        /* 1 */
84       "client",                       /* 2 */
85       "fd",
86       "fileset",                      /* 4 */
87       "level",                        /* 5 */
88       "storage",                      /* 6 */
89       "sd",                           /* 7 */
90       "pool",                         /* 8 */
91       "where",                        /* 9 */
92       "bootstrap",                    /* 10 */
93       "replace",                      /* 11 */
94       "when",                         /* 12 */
95       "priority",                     /* 13 */
96       "yes",          /* 14  -- if you change this change YES_POS too */
97       "verifyjob",                    /* 15 */
98       "files",                        /* 16 number of files to restore */
99       "catalog",                      /* 17 override catalog */
100       "since",                        /* 18 since */
101       "cloned",                       /* 19 cloned */
102       "verifylist",                   /* 20 verify output list */
103       "migrationjob",                 /* 21 migration job name */
104       NULL};
105
106 #define YES_POS 14
107
108    if (!open_client_db(ua)) {
109       return 1;
110    }
111
112    job_name = NULL;
113    level_name = NULL;
114    jid = NULL;
115    store_name = NULL;
116    pool_name = NULL;
117    where = NULL;
118    when = NULL;
119    client_name = NULL;
120    fileset_name = NULL;
121    bootstrap = NULL;
122    replace = NULL;
123    verify_job_name = NULL;
124    previous_job_name = NULL;
125    catalog_name = NULL;
126    verify_list = NULL;
127
128    for (i=1; i<ua->argc; i++) {
129       Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
130       kw_ok = false;
131       /* Keep looking until we find a good keyword */
132       for (j=0; !kw_ok && kw[j]; j++) {
133          if (strcasecmp(ua->argk[i], kw[j]) == 0) {
134             /* Note, yes and run have no value, so do not fail */
135             if (!ua->argv[i] && j != YES_POS /*yes*/) {
136                ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("Where specified twice.\n"));
202                   return 0;
203                }
204                where = ua->argv[i];
205                if (!acl_access_ok(ua, Where_ACL, where)) {
206                   ua->send_msg(_("Forbidden \"where\" specified.\n"));
207                   return 0;
208                }
209                kw_ok = true;
210                break;
211             case 10: /* bootstrap */
212                if (bootstrap) {
213                   ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("Priority specified twice.\n"));
238                   return 0;
239                }
240                Priority = atoi(ua->argv[i]);
241                if (Priority <= 0) {
242                   ua->send_msg(_("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                   ua->send_msg(_("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                   ua->send_msg(_("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             ua->send_msg(_("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             ua->error_msg(_("Catalog \"%s\" not found\n"), catalog_name);
323            return 0;
324        }
325        if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
326           ua->error_msg(_("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             ua->send_msg(_("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       ua->send_msg(_("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       ua->error_msg( _("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             ua->warning_msg(_("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       ua->error_msg(_("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             ua->warning_msg(_("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       ua->error_msg(_("No storage specified.\n"));
390       return 1;
391    } else if (!acl_access_ok(ua, Storage_ACL, store.store->name())) {
392       ua->error_msg(_("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             ua->warning_msg(_("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       ua->error_msg(_("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          ua->send_msg(_("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       ua->send_msg(_("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          ua->send_msg(_("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          ua->send_msg(_("Migration Job \"%s\" not found.\n"), previous_job_name);
449          previous_job = select_job_resource(ua);
450       }
451    } else {
452       previous_job = job->verify_job;
453    }
454
455
456    /*
457     * Create JCR to run job.  NOTE!!! after this point, free_jcr()
458     *  before returning.
459     */
460    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
461    set_jcr_defaults(jcr, job);
462    jcr->unlink_bsr = ua->jcr->unlink_bsr;    /* copy unlink flag from caller */
463    ua->jcr->unlink_bsr = false;
464
465    jcr->verify_job = verify_job;
466    jcr->previous_job = previous_job;
467    jcr->pool = pool;
468    set_rwstorage(jcr, &store);
469    jcr->client = client;
470    pm_strcpy(jcr->client_name, client->name());
471    jcr->fileset = fileset;
472    jcr->ExpectedFiles = files;
473    if (catalog != NULL) {
474       jcr->catalog = catalog;
475    }
476    if (where) {
477       if (jcr->where) {
478          free(jcr->where);
479       }
480       jcr->where = bstrdup(where);
481    }
482
483    if (when) {
484       jcr->sched_time = str_to_utime(when);
485       if (jcr->sched_time == 0) {
486          ua->send_msg(_("Invalid time, using current time.\n"));
487          jcr->sched_time = time(NULL);
488       }
489    }
490
491    if (bootstrap) {
492       if (jcr->RestoreBootstrap) {
493          free(jcr->RestoreBootstrap);
494       }
495       jcr->RestoreBootstrap = bstrdup(bootstrap);
496    }
497
498    if (replace) {
499       jcr->replace = 0;
500       for (i=0; ReplaceOptions[i].name; i++) {
501          if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
502             jcr->replace = ReplaceOptions[i].token;
503          }
504       }
505       if (!jcr->replace) {
506          ua->send_msg(_("Invalid replace option: %s\n"), replace);
507          goto bail_out;
508       }
509    } else if (job->replace) {
510       jcr->replace = job->replace;
511    } else {
512       jcr->replace = REPLACE_ALWAYS;
513    }
514
515    if (Priority) {
516       jcr->JobPriority = Priority;
517    }
518
519    if (since) {
520       if (!jcr->stime) {
521          jcr->stime = get_pool_memory(PM_MESSAGE);
522       }
523       pm_strcpy(jcr->stime, since);
524    }
525
526    jcr->cloned = cloned;
527
528    if (find_arg(ua, NT_("fdcalled")) > 0) {
529       jcr->file_bsock = dup_bsock(ua->UA_sock);
530       ua->quit = true;
531    }
532
533 try_again:
534    /* If pool changed, update migration write storage */
535    if (jcr->JobType == JT_MIGRATE) {
536       if (!set_migration_wstorage(jcr, pool)) {
537          goto bail_out;
538       }
539    }
540    replace = ReplaceOptions[0].name;
541    for (i=0; ReplaceOptions[i].name; i++) {
542       if (ReplaceOptions[i].token == jcr->replace) {
543          replace = ReplaceOptions[i].name;
544       }
545    }
546    if (level_name) {
547       if (!get_level_from_name(jcr, level_name)) {
548          ua->send_msg(_("Level %s not valid.\n"), level_name);
549          goto bail_out;
550       }
551    }
552    if (jid) {
553       /* Note, this is also MigrateJobId */
554       jcr->RestoreJobId = str_to_int64(jid);
555    }
556
557    /* Run without prompting? */
558    if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
559       goto start_job;
560    }
561
562    /*
563     * Prompt User to see if all run job parameters are correct, and
564     *   allow him to modify them.
565     */
566    if (!display_job_parameters(ua, jcr, job, verify_list, jid, replace)) {
567       goto bail_out;
568    }
569
570    if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
571       goto bail_out;
572    }
573
574    /*
575     * At user request modify parameters of job to be run.
576     */
577    if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
578       FILE *fd;
579
580       start_prompt(ua, _("Parameters to modify:\n"));
581       add_prompt(ua, _("Level"));            /* 0 */
582       add_prompt(ua, _("Storage"));          /* 1 */
583       add_prompt(ua, _("Job"));              /* 2 */
584       add_prompt(ua, _("FileSet"));          /* 3 */
585       add_prompt(ua, _("Client"));           /* 4 */
586       add_prompt(ua, _("When"));             /* 5 */
587       add_prompt(ua, _("Priority"));         /* 6 */
588       if (jcr->JobType == JT_BACKUP ||
589           jcr->JobType == JT_MIGRATE ||
590           jcr->JobType == JT_VERIFY) {
591          add_prompt(ua, _("Pool"));          /* 7 */
592          if (jcr->JobType == JT_VERIFY) {
593             add_prompt(ua, _("Verify Job"));  /* 8 */
594          }
595       } else if (jcr->JobType == JT_RESTORE) {
596          add_prompt(ua, _("Bootstrap"));     /* 7 */
597          add_prompt(ua, _("Where"));         /* 8 */
598          add_prompt(ua, _("Replace"));       /* 9 */
599          add_prompt(ua, _("JobId"));         /* 10 */
600       }
601       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
602       case 0:
603          /* Level */
604          select_job_level(ua, jcr);
605          goto try_again;
606       case 1:
607          /* Storage */
608          store.store = select_storage_resource(ua);
609          if (store.store) {
610             pm_strcpy(store.store_source, _("user selection"));
611             set_rwstorage(jcr, &store);
612             goto try_again;
613          }
614          break;
615       case 2:
616          /* Job */
617          job = select_job_resource(ua);
618          if (job) {
619             jcr->job = job;
620             set_jcr_defaults(jcr, job);
621             goto try_again;
622          }
623          break;
624       case 3:
625          /* FileSet */
626          fileset = select_fileset_resource(ua);
627          if (fileset) {
628             jcr->fileset = fileset;
629             goto try_again;
630          }
631          break;
632       case 4:
633          /* Client */
634          client = select_client_resource(ua);
635          if (client) {
636             jcr->client = client;
637             goto try_again;
638          }
639          break;
640       case 5:
641          /* When */
642          if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
643             break;
644          }
645          if (ua->cmd[0] == 0) {
646             jcr->sched_time = time(NULL);
647          } else {
648             jcr->sched_time = str_to_utime(ua->cmd);
649             if (jcr->sched_time == 0) {
650                ua->send_msg(_("Invalid time, using current time.\n"));
651                jcr->sched_time = time(NULL);
652             }
653          }
654          goto try_again;
655       case 6:
656          /* Priority */
657          if (!get_pint(ua, _("Enter new Priority: "))) {
658             break;
659          }
660          if (ua->pint32_val == 0) {
661             ua->send_msg(_("Priority must be a positive integer.\n"));
662          } else {
663             jcr->JobPriority = ua->pint32_val;
664          }
665          goto try_again;
666       case 7:
667          /* Pool or Bootstrap depending on JobType */
668          if (jcr->JobType == JT_BACKUP ||
669              jcr->JobType == JT_MIGRATE ||
670              jcr->JobType == JT_VERIFY) {      /* Pool */
671             pool = select_pool_resource(ua);
672             if (pool) {
673                jcr->pool = pool;
674                Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
675                goto try_again;
676             }
677             break;
678          }
679
680          /* Bootstrap */
681          if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
682             break;
683          }
684          if (jcr->RestoreBootstrap) {
685             free(jcr->RestoreBootstrap);
686             jcr->RestoreBootstrap = NULL;
687          }
688          if (ua->cmd[0] != 0) {
689             jcr->RestoreBootstrap = bstrdup(ua->cmd);
690             fd = fopen(jcr->RestoreBootstrap, "rb");
691             if (!fd) {
692                ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
693                   jcr->RestoreBootstrap, strerror(errno));
694                free(jcr->RestoreBootstrap);
695                jcr->RestoreBootstrap = NULL;
696             } else {
697                fclose(fd);
698             }
699          }
700          goto try_again;
701       case 8:
702          /* Verify Job */
703          if (jcr->JobType == JT_VERIFY) {
704             verify_job = select_job_resource(ua);
705             if (verify_job) {
706               jcr->verify_job = verify_job;
707             }
708             goto try_again;
709          }
710          /* Where */
711          if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
712             break;
713          }
714          if (jcr->where) {
715             free(jcr->where);
716             jcr->where = NULL;
717          }
718          if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
719             ua->cmd[0] = 0;
720          }
721          jcr->where = bstrdup(ua->cmd);
722          goto try_again;
723       case 9:
724          /* Replace */
725          start_prompt(ua, _("Replace:\n"));
726          for (i=0; ReplaceOptions[i].name; i++) {
727             add_prompt(ua, ReplaceOptions[i].name);
728          }
729          opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
730          if (opt >=  0) {
731             jcr->replace = ReplaceOptions[opt].token;
732          }
733          goto try_again;
734       case 10:
735          /* JobId */
736          jid = NULL;                  /* force reprompt */
737          jcr->RestoreJobId = 0;
738          if (jcr->RestoreBootstrap) {
739             ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
740          }
741          goto try_again;
742       case -1:                        /* error or cancel */
743          goto bail_out;
744       default:
745          goto try_again;
746       }
747       goto bail_out;
748    }
749
750    if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
751       JobId_t JobId;
752       Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
753 start_job:
754       Dmsg1(100, "Using pool %s\n", jcr->pool->name());
755       JobId = run_job(jcr);
756 #if 0  
757       ua->send_msg("<job director=\"console\" time=\"%u\" status=\"%c\" type=\"%c\" "
758               "jobid=\"%u\" job=\"%s\" level=\"%c\" finished=\"false\" priority=\"%u\"/>\n",
759                time(NULL), jcr->JobStatus, jcr->JobType, jcr->JobId,
760               jcr->Job, jcr->JobLevel, jcr->JobPriority);
761 #endif
762       free_jcr(jcr);                  /* release jcr */
763       if (JobId == 0) {
764          ua->error_msg(_("Job failed.\n"));
765       } else {
766          char ed1[50];
767          ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId,ed1));
768       }
769       return JobId;
770    }
771
772 bail_out:
773    ua->send_msg(_("Job not run.\n"));
774    free_jcr(jcr);
775    return 0;                       /* do not run */
776 }
777
778 static void select_job_level(UAContext *ua, JCR *jcr)
779 {
780    if (jcr->JobType == JT_BACKUP) {
781       start_prompt(ua, _("Levels:\n"));
782       add_prompt(ua, _("Base"));
783       add_prompt(ua, _("Full"));
784       add_prompt(ua, _("Incremental"));
785       add_prompt(ua, _("Differential"));
786       add_prompt(ua, _("Since"));
787       switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
788       case 0:
789          jcr->JobLevel = L_BASE;
790          break;
791       case 1:
792          jcr->JobLevel = L_FULL;
793          break;
794       case 2:
795          jcr->JobLevel = L_INCREMENTAL;
796          break;
797       case 3:
798          jcr->JobLevel = L_DIFFERENTIAL;
799          break;
800       case 4:
801          jcr->JobLevel = L_SINCE;
802          break;
803       default:
804          break;
805       }
806    } else if (jcr->JobType == JT_VERIFY) {
807       start_prompt(ua, _("Levels:\n"));
808       add_prompt(ua, _("Initialize Catalog"));
809       add_prompt(ua, _("Verify Catalog"));
810       add_prompt(ua, _("Verify Volume to Catalog"));
811       add_prompt(ua, _("Verify Disk to Catalog"));
812       add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
813       switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
814       case 0:
815          jcr->JobLevel = L_VERIFY_INIT;
816          break;
817       case 1:
818          jcr->JobLevel = L_VERIFY_CATALOG;
819          break;
820       case 2:
821          jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
822          break;
823       case 3:
824          jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
825          break;
826       case 4:
827          jcr->JobLevel = L_VERIFY_DATA;
828          break;
829       default:
830          break;
831       }
832    } else {
833       ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
834    }
835    return;
836 }
837
838 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *verify_list,
839    char *jid, const char *replace) 
840 {
841    Dmsg1(800, "JobType=%c\n", jcr->JobType);
842    switch (jcr->JobType) {
843       char ec1[30];
844       char dt[MAX_TIME_LENGTH];
845    case JT_ADMIN:
846       if (ua->api) ua->signal(BNET_RUN_CMD);   
847       ua->send_msg(_("Run %s job\n"
848                      "JobName:  %s\n"
849                      "FileSet:  %s\n"
850                      "Client:   %s\n"
851                      "Storage:  %s\n"
852                      "When:     %s\n"
853                      "Priority: %d\n"),
854                  _("Admin"),
855                  job->name(),
856                  jcr->fileset->name(),
857                  NPRT(jcr->client->name()),
858                  jcr->wstore?jcr->wstore->name():"*None*",
859                  bstrutime(dt, sizeof(dt), jcr->sched_time),
860                  jcr->JobPriority);
861       jcr->JobLevel = L_FULL;
862       break;
863    case JT_BACKUP:
864    case JT_VERIFY:
865       if (jcr->JobType == JT_BACKUP) {
866          if (ua->api) ua->signal(BNET_RUN_CMD);   
867          ua->send_msg(_("Run %s job\n"
868                         "JobName:  %s\n"
869                         "Level:    %s\n"
870                         "Client:   %s\n"
871                         "FileSet:  %s\n"
872                         "Pool:     %s (From %s)\n"
873                         "Storage:  %s (From %s)\n"
874                         "When:     %s\n"
875                         "Priority: %d\n"),
876                  _("Backup"),
877                  job->name(),
878                  level_to_str(jcr->JobLevel),
879                  jcr->client->name(),
880                  jcr->fileset->name(),
881                  NPRT(jcr->pool->name()), jcr->pool_source,
882                  jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
883                  bstrutime(dt, sizeof(dt), jcr->sched_time),
884                  jcr->JobPriority);
885       } else {  /* JT_VERIFY */
886          const char *Name;
887          if (jcr->verify_job) {
888             Name = jcr->verify_job->name();
889          } else {
890             Name = "";
891          }
892          if (!verify_list) {
893             verify_list = job->WriteVerifyList;
894          }
895          if (!verify_list) {
896             verify_list = "";
897          }
898          if (ua->api) ua->signal(BNET_RUN_CMD);   
899          ua->send_msg(_("Run %s job\n"
900                         "JobName:     %s\n"
901                         "Level:       %s\n"
902                         "Client:      %s\n"
903                         "FileSet:     %s\n"
904                         "Pool:        %s (From %s)\n"
905                         "Storage:     %s (From %s)\n"
906                         "Verify Job:  %s\n"
907                         "Verify List: %s\n"
908                         "When:        %s\n"
909                         "Priority:    %d\n"),
910               _("Verify"),
911               job->name(),
912               level_to_str(jcr->JobLevel),
913               jcr->client->name(),
914               jcr->fileset->name(),
915               NPRT(jcr->pool->name()), jcr->pool_source,
916               jcr->rstore->name(), jcr->rstore_source,
917               Name,
918               verify_list,
919               bstrutime(dt, sizeof(dt), jcr->sched_time),
920               jcr->JobPriority);
921       }
922       break;
923    case JT_RESTORE:
924       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
925          if (jid) {
926             jcr->RestoreJobId = str_to_int64(jid);
927          } else {
928             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
929                return false;
930             }
931             jcr->RestoreJobId = ua->int64_val;
932          }
933       }
934       jcr->JobLevel = L_FULL;      /* default level */
935       Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
936       if (jcr->RestoreJobId == 0) {
937          if (ua->api) ua->signal(BNET_RUN_CMD);   
938          ua->send_msg(_("Run Restore job\n"
939                         "JobName:    %s\n"
940                         "Bootstrap:  %s\n"
941                         "Where:      %s\n"
942                         "Replace:    %s\n"
943                         "FileSet:    %s\n"
944                         "Client:     %s\n"
945                         "Storage:    %s\n"
946                         "When:       %s\n"
947                         "Catalog:    %s\n"
948                         "Priority:   %d\n"),
949               job->name(),
950               NPRT(jcr->RestoreBootstrap),
951               jcr->where?jcr->where:NPRT(job->RestoreWhere),
952               replace,
953               jcr->fileset->name(),
954               jcr->client->name(),
955               jcr->rstore->name(),
956               bstrutime(dt, sizeof(dt), jcr->sched_time),
957               jcr->catalog->name(),
958               jcr->JobPriority);
959       } else {
960          if (ua->api) ua->signal(BNET_RUN_CMD);   
961          ua->send_msg(_("Run Restore job\n"
962                        "JobName:    %s\n"
963                        "Bootstrap:  %s\n"
964                        "Where:      %s\n"
965                        "Replace:    %s\n"
966                        "Client:     %s\n"
967                        "Storage:    %s\n"
968                        "JobId:      %s\n"
969                        "When:       %s\n"
970                        "Catalog:    %s\n"
971                        "Priority:   %d\n"),
972               job->name(),
973               NPRT(jcr->RestoreBootstrap),
974               jcr->where?jcr->where:NPRT(job->RestoreWhere),
975               replace,
976               jcr->client->name(),
977               jcr->rstore->name(),
978               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
979               bstrutime(dt, sizeof(dt), jcr->sched_time),
980               jcr->catalog->name(),
981               jcr->JobPriority);
982       }
983       break;
984    case JT_MIGRATE:
985       jcr->JobLevel = L_FULL;      /* default level */
986       if (ua->api) ua->signal(BNET_RUN_CMD);   
987       ua->send_msg(_("Run Migration job\n"
988                      "JobName:       %s\n"
989                      "Bootstrap:     %s\n"
990                      "Client:        %s\n"
991                      "FileSet:       %s\n"
992                      "Pool:          %s (From %s)\n"
993                      "Read Storage:  %s (From %s)\n"
994                      "Write Storage: %s (From %s)\n"
995                      "JobId:         %s\n"
996                      "When:          %s\n"
997                      "Catalog:       %s\n"
998                      "Priority:      %d\n"),
999            job->name(),
1000            NPRT(jcr->RestoreBootstrap),
1001            jcr->client->name(),
1002            jcr->fileset->name(),
1003            NPRT(jcr->pool->name()), jcr->pool_source,
1004            jcr->rstore->name(), jcr->rstore_source,
1005            jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1006            jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1007            bstrutime(dt, sizeof(dt), jcr->sched_time),
1008            jcr->catalog->name(),
1009            jcr->JobPriority);
1010       break;
1011    default:
1012       ua->error_msg(_("Unknown Job Type=%d\n"), jcr->JobType);
1013       return false;
1014    }
1015    return true;
1016 }