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