]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/dird.c
Restore JobIds in right order + Tru64 porting
[bacula/bacula] / bacula / src / dird / dird.c
1 /*
2  *
3  *   Bacula Director daemon -- this is the main program
4  *
5  *     Kern Sibbald, March MM
6  *
7  *   Version $Id$
8  */
9 /*
10    Copyright (C) 2000-2004 Kern Sibbald and John Walker
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "dird.h"
31
32 /* Forward referenced subroutines */
33 static void terminate_dird(int sig);
34 static int check_resources();
35
36 /* Exported subroutines */
37
38 extern "C" void reload_config(int sig);
39
40
41 /* Imported subroutines */
42 JCR *wait_for_next_job(char *runjob);
43 void term_scheduler();
44 void term_ua_server();
45 int do_backup(JCR *jcr);
46 void backup_cleanup(void);
47 void start_UA_server(char *addr, int port);
48 void init_job_server(int max_workers);
49 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
50 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
51 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
52
53 static char *configfile = NULL;
54 static char *runjob = NULL;
55 static int background = 1;
56 static void init_reload(void);
57
58 /* Globals Exported */
59 DIRRES *director;                     /* Director resource */
60 int FDConnectTimeout;
61 int SDConnectTimeout;
62
63 /* Globals Imported */
64 extern int r_first, r_last;           /* first and last resources */
65 extern RES_TABLE resources[];
66 extern RES **res_head;
67 extern RES_ITEM job_items[];
68 extern URES res_all;
69
70
71 #define CONFIG_FILE "./bacula-dir.conf" /* default configuration file */
72
73 static void usage()
74 {
75    fprintf(stderr, _(
76 "\nVersion: " VERSION " (" BDATE ")\n\n"
77 "Usage: dird [-f -s] [-c config_file] [-d debug_level] [config_file]\n"
78 "       -c <file>   set configuration file to file\n"
79 "       -dnn        set debug level to nn\n"
80 "       -f          run in foreground (for debugging)\n"
81 "       -g          groupid\n"
82 "       -r <job>    run <job> now\n"
83 "       -s          no signals\n"
84 "       -t          test - read configuration and exit\n"
85 "       -u          userid\n"
86 "       -v          verbose user messages\n"
87 "       -?          print this message.\n"  
88 "\n"));
89
90    exit(1);
91 }
92
93
94 /*********************************************************************
95  *
96  *         Main Bacula Server program
97  *
98  */
99 int main (int argc, char *argv[])
100 {
101    int ch;
102    JCR *jcr;
103    int no_signals = FALSE;
104    int test_config = FALSE;
105    char *uid = NULL;
106    char *gid = NULL;
107
108    init_stack_dump();
109    my_name_is(argc, argv, "bacula-dir");
110    textdomain("bacula");
111    init_msg(NULL, NULL);              /* initialize message handler */
112    init_reload();
113    daemon_start_time = time(NULL);
114
115    while ((ch = getopt(argc, argv, "c:d:fg:r:stu:v?")) != -1) {
116       switch (ch) {
117       case 'c':                    /* specify config file */
118          if (configfile != NULL) {
119             free(configfile);
120          }
121          configfile = bstrdup(optarg);
122          break;
123
124       case 'd':                    /* set debug level */
125          debug_level = atoi(optarg);
126          if (debug_level <= 0) {
127             debug_level = 1; 
128          }
129          Dmsg1(0, "Debug level = %d\n", debug_level);
130          break;
131
132       case 'f':                    /* run in foreground */
133          background = FALSE;
134          break;
135
136       case 'g':                    /* set group id */
137          gid = optarg;
138          break;
139
140       case 'r':                    /* run job */
141          if (runjob != NULL) {
142             free(runjob);
143          }
144          if (optarg) {
145             runjob = bstrdup(optarg);
146          }
147          break;
148
149       case 's':                    /* turn off signals */
150          no_signals = TRUE;
151          break;
152
153       case 't':                    /* test config */
154          test_config = TRUE;
155          break;
156
157       case 'u':                    /* set uid */
158          uid = optarg;
159          break;
160
161       case 'v':                    /* verbose */
162          verbose++;
163          break;
164
165       case '?':
166       default:
167          usage();
168
169       }  
170    }
171    argc -= optind;
172    argv += optind;
173
174    if (!no_signals) {
175       init_signals(terminate_dird);
176    }
177
178    if (argc) {
179       if (configfile != NULL) {
180          free(configfile);
181       }
182       configfile = bstrdup(*argv);
183       argc--; 
184       argv++;
185    }
186    if (argc) {
187       usage();
188    }
189
190    if (configfile == NULL) {
191       configfile = bstrdup(CONFIG_FILE);
192    }
193
194    parse_config(configfile);
195
196    if (!check_resources()) {
197       Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile);
198    }
199
200    if (test_config) {
201       terminate_dird(0);
202    }
203
204    my_name_is(0, NULL, director->hdr.name);    /* set user defined name */
205
206    FDConnectTimeout = (int)director->FDConnectTimeout;
207    SDConnectTimeout = (int)director->SDConnectTimeout;
208
209    if (background) {
210       daemon_start();
211       init_stack_dump();              /* grab new pid */
212    }
213
214    /* Create pid must come after we are a daemon -- so we have our final pid */
215    create_pid_file(director->pid_directory, "bacula-dir", director->DIRport);
216    read_state_file(director->working_directory, "bacula-dir", director->DIRport);
217
218    drop(uid, gid);                    /* reduce priveleges if requested */
219
220    signal(SIGHUP, reload_config);
221
222    init_console_msg(working_directory);
223
224    set_thread_concurrency(director->MaxConcurrentJobs * 2 +
225       4 /* UA */ + 4 /* sched+watchdog+jobsvr+misc */);
226
227    Dmsg0(200, "Start UA server\n");
228    start_UA_server(director->DIRaddr, director->DIRport);
229
230    start_watchdog();                  /* start network watchdog thread */
231
232    init_jcr_subsystem();              /* start JCR watchdogs etc. */
233
234    init_job_server(director->MaxConcurrentJobs);
235   
236    Dmsg0(200, "wait for next job\n");
237    /* Main loop -- call scheduler to get next job to run */
238    while ((jcr = wait_for_next_job(runjob))) {
239       run_job(jcr);                   /* run job */
240       free_jcr(jcr);                  /* release jcr */
241       if (runjob) {                   /* command line, run a single job? */
242          break;                       /* yes, terminate */
243       }
244    }
245
246    terminate_dird(0);
247 }
248
249 /* Cleanup and then exit */
250 static void terminate_dird(int sig)
251 {
252    static int already_here = FALSE;
253
254    if (already_here) {                /* avoid recursive temination problems */
255       exit(1);
256    }
257    already_here = TRUE;
258    write_state_file(director->working_directory, "bacula-dir", director->DIRport);
259    delete_pid_file(director->pid_directory, "bacula-dir", director->DIRport);
260 // signal(SIGCHLD, SIG_IGN);          /* don't worry about children now */
261    term_scheduler();
262    if (runjob) {
263       free(runjob);
264    }
265    if (configfile != NULL) {
266       free(configfile);
267    }
268    if (debug_level > 5) {
269       print_memory_pool_stats(); 
270    }
271    free_config_resources();
272    term_ua_server();
273    term_msg();                        /* terminate message handler */
274    stop_watchdog();
275    close_memory_pool();               /* release free memory in pool */
276    sm_dump(false);  
277    exit(sig);
278 }
279
280 struct RELOAD_TABLE {
281    int job_count;
282    RES **res_table;
283 };
284
285 static const int max_reloads = 10;
286 static RELOAD_TABLE reload_table[max_reloads];
287
288 static void init_reload(void) 
289 {
290    for (int i=0; i < max_reloads; i++) {
291       reload_table[i].job_count = 0;
292       reload_table[i].res_table = NULL;
293    }
294 }
295
296 static void free_saved_resources(int table)
297 {
298    int num = r_last - r_first + 1;
299    RES **res_tab = reload_table[table].res_table;
300    if (!res_tab) {
301       Dmsg1(100, "res_tab for table %d already released.\n", table);
302       return;
303    }
304    Dmsg1(100, "Freeing resources for table %d\n", table);
305    for (int j=0; j<num; j++) {
306       free_resource(res_tab[j], r_first + j);
307    }
308    free(res_tab);
309    reload_table[table].job_count = 0;
310    reload_table[table].res_table = NULL;
311 }
312
313 /*
314  * Called here at the end of every job that was
315  * hooked decrementing the active job_count. When
316  * it goes to zero, no one is using the associated
317  * resource table, so free it.
318  */
319 static void reload_job_end_cb(JCR *jcr, void *ctx)
320 {
321    int reload_id = (int)((long int)ctx);
322    Dmsg3(100, "reload job_end JobId=%d table=%d cnt=%d\n", jcr->JobId,
323       reload_id, reload_table[reload_id].job_count);
324    lock_jcr_chain();
325    LockRes();
326    if (--reload_table[reload_id].job_count <= 0) {
327       free_saved_resources(reload_id);
328    }
329    UnlockRes();
330    unlock_jcr_chain();
331 }
332
333 static int find_free_reload_table_entry()
334 {
335    int table = -1;
336    for (int i=0; i < max_reloads; i++) {
337       if (reload_table[i].res_table == NULL) {
338          table = i;
339          break;
340       }
341    }
342    return table;
343 }
344
345 /*
346  * If we get here, we have received a SIGHUP, which means to
347  *    reread our configuration file. 
348  *
349  * The algorithm used is as follows: we count how many jobs are
350  *   running and mark the running jobs to make a callback on 
351  *   exiting. The old config is saved with the reload table
352  *   id in a reload table. The new config file is read. Now, as
353  *   each job exits, it calls back to the reload_job_end_cb(), which
354  *   decrements the count of open jobs for the given reload table.
355  *   When the count goes to zero, we release those resources.
356  *   This allows us to have pointers into the resource table (from
357  *   jobs), and once they exit and all the pointers are released, we
358  *   release the old table. Note, if no new jobs are running since the
359  *   last reload, then the old resources will be immediately release.
360  *   A console is considered a job because it may have pointers to
361  *   resources, but a SYSTEM job is not since it *should* not have any
362  *   permanent pointers to jobs.
363  */
364 extern "C"
365 void reload_config(int sig)
366 {
367    static bool already_here = false;
368    sigset_t set;        
369    JCR *jcr;
370    int njobs = 0;                     /* number of running jobs */
371    int table, rtable;
372
373    if (already_here) {
374       abort();                        /* Oops, recursion -> die */
375    }
376    already_here = true;
377    sigemptyset(&set);
378    sigaddset(&set, SIGHUP);
379    sigprocmask(SIG_BLOCK, &set, NULL);
380
381 // Jmsg(NULL, M_INFO, 0, "Entering experimental reload config code. Bug reports will not be accepted.\n");
382
383    lock_jcr_chain();
384    LockRes();
385
386    table = find_free_reload_table_entry();
387    if (table < 0) {
388       Jmsg(NULL, M_ERROR, 0, _("Too many open reload requests. Request ignored.\n"));
389       goto bail_out;
390    }
391
392    Dmsg1(100, "Reload_config njobs=%d\n", njobs);
393    reload_table[table].res_table = save_config_resources();
394    Dmsg1(100, "Saved old config in table %d\n", table);
395
396    parse_config(configfile);
397
398    Dmsg0(100, "Reloaded config file\n");
399    if (!check_resources()) {
400       rtable = find_free_reload_table_entry();    /* save new, bad table */
401       if (rtable < 0) {
402          Jmsg(NULL, M_ERROR, 0, _("Please correct configuration file: %s\n"), configfile);
403          Jmsg(NULL, M_ERROR_TERM, 0, _("Out of reload table entries. Giving up.\n"));
404       } else {
405          Jmsg(NULL, M_ERROR, 0, _("Please correct configuration file: %s\n"), configfile);
406       }
407       reload_table[rtable].res_table = save_config_resources();
408       /* Now restore old resoure values */
409       int num = r_last - r_first + 1;
410       RES **res_tab = reload_table[table].res_table;
411       for (int i=0; i<num; i++) {
412          res_head[i] = res_tab[i];
413       }
414       table = rtable;                 /* release new, bad, saved table below */
415    } else {
416       /*
417        * Hook all active jobs so that they release this table 
418        */
419       foreach_jcr(jcr) {
420          if (jcr->JobType != JT_SYSTEM) {
421             reload_table[table].job_count++;
422             job_end_push(jcr, reload_job_end_cb, (void *)((long int)table));
423             njobs++;
424          }
425          free_locked_jcr(jcr);
426       }
427    }
428
429    /* Reset globals */
430    set_working_directory(director->working_directory);
431    FDConnectTimeout = director->FDConnectTimeout;
432    SDConnectTimeout = director->SDConnectTimeout;
433    Dmsg0(0, "Director's configuration file reread.\n");
434         
435    /* Now release saved resources, if no jobs using the resources */
436    if (njobs == 0) {
437       free_saved_resources(table);
438    }
439
440 bail_out:
441    UnlockRes();
442    unlock_jcr_chain();
443    sigprocmask(SIG_UNBLOCK, &set, NULL);
444    signal(SIGHUP, reload_config);
445    already_here = false;
446 }
447
448 /*
449  * Make a quick check to see that we have all the
450  * resources needed.
451  *
452  *  **** FIXME **** this routine could be a lot more
453  *   intelligent and comprehensive.
454  */
455 static int check_resources()
456 {
457    bool OK = true;
458    JOB *job;
459
460    LockRes();
461
462    job = (JOB *)GetNextRes(R_JOB, NULL);
463    director = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
464    if (!director) {
465       Jmsg(NULL, M_FATAL, 0, _("No Director resource defined in %s\n\
466 Without that I don't know who I am :-(\n"), configfile);
467       OK = false;
468    } else {
469       set_working_directory(director->working_directory);
470       if (!director->messages) {       /* If message resource not specified */
471          director->messages = (MSGS *)GetNextRes(R_MSGS, NULL);
472          if (!director->messages) {
473             Jmsg(NULL, M_FATAL, 0, _("No Messages resource defined in %s\n"), configfile);
474             OK = false;
475          }
476       }
477       if (GetNextRes(R_DIRECTOR, (RES *)director) != NULL) {
478          Jmsg(NULL, M_FATAL, 0, _("Only one Director resource permitted in %s\n"),
479             configfile);
480          OK = false;
481       } 
482    }
483
484    if (!job) {
485       Jmsg(NULL, M_FATAL, 0, _("No Job records defined in %s\n"), configfile);
486       OK = false;
487    }
488    foreach_res(job, R_JOB) {
489       int i;
490
491       if (job->jobdefs) {
492          /* Transfer default items from JobDefs Resource */
493          for (i=0; job_items[i].name; i++) {
494             char **def_svalue, **svalue;  /* string value */
495             int *def_ivalue, *ivalue;     /* integer value */
496             int64_t *def_lvalue, *lvalue; /* 64 bit values */
497             uint32_t offset;
498
499             Dmsg4(400, "Job \"%s\", field \"%s\" bit=%d def=%d\n",
500                 job->hdr.name, job_items[i].name, 
501                 bit_is_set(i, job->hdr.item_present),  
502                 bit_is_set(i, job->jobdefs->hdr.item_present));
503
504             if (!bit_is_set(i, job->hdr.item_present) &&
505                  bit_is_set(i, job->jobdefs->hdr.item_present)) { 
506                Dmsg2(400, "Job \"%s\", field \"%s\": getting default.\n",
507                  job->hdr.name, job_items[i].name);
508                offset = (char *)(job_items[i].value) - (char *)&res_all;   
509                /*
510                 * Handle strings and directory strings
511                 */
512                if (job_items[i].handler == store_str ||
513                    job_items[i].handler == store_dir) {
514                   def_svalue = (char **)((char *)(job->jobdefs) + offset);
515                   Dmsg5(400, "Job \"%s\", field \"%s\" def_svalue=%s item %d offset=%u\n", 
516                        job->hdr.name, job_items[i].name, *def_svalue, i, offset);
517                   svalue = (char **)((char *)job + offset);
518                   if (*svalue) {
519                      Pmsg1(000, "Hey something is wrong. p=0x%lu\n", *svalue);
520                   }
521                   *svalue = bstrdup(*def_svalue);
522                   set_bit(i, job->hdr.item_present);
523                } else if (job_items[i].handler == store_res) {
524                   def_svalue = (char **)((char *)(job->jobdefs) + offset);
525                   Dmsg4(400, "Job \"%s\", field \"%s\" item %d offset=%u\n", 
526                        job->hdr.name, job_items[i].name, i, offset);
527                   svalue = (char **)((char *)job + offset);
528                   if (*svalue) {
529                      Pmsg1(000, "Hey something is wrong. p=0x%lu\n", *svalue);
530                   }
531                   *svalue = *def_svalue;
532                   set_bit(i, job->hdr.item_present);
533                /*
534                 * Handle integer fields 
535                 *    Note, our store_yesno does not handle bitmaped fields
536                 */
537                } else if (job_items[i].handler == store_yesno   ||
538                           job_items[i].handler == store_pint    ||
539                           job_items[i].handler == store_jobtype ||
540                           job_items[i].handler == store_level   ||
541                           job_items[i].handler == store_pint    ||
542                           job_items[i].handler == store_replace) {
543                   def_ivalue = (int *)((char *)(job->jobdefs) + offset);
544                   Dmsg5(400, "Job \"%s\", field \"%s\" def_ivalue=%d item %d offset=%u\n", 
545                        job->hdr.name, job_items[i].name, *def_ivalue, i, offset);
546                   ivalue = (int *)((char *)job + offset);
547                   *ivalue = *def_ivalue;
548                   set_bit(i, job->hdr.item_present);
549                /*
550                 * Handle 64 bit integer fields 
551                 */
552                } else if (job_items[i].handler == store_time   ||
553                           job_items[i].handler == store_size   ||
554                           job_items[i].handler == store_int64) {
555                   def_lvalue = (int64_t *)((char *)(job->jobdefs) + offset);
556                   Dmsg5(400, "Job \"%s\", field \"%s\" def_lvalue=%" lld " item %d offset=%u\n", 
557                        job->hdr.name, job_items[i].name, *def_lvalue, i, offset);
558                   lvalue = (int64_t *)((char *)job + offset);
559                   *lvalue = *def_lvalue;
560                   set_bit(i, job->hdr.item_present);
561                }
562             }
563          }
564       }
565       /* 
566        * Ensure that all required items are present
567        */
568       for (i=0; job_items[i].name; i++) {
569          if (job_items[i].flags & ITEM_REQUIRED) {
570                if (!bit_is_set(i, job->hdr.item_present)) {  
571                   Jmsg(NULL, M_FATAL, 0, "Field \"%s\" in Job \"%s\" resource is required, but not found.\n",
572                     job_items[i].name, job->hdr.name);
573                   OK = false;
574                 }
575          }
576          /* If this triggers, take a look at lib/parse_conf.h */
577          if (i >= MAX_RES_ITEMS) {
578             Emsg0(M_ERROR_TERM, 0, "Too many items in Job resource\n");
579          }
580       }
581       if (job->client && job->client->catalog) {
582          CAT *catalog = job->client->catalog;
583          B_DB *db;
584
585          /*
586           * Make sure we can open catalog, otherwise print a warning
587           * message because the server is probably not running.
588           */
589          db = db_init_database(NULL, catalog->db_name, catalog->db_user,
590                             catalog->db_password, catalog->db_address,
591                             catalog->db_port, catalog->db_socket);
592          if (!db || !db_open_database(NULL, db)) {
593             Jmsg(NULL, M_FATAL, 0, _("Could not open database \"%s\".\n"),
594                  catalog->db_name);
595             if (db) {
596                Jmsg(NULL, M_FATAL, 0, _("%s"), db_strerror(db));
597             }
598             OK = false;
599          } else {
600             /* If a pool is defined for this job, create the pool DB       
601              *  record if it is not already created. 
602              */
603             if (job->pool) {
604                create_pool(NULL, db, job->pool, POOL_OP_UPDATE);  /* update request */
605             }
606             /* Set default value in all counters */
607             COUNTER *counter;
608             foreach_res(counter, R_COUNTER) {
609                /* Write to catalog? */
610                if (!counter->created && counter->Catalog == catalog) {
611                   COUNTER_DBR cr;
612                   bstrncpy(cr.Counter, counter->hdr.name, sizeof(cr.Counter));
613                   cr.MinValue = counter->MinValue;
614                   cr.MaxValue = counter->MaxValue;
615                   cr.CurrentValue = counter->MinValue;
616                   if (counter->WrapCounter) {
617                      bstrncpy(cr.WrapCounter, counter->WrapCounter->hdr.name, sizeof(cr.WrapCounter));
618                   } else {
619                      cr.WrapCounter[0] = 0;  /* empty string */
620                   }
621                   if (db_create_counter_record(NULL, db, &cr)) {
622                      counter->CurrentValue = cr.CurrentValue;
623                      counter->created = true;
624                      Dmsg2(100, "Create counter %s val=%d\n", counter->hdr.name, counter->CurrentValue);
625                   }
626                } 
627                if (!counter->created) {
628                   counter->CurrentValue = counter->MinValue;  /* default value */
629                }
630             }
631          }
632          db_close_database(NULL, db);
633       }
634    }
635
636    UnlockRes();
637    if (OK) {
638       close_msg(NULL);                /* close temp message handler */
639       init_msg(NULL, director->messages); /* open daemon message handler */
640    }
641    return OK;
642 }