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