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