/* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* * BSD 3 Clause License * * Copyright (c) 2007, The Storage Networking Industry Association. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * - Neither the name of The Storage Networking Industry Association (SNIA) * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include "ndmpd.h" #include "ndmpd_common.h" /* zfs library handle & mutex */ libzfs_handle_t *zlibh; mutex_t zlib_mtx; void *mod_plp; static void ndmpd_sig_handler(int sig); typedef struct ndmpd { int s_shutdown_flag; /* Fields for shutdown control */ int s_sigval; } ndmpd_t; ndmpd_t ndmpd; /* * Load and initialize the plug-in module */ static int mod_init() { char *plname; ndmp_plugin_t *(*plugin_init)(int); ndmp_pl = NULL; plname = ndmpd_get_prop(NDMP_PLUGIN_PATH); if (plname == NULL || *plname == '\0') return (0); if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) { NDMP_LOG(LOG_ERR, "Error loading the plug-in %s: %s", plname, dlerror()); return (0); } plugin_init = (ndmp_plugin_t *(*)(int))dlsym(mod_plp, "_ndmp_init"); if (plugin_init == NULL) { (void) dlclose(mod_plp); return (0); } if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) { NDMP_LOG(LOG_ERR, "Error loading the plug-in %s", plname); return (-1); } return (0); } /* * Unload */ static void mod_fini() { if (ndmp_pl == NULL) return; void (*plugin_fini)(ndmp_plugin_t *); plugin_fini = (void (*)(ndmp_plugin_t *))dlsym(mod_plp, "_ndmp_fini"); if (plugin_fini == NULL) { (void) dlclose(mod_plp); return; } plugin_fini(ndmp_pl); (void) dlclose(mod_plp); } static void set_privileges(void) { priv_set_t *pset = priv_allocset(); /* * Set effective sets privileges to 'least' required. If fails, send * error messages to log file and proceed. */ if (pset != NULL) { priv_basicset(pset); (void) priv_addset(pset, PRIV_PROC_AUDIT); (void) priv_addset(pset, PRIV_PROC_SETID); (void) priv_addset(pset, PRIV_PROC_OWNER); (void) priv_addset(pset, PRIV_FILE_CHOWN); (void) priv_addset(pset, PRIV_FILE_CHOWN_SELF); (void) priv_addset(pset, PRIV_FILE_DAC_READ); (void) priv_addset(pset, PRIV_FILE_DAC_SEARCH); (void) priv_addset(pset, PRIV_FILE_DAC_WRITE); (void) priv_addset(pset, PRIV_FILE_OWNER); (void) priv_addset(pset, PRIV_FILE_SETID); (void) priv_addset(pset, PRIV_SYS_LINKDIR); (void) priv_addset(pset, PRIV_SYS_DEVICES); (void) priv_addset(pset, PRIV_SYS_MOUNT); (void) priv_addset(pset, PRIV_SYS_CONFIG); } if (pset == NULL || setppriv(PRIV_SET, PRIV_EFFECTIVE, pset) != 0) { (void) fprintf(stderr, "Failed to set least required privileges to the service\n"); } priv_freeset(pset); } static void daemonize_init(void) { sigset_t set, oset; pid_t pid; /* * Block all signals prior to the fork and leave them blocked in the * parent so we don't get in a situation where the parent gets SIGINT * and returns non-zero exit status and the child is actually running. * In the child, restore the signal mask once we've done our setsid(). */ (void) sigfillset(&set); (void) sigdelset(&set, SIGABRT); (void) sigprocmask(SIG_BLOCK, &set, &oset); if ((pid = fork()) == -1) { (void) fprintf(stderr, "Failed to start process in background.\n"); exit(SMF_EXIT_ERR_CONFIG); } /* If we're the parent process, exit. */ if (pid != 0) { _exit(0); } (void) setsid(); (void) sigprocmask(SIG_SETMASK, &oset, NULL); (void) chdir("/"); } /* * main * * The main NDMP daemon function * * Parameters: * argc (input) - the argument count * argv (input) - command line options * * Returns: * 0 */ int main(int argc, char *argv[]) { struct sigaction act; sigset_t set; int c; void *arg = NULL; boolean_t run_in_foreground = B_FALSE; boolean_t override_debug = B_FALSE; /* * Check for existing ndmpd door server (make sure ndmpd is not already * running) */ if (ndmp_door_check()) { /* ndmpd is already running, exit. */ (void) fprintf(stderr, "ndmpd is already running.\n"); return (0); } /* Global zone check */ if (getzoneid() != GLOBAL_ZONEID) { (void) fprintf(stderr, "Non-global zone not supported.\n"); exit(SMF_EXIT_ERR_FATAL); } /* Trusted Solaris check */ if (is_system_labeled()) { (void) fprintf(stderr, "Trusted Solaris not supported.\n"); exit(SMF_EXIT_ERR_FATAL); } /* load SMF configuration */ if (ndmpd_load_prop()) { (void) fprintf(stderr, "SMF properties initialization failed.\n"); exit(SMF_EXIT_ERR_CONFIG); } opterr = 0; while ((c = getopt(argc, argv, "df")) != -1) { switch (c) { case 'd': override_debug = B_TRUE; break; case 'f': run_in_foreground = B_TRUE; break; default: (void) fprintf(stderr, "%s: Invalid option -%c.\n", argv[0], optopt); (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]); exit(SMF_EXIT_ERR_CONFIG); } } /* set up signal handler */ (void) sigfillset(&set); (void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */ (void) sigfillset(&act.sa_mask); act.sa_handler = ndmpd_sig_handler; act.sa_flags = 0; (void) sigaction(SIGTERM, &act, NULL); (void) sigaction(SIGHUP, &act, NULL); (void) sigaction(SIGINT, &act, NULL); (void) sigaction(SIGUSR1, &act, NULL); (void) sigaction(SIGPIPE, &act, NULL); (void) sigdelset(&set, SIGTERM); (void) sigdelset(&set, SIGHUP); (void) sigdelset(&set, SIGINT); (void) sigdelset(&set, SIGUSR1); (void) sigdelset(&set, SIGPIPE); set_privileges(); (void) umask(077); openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); /* * Open log file before we detach from terminal in case that open * fails and error message is printed to stderr. */ if (ndmp_log_open_file(run_in_foreground, override_debug) != 0) exit(SMF_EXIT_ERR_FATAL); if (!run_in_foreground) daemonize_init(); (void) mutex_init(&ndmpd_zfs_fd_lock, 0, NULL); if (mod_init() != 0) { NDMP_LOG(LOG_ERR, "Failed to load the plugin module."); exit(SMF_EXIT_ERR_CONFIG); } /* libzfs init */ if ((zlibh = libzfs_init()) == NULL) { NDMP_LOG(LOG_ERR, "Failed to initialize ZFS library."); exit(SMF_EXIT_ERR_CONFIG); } /* initialize and start the door server */ if (ndmp_door_init()) { NDMP_LOG(LOG_ERR, "Can not start ndmpd door server."); exit(SMF_EXIT_ERR_CONFIG); } if (tlm_init() == -1) { NDMP_LOG(LOG_ERR, "Failed to initialize tape manager."); exit(SMF_EXIT_ERR_CONFIG); } /* * Prior to this point, we are single-threaded. We will be * multi-threaded from this point on. */ (void) pthread_create(NULL, NULL, (funct_t)ndmpd_main, (void *)&arg); while (!ndmpd.s_shutdown_flag) { (void) sigsuspend(&set); switch (ndmpd.s_sigval) { case 0: break; case SIGPIPE: break; case SIGHUP: /* Refresh SMF properties */ if (ndmpd_load_prop()) NDMP_LOG(LOG_ERR, "Service properties initialization " "failed."); break; default: /* * Typically SIGINT or SIGTERM. */ ndmpd.s_shutdown_flag = 1; break; } ndmpd.s_sigval = 0; } (void) mutex_destroy(&ndmpd_zfs_fd_lock); libzfs_fini(zlibh); mod_fini(); ndmp_door_fini(); ndmp_log_close_file(); return (SMF_EXIT_OK); } static void ndmpd_sig_handler(int sig) { if (ndmpd.s_sigval == 0) ndmpd.s_sigval = sig; } /* * Enable libumem debugging by default on DEBUG builds. */ #ifdef DEBUG const char * _umem_debug_init(void) { return ("default,verbose"); /* $UMEM_DEBUG setting */ } const char * _umem_logging_init(void) { return ("fail,contents"); /* $UMEM_LOGGING setting */ } #endif