1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * BSD 3 Clause License 8 * 9 * Copyright (c) 2007, The Storage Networking Industry Association. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * - Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * - Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 22 * - Neither the name of The Storage Networking Industry Association (SNIA) 23 * nor the names of its contributors may be used to endorse or promote 24 * products derived from this software without specific prior written 25 * permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ 40 41 #include <errno.h> 42 #include <signal.h> 43 #include <libgen.h> 44 #include <libscf.h> 45 #include <libintl.h> 46 #include <sys/wait.h> 47 #include <zone.h> 48 #include <tsol/label.h> 49 #include <dlfcn.h> 50 #include "ndmpd.h" 51 #include "ndmpd_common.h" 52 53 /* zfs library handle & mutex */ 54 libzfs_handle_t *zlibh; 55 mutex_t zlib_mtx; 56 void *mod_plp; 57 58 static void ndmpd_sig_handler(int sig); 59 60 typedef struct ndmpd { 61 int s_shutdown_flag; /* Fields for shutdown control */ 62 int s_sigval; 63 } ndmpd_t; 64 65 ndmpd_t ndmpd; 66 67 68 /* 69 * Load and initialize the plug-in module 70 */ 71 static int 72 mod_init() 73 { 74 char *plname; 75 ndmp_plugin_t *(*plugin_init)(int); 76 77 ndmp_pl = NULL; 78 if ((plname = ndmpd_get_prop(NDMP_PLUGIN_PATH)) == NULL) 79 return (0); 80 81 if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) { 82 syslog(LOG_ERR, "Error loading the plug-in %s", plname); 83 return (0); 84 } 85 86 plugin_init = (ndmp_plugin_t *(*)(int))dlsym(mod_plp, "_ndmp_init"); 87 if (plugin_init == NULL) { 88 (void) dlclose(mod_plp); 89 return (0); 90 } 91 if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) { 92 syslog(LOG_ERR, "Error loading the plug-in %s", plname); 93 return (-1); 94 } 95 return (0); 96 } 97 98 /* 99 * Unload 100 */ 101 static void 102 mod_fini() 103 { 104 if (ndmp_pl == NULL) 105 return; 106 107 void (*plugin_fini)(ndmp_plugin_t *); 108 109 plugin_fini = (void (*)(ndmp_plugin_t *))dlsym(mod_plp, "_ndmp_fini"); 110 if (plugin_fini == NULL) { 111 (void) dlclose(mod_plp); 112 return; 113 } 114 plugin_fini(ndmp_pl); 115 (void) dlclose(mod_plp); 116 } 117 118 static void 119 daemonize_init(char *arg) 120 { 121 sigset_t set, oset; 122 pid_t pid; 123 124 /* 125 * Set effective sets privileges to 'least' required. If fails, send 126 * error messages to log file and proceed. 127 */ 128 if (priv_set(PRIV_SET, PRIV_EFFECTIVE, 129 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, PRIV_PROC_SESSION, 130 PRIV_PROC_FORK, PRIV_PROC_EXEC, 131 PRIV_PROC_AUDIT, PRIV_PROC_SETID, PRIV_PROC_OWNER, PRIV_FILE_CHOWN, 132 PRIV_FILE_CHOWN_SELF, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH, 133 PRIV_FILE_DAC_WRITE, PRIV_FILE_OWNER, PRIV_FILE_SETID, 134 PRIV_SYS_LINKDIR, PRIV_SYS_DEVICES, PRIV_SYS_MOUNT, PRIV_SYS_CONFIG, 135 NULL)) 136 syslog(LOG_ERR, 137 "Failed to set least required privileges to the service."); 138 139 /* 140 * Block all signals prior to the fork and leave them blocked in the 141 * parent so we don't get in a situation where the parent gets SIGINT 142 * and returns non-zero exit status and the child is actually running. 143 * In the child, restore the signal mask once we've done our setsid(). 144 */ 145 (void) sigfillset(&set); 146 (void) sigdelset(&set, SIGABRT); 147 (void) sigprocmask(SIG_BLOCK, &set, &oset); 148 149 if ((pid = fork()) == -1) { 150 openlog(arg, LOG_PID | LOG_NDELAY, LOG_DAEMON); 151 syslog(LOG_ERR, "Failed to start process in background."); 152 exit(SMF_EXIT_ERR_CONFIG); 153 } 154 155 /* If we're the parent process, exit. */ 156 if (pid != 0) { 157 _exit(0); 158 } 159 (void) setsid(); 160 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 161 (void) chdir("/"); 162 (void) umask(0); 163 } 164 165 static void 166 daemonize_fini(void) 167 { 168 int fd; 169 170 if ((fd = open("/dev/null", O_RDWR)) >= 0) { 171 (void) fcntl(fd, F_DUP2FD, STDIN_FILENO); 172 (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO); 173 (void) fcntl(fd, F_DUP2FD, STDERR_FILENO); 174 (void) close(fd); 175 } 176 } 177 178 /* 179 * main 180 * 181 * The main NDMP daemon function 182 * 183 * Parameters: 184 * argc (input) - the argument count 185 * argv (input) - command line options 186 * 187 * Returns: 188 * 0 189 */ 190 int 191 main(int argc, char *argv[]) 192 { 193 char c; 194 struct sigaction act; 195 sigset_t set; 196 void *arg = 0; 197 198 openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); 199 200 /* 201 * Check for existing ndmpd door server (make sure ndmpd is not already 202 * running) 203 */ 204 if (ndmp_door_check()) { 205 /* ndmpd is already running, exit. */ 206 return (0); 207 } 208 209 /* load ENVs */ 210 if (ndmpd_load_prop()) { 211 syslog(LOG_ERR, 212 "%s SMF properties initialization failed.", argv[0]); 213 exit(SMF_EXIT_ERR_CONFIG); 214 } 215 216 /* Global zone check */ 217 if (getzoneid() != GLOBAL_ZONEID) { 218 syslog(LOG_ERR, "Local zone not supported."); 219 exit(SMF_EXIT_ERR_FATAL); 220 } 221 222 /* Trusted Solaris check */ 223 if (is_system_labeled()) { 224 syslog(LOG_ERR, "Trusted Solaris not supported."); 225 exit(SMF_EXIT_ERR_FATAL); 226 } 227 228 opterr = 0; 229 while ((c = getopt(argc, argv, ":d")) != -1) { 230 switch (c) { 231 case 'd': 232 (void) set_debug_level(TRUE); 233 break; 234 default: 235 syslog(LOG_ERR, "%s: Invalid option -%c.", 236 argv[0], optopt); 237 syslog(LOG_ERR, "Usage: %s [-d]", argv[0]); 238 exit(SMF_EXIT_ERR_CONFIG); 239 } 240 241 } 242 243 closelog(); 244 /* 245 * close any open file descriptors which are greater 246 * than STDERR_FILENO 247 */ 248 closefrom(STDERR_FILENO + 1); 249 250 /* set up signal handler */ 251 (void) sigfillset(&set); 252 (void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */ 253 (void) sigfillset(&act.sa_mask); 254 act.sa_handler = ndmpd_sig_handler; 255 act.sa_flags = 0; 256 257 (void) sigaction(SIGTERM, &act, NULL); 258 (void) sigaction(SIGHUP, &act, NULL); 259 (void) sigaction(SIGINT, &act, NULL); 260 (void) sigaction(SIGUSR1, &act, NULL); 261 (void) sigaction(SIGPIPE, &act, NULL); 262 (void) sigdelset(&set, SIGTERM); 263 (void) sigdelset(&set, SIGHUP); 264 (void) sigdelset(&set, SIGINT); 265 (void) sigdelset(&set, SIGUSR1); 266 (void) sigdelset(&set, SIGPIPE); 267 268 (void) daemonize_init(argv[0]); 269 270 openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); 271 (void) mutex_init(&log_lock, 0, NULL); 272 273 if (mod_init() != 0) { 274 syslog(LOG_ERR, "Failed to load the plugin module."); 275 exit(SMF_EXIT_ERR_CONFIG); 276 } 277 278 /* libzfs init */ 279 if ((zlibh = libzfs_init()) == NULL) { 280 syslog(LOG_ERR, "Failed to initialize ZFS library."); 281 exit(SMF_EXIT_ERR_CONFIG); 282 } 283 284 /* initialize and start the door server */ 285 if (ndmp_door_init()) { 286 syslog(LOG_ERR, "Can not start ndmpd door server."); 287 exit(SMF_EXIT_ERR_CONFIG); 288 } 289 290 (void) tlm_init(); 291 292 /* 293 * Prior to this point, we are single-threaded. We will be 294 * multi-threaded from this point on. 295 */ 296 (void) pthread_create(NULL, NULL, (funct_t)ndmpd_main, 297 (void *)&arg); 298 299 while (!ndmpd.s_shutdown_flag) { 300 (void) sigsuspend(&set); 301 302 switch (ndmpd.s_sigval) { 303 case 0: 304 break; 305 306 case SIGPIPE: 307 break; 308 309 case SIGHUP: 310 /* Refresh SMF properties */ 311 if (ndmpd_load_prop()) 312 syslog(LOG_ERR, 313 "Service properties initialization " 314 "failed."); 315 break; 316 317 default: 318 /* 319 * Typically SIGINT or SIGTERM. 320 */ 321 ndmpd.s_shutdown_flag = 1; 322 break; 323 } 324 325 ndmpd.s_sigval = 0; 326 } 327 328 (void) mutex_destroy(&log_lock); 329 libzfs_fini(zlibh); 330 mod_fini(); 331 ndmp_door_fini(); 332 daemonize_fini(); 333 return (SMF_EXIT_OK); 334 } 335 336 static void 337 ndmpd_sig_handler(int sig) 338 { 339 if (ndmpd.s_sigval == 0) 340 ndmpd.s_sigval = sig; 341 } 342 343 /* 344 * Enable libumem debugging by default on DEBUG builds. 345 */ 346 #ifdef DEBUG 347 const char * 348 _umem_debug_init(void) 349 { 350 return ("default,verbose"); /* $UMEM_DEBUG setting */ 351 } 352 353 const char * 354 _umem_logging_init(void) 355 { 356 return ("fail,contents"); /* $UMEM_LOGGING setting */ 357 } 358 #endif 359