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