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