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