X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fstored.c;h=caa53f8a80d6353f5dad44f35cd6f8e319de14b7;hb=8bc2739483be88049421740913d40929de7e118b;hp=baea8fd55f494725b4d52e82b12a40b953788117;hpb=ceda1ea2e5742ad8ad15ec0780316d11693eb708;p=bacula%2Fbacula diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index baea8fd55f..caa53f8a80 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -1,6 +1,8 @@ /* * Second generation Storage daemon. * + * Kern Sibbald, MM + * * It accepts a number of simple commands from the File daemon * and acts on them. When a request to append data is made, * it opens a data channel and accepts data from the @@ -10,24 +12,32 @@ * */ /* - Copyright (C) 2000-2005 Kern Sibbald + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2006 Free Software Foundation Europe e.V. - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation plus additions + that are listed in the file LICENSE. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. - */ + Bacula® is a registered trademark of John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ #include "bacula.h" #include "stored.h" @@ -37,36 +47,38 @@ /* Forward referenced functions */ void terminate_stored(int sig); -static void check_config(); - -extern "C" void *device_allocation(void *arg); - +static int check_resources(); +static void cleanup_old_files(); +extern "C" void *device_initialization(void *arg); #define CONFIG_FILE "bacula-sd.conf" /* Default config file */ - /* Global variables exported */ char OK_msg[] = "3000 OK\n"; char TERM_msg[] = "3999 Terminate\n"; -STORES *me = NULL; /* our Global resource */ -bool forge_on = false; /* proceed inspite of I/O errors */ +STORES *me = NULL; /* our Global resource */ +bool forge_on = false; /* proceed inspite of I/O errors */ +pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER; + static uint32_t VolSessionId = 0; uint32_t VolSessionTime; -char *configfile; +char *configfile = NULL; +bool init_done = false; /* Global static variables */ -static int foreground = 0; +static bool foreground = 0; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static workq_t dird_workq; /* queue for processing connections */ +static workq_t dird_workq; /* queue for processing connections */ static void usage() { fprintf(stderr, _( -"Copyright (C) 2000-2005 Kern Sibbald.\n" -"\nVersion: " VERSION " (" BDATE ")\n\n" +PROG_COPYRIGHT +"\nVersion: %s (%s)\n\n" "Usage: stored [options] [-c config_file] [config_file]\n" " -c use as configuration file\n" " -dnn set debug level to nn\n" @@ -78,7 +90,7 @@ static void usage() " -u userid to \n" " -v verbose user messages\n" " -? print this message.\n" -"\n")); +"\n"), 2000, VERSION, BDATE); exit(1); } @@ -87,78 +99,85 @@ static void usage() * Main Bacula Unix Storage Daemon * */ +#if defined(HAVE_WIN32) +#define main BaculaMain +#endif + int main (int argc, char *argv[]) { int ch; - int no_signals = FALSE; - int test_config = FALSE; + bool no_signals = false; + bool test_config = false; pthread_t thid; char *uid = NULL; char *gid = NULL; + setlocale(LC_ALL, ""); + bindtextdomain("bacula", LOCALEDIR); + textdomain("bacula"); + init_stack_dump(); my_name_is(argc, argv, "bacula-sd"); - textdomain("bacula"); init_msg(NULL, NULL); daemon_start_time = time(NULL); /* Sanity checks */ if (TAPE_BSIZE % B_DEV_BSIZE != 0 || TAPE_BSIZE / B_DEV_BSIZE == 0) { - Emsg2(M_ABORT, 0, "Tape block size (%d) not multiple of system size (%d)\n", - TAPE_BSIZE, B_DEV_BSIZE); + Emsg2(M_ABORT, 0, _("Tape block size (%d) not multiple of system size (%d)\n"), + TAPE_BSIZE, B_DEV_BSIZE); } if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) { - Emsg1(M_ABORT, 0, "Tape block size (%d) is not a power of 2\n", TAPE_BSIZE); + Emsg1(M_ABORT, 0, _("Tape block size (%d) is not a power of 2\n"), TAPE_BSIZE); } while ((ch = getopt(argc, argv, "c:d:fg:pstu:v?")) != -1) { switch (ch) { case 'c': /* configuration file */ - if (configfile != NULL) { - free(configfile); - } - configfile = bstrdup(optarg); - break; + if (configfile != NULL) { + free(configfile); + } + configfile = bstrdup(optarg); + break; case 'd': /* debug level */ - debug_level = atoi(optarg); - if (debug_level <= 0) { - debug_level = 1; - } - break; + debug_level = atoi(optarg); + if (debug_level <= 0) { + debug_level = 1; + } + break; case 'f': /* run in foreground */ - foreground = TRUE; - break; + foreground = true; + break; case 'g': /* set group id */ - gid = optarg; - break; + gid = optarg; + break; case 'p': /* proceed in spite of I/O errors */ - forge_on = true; - break; + forge_on = true; + break; case 's': /* no signals */ - no_signals = TRUE; - break; + no_signals = true; + break; case 't': - test_config = TRUE; - break; + test_config = true; + break; case 'u': /* set uid */ - uid = optarg; - break; + uid = optarg; + break; case 'v': /* verbose */ - verbose++; - break; + verbose++; + break; case '?': default: - usage(); - break; + usage(); + break; } } argc -= optind; @@ -166,7 +185,7 @@ int main (int argc, char *argv[]) if (argc) { if (configfile != NULL) { - free(configfile); + free(configfile); } configfile = bstrdup(*argv); argc--; @@ -184,15 +203,26 @@ int main (int argc, char *argv[]) } parse_config(configfile); - check_config(); + + if (init_crypto() != 0) { + Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n")); + } + + if (!check_resources()) { + Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile); + } + + init_reservations_lock(); if (test_config) { terminate_stored(0); } + my_name_is(0, (char **)NULL, me->hdr.name); /* Set our real name */ + if (!foreground) { - daemon_start(); /* become daemon */ - init_stack_dump(); /* pick up new pid */ + daemon_start(); /* become daemon */ + init_stack_dump(); /* pick up new pid */ } create_pid_file(me->pid_directory, "bacula-sd", get_first_port_host_order(me->sdaddrs)); @@ -200,38 +230,37 @@ int main (int argc, char *argv[]) drop(uid, gid); + cleanup_old_files(); + + /* Ensure that Volume Session Time and Id are both * set and are both non-zero. */ - VolSessionTime = (long)daemon_start_time; + VolSessionTime = (uint32_t)daemon_start_time; if (VolSessionTime == 0) { /* paranoid */ Jmsg0(NULL, M_ABORT, 0, _("Volume Session Time is ZERO!\n")); } + init_python_interpreter(me->hdr.name, me->scripts_directory, "SDStartUp"); + /* Make sure on Solaris we can run concurrent, watch dog + servers + misc */ set_thread_concurrency(me->max_concurrent_jobs * 2 + 4); /* * Start the device allocation thread */ - if (pthread_create(&thid, NULL, device_allocation, NULL) != 0) { + create_volume_list(); /* do before device_init */ + if (pthread_create(&thid, NULL, device_initialization, NULL) != 0) { Emsg1(M_ABORT, 0, _("Unable to create thread. ERR=%s\n"), strerror(errno)); } - start_watchdog(); /* start watchdog thread */ - - init_jcr_subsystem(); /* start JCR watchdogs etc. */ - - /* - * Sleep a bit to give device thread a chance to lock the resource - * chain before we start the server. - */ - bmicrosleep(1, 0); + start_watchdog(); /* start watchdog thread */ + init_jcr_subsystem(); /* start JCR watchdogs etc. */ /* Single server used for Director and File daemon */ bnet_thread_server(me->sdaddrs, me->max_concurrent_jobs * 2 + 1, - &dird_workq, handle_connection_request); - exit(1); /* to keep compiler quiet */ + &dird_workq, handle_connection_request); + exit(1); /* to keep compiler quiet */ } /* Return a new Session Id */ @@ -247,103 +276,249 @@ uint32_t newVolSessionId() } /* Check Configuration file for necessary info */ -static void check_config() +static int check_resources() { - LockRes(); + bool OK = true; + + me = (STORES *)GetNextRes(R_STORAGE, NULL); if (!me) { - UnlockRes(); - Jmsg1(NULL, M_ERROR_TERM, 0, _("No Storage resource defined in %s. Cannot continue.\n"), - configfile); + Jmsg1(NULL, M_ERROR, 0, _("No Storage resource defined in %s. Cannot continue.\n"), + configfile); + OK = false; } - my_name_is(0, (char **)NULL, me->hdr.name); /* Set our real name */ - if (GetNextRes(R_STORAGE, (RES *)me) != NULL) { - UnlockRes(); - Jmsg1(NULL, M_ERROR_TERM, 0, _("Only one Storage resource permitted in %s\n"), - configfile); + Jmsg1(NULL, M_ERROR, 0, _("Only one Storage resource permitted in %s\n"), + configfile); + OK = false; } if (GetNextRes(R_DIRECTOR, NULL) == NULL) { - UnlockRes(); - Jmsg1(NULL, M_ERROR_TERM, 0, _("No Director resource defined in %s. Cannot continue.\n"), - configfile); + Jmsg1(NULL, M_ERROR, 0, _("No Director resource defined in %s. Cannot continue.\n"), + configfile); + OK = false; } if (GetNextRes(R_DEVICE, NULL) == NULL){ - UnlockRes(); - Jmsg1(NULL, M_ERROR_TERM, 0, _("No Device resource defined in %s. Cannot continue.\n"), - configfile); + Jmsg1(NULL, M_ERROR, 0, _("No Device resource defined in %s. Cannot continue.\n"), + configfile); + OK = false; } + if (!me->messages) { me->messages = (MSGS *)GetNextRes(R_MSGS, NULL); if (!me->messages) { - Jmsg1(NULL, M_ERROR_TERM, 0, _("No Messages resource defined in %s. Cannot continue.\n"), - configfile); + Jmsg1(NULL, M_ERROR, 0, _("No Messages resource defined in %s. Cannot continue.\n"), + configfile); + OK = false; } } - close_msg(NULL); /* close temp message handler */ - init_msg(NULL, me->messages); /* open daemon message handler */ - - UnlockRes(); if (!me->working_directory) { - Jmsg1(NULL, M_ERROR_TERM, 0, _("No Working Directory defined in %s. Cannot continue.\n"), - configfile); + Jmsg1(NULL, M_ERROR, 0, _("No Working Directory defined in %s. Cannot continue.\n"), + configfile); + OK = false; } - set_working_directory(me->working_directory); + DIRRES *director; + STORES *store; + foreach_res(store, R_STORAGE) { + /* tls_require implies tls_enable */ + if (store->tls_require) { + if (have_tls) { + store->tls_enable = true; + } else { + Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n")); + OK = false; + continue; + } + } + + if (!store->tls_certfile && store->tls_enable) { + Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Storage \"%s\" in %s.\n"), + store->hdr.name, configfile); + OK = false; + } + + if (!store->tls_keyfile && store->tls_enable) { + Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Storage \"%s\" in %s.\n"), + store->hdr.name, configfile); + OK = false; + } + + if ((!store->tls_ca_certfile && !store->tls_ca_certdir) && store->tls_enable && store->tls_verify_peer) { + Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\"" + " or \"TLS CA Certificate Dir\" are defined for Storage \"%s\" in %s." + " At least one CA certificate store is required" + " when using \"TLS Verify Peer\".\n"), + store->hdr.name, configfile); + OK = false; + } + + /* If everything is well, attempt to initialize our per-resource TLS context */ + if (OK && (store->tls_enable || store->tls_require)) { + /* Initialize TLS context: + * Args: CA certfile, CA certdir, Certfile, Keyfile, + * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ + store->tls_ctx = new_tls_context(store->tls_ca_certfile, + store->tls_ca_certdir, store->tls_certfile, + store->tls_keyfile, NULL, NULL, store->tls_dhfile, + store->tls_verify_peer); + + if (!store->tls_ctx) { + Jmsg(NULL, M_FATAL, 0, _("Failed to initialize TLS context for Storage \"%s\" in %s.\n"), + store->hdr.name, configfile); + OK = false; + } + } + } + + foreach_res(director, R_DIRECTOR) { + /* tls_require implies tls_enable */ + if (director->tls_require) { + director->tls_enable = true; + } + + if (!director->tls_certfile && director->tls_enable) { + Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Director \"%s\" in %s.\n"), + director->hdr.name, configfile); + OK = false; + } + + if (!director->tls_keyfile && director->tls_enable) { + Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Director \"%s\" in %s.\n"), + director->hdr.name, configfile); + OK = false; + } + + if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable && director->tls_verify_peer) { + Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\"" + " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in %s." + " At least one CA certificate store is required" + " when using \"TLS Verify Peer\".\n"), + director->hdr.name, configfile); + OK = false; + } + + /* If everything is well, attempt to initialize our per-resource TLS context */ + if (OK && (director->tls_enable || director->tls_require)) { + /* Initialize TLS context: + * Args: CA certfile, CA certdir, Certfile, Keyfile, + * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ + director->tls_ctx = new_tls_context(director->tls_ca_certfile, + director->tls_ca_certdir, director->tls_certfile, + director->tls_keyfile, NULL, NULL, director->tls_dhfile, + director->tls_verify_peer); + + if (!director->tls_ctx) { + Jmsg(NULL, M_FATAL, 0, _("Failed to initialize TLS context for Director \"%s\" in %s.\n"), + director->hdr.name, configfile); + OK = false; + } + } + } + + OK = init_autochangers(); + + + if (OK) { + close_msg(NULL); /* close temp message handler */ + init_msg(NULL, me->messages); /* open daemon message handler */ + set_working_directory(me->working_directory); + } + + return OK; } +static void cleanup_old_files() +{ + POOLMEM *cleanup = get_pool_memory(PM_MESSAGE); + int len = strlen(me->working_directory); +#if defined(HAVE_WIN32) + pm_strcpy(cleanup, "del /q "); +#else + pm_strcpy(cleanup, "/bin/rm -f "); +#endif + pm_strcat(cleanup, me->working_directory); + if (len > 0 && !IsPathSeparator(me->working_directory[len-1])) { + pm_strcat(cleanup, "/"); + } + pm_strcat(cleanup, my_name); + pm_strcat(cleanup, "*.spool"); + run_program(cleanup, 0, NULL); + free_pool_memory(cleanup); +} + + /* * Here we attempt to init and open each device. This is done * once at startup in a separate thread. */ extern "C" -void *device_allocation(void *arg) +void *device_initialization(void *arg) { DEVRES *device; + DCR *dcr; + JCR *jcr; + DEVICE *dev; LockRes(); + pthread_detach(pthread_self()); + jcr = new_jcr(sizeof(JCR), stored_free_jcr); + jcr->JobType = JT_SYSTEM; + /* Initialize FD start condition variable */ + int errstat = pthread_cond_init(&jcr->job_start_wait, NULL); + if (errstat != 0) { + Jmsg1(jcr, M_ABORT, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat)); + } foreach_res(device, R_DEVICE) { Dmsg1(90, "calling init_dev %s\n", device->device_name); - device->dev = init_dev(NULL, NULL, device); + dev = init_dev(NULL, device); Dmsg1(10, "SD init done %s\n", device->device_name); - if (!device->dev) { + if (!dev) { Jmsg1(NULL, M_ERROR, 0, _("Could not initialize %s\n"), device->device_name); - continue; + continue; + } + + jcr->dcr = dcr = new_dcr(jcr, dev); + if (dev->is_autochanger()) { + /* If autochanger set slot in dev sturcture */ + get_autochanger_loaded_slot(dcr); } if (device->cap_bits & CAP_ALWAYSOPEN) { - Dmsg1(20, "calling first_open_device %s\n", device->device_name); - if (!first_open_device(device->dev)) { - Jmsg1(NULL, M_ERROR, 0, _("Could not open device %s\n"), device->device_name); - } + Dmsg1(20, "calling first_open_device %s\n", dev->print_name()); + if (!first_open_device(dcr)) { + Jmsg1(NULL, M_ERROR, 0, _("Could not open device %s\n"), dev->print_name()); + Dmsg1(20, "Could not open device %s\n", dev->print_name()); + free_dcr(dcr); + jcr->dcr = NULL; + continue; + } } - if (device->cap_bits & CAP_AUTOMOUNT && device->dev && - device->dev->state & ST_OPENED) { - JCR *jcr; - DCR *dcr; - jcr = new_jcr(sizeof(JCR), stored_free_jcr); - jcr->JobType = JT_SYSTEM; - /* Initialize FD start condition variable */ - int errstat = pthread_cond_init(&jcr->job_start_wait, NULL); - if (errstat != 0) { - Jmsg1(jcr, M_ABORT, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat)); - } - dcr = new_dcr(jcr, device->dev); - switch (read_dev_volume_label(dcr)) { - case VOL_OK: - memcpy(&dcr->dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dcr->dev->VolCatInfo)); - break; - default: - Jmsg1(NULL, M_WARNING, 0, _("Could not mount device %s\n"), device->device_name); - break; - } - free_jcr(jcr); + if (device->cap_bits & CAP_AUTOMOUNT && dev->is_open()) { + switch (read_dev_volume_label(dcr)) { + case VOL_OK: + memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); + break; + default: + Jmsg1(NULL, M_WARNING, 0, _("Could not mount device %s\n"), dev->print_name()); + break; + } } + free_dcr(dcr); + jcr->dcr = NULL; } +#ifdef xxx + if (jcr->dcr) { + Dmsg1(000, "free_dcr=%p\n", jcr->dcr); + free_dcr(jcr->dcr); + jcr->dcr = NULL; + } +#endif + free_jcr(jcr); + init_done = true; UnlockRes(); return NULL; } @@ -356,40 +531,44 @@ void terminate_stored(int sig) DEVRES *device; JCR *jcr; - if (in_here) { /* prevent loops */ + if (in_here) { /* prevent loops */ exit(1); } in_here = true; - if (sig == SIGTERM) { /* normal shutdown request? */ + if (sig == SIGTERM) { /* normal shutdown request? */ /* * This is a normal shutdown request. We wiffle through * all open jobs canceling them and trying to wake * them up so that they will report back the correct * volume status. */ - lock_jcr_chain(); foreach_jcr(jcr) { - BSOCK *fd; - free_locked_jcr(jcr); - if (jcr->JobId == 0) { - continue; /* ignore console */ - } - set_jcr_job_status(jcr, JS_Canceled); - fd = jcr->file_bsock; - if (fd) { - fd->timed_out = true; + BSOCK *fd; + if (jcr->JobId == 0) { + free_jcr(jcr); + continue; /* ignore console */ + } + set_jcr_job_status(jcr, JS_Canceled); + fd = jcr->file_bsock; + if (fd) { + fd->timed_out = true; Dmsg1(100, "term_stored killing JobId=%d\n", jcr->JobId); - pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL); - /* ***FIXME*** wiffle through all dcrs */ - if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->dev_blocked) { - pthread_cond_signal(&jcr->dcr->dev->wait_next_vol); - } - bmicrosleep(0, 50000); - } + pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL); + /* ***FIXME*** wiffle through all dcrs */ + if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->dev_blocked) { + pthread_cond_broadcast(&jcr->dcr->dev->wait_next_vol); + pthread_cond_broadcast(&wait_device_release); + } + if (jcr->read_dcr && jcr->read_dcr->dev && jcr->read_dcr->dev->dev_blocked) { + pthread_cond_broadcast(&jcr->read_dcr->dev->wait_next_vol); + pthread_cond_broadcast(&wait_device_release); + } + bmicrosleep(0, 50000); + } + free_jcr(jcr); } - unlock_jcr_chain(); - bmicrosleep(0, 500000); /* give them 1/2 sec to clean up */ + bmicrosleep(0, 500000); /* give them 1/2 sec to clean up */ } write_state_file(me->working_directory, "bacula-sd", get_first_port_host_order(me->sdaddrs)); @@ -397,25 +576,33 @@ void terminate_stored(int sig) Dmsg1(200, "In terminate_stored() sig=%d\n", sig); - LockRes(); foreach_res(device, R_DEVICE) { + Dmsg1(10, "Term device %s\n", device->device_name); if (device->dev) { - term_dev(device->dev); + free_volume(device->dev); + device->dev->term(); + device->dev = NULL; + } else { + Dmsg1(10, "No dev structure %s\n", device->device_name); } } - UnlockRes(); - if (configfile) - free(configfile); + if (configfile) { + free(configfile); + configfile = NULL; + } free_config_resources(); if (debug_level > 10) { print_memory_pool_stats(); } + term_reservations_lock(); term_msg(); stop_watchdog(); + cleanup_crypto(); + free_volume_list(); close_memory_pool(); - sm_dump(false); /* dump orphaned buffers */ + sm_dump(false); /* dump orphaned buffers */ exit(sig); }