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