X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Fdird.c;h=c1c1b151a0bb08dbe73d8972033ce08d840f4ed1;hb=baa7ca256d3146c8991d27745825af2817ffddbc;hp=aa1ec186a8c3225b4346e565fc214e86c5771c4b;hpb=4d2b94fa3e8018d1a462756ad6e1df7e12a29d20;p=bacula%2Fbacula diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index aa1ec186a8..c1c1b151a0 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -1,8 +1,7 @@ /* Bacula(R) - The Network Backup Solution - Copyright (C) 2000-2015 Kern Sibbald - Copyright (C) 2000-2014 Free Software Foundation Europe e.V. + Copyright (C) 2000-2017 Kern Sibbald The original author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -12,17 +11,15 @@ Public License, v3.0 ("AGPLv3") and some additional permissions and terms pursuant to its AGPLv3 Section 7. - This notice must be preserved when any source code is + This notice must be preserved when any source code is conveyed and/or propagated. Bacula(R) is a registered trademark of Kern Sibbald. */ /* - * * Bacula Director daemon -- this is the main program * * Kern Sibbald, March MM - * */ #include "bacula.h" @@ -44,6 +41,7 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); void terminate_dird(int sig); static bool check_resources(); static void cleanup_old_files(); +static void resize_reload(int nb); /* Exported subroutines */ extern "C" void reload_config(int sig); @@ -65,9 +63,11 @@ void init_device_resources(); static char *runjob = NULL; -static bool background = true; +static bool foreground = false; +static bool make_pid_file = true; /* create pid file */ static void init_reload(void); static CONFIG *config; +static bool test_config = false; /* Globals Exported */ DIRRES *director; /* Director resource */ @@ -77,7 +77,12 @@ char *configfile = NULL; void *start_heap; utime_t last_reload_time = 0; + /* Globals Imported */ +extern dlist client_globals; +extern dlist store_globals; +extern dlist job_globals; +extern dlist sched_globals; extern RES_ITEM job_items[]; #if defined(_MSC_VER) extern "C" { // work around visual compiler mangling variables @@ -117,7 +122,7 @@ static void usage() { fprintf(stderr, _( PROG_COPYRIGHT - "\nVersion: %s (%s)\n\n" + "\n%sVersion: %s (%s)\n\n" "Usage: bacula-dir [-f -s] [-c config_file] [-d debug_level] [config_file]\n" " -c set configuration file to file\n" " -d [,] set debug level to , debug tags to \n" @@ -127,12 +132,13 @@ static void usage() " -g groupid\n" " -m print kaboom output (for debugging)\n" " -r run now\n" + " -P do not create pid file\n" " -s no signals\n" " -t test - read configuration and exit\n" " -u userid\n" " -v verbose user messages\n" " -? print this message.\n" - "\n"), 2000, VERSION, BDATE); + "\n"), 2000, "", VERSION, BDATE); exit(1); } @@ -158,15 +164,21 @@ static void dir_debug_print(JCR *jcr, FILE *fp) #define main BaculaMain #endif +/* DELETE ME when bugs in MA1512, MA1632 MA1639 are fixed */ +extern void (*MA1512_reload_job_end_cb)(JCR *,void *); +static void reload_job_end_cb(JCR *jcr, void *ctx); + int main (int argc, char *argv[]) { int ch; JCR *jcr; bool no_signals = false; - bool test_config = false; char *uid = NULL; char *gid = NULL; + /* DELETE ME when bugs in MA1512, MA1632 MA1639 are fixed */ + MA1512_reload_job_end_cb = reload_job_end_cb; + start_heap = sbrk(0); setlocale(LC_ALL, ""); bindtextdomain("bacula", LOCALEDIR); @@ -177,10 +189,10 @@ int main (int argc, char *argv[]) init_msg(NULL, NULL); /* initialize message handler */ init_reload(); daemon_start_time = time(NULL); - + setup_daemon_message_queue(); console_command = run_console_command; - while ((ch = getopt(argc, argv, "c:d:fg:mr:stu:v?T")) != -1) { + while ((ch = getopt(argc, argv, "c:d:fg:mPr:stu:v?T")) != -1) { switch (ch) { case 'c': /* specify config file */ if (configfile != NULL) { @@ -214,7 +226,7 @@ int main (int argc, char *argv[]) break; case 'f': /* run in foreground */ - background = false; + foreground = true; break; case 'g': /* set group id */ @@ -225,6 +237,10 @@ int main (int argc, char *argv[]) prt_kaboom = true; break; + case 'P': /* no pid file */ + make_pid_file = false; + break; + case 'r': /* run job */ if (runjob != NULL) { free(runjob); @@ -259,10 +275,6 @@ int main (int argc, char *argv[]) argc -= optind; argv += optind; - if (!no_signals) { - init_signals(terminate_dird); - } - if (argc) { if (configfile != NULL) { free(configfile); @@ -275,19 +287,20 @@ int main (int argc, char *argv[]) usage(); } - if (!test_config) { /* we don't need to do this block in test mode */ - if (background) { - daemon_start(); - init_stack_dump(); /* grab new pid */ - } + if (!foreground && !test_config) { + daemon_start(); + init_stack_dump(); /* grab new pid */ + } + + if (!no_signals) { + init_signals(terminate_dird); } if (configfile == NULL) { configfile = bstrdup(CONFIG_FILE); } - config = new_config_parser(); - + config = New(CONFIG()); parse_dir_config(config, configfile, M_ERROR_TERM); if (init_crypto() != 0) { @@ -300,8 +313,10 @@ int main (int argc, char *argv[]) if (!test_config) { /* Create pid must come after we are a daemon -- so we have our final pid */ - create_pid_file(director->pid_directory, "bacula-dir", - get_first_port_host_order(director->DIRaddrs)); + if (make_pid_file) { + create_pid_file(director->pid_directory, "bacula-dir", + get_first_port_host_order(director->DIRaddrs)); + } read_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs)); } @@ -337,6 +352,8 @@ int main (int argc, char *argv[]) FDConnectTimeout = (int)director->FDConnectTimeout; SDConnectTimeout = (int)director->SDConnectTimeout; + resize_reload(director->MaxReload); + #if !defined(HAVE_WIN32) signal(SIGHUP, reload_config); #endif @@ -375,17 +392,32 @@ int main (int argc, char *argv[]) struct RELOAD_TABLE { int job_count; - RES **res_table; + RES_HEAD **res_head; }; -static const int max_reloads = 50; -static RELOAD_TABLE reload_table[max_reloads]; +static int max_reloads = 32; +static RELOAD_TABLE *reload_table=NULL; + +static void resize_reload(int nb) +{ + if (nb <= max_reloads) { + return; + } + + reload_table = (RELOAD_TABLE*)realloc(reload_table, nb * sizeof(RELOAD_TABLE)); + for (int i=max_reloads; i < nb ; i++) { + reload_table[i].job_count = 0; + reload_table[i].res_head = NULL; + } + max_reloads = nb; +} static void init_reload(void) { + reload_table = (RELOAD_TABLE*)malloc(max_reloads * sizeof(RELOAD_TABLE)); for (int i=0; i < max_reloads; i++) { reload_table[i].job_count = 0; - reload_table[i].res_table = NULL; + reload_table[i].res_head = NULL; } } @@ -395,19 +427,31 @@ static void init_reload(void) */ static void free_saved_resources(int table) { + RES *next, *res; int num = r_last - r_first + 1; - RES **res_tab = reload_table[table].res_table; - if (!res_tab) { + RES_HEAD **res_tab = reload_table[table].res_head; + + if (res_tab == NULL) { Dmsg1(100, "res_tab for table %d already released.\n", table); return; } Dmsg1(100, "Freeing resources for table %d\n", table); for (int j=0; jfirst; + for ( ; next; ) { + res = next; + next = res->res_next; + free_resource(res, r_first + j); + } + free(res_tab[j]->res_list); + free(res_tab[j]); + res_tab[j] = NULL; + } } free(res_tab); reload_table[table].job_count = 0; - reload_table[table].res_table = NULL; + reload_table[table].res_head = NULL; } /* @@ -434,7 +478,7 @@ static int find_free_reload_table_entry() { int table = -1; for (int i=0; i < max_reloads; i++) { - if (reload_table[i].res_table == NULL) { + if (reload_table[i].res_head == NULL) { table = i; break; } @@ -442,6 +486,8 @@ static int find_free_reload_table_entry() return table; } +static pthread_mutex_t reload_mutex = PTHREAD_MUTEX_INITIALIZER; + /* * If we get here, we have received a SIGHUP, which means to * reread our configuration file. @@ -471,12 +517,27 @@ void reload_config(int sig) JCR *jcr; int njobs = 0; /* number of running jobs */ int table, rtable; - bool ok; - - if (already_here) { - abort(); /* Oops, recursion -> die */ - } - already_here = true; + bool ok=false; + int tries=0; + + /* Wait to do the reload */ + do { + P(reload_mutex); + if (already_here) { + V(reload_mutex); + if (tries++ > 10) { + Qmsg(NULL, M_INFO, 0, _("Already doing a reload request, " + "request ignored.\n")); + return; + } + Dmsg0(10, "Already doing a reload request, waiting a bit\n"); + bmicrosleep(1, 0); + } else { + already_here = true; + V(reload_mutex); + ok = true; + } + } while (!ok); #if !defined(HAVE_WIN32) sigemptyset(&set); @@ -489,34 +550,39 @@ void reload_config(int sig) table = find_free_reload_table_entry(); if (table < 0) { - Jmsg(NULL, M_ERROR, 0, _("Too many open reload requests. Request ignored.\n")); + Qmsg(NULL, M_ERROR, 0, _("Too many (%d) open reload requests. " + "Request ignored.\n"), max_reloads); goto bail_out; } Dmsg1(100, "Reload_config njobs=%d\n", njobs); - reload_table[table].res_table = config->save_resources(); + /* Save current res_head */ + reload_table[table].res_head = res_head; Dmsg1(100, "Saved old config in table %d\n", table); + /* Create a new res_head and parse into it */ ok = parse_dir_config(config, configfile, M_ERROR); Dmsg0(100, "Reloaded config file\n"); if (!ok || !check_resources() || !check_catalog(UPDATE_CATALOG)) { + /* + * We got an error, save broken point, restore old one, + * then release everything from broken pointer. + */ rtable = find_free_reload_table_entry(); /* save new, bad table */ if (rtable < 0) { - Jmsg(NULL, M_ERROR, 0, _("Please correct configuration file: %s\n"), configfile); - Jmsg(NULL, M_ERROR_TERM, 0, _("Out of reload table entries. Giving up.\n")); + Qmsg(NULL, M_ERROR, 0, _("Please correct configuration file: %s\n"), configfile); + Qmsg(NULL, M_ERROR_TERM, 0, _("Out of reload table entries. Giving up.\n")); } else { - Jmsg(NULL, M_ERROR, 0, _("Please correct configuration file: %s\n"), configfile); - Jmsg(NULL, M_ERROR, 0, _("Resetting previous configuration.\n")); - } - reload_table[rtable].res_table = config->save_resources(); - /* Now restore old resource values */ - int num = r_last - r_first + 1; - RES **res_tab = reload_table[table].res_table; - for (int i=0; iname); + if (!client) { + Qmsg(NULL, M_INFO, 0, _("Client=%s not found. Assuming it was removed!!!\n"), cg->name); + } else { + client->globals = cg; /* Set globals pointer */ + } + } + STORE_GLOBALS *sg; + foreach_dlist(sg, &store_globals) { + STORE *store; + store = GetStoreResWithName(sg->name); + if (!store) { + Qmsg(NULL, M_INFO, 0, _("Storage=%s not found. Assuming it was removed!!!\n"), sg->name); + } else { + store->globals = sg; /* set globals pointer */ + Dmsg2(200, "Reload found numConcurrent=%ld for Store %s\n", + sg->NumConcurrentJobs, sg->name); + } + } + JOB_GLOBALS *jg; + foreach_dlist(jg, &job_globals) { + JOB *job; + job = GetJobResWithName(jg->name); + if (!job) { + Qmsg(NULL, M_INFO, 0, _("Job=%s not found. Assuming it was removed!!!\n"), jg->name); + } else { + job->globals = jg; /* Set globals pointer */ + } + } + SCHED_GLOBALS *schg; + foreach_dlist(schg, &sched_globals) { + SCHED *sched; + sched = GetSchedResWithName(schg->name); + if (!sched) { + Qmsg(NULL, M_INFO, 0, _("Schedule=%s not found. Assuming it was removed!!!\n"), schg->name); + } else { + sched->globals = schg; /* Set globals pointer */ + } + } } - /* Reset globals */ + /* Reset other globals */ set_working_directory(director->working_directory); FDConnectTimeout = director->FDConnectTimeout; SDConnectTimeout = director->SDConnectTimeout; @@ -567,8 +679,12 @@ void terminate_dird(int sig) stop_watchdog(); generate_daemon_event(NULL, "Exit"); unload_plugins(); - write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs)); - delete_pid_file(director->pid_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs)); + if (!test_config) { + write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs)); + if (make_pid_file) { + delete_pid_file(director->pid_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs)); + } + } term_scheduler(); term_job_server(); if (runjob) { @@ -581,13 +697,41 @@ void terminate_dird(int sig) print_memory_pool_stats(); } if (config) { - config->free_resources(); - free(config); + delete config; config = NULL; } term_ua_server(); term_msg(); /* terminate message handler */ cleanup_crypto(); + + free_daemon_message_queue(); + + if (reload_table) { + free(reload_table); + } + free(res_head); + res_head = NULL; + /* + * Now walk through resource globals tables and release them + */ + CLIENT_GLOBALS *cg; + foreach_dlist(cg, &client_globals) { + free(cg->name); + if (cg->SetIPaddress) { + free(cg->SetIPaddress); + } + free(cg); + } + STORE_GLOBALS *sg; + foreach_dlist(sg, &store_globals) { + free(sg->name); + free(sg); + } + JOB_GLOBALS *jg; + foreach_dlist(jg, &job_globals) { + free(jg->name); + free(jg); + } close_memory_pool(); /* release free memory in pool */ lmgr_cleanup_main(); sm_dump(false); @@ -689,15 +833,7 @@ static bool check_resources() int i; if (job->jobdefs) { - /* Handle Storage alists specifically */ JOB *jobdefs = job->jobdefs; - if (jobdefs->storage && !job->storage) { - STORE *st; - job->storage = New(alist(10, not_owned_by_alist)); - foreach_alist(st, jobdefs->storage) { - job->storage->append(st); - } - } /* Handle RunScripts alists specifically */ if (jobdefs->RunScripts) { RUNSCRIPT *rs, *elt; @@ -718,6 +854,7 @@ static bool check_resources() uint32_t *def_ivalue, *ivalue; /* integer value */ bool *def_bvalue, *bvalue; /* bool value */ int64_t *def_lvalue, *lvalue; /* 64 bit values */ + alist **def_avalue, **avalue; /* alist values */ uint32_t offset; Dmsg4(1400, "Job \"%s\", field \"%s\" bit=%d def=%d\n", @@ -761,9 +898,17 @@ static bool check_resources() * Handle alist resources */ } else if (job_items[i].handler == store_alist_res) { - if (bit_is_set(i, job->jobdefs->hdr.item_present)) { - set_bit(i, job->hdr.item_present); + void *elt; + + def_avalue = (alist **)((char *)(job->jobdefs) + offset); + avalue = (alist **)((char *)job + offset); + + *avalue = New(alist(10, not_owned_by_alist)); + + foreach_alist(elt, (*def_avalue)) { + (*avalue)->append(elt); } + set_bit(i, job->hdr.item_present); /* * Handle integer fields * Note, our store_bit does not handle bitmaped fields @@ -830,6 +975,16 @@ static bool check_resources() job->name()); OK = false; } + + /* Make sure the job doesn't use the Scratch Pool to start with */ + const char *name; + if (!check_pool(job->JobType, job->JobLevel, + job->pool, job->next_pool, &name)) { + Jmsg(NULL, M_FATAL, 0, + _("%s \"Scratch\" not valid in Job \"%s\".\n"), + name, job->name()); + OK = false; + } } /* End loop over Job res */ @@ -927,6 +1082,34 @@ static bool check_resources() } } + /* Loop over all pools, check PoolType */ + POOL *pool; + foreach_res(pool, R_POOL) { + if (!pool->pool_type) { + /* This case is checked by the parse engine, we should not */ + Jmsg(NULL, M_FATAL, 0, _("PoolType required in Pool resource \"%s\".\n"), pool->hdr.name); + OK = false; + continue; + } + if ((strcasecmp(pool->pool_type, NT_("backup")) != 0) && + (strcasecmp(pool->pool_type, NT_("copy")) != 0) && + (strcasecmp(pool->pool_type, NT_("cloned")) != 0) && + (strcasecmp(pool->pool_type, NT_("archive")) != 0) && + (strcasecmp(pool->pool_type, NT_("migration")) != 0) && + (strcasecmp(pool->pool_type, NT_("scratch")) != 0)) + { + Jmsg(NULL, M_FATAL, 0, _("Invalid PoolType \"%s\" in Pool resource \"%s\".\n"), pool->pool_type, pool->hdr.name); + OK = false; + } + + if (pool->NextPool && strcmp(pool->NextPool->name(), "Scratch") == 0) { + Jmsg(NULL, M_FATAL, 0, + _("NextPool \"Scratch\" not valid in Pool \"%s\".\n"), + pool->name()); + OK = false; + } + } + UnlockRes(); if (OK) { close_msg(NULL); /* close temp message handler */ @@ -941,11 +1124,14 @@ static bool check_resources() * - we can check the connection (mode=CHECK_CONNECTION) * - we can synchronize the catalog with the configuration (mode=UPDATE_CATALOG) * - we can synchronize, and fix old job records (mode=UPDATE_AND_FIX) + * - we hook up the Autochange children with the parent, and + * we hook the shared autochangers together. */ static bool check_catalog(cat_op mode) { bool OK = true; bool need_tls; + STORE *store, *ac_child; /* Loop over databases */ CAT *catalog; @@ -959,6 +1145,9 @@ static bool check_catalog(cat_op mode) catalog->db_user, catalog->db_password, catalog->db_address, catalog->db_port, catalog->db_socket, + catalog->db_ssl_mode, catalog->db_ssl_key, + catalog->db_ssl_cert, catalog->db_ssl_ca, + catalog->db_ssl_capath, catalog->db_ssl_cipher, catalog->mult_db_connections, catalog->disable_batch_insert); if (!db || !db_open_database(NULL, db)) { @@ -1031,7 +1220,6 @@ static bool check_catalog(cat_op mode) } /* Ensure basic storage record is in DB */ - STORE *store; foreach_res(store, R_STORAGE) { STORAGE_DBR sr; MEDIATYPE_DBR mtr; @@ -1097,6 +1285,38 @@ static bool check_catalog(cat_op mode) } } + /* Link up all the children for each changer */ + foreach_res(store, R_STORAGE) { + char sid[50]; + if (store->changer == store) { /* we are a real Autochanger */ + store->ac_group = get_pool_memory(PM_FNAME); + store->ac_group[0] = 0; + pm_strcat(store->ac_group, edit_int64(store->StorageId, sid)); + /* Now look for children who point to this storage */ + foreach_res(ac_child, R_STORAGE) { + if (ac_child != store && ac_child->changer == store) { + /* Found a child -- add StorageId */ + pm_strcat(store->ac_group, ","); + pm_strcat(store->ac_group, edit_int64(ac_child->StorageId, sid)); + } + } + } + } + + /* Link up all the shared storage devices */ + foreach_res(store, R_STORAGE) { + if (store->ac_group) { /* we are a real Autochanger */ + /* Now look for Shared Storage who point to this storage */ + foreach_res(ac_child, R_STORAGE) { + if (ac_child->shared_storage == store && ac_child->ac_group && + ac_child->shared_storage != ac_child) { + pm_strcat(store->ac_group, ","); + pm_strcat(store->ac_group, ac_child->ac_group); + } + } + } + } + /* Loop over all counters, defining them in each database */ /* Set default value in all counters */ COUNTER *counter;