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