]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/dird.c
Put resources on a pointer
[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(000, "res_tab for table %d already released.\n", table);
302       return;
303    }
304    Dmsg1(000, "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)
320 {
321    if (jcr->reload_id == 0) {
322       return;                         /* nothing to do */
323    }
324    int i = jcr->reload_id - 1;
325    Dmsg3(000, "reload job_end JobId=%d table=%d cnt=%d\n", jcr->JobId,
326       i, reload_table[i].job_count);
327    lock_jcr_chain();
328    LockRes();
329    if (--reload_table[i].job_count <= 0) {
330       free_saved_resources(i);
331    }
332    UnlockRes();
333    unlock_jcr_chain();
334 }
335
336 static int find_free_reload_table_entry()
337 {
338    int table = -1;
339    for (int i=0; i < max_reloads; i++) {
340       if (reload_table[i].res_table == NULL) {
341          table = i;
342          break;
343       }
344    }
345    return table;
346 }
347
348 /*
349  * If we get here, we have received a SIGHUP, which means to
350  *    reread our configuration file. 
351  *
352  * The algorithm used is as follows: we count how many jobs are
353  *   running since the last reload and set those jobs to make a
354  *   callback. Also, we set each job with the current reload table
355  *   id. . The old config is saved with the reload table
356  *   id in a reload table. The new config file is read. Now, as
357  *   each job exits, it calls back to the reload_job_end_cb(), which
358  *   decrements the count of open jobs for the given reload table.
359  *   When the count goes to zero, we release those resources.
360  *   This allows us to have pointers into the resource table (from
361  *   jobs), and once they exit and all the pointers are released, we
362  *   release the old table. Note, if no new jobs are running since the
363  *   last reload, then the old resources will be immediately release.
364  *   A console is considered a job because it may have pointers to
365  *   resources, but a SYSTEM job is not since it *should* not have any
366  *   permanent pointers to jobs.
367  */
368 extern "C"
369 void reload_config(int sig)
370 {
371    static bool already_here = false;
372    sigset_t set;        
373    JCR *jcr;
374    int njobs = 0;
375    int table, rtable;
376
377    if (already_here) {
378       abort();                        /* Oops, recursion -> die */
379    }
380    already_here = true;
381    sigemptyset(&set);
382    sigaddset(&set, SIGHUP);
383    sigprocmask(SIG_BLOCK, &set, NULL);
384
385 // Jmsg(NULL, M_INFO, 0, "Entering experimental reload config code. Bug reports will not be accepted.\n");
386
387    lock_jcr_chain();
388    LockRes();
389
390    table = find_free_reload_table_entry();
391    if (table < 0) {
392       Jmsg(NULL, M_ERROR, 0, _("Too many open reload requests. Request ignored.\n"));
393       goto bail_out;
394    }
395
396    /*
397     * Hook all active jobs that are not already hooked (i.e.
398     *  reload_id == 0
399     */
400    foreach_jcr(jcr) {
401       if (jcr->reload_id == 0 && jcr->JobType != JT_SYSTEM) {
402          reload_table[table].job_count++;
403          jcr->reload_id = table + 1;
404          job_end_push(jcr, reload_job_end_cb);
405          njobs++;
406       }
407       free_locked_jcr(jcr);
408    }
409    Dmsg1(000, "Reload_config njobs=%d\n", njobs);
410    reload_table[table].res_table = save_config_resources();
411    Dmsg1(000, "Saved old config in table %d\n", table);
412
413    Dmsg0(000, "Calling parse config\n");
414    parse_config(configfile);
415
416    Dmsg0(000, "Reloaded config file\n");
417    if (!check_resources()) {
418       rtable = find_free_reload_table_entry();    /* save new, bad table */
419       if (rtable < 0) {
420          Jmsg(NULL, M_ERROR, 0, _("Please correct configuration file: %s\n"), configfile);
421          Jmsg(NULL, M_ERROR_TERM, 0, _("Out of reload table entries. Giving up.\n"));
422       } else {
423          Jmsg(NULL, M_ERROR, 0, _("Please correct configuration file: %s\n"), configfile);
424       }
425       reload_table[rtable].res_table = save_config_resources();
426       /* Now restore old resoure values */
427       int num = r_last - r_first + 1;
428       RES **res_tab = reload_table[table].res_table;
429       for (int i=0; i<num; i++) {
430          res_head[i] = res_tab[i];
431       }
432       table = rtable;                 /* release new, bad, saved table below */
433       if (njobs != 0) {
434          foreach_jcr(jcr) {
435             if (jcr->reload_id == table) {
436                jcr->reload_id = 0;
437             }
438             free_locked_jcr(jcr);
439          }
440       }
441       njobs = 0;                      /* force bad tabel to be released below */
442    }
443
444    /* Reset globals */
445    set_working_directory(director->working_directory);
446    FDConnectTimeout = director->FDConnectTimeout;
447    SDConnectTimeout = director->SDConnectTimeout;
448    Dmsg0(0, "Director's configuration file reread.\n");
449         
450    /* Now release saved resources, if no jobs using the resources */
451    if (njobs == 0) {
452       free_saved_resources(table);
453    }
454
455 bail_out:
456    UnlockRes();
457    unlock_jcr_chain();
458    sigprocmask(SIG_UNBLOCK, &set, NULL);
459    signal(SIGHUP, reload_config);
460    already_here = false;
461 }
462
463 /*
464  * Make a quick check to see that we have all the
465  * resources needed.
466  *
467  *  **** FIXME **** this routine could be a lot more
468  *   intelligent and comprehensive.
469  */
470 static int check_resources()
471 {
472    bool OK = true;
473    JOB *job;
474
475    LockRes();
476
477    job = (JOB *)GetNextRes(R_JOB, NULL);
478    director = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
479    if (!director) {
480       Jmsg(NULL, M_FATAL, 0, _("No Director resource defined in %s\n\
481 Without that I don't know who I am :-(\n"), configfile);
482       OK = false;
483    } else {
484       set_working_directory(director->working_directory);
485       if (!director->messages) {       /* If message resource not specified */
486          director->messages = (MSGS *)GetNextRes(R_MSGS, NULL);
487          if (!director->messages) {
488             Jmsg(NULL, M_FATAL, 0, _("No Messages resource defined in %s\n"), configfile);
489             OK = false;
490          }
491       }
492       if (GetNextRes(R_DIRECTOR, (RES *)director) != NULL) {
493          Jmsg(NULL, M_FATAL, 0, _("Only one Director resource permitted in %s\n"),
494             configfile);
495          OK = false;
496       } 
497    }
498
499    if (!job) {
500       Jmsg(NULL, M_FATAL, 0, _("No Job records defined in %s\n"), configfile);
501       OK = false;
502    }
503    foreach_res(job, R_JOB) {
504       int i;
505
506       if (job->jobdefs) {
507          /* Transfer default items from JobDefs Resource */
508          for (i=0; job_items[i].name; i++) {
509             char **def_svalue, **svalue;  /* string value */
510             int *def_ivalue, *ivalue;     /* integer value */
511             int64_t *def_lvalue, *lvalue; /* 64 bit values */
512             uint32_t offset;
513
514             Dmsg4(400, "Job \"%s\", field \"%s\" bit=%d def=%d\n",
515                 job->hdr.name, job_items[i].name, 
516                 bit_is_set(i, job->hdr.item_present),  
517                 bit_is_set(i, job->jobdefs->hdr.item_present));
518
519             if (!bit_is_set(i, job->hdr.item_present) &&
520                  bit_is_set(i, job->jobdefs->hdr.item_present)) { 
521                Dmsg2(400, "Job \"%s\", field \"%s\": getting default.\n",
522                  job->hdr.name, job_items[i].name);
523                offset = (char *)(job_items[i].value) - (char *)&res_all;   
524                /*
525                 * Handle strings and directory strings
526                 */
527                if (job_items[i].handler == store_str ||
528                    job_items[i].handler == store_dir) {
529                   def_svalue = (char **)((char *)(job->jobdefs) + offset);
530                   Dmsg5(400, "Job \"%s\", field \"%s\" def_svalue=%s item %d offset=%u\n", 
531                        job->hdr.name, job_items[i].name, *def_svalue, i, offset);
532                   svalue = (char **)((char *)job + offset);
533                   if (*svalue) {
534                      Dmsg1(000, "Hey something is wrong. p=0x%lu\n", *svalue);
535                   }
536                   *svalue = bstrdup(*def_svalue);
537                   set_bit(i, job->hdr.item_present);
538                } else if (job_items[i].handler == store_res) {
539                   def_svalue = (char **)((char *)(job->jobdefs) + offset);
540                   Dmsg4(400, "Job \"%s\", field \"%s\" item %d offset=%u\n", 
541                        job->hdr.name, job_items[i].name, i, offset);
542                   svalue = (char **)((char *)job + offset);
543                   if (*svalue) {
544                      Dmsg1(000, "Hey something is wrong. p=0x%lu\n", *svalue);
545                   }
546                   *svalue = *def_svalue;
547                   set_bit(i, job->hdr.item_present);
548                /*
549                 * Handle integer fields 
550                 *    Note, our store_yesno does not handle bitmaped fields
551                 */
552                } else if (job_items[i].handler == store_yesno   ||
553                           job_items[i].handler == store_pint    ||
554                           job_items[i].handler == store_jobtype ||
555                           job_items[i].handler == store_level   ||
556                           job_items[i].handler == store_pint    ||
557                           job_items[i].handler == store_replace) {
558                   def_ivalue = (int *)((char *)(job->jobdefs) + offset);
559                   Dmsg5(400, "Job \"%s\", field \"%s\" def_ivalue=%d item %d offset=%u\n", 
560                        job->hdr.name, job_items[i].name, *def_ivalue, i, offset);
561                   ivalue = (int *)((char *)job + offset);
562                   *ivalue = *def_ivalue;
563                   set_bit(i, job->hdr.item_present);
564                /*
565                 * Handle 64 bit integer fields 
566                 */
567                } else if (job_items[i].handler == store_time   ||
568                           job_items[i].handler == store_size   ||
569                           job_items[i].handler == store_int64) {
570                   def_lvalue = (int64_t *)((char *)(job->jobdefs) + offset);
571                   Dmsg5(400, "Job \"%s\", field \"%s\" def_lvalue=%" lld " item %d offset=%u\n", 
572                        job->hdr.name, job_items[i].name, *def_lvalue, i, offset);
573                   lvalue = (int64_t *)((char *)job + offset);
574                   *lvalue = *def_lvalue;
575                   set_bit(i, job->hdr.item_present);
576                }
577             }
578          }
579       }
580       /* 
581        * Ensure that all required items are present
582        */
583       for (i=0; job_items[i].name; i++) {
584          if (job_items[i].flags & ITEM_REQUIRED) {
585                if (!bit_is_set(i, job->hdr.item_present)) {  
586                   Jmsg(NULL, M_FATAL, 0, "Field \"%s\" in Job \"%s\" resource is required, but not found.\n",
587                     job_items[i].name, job->hdr.name);
588                   OK = false;
589                 }
590          }
591          /* If this triggers, take a look at lib/parse_conf.h */
592          if (i >= MAX_RES_ITEMS) {
593             Emsg0(M_ERROR_TERM, 0, "Too many items in Job resource\n");
594          }
595       }
596       if (job->client && job->client->catalog) {
597          CAT *catalog = job->client->catalog;
598          B_DB *db;
599
600          /*
601           * Make sure we can open catalog, otherwise print a warning
602           * message because the server is probably not running.
603           */
604          db = db_init_database(NULL, catalog->db_name, catalog->db_user,
605                             catalog->db_password, catalog->db_address,
606                             catalog->db_port, catalog->db_socket);
607          if (!db || !db_open_database(NULL, db)) {
608             Jmsg(NULL, M_FATAL, 0, _("Could not open database \"%s\".\n"),
609                  catalog->db_name);
610             if (db) {
611                Jmsg(NULL, M_FATAL, 0, _("%s"), db_strerror(db));
612             }
613             OK = false;
614          } else {
615             /* If a pool is defined for this job, create the pool DB       
616              *  record if it is not already created. 
617              */
618             if (job->pool) {
619                create_pool(NULL, db, job->pool, POOL_OP_UPDATE);  /* update request */
620             }
621             /* Set default value in all counters */
622             COUNTER *counter;
623             foreach_res(counter, R_COUNTER) {
624                /* Write to catalog? */
625                if (!counter->created && counter->Catalog == catalog) {
626                   COUNTER_DBR cr;
627                   bstrncpy(cr.Counter, counter->hdr.name, sizeof(cr.Counter));
628                   cr.MinValue = counter->MinValue;
629                   cr.MaxValue = counter->MaxValue;
630                   cr.CurrentValue = counter->MinValue;
631                   if (counter->WrapCounter) {
632                      bstrncpy(cr.WrapCounter, counter->WrapCounter->hdr.name, sizeof(cr.WrapCounter));
633                   } else {
634                      cr.WrapCounter[0] = 0;  /* empty string */
635                   }
636                   if (db_create_counter_record(NULL, db, &cr)) {
637                      counter->CurrentValue = cr.CurrentValue;
638                      counter->created = true;
639                      Dmsg2(100, "Create counter %s val=%d\n", counter->hdr.name, counter->CurrentValue);
640                   }
641                } 
642                if (!counter->created) {
643                   counter->CurrentValue = counter->MinValue;  /* default value */
644                }
645             }
646          }
647          db_close_database(NULL, db);
648       }
649    }
650
651    UnlockRes();
652    if (OK) {
653       close_msg(NULL);                /* close temp message handler */
654       init_msg(NULL, director->messages); /* open daemon message handler */
655    }
656    return OK;
657 }