]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_run.c
05113cc2b9e032107629467015017ee7451c915d
[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 /*
11    Copyright (C) 2001-2003 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32
33 /* Imported subroutines */
34
35 /* Imported variables */
36 extern struct s_jl joblevels[];
37 extern struct s_kw ReplaceOptions[];
38
39 /*
40  * For Backup and Verify Jobs
41  *     run [job=]<job-name> level=<level-name>
42  *
43  * For Restore Jobs
44  *     run <job-name> jobid=nn
45  *
46  */
47 int run_cmd(UAContext *ua, char *cmd)
48 {
49    JCR *jcr;
50    char *job_name, *level_name, *jid, *store_name, *pool_name;
51    char *where, *fileset_name, *client_name, *bootstrap, *replace;
52    char *when, *verify_job_name;
53    int Priority = 0;
54    int i, j, opt;
55    bool found;
56    JOB *job = NULL;
57    JOB *verify_job = NULL;
58    STORE *store = NULL;
59    CLIENT *client = NULL;
60    FILESET *fileset = NULL;
61    POOL *pool = NULL;
62    static char *kw[] = {              /* command line arguments */
63       N_("job"),                      /*  Used in a switch() */
64       N_("jobid"),                    /* 1 */
65       N_("client"),                   /* 2 */
66       N_("fd"), 
67       N_("fileset"),                  /* 4 */
68       N_("level"),                    /* 5 */
69       N_("storage"),                  /* 6 */
70       N_("sd"),                       /* 7 */
71       N_("pool"),                     /* 8 */
72       N_("where"),                    /* 9 */
73       N_("bootstrap"),                /* 10 */
74       N_("replace"),                  /* 11 */
75       N_("when"),                     /* 12 */
76       N_("priority"),                 /* 13 */
77       N_("yes"),          /* 14 -- if you change this change YES_POS too */
78       N_("verifyjob"),                /* 16 */
79       NULL};
80
81 #define YES_POS 14
82
83    if (!open_db(ua)) {
84       return 1;
85    }
86
87    job_name = NULL;
88    level_name = NULL;
89    jid = NULL;
90    store_name = NULL;
91    pool_name = NULL;
92    where = NULL;
93    when = NULL;
94    client_name = NULL;
95    fileset_name = NULL;
96    bootstrap = NULL;
97    replace = NULL;
98    verify_job_name = NULL;
99
100    for (i=1; i<ua->argc; i++) {
101       found = false;
102       Dmsg2(200, "Doing arg %d = %s\n", i, ua->argk[i]);
103       for (j=0; !found && kw[j]; j++) {
104          if (strcasecmp(ua->argk[i], _(kw[j])) == 0) {
105             /* Note, yes and run have no value, so do not err */
106             if (!ua->argv[i] && j != YES_POS /*yes*/) {  
107                bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]);
108                return 1;
109             }
110             Dmsg1(200, "Got keyword=%s\n", kw[j]);
111             switch (j) {
112             case 0: /* job */
113                if (job_name) {
114                   bsendmsg(ua, _("Job name specified twice.\n"));
115                   return 1;
116                }
117                job_name = ua->argv[i];
118                found = true;
119                break;
120             case 1: /* JobId */
121                if (jid) {
122                   bsendmsg(ua, _("JobId specified twice.\n"));
123                   return 1;
124                }
125                jid = ua->argv[i];
126                found = true;
127                break;
128             case 2: /* client */
129             case 3: /* fd */
130                if (client_name) {
131                   bsendmsg(ua, _("Client specified twice.\n"));
132                   return 1;
133                }
134                client_name = ua->argv[i];
135                found = true;
136                break;
137             case 4: /* fileset */
138                if (fileset_name) {
139                   bsendmsg(ua, _("FileSet specified twice.\n"));
140                   return 1;
141                }
142                fileset_name = ua->argv[i];
143                found = true;
144                break;
145             case 5: /* level */
146                if (level_name) {
147                   bsendmsg(ua, _("Level specified twice.\n"));
148                   return 1;
149                }
150                level_name = ua->argv[i];
151                found = true;
152                break;
153             case 6: /* storage */
154             case 7: /* sd */
155                if (store_name) {
156                   bsendmsg(ua, _("Storage specified twice.\n"));
157                   return 1;
158                }
159                store_name = ua->argv[i];
160                found = true;
161                break;
162             case 8: /* pool */
163                if (pool_name) {
164                   bsendmsg(ua, _("Pool specified twice.\n"));
165                   return 1;
166                }
167                pool_name = ua->argv[i];
168                found = true;
169                break;
170             case 9: /* where */
171                if (where) {
172                   bsendmsg(ua, _("Where specified twice.\n"));
173                   return 1;
174                }
175                where = ua->argv[i];
176                found = true;
177                break;
178             case 10: /* bootstrap */
179                if (bootstrap) {
180                   bsendmsg(ua, _("Bootstrap specified twice.\n"));
181                   return 1;
182                }
183                bootstrap = ua->argv[i];
184                found = true;
185                break;
186             case 11: /* replace */
187                if (replace) {
188                   bsendmsg(ua, _("Replace specified twice.\n"));
189                   return 1;
190                }
191                replace = ua->argv[i];
192                found = true;
193                break;
194             case 12: /* When */
195                if (when) {
196                   bsendmsg(ua, _("When specified twice.\n"));
197                   return 1;
198                }
199                when = ua->argv[i];
200                found = true;
201                break;
202             case 13:  /* Priority */
203                if (Priority) {
204                   bsendmsg(ua, _("Priority specified twice.\n"));
205                   return 1;
206                }
207                Priority = atoi(ua->argv[i]);
208                if (Priority <= 0) {
209                   bsendmsg(ua, _("Priority must be positive nonzero setting it to 10.\n"));
210                   Priority = 10;
211                }
212                break;
213             case 14: /* yes */
214                found = true;
215                break;
216             case 15: /* Verify Job */
217                if (verify_job_name) {
218                   bsendmsg(ua, _("Verify Job specified twice.\n"));
219                   return 1;
220                }
221                verify_job_name = ua->argv[i];
222                found = true;
223                break;
224
225             default:
226                break;
227             }
228          } /* end strcase compare */
229       } /* end keyword loop */
230       if (!found) {
231          Dmsg1(200, "%s not found\n", ua->argk[i]);
232          /*
233           * Special case for Job Name, it can be the first
234           * keyword that has no value.
235           */
236          if (!job_name && !ua->argv[i]) {
237             job_name = ua->argk[i];   /* use keyword as job name */
238             Dmsg1(200, "Set jobname=%s\n", job_name);
239          } else {
240             bsendmsg(ua, _("Invalid keyword: %s\n"), ua->argk[i]);
241             return 1;
242          }
243       }
244    } /* end argc loop */
245              
246    Dmsg0(200, "Done scan.\n");
247
248    if (job_name) {
249       /* Find Job */
250       job = (JOB *)GetResWithName(R_JOB, job_name);
251       if (!job) {
252          bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
253          job = select_job_resource(ua);
254       } else {
255          Dmsg1(200, "Found job=%s\n", job_name);
256       }
257    } else {
258       bsendmsg(ua, _("A job name must be specified.\n"));
259       job = select_job_resource(ua);
260    }
261    if (!job) {
262       return 1;
263    }
264
265    if (store_name) {
266       store = (STORE *)GetResWithName(R_STORAGE, store_name);
267       if (!store) {
268          bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
269          store = select_storage_resource(ua);
270       }
271    } else {
272       store = job->storage;           /* use default */
273    }
274    if (!store) {
275       return 1;
276    }
277
278
279    if (pool_name) {
280       pool = (POOL *)GetResWithName(R_POOL, pool_name);
281       if (!pool) {
282          bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
283          pool = get_pool_resource(ua);
284       }
285    } else {
286       pool = job->pool;             /* use default */
287    }
288
289    if (client_name) {
290       client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
291       if (!client) {
292          bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
293          client = select_client_resource(ua);
294       }
295    } else {
296       client = job->client;           /* use default */
297    }
298    if (!client) {
299       return 1;
300    }
301
302    if (fileset_name) {
303       fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
304       if (!fileset) {
305          bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
306          fileset = select_fileset_resource(ua);
307       }
308    } else {
309       fileset = job->fileset;           /* use default */
310    }
311    if (!fileset) {
312       return 1;
313    }
314
315    if (verify_job_name) {
316       verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
317       if (!verify_job) {
318          bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
319          verify_job = select_job_resource(ua);
320       }
321    } else {
322       verify_job = job->verify_job;
323    }
324
325    /*
326     * Create JCR to run job.  NOTE!!! after this point, free_jcr()
327     *  before returning.
328     */
329    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
330    set_jcr_defaults(jcr, job);
331
332    jcr->store = store;
333    jcr->client = client;
334    jcr->fileset = fileset;
335    jcr->pool = pool;
336    if (where) {
337       if (jcr->where) {
338          free(jcr->where);
339       }
340       jcr->where = bstrdup(where);
341    }
342
343    if (when) {
344       jcr->sched_time = str_to_utime(when);
345       if (jcr->sched_time == 0) {
346          bsendmsg(ua, _("Invalid time, using current time.\n"));
347          jcr->sched_time = time(NULL);
348       }
349    }
350          
351    if (bootstrap) {
352       if (jcr->RestoreBootstrap) {
353          free(jcr->RestoreBootstrap);
354       }
355       jcr->RestoreBootstrap = bstrdup(bootstrap);
356    }
357
358    if (replace) {
359       jcr->replace = 0;
360       for (i=0; ReplaceOptions[i].name; i++) {
361          if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
362             jcr->replace = ReplaceOptions[i].token;
363          }
364       }
365       if (!jcr->replace) {
366          bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
367          goto bail_out;
368       }
369    } else if (job->replace) {
370       jcr->replace = job->replace;
371    } else {
372       jcr->replace = REPLACE_ALWAYS;
373    }
374
375    if (Priority) {
376       jcr->JobPriority = Priority;
377    }
378
379 try_again:
380    replace = ReplaceOptions[0].name;
381    for (i=0; ReplaceOptions[i].name; i++) {
382       if (ReplaceOptions[i].token == jcr->replace) {
383          replace = ReplaceOptions[i].name;
384       }
385    }
386    if (level_name) {
387       /* Look up level name and pull code */
388       found = 0;
389       for (i=0; joblevels[i].level_name; i++) {
390          if (strcasecmp(level_name, _(joblevels[i].level_name)) == 0) {
391             jcr->JobLevel = joblevels[i].level;
392             found = 1;
393             break;
394          }
395       }
396       if (!found) { 
397          bsendmsg(ua, _("Level %s not valid.\n"), level_name);
398          goto bail_out;
399       }
400    }
401    level_name = NULL;
402    if (jid) {
403       jcr->RestoreJobId = atoi(jid);
404    }
405
406    /* Run without prompting? */
407    if (find_arg(ua, _("yes")) > 0) {
408       Dmsg1(200, "Calling run_job job=%x\n", jcr->job);
409       run_job(jcr);
410       free_jcr(jcr);                  /* release jcr */
411       bsendmsg(ua, _("Run command submitted.\n"));
412       return 1;
413    }
414
415    /*  
416     * Prompt User to see if all run job parameters are correct, and
417     *   allow him to modify them.
418     */
419    Dmsg1(20, "JobType=%c\n", jcr->JobType);
420    switch (jcr->JobType) {
421       char ec1[30];
422       char dt[MAX_TIME_LENGTH];
423    case JT_ADMIN:
424          bsendmsg(ua, _("Run %s job\n\
425 JobName:  %s\n\
426 FileSet:  %s\n\
427 Client:   %s\n\
428 Storage:  %s\n\
429 When:     %s\n\
430 Priority: %d\n"),
431                  _("Admin"),
432                  job->hdr.name,
433                  jcr->fileset->hdr.name,
434                  NPRT(jcr->client->hdr.name),
435                  NPRT(jcr->store->hdr.name), 
436                  bstrutime(dt, sizeof(dt), jcr->sched_time), 
437                  jcr->JobPriority);
438       jcr->JobLevel = L_FULL;
439       break;
440    case JT_BACKUP:
441    case JT_VERIFY:
442       if (jcr->JobType == JT_BACKUP) {
443          bsendmsg(ua, _("Run %s job\n\
444 JobName:  %s\n\
445 FileSet:  %s\n\
446 Level:    %s\n\
447 Client:   %s\n\
448 Storage:  %s\n\
449 Pool:     %s\n\
450 When:     %s\n\
451 Priority: %d\n"),
452                  _("Backup"),
453                  job->hdr.name,
454                  jcr->fileset->hdr.name,
455                  level_to_str(jcr->JobLevel),
456                  jcr->client->hdr.name,
457                  jcr->store->hdr.name,
458                  NPRT(jcr->pool->hdr.name), 
459                  bstrutime(dt, sizeof(dt), jcr->sched_time),
460                  jcr->JobPriority);
461       } else {  /* JT_VERIFY */
462          char *Name;
463          if (jcr->job->verify_job) {
464             Name = jcr->job->verify_job->hdr.name;
465          } else {
466             Name = "";
467          }
468          bsendmsg(ua, _("Run %s job\n\
469 JobName:     %s\n\
470 FileSet:     %s\n\
471 Level:       %s\n\
472 Client:      %s\n\
473 Storage:     %s\n\
474 Pool:        %s\n\
475 Verify Job:  %s\n\
476 When:        %s\n\
477 Priority:    %d\n"),
478               _("Verify"),
479               job->hdr.name,
480               jcr->fileset->hdr.name,
481               level_to_str(jcr->JobLevel),
482               jcr->client->hdr.name,
483               jcr->store->hdr.name,
484               NPRT(jcr->pool->hdr.name), 
485               Name,            
486               bstrutime(dt, sizeof(dt), jcr->sched_time),
487               jcr->JobPriority);
488       }
489       break;
490    case JT_RESTORE:
491       if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
492          if (jid) {
493             jcr->RestoreJobId = atoi(jid);
494          } else {
495             if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
496                goto bail_out;
497             }  
498             jcr->RestoreJobId = ua->pint32_val;
499          }
500       }
501       jcr->JobLevel = L_FULL;      /* default level */
502       Dmsg1(20, "JobId to restore=%d\n", jcr->RestoreJobId);
503       if (jcr->RestoreJobId == 0) {
504          bsendmsg(ua, _("Run Restore job\n\
505 JobName:    %s\n\
506 Bootstrap:  %s\n\
507 Where:      %s\n\
508 Replace:    %s\n\
509 FileSet:    %s\n\
510 Client:     %s\n\
511 Storage:    %s\n\
512 When:       %s\n\
513 Priority:   %d\n"),
514               job->hdr.name,
515               NPRT(jcr->RestoreBootstrap),
516               jcr->where?jcr->where:NPRT(job->RestoreWhere),
517               replace,
518               jcr->fileset->hdr.name,
519               jcr->client->hdr.name,
520               jcr->store->hdr.name, 
521               bstrutime(dt, sizeof(dt), jcr->sched_time),
522               jcr->JobPriority);
523       } else {
524          bsendmsg(ua, _("Run Restore job\n\
525 JobName:    %s\n\
526 Bootstrap:  %s\n\
527 Where:      %s\n\
528 Replace:    %s\n\
529 FileSet:    %s\n\
530 Client:     %s\n\
531 Storage:    %s\n\
532 JobId:      %s\n\
533 When:       %s\n\
534 Priority:   %d\n"),
535               job->hdr.name,
536               NPRT(jcr->RestoreBootstrap),
537               jcr->where?jcr->where:NPRT(job->RestoreWhere),
538               replace,
539               jcr->fileset->hdr.name,
540               jcr->client->hdr.name,
541               jcr->store->hdr.name, 
542               jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1), 
543               bstrutime(dt, sizeof(dt), jcr->sched_time),
544               jcr->JobPriority);
545       }
546       break;
547    default:
548       bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
549       goto bail_out;
550    }
551
552
553    if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
554       goto bail_out;
555    }
556    /*
557     * At user request modify parameters of job to be run.
558     */
559    if (ua->cmd[0] == 0) {
560       goto bail_out;
561    }
562    if (strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
563       FILE *fd;
564
565       start_prompt(ua, _("Parameters to modify:\n"));
566       add_prompt(ua, _("Level"));            /* 0 */
567       add_prompt(ua, _("Storage"));          /* 1 */
568       add_prompt(ua, _("Job"));              /* 2 */
569       add_prompt(ua, _("FileSet"));          /* 3 */
570       add_prompt(ua, _("Client"));           /* 4 */
571       add_prompt(ua, _("When"));             /* 5 */
572       add_prompt(ua, _("Priority"));         /* 6 */
573       if (jcr->JobType == JT_BACKUP ||
574           jcr->JobType == JT_VERIFY) {
575          add_prompt(ua, _("Pool"));          /* 7 */
576          if (jcr->JobType == JT_VERIFY) {
577             add_prompt(ua, _("Verify Job"));  /* 8 */
578          }
579       } else if (jcr->JobType == JT_RESTORE) {
580          add_prompt(ua, _("Bootstrap"));     /* 7 */
581          add_prompt(ua, _("Where"));         /* 8 */
582          add_prompt(ua, _("Replace"));       /* 9 */
583          add_prompt(ua, _("JobId"));         /* 10 */
584       }
585       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
586       case 0:
587          /* Level */
588          if (jcr->JobType == JT_BACKUP) {
589             start_prompt(ua, _("Levels:\n"));
590             add_prompt(ua, _("Base"));
591             add_prompt(ua, _("Full"));
592             add_prompt(ua, _("Incremental"));
593             add_prompt(ua, _("Differential"));
594             add_prompt(ua, _("Since"));
595             switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
596             case 0:
597                jcr->JobLevel = L_BASE;
598                break;
599             case 1:
600                jcr->JobLevel = L_FULL;
601                break;
602             case 2:
603                jcr->JobLevel = L_INCREMENTAL;
604                break;
605             case 3:
606                jcr->JobLevel = L_DIFFERENTIAL;
607                break;
608             case 4:
609                jcr->JobLevel = L_SINCE;
610                break;
611             default:
612                break;
613             }
614             goto try_again;
615          } else if (jcr->JobType == JT_VERIFY) {
616             start_prompt(ua, _("Levels:\n"));
617             add_prompt(ua, _("Initialize Catalog"));
618             add_prompt(ua, _("Verify Catalog"));
619             add_prompt(ua, _("Verify Volume to Catalog"));
620             add_prompt(ua, _("Verify Disk to Catalog"));
621             add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
622             switch (do_prompt(ua, "",  _("Select level"), NULL, 0)) {
623             case 0:
624                jcr->JobLevel = L_VERIFY_INIT;
625                break;
626             case 1:
627                jcr->JobLevel = L_VERIFY_CATALOG;
628                break;
629             case 2:
630                jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
631                break;
632             case 3:
633                jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
634                break;
635             case 4:
636                jcr->JobLevel = L_VERIFY_DATA;
637                break;
638             default:
639                break;
640             }
641             goto try_again;
642          } else {
643             bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
644          }
645          goto try_again;
646       case 1:
647          /* Storage */
648          store = select_storage_resource(ua);
649          if (store) {
650             jcr->store = store;
651             goto try_again;
652          }
653          break;
654       case 2:
655          /* Job */
656          job = select_job_resource(ua);
657          if (job) {
658             jcr->job = job;
659             set_jcr_defaults(jcr, job);
660             goto try_again;
661          }
662          break;
663       case 3:
664          /* FileSet */
665          fileset = select_fileset_resource(ua);
666          if (fileset) {
667             jcr->fileset = fileset;
668             goto try_again;
669          }      
670          break;
671       case 4:
672          /* Client */
673          client = select_client_resource(ua);
674          if (client) {
675             jcr->client = client;
676             goto try_again;
677          }
678          break;
679       case 5:
680          /* When */
681          if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
682             break;
683          }
684          if (ua->cmd[0] == 0) {
685             jcr->sched_time = time(NULL);
686          } else {
687             jcr->sched_time = str_to_utime(ua->cmd);
688             if (jcr->sched_time == 0) {
689                bsendmsg(ua, _("Invalid time, using current time.\n"));
690                jcr->sched_time = time(NULL);
691             }
692          }
693          goto try_again;
694       case 6:
695          /* Priority */
696          if (!get_pint(ua, _("Enter new Priority: "))) {
697             break;
698          }
699          if (ua->pint32_val == 0) {
700             bsendmsg(ua, _("Priority must be a positive integer.\n"));
701          } else {
702             jcr->JobPriority = ua->pint32_val;
703          }
704          goto try_again;
705       case 7:
706          /* Pool or Bootstrap depending on JobType */
707          if (jcr->JobType == JT_BACKUP ||
708              jcr->JobType == JT_VERIFY) {      /* Pool */
709             pool = select_pool_resource(ua);
710             if (pool) {
711                jcr->pool = pool;
712                goto try_again;
713             }
714             break;
715          }
716
717          /* Bootstrap */
718          if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
719             break;
720          }
721          if (jcr->RestoreBootstrap) {
722             free(jcr->RestoreBootstrap);
723             jcr->RestoreBootstrap = NULL;
724          }
725          if (ua->cmd[0] != 0) {
726             jcr->RestoreBootstrap = bstrdup(ua->cmd);
727             fd = fopen(jcr->RestoreBootstrap, "r");
728             if (!fd) {
729                bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
730                   jcr->RestoreBootstrap, strerror(errno));
731                free(jcr->RestoreBootstrap);
732                jcr->RestoreBootstrap = NULL;
733             } else {
734                fclose(fd);
735             }
736          }
737          goto try_again;
738       case 8:
739          /* Verify Job */
740          if (jcr->JobType == JT_VERIFY) {
741             JOB *job = select_job_resource(ua);
742             if (job) {
743                jcr->job->verify_job = job;
744             } else {
745                jcr->job->verify_job = NULL;
746             }
747             goto try_again;
748          }
749          /* Where */
750          if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
751             break;
752          }
753          if (jcr->where) {
754             free(jcr->where);
755             jcr->where = NULL;
756          }
757          if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
758             ua->cmd[0] = 0;
759          }
760          jcr->where = bstrdup(ua->cmd);
761          goto try_again;
762       case 9:
763          /* Replace */
764          start_prompt(ua, _("Replace:\n"));
765          for (i=0; ReplaceOptions[i].name; i++) {
766             add_prompt(ua, ReplaceOptions[i].name);
767          }
768          opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
769          if (opt >=  0) {
770             jcr->replace = ReplaceOptions[opt].token;
771          }
772          goto try_again;
773       case 10:
774          /* JobId */
775          jid = NULL;                  /* force reprompt */
776          jcr->RestoreJobId = 0;
777          if (jcr->RestoreBootstrap) {
778             bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
779          }
780          goto try_again;
781       default: 
782          goto try_again;
783       }
784       goto bail_out;
785    }
786
787    if (strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
788       Dmsg1(200, "Calling run_job job=%x\n", jcr->job);
789       run_job(jcr);
790       free_jcr(jcr);                  /* release jcr */
791       bsendmsg(ua, _("Run command submitted.\n"));
792       return 1;
793    }
794
795 bail_out:
796    bsendmsg(ua, _("Job not run.\n"));
797    free_jcr(jcr);
798    return 0;                       /* do not run */
799 }