]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/stored.c
Backport from Bacula Enterprise
[bacula/bacula] / bacula / src / stored / stored.c
index dbce1a6b66290d870f5455de5ff40ae34b4c8d78..57820883402fee8d1ec54dca07b6ca526c87a612 100644 (file)
@@ -1,49 +1,45 @@
 /*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
-
-   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
-   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., 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.
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2015 Kern Sibbald
+   Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   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 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
  * Second generation Storage daemon.
  *
- *  Kern Sibbald, MM
+ *  Written by 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
  * File daemon.
  *
- *   Version $Id$
- *
  */
 
 #include "bacula.h"
 #include "stored.h"
 
-/* Imported functions */
+/* TODO: fix problem with bls, bextract
+ * that use findlib and already declare
+ * filed plugins
+ */
+#include "sd_plugins.h"
 
+/* Imported functions */
+extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
 
 /* Forward referenced functions */
 void terminate_stored(int sig);
@@ -58,39 +54,47 @@ extern "C" void *device_initialization(void *arg);
 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 */
 pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
 pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
+void *start_heap;
 
 
 static uint32_t VolSessionId = 0;
 uint32_t VolSessionTime;
 char *configfile = NULL;
 bool init_done = false;
+static pthread_t server_tid;
+static bool server_tid_valid = false;
 
 /* Global static variables */
 static bool foreground = 0;
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 static workq_t dird_workq;            /* queue for processing connections */
+static CONFIG *config;
 
 
 static void usage()
 {
    fprintf(stderr, _(
-PROG_COPYRIGHT
-"\nVersion: %s (%s)\n\n"
-"Usage: stored [options] [-c config_file] [config_file]\n"
-"        -c <file>   use <file> as configuration file\n"
-"        -dnn        set debug level to nn\n"
-"        -f          run in foreground (for debugging)\n"
-"        -g <group>  set groupid to group\n"
-"        -p          proceed despite I/O errors\n"
-"        -s          no signals (for debugging)\n"
-"        -t          test - read config and exit\n"
-"        -u <user>   userid to <user>\n"
-"        -v          verbose user messages\n"
-"        -?          print this message.\n"
-"\n"), 2000, VERSION, BDATE);
+      PROG_COPYRIGHT
+      "\n%sVersion: %s (%s)\n\n"
+      "Usage: bacula-sd [options] [-c config_file] [config_file]\n"
+      "     -c <file>         use <file> as configuration file\n"
+      "     -d <nn>[,<tags>]  set debug level to <nn>, debug tags to <tags>\n"
+      "     -dt               print timestamp in debug output\n"
+      "     -T                set trace on\n"
+      "     -f                run in foreground (for debugging)\n"
+      "     -g <group>        set groupid to group\n"
+      "     -m                print kaboom output (for debugging)\n"
+      "     -p                proceed despite I/O errors\n"
+      "     -s                no signals (for debugging)\n"
+      "     -t                test - read config and exit\n"
+      "     -u <user>         userid to <user>\n"
+      "     -v                verbose user messages\n"
+      "     -?                print this message.\n"
+      "\n"), 2000, "", VERSION, BDATE);
    exit(1);
 }
 
@@ -112,6 +116,7 @@ int main (int argc, char *argv[])
    char *uid = NULL;
    char *gid = NULL;
 
+   start_heap = sbrk(0);
    setlocale(LC_ALL, "");
    bindtextdomain("bacula", LOCALEDIR);
    textdomain("bacula");
@@ -130,7 +135,7 @@ int main (int argc, char *argv[])
       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) {
+   while ((ch = getopt(argc, argv, "c:d:fg:mpstu:v?T")) != -1) {
       switch (ch) {
       case 'c':                    /* configuration file */
          if (configfile != NULL) {
@@ -140,12 +145,28 @@ int main (int argc, char *argv[])
          break;
 
       case 'd':                    /* debug level */
-         debug_level = atoi(optarg);
-         if (debug_level <= 0) {
-            debug_level = 1;
+         if (*optarg == 't') {
+            dbg_timestamp = true;
+         } else {
+            char *p;
+            /* We probably find a tag list -d 10,sql,bvfs */
+            if ((p = strchr(optarg, ',')) != NULL) {
+               *p = 0;
+            }
+            debug_level = atoi(optarg);
+            if (debug_level <= 0) {
+               debug_level = 1;
+            }
+            if (p) {
+               debug_parse_tags(p+1, &debug_level_tags);
+            }
          }
          break;
 
+      case 'T':
+         set_trace(true);
+         break;
+
       case 'f':                    /* run in foreground */
          foreground = true;
          break;
@@ -154,6 +175,10 @@ int main (int argc, char *argv[])
          gid = optarg;
          break;
 
+      case 'm':                    /* print kaboom output */
+         prt_kaboom = true;
+         break;
+
       case 'p':                    /* proceed in spite of I/O errors */
          forge_on = true;
          break;
@@ -194,6 +219,11 @@ int main (int argc, char *argv[])
    if (argc)
       usage();
 
+   if (!foreground) {
+      daemon_start();                 /* become daemon */
+      init_stack_dump();              /* pick up new pid */
+   }
+
    if (!no_signals) {
       init_signals(terminate_stored);
    }
@@ -202,7 +232,8 @@ int main (int argc, char *argv[])
       configfile = bstrdup(CONFIG_FILE);
    }
 
-   parse_config(configfile);
+   config = new_config_parser();
+   parse_sd_config(config, configfile, M_ERROR_TERM);
 
    if (init_crypto() != 0) {
       Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
@@ -220,18 +251,22 @@ int main (int argc, char *argv[])
 
    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 */
-   }
 
-   create_pid_file(me->pid_directory, "bacula-sd", get_first_port_host_order(me->sdaddrs));
-   read_state_file(me->working_directory, "bacula-sd", get_first_port_host_order(me->sdaddrs));
+   create_pid_file(me->pid_directory, "bacula-sd",
+                   get_first_port_host_order(me->sdaddrs));
+   read_state_file(me->working_directory, "bacula-sd",
+                   get_first_port_host_order(me->sdaddrs));
 
-   drop(uid, gid);
+   set_jcr_in_tsd(INVALID_JCR);
+   /* Make sure on Solaris we can run concurrent, watch dog + servers + misc */
+   set_thread_concurrency(me->max_concurrent_jobs * 2 + 4);
+   lmgr_init_thread(); /* initialize the lockmanager stack */
 
-   cleanup_old_files();
+   load_sd_plugins(me->plugin_directory);
 
+   drop(uid, gid, false);
+
+   cleanup_old_files();
 
    /* Ensure that Volume Session Time and Id are both
     * set and are both non-zero.
@@ -241,23 +276,21 @@ int main (int argc, char *argv[])
       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
-     */
-   create_volume_list();              /* do before device_init */
+   /*
+    * Start the device allocation thread
+    */
+   create_volume_lists();             /* 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));
+      berrno be;
+      Emsg1(M_ABORT, 0, _("Unable to create thread. ERR=%s\n"), be.bstrerror());
    }
 
    start_watchdog();                  /* start watchdog thread */
    init_jcr_subsystem();              /* start JCR watchdogs etc. */
 
    /* Single server used for Director and File daemon */
+   server_tid = pthread_self();
+   server_tid_valid = true;
    bnet_thread_server(me->sdaddrs, me->max_concurrent_jobs * 2 + 1,
                       &dird_workq, handle_connection_request);
    exit(1);                           /* to keep compiler quiet */
@@ -279,7 +312,7 @@ uint32_t newVolSessionId()
 static int check_resources()
 {
    bool OK = true;
-
+   bool tls_needed;
 
    me = (STORES *)GetNextRes(R_STORAGE, NULL);
    if (!me) {
@@ -321,7 +354,7 @@ static int check_resources()
 
    DIRRES *director;
    STORES *store;
-   foreach_res(store, R_STORAGE) { 
+   foreach_res(store, R_STORAGE) {
       /* tls_require implies tls_enable */
       if (store->tls_require) {
          if (have_tls) {
@@ -333,19 +366,21 @@ static int check_resources()
          }
       }
 
-      if (!store->tls_certfile && store->tls_enable) {
+      tls_needed = store->tls_enable || store->tls_authenticate;
+
+      if (!store->tls_certfile && tls_needed) {
          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) {
+      if (!store->tls_keyfile && tls_needed) {
          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) {
+      if ((!store->tls_ca_certfile && !store->tls_ca_certdir) && tls_needed && 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"
@@ -355,7 +390,7 @@ static int check_resources()
       }
 
       /* If everything is well, attempt to initialize our per-resource TLS context */
-      if (OK && (store->tls_enable || store->tls_require)) {
+      if (OK && (tls_needed || store->tls_require)) {
          /* Initialize TLS context:
           * Args: CA certfile, CA certdir, Certfile, Keyfile,
           * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
@@ -364,7 +399,7 @@ static int check_resources()
             store->tls_keyfile, NULL, NULL, store->tls_dhfile,
             store->tls_verify_peer);
 
-         if (!store->tls_ctx) { 
+         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;
@@ -372,25 +407,27 @@ static int check_resources()
       }
    }
 
-   foreach_res(director, R_DIRECTOR) { 
+   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) {
+      tls_needed = director->tls_enable || director->tls_authenticate;
+
+      if (!director->tls_certfile && tls_needed) {
          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) {
+      if (!director->tls_keyfile && tls_needed) {
          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) {
+      if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && tls_needed && 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"
@@ -400,7 +437,7 @@ static int check_resources()
       }
 
       /* If everything is well, attempt to initialize our per-resource TLS context */
-      if (OK && (director->tls_enable || director->tls_require)) {
+      if (OK && (tls_needed || director->tls_require)) {
          /* Initialize TLS context:
           * Args: CA certfile, CA certdir, Certfile, Keyfile,
           * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
@@ -409,7 +446,7 @@ static int check_resources()
             director->tls_keyfile, NULL, NULL, director->tls_dhfile,
             director->tls_verify_peer);
 
-         if (!director->tls_ctx) { 
+         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;
@@ -419,7 +456,7 @@ static int check_resources()
 
    OK = init_autochangers();
 
-   
+
    if (OK) {
       close_msg(NULL);                   /* close temp message handler */
       init_msg(NULL, me->messages);      /* open daemon message handler */
@@ -429,26 +466,84 @@ static int check_resources()
    return OK;
 }
 
+/*
+ * Remove old .spool files written by me from the working directory.
+ */
 static void cleanup_old_files()
 {
-   POOLMEM *cleanup = get_pool_memory(PM_MESSAGE);
+   DIR* dp;
+   struct dirent *entry, *result;
+   int rc, name_max;
+   int my_name_len = strlen(my_name);
    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);
+   POOLMEM *cleanup = get_pool_memory(PM_MESSAGE);
+   POOLMEM *basename = get_pool_memory(PM_MESSAGE);
+   regex_t preg1;
+   char prbuf[500];
+   const int nmatch = 30;
+   regmatch_t pmatch[nmatch];
+   berrno be;
+
+   /* Look for .spool files but don't allow spaces */
+   const char *pat1 = "^[^ ]+\\.spool$";
+
+   /* Setup working directory prefix */
+   pm_strcpy(basename, me->working_directory);
    if (len > 0 && !IsPathSeparator(me->working_directory[len-1])) {
-      pm_strcat(cleanup, "/");
+      pm_strcat(basename, "/");
+   }
+
+   /* Compile regex expressions */
+   rc = regcomp(&preg1, pat1, REG_EXTENDED);
+   if (rc != 0) {
+      regerror(rc, &preg1, prbuf, sizeof(prbuf));
+      Pmsg2(000,  _("Could not compile regex pattern \"%s\" ERR=%s\n"),
+           pat1, prbuf);
+      goto get_out2;
+   }
+
+   name_max = pathconf(".", _PC_NAME_MAX);
+   if (name_max < 1024) {
+      name_max = 1024;
+   }
+
+   if (!(dp = opendir(me->working_directory))) {
+      berrno be;
+      Pmsg2(000, "Failed to open working dir %s for cleanup: ERR=%s\n",
+            me->working_directory, be.bstrerror());
+      goto get_out1;
+   }
+
+   entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
+   while (1) {
+      if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
+         break;
+      }
+      /* Exclude any name with ., .., not my_name or containing a space */
+      if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0 ||
+          strncmp(result->d_name, my_name, my_name_len) != 0) {
+         Dmsg1(500, "Skipped: %s\n", result->d_name);
+         continue;
+      }
+
+      /* Unlink files that match regex */
+      if (regexec(&preg1, result->d_name, nmatch, pmatch,  0) == 0) {
+         pm_strcpy(cleanup, basename);
+         pm_strcat(cleanup, result->d_name);
+         Dmsg1(500, "Unlink: %s\n", cleanup);
+         unlink(cleanup);
+      }
    }
-   pm_strcat(cleanup, my_name);
-   pm_strcat(cleanup, "*.spool");
-   run_program(cleanup, 0, NULL);
+   free(entry);
+   closedir(dp);
+
+get_out1:
+   regfree(&preg1);
+get_out2:
    free_pool_memory(cleanup);
+   free_pool_memory(basename);
 }
 
-
 /*
  * Here we attempt to init and open each device. This is done
  *  once at startup in a separate thread.
@@ -465,11 +560,13 @@ void *device_initialization(void *arg)
 
    pthread_detach(pthread_self());
    jcr = new_jcr(sizeof(JCR), stored_free_jcr);
-   jcr->JobType = JT_SYSTEM;
+   new_plugins(jcr);  /* instantiate plugins */
+   jcr->setJobType(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));
+      berrno be;
+      Jmsg1(jcr, M_ABORT, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
    }
 
    foreach_res(device, R_DEVICE) {
@@ -481,43 +578,58 @@ void *device_initialization(void *arg)
          continue;
       }
 
-      jcr->dcr = dcr = new_dcr(jcr, dev);
-      if (dev->is_autochanger()) {
-         /* If autochanger set slot in dev sturcture */
-         get_autochanger_loaded_slot(dcr);
-      }
+      jcr->dcr = dcr = new_dcr(jcr, NULL, dev);
+      generate_plugin_event(jcr, bsdEventDeviceInit, dcr);
 
       if (device->cap_bits & CAP_ALWAYSOPEN) {
+         if (dev->is_autochanger()) {
+            /* If autochanger set slot in dev sturcture */
+            get_autochanger_loaded_slot(dcr);
+         }
          Dmsg1(20, "calling first_open_device %s\n", dev->print_name());
+         if (generate_plugin_event(jcr, bsdEventDeviceOpen, dcr) != bRC_OK) {
+            Jmsg(jcr, M_FATAL, 0, _("generate_plugin_event(bsdEventDeviceOpen) Failed\n"));
+            continue;
+         }
+
          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());
+            generate_plugin_event(jcr, bsdEventDeviceClose, dcr);
             free_dcr(dcr);
             jcr->dcr = NULL;
             continue;
          }
+      } else {
+         /* If not always open, we don't know what is in the drive */
+         dev->clear_slot();
       }
       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));
+            volume_unused(dcr);             /* mark volume "released" */
             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);
+      Pmsg1(000, "free_dcr=%p\n", jcr->dcr);
       free_dcr(jcr->dcr);
       jcr->dcr = NULL;
    }
 #endif
-   free_jcr(jcr); 
+   free_plugins(jcr);
+   free_jcr(jcr);
    init_done = true;
    UnlockRes();
    return NULL;
@@ -532,11 +644,14 @@ void terminate_stored(int sig)
    JCR *jcr;
 
    if (in_here) {                     /* prevent loops */
+      bmicrosleep(2, 0);              /* yield */
       exit(1);
    }
    in_here = true;
+   debug_level = 0;                   /* turn off any debug */
+   stop_watchdog();
 
-   if (sig == SIGTERM) {              /* normal shutdown request? */
+   if (sig == SIGTERM || sig == SIGINT) { /* normal shutdown request? or ^C */
       /*
        * This is a normal shutdown request. We wiffle through
        *   all open jobs canceling them and trying to wake
@@ -549,12 +664,16 @@ void terminate_stored(int sig)
             free_jcr(jcr);
             continue;                 /* ignore console */
          }
-         set_jcr_job_status(jcr, JS_Canceled);
+         if (jcr->dcr) {
+            /* Make sure no device remains locked */
+            generate_plugin_event(jcr, bsdEventDeviceClose, jcr->dcr);
+         }
+         jcr->setJobStatus(JS_Canceled);
          fd = jcr->file_bsock;
          if (fd) {
-            fd->timed_out = true;
+            fd->set_timed_out();
+            jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
             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->blocked()) {
                pthread_cond_broadcast(&jcr->dcr->dev->wait_next_vol);
@@ -577,6 +696,9 @@ void terminate_stored(int sig)
 
    Dmsg1(200, "In terminate_stored() sig=%d\n", sig);
 
+   unload_plugins();
+   free_volume_lists();
+
    foreach_res(device, R_DEVICE) {
       Dmsg1(10, "Term device %s\n", device->device_name);
       if (device->dev) {
@@ -587,22 +709,28 @@ void terminate_stored(int sig)
          Dmsg1(10, "No dev structure %s\n", device->device_name);
       }
    }
+   if (server_tid_valid) {
+      bnet_stop_thread_server(server_tid);
+   }
 
    if (configfile) {
       free(configfile);
       configfile = NULL;
    }
-   free_config_resources();
+   if (config) {
+      config->free_resources();
+      free(config);
+      config = NULL;
+   }
 
-   if (debug_level > 10) {
+   if (chk_dbglvl(10)) {
       print_memory_pool_stats();
    }
-   term_reservations_lock();
    term_msg();
-   stop_watchdog();
    cleanup_crypto();
-   free_volume_list();
+   term_reservations_lock();
    close_memory_pool();
+   lmgr_cleanup_main();
 
    sm_dump(false);                    /* dump orphaned buffers */
    exit(sig);