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