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