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