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