1 /* 2 * Copyright 2008 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 54 /* zfs library handle & mutex */ 55 libzfs_handle_t *zlibh; 56 mutex_t zlib_mtx; 57 void *mod_plp; 58 59 static void ndmpd_sig_handler(int sig); 60 61 typedef struct ndmpd { 62 int s_shutdown_flag; /* Fields for shutdown control */ 63 int s_sigval; 64 } ndmpd_t; 65 66 ndmpd_t ndmpd; 67 68 69 /* 70 * Load and initialize the plug-in module 71 */ 72 static int 73 mod_init() 74 { 75 char *plname; 76 ndmp_plugin_t *(*plugin_init)(int); 77 78 ndmp_pl = NULL; 79 if ((plname = ndmpd_get_prop(NDMP_PLUGIN_PATH)) == NULL) 80 return (0); 81 82 if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) { 83 syslog(LOG_ERR, "Error loading the plug-in %s", plname); 84 return (0); 85 } 86 87 plugin_init = (ndmp_plugin_t *(*)(int))dlsym(mod_plp, "_ndmp_init"); 88 if (plugin_init == NULL) { 89 (void) dlclose(mod_plp); 90 return (0); 91 } 92 if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) { 93 syslog(LOG_ERR, "Error loading the plug-in %s", plname); 94 return (-1); 95 } 96 return (0); 97 } 98 99 /* 100 * Unload 101 */ 102 static void 103 mod_fini() 104 { 105 if (ndmp_pl == NULL) 106 return; 107 108 void (*plugin_fini)(ndmp_plugin_t *); 109 110 plugin_fini = (void (*)(ndmp_plugin_t *))dlsym(mod_plp, "_ndmp_fini"); 111 if (plugin_fini == NULL) { 112 (void) dlclose(mod_plp); 113 return; 114 } 115 plugin_fini(ndmp_pl); 116 (void) dlclose(mod_plp); 117 } 118 119 static void 120 daemonize_init(char *arg) 121 { 122 sigset_t set, oset; 123 pid_t pid; 124 125 /* 126 * Set effective sets privileges to 'least' required. If fails, send 127 * error messages to log file and proceed. 128 */ 129 if (priv_set(PRIV_SET, PRIV_EFFECTIVE, 130 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, PRIV_PROC_SESSION, 131 PRIV_PROC_FORK, PRIV_PROC_EXEC, 132 PRIV_PROC_AUDIT, PRIV_PROC_SETID, PRIV_PROC_OWNER, PRIV_FILE_CHOWN, 133 PRIV_FILE_CHOWN_SELF, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH, 134 PRIV_FILE_DAC_WRITE, PRIV_FILE_OWNER, PRIV_FILE_SETID, 135 PRIV_SYS_LINKDIR, PRIV_SYS_DEVICES, PRIV_SYS_MOUNT, PRIV_SYS_CONFIG, 136 NULL)) 137 syslog(LOG_ERR, 138 "Failed to set least required privileges to the service."); 139 140 /* 141 * Block all signals prior to the fork and leave them blocked in the 142 * parent so we don't get in a situation where the parent gets SIGINT 143 * and returns non-zero exit status and the child is actually running. 144 * In the child, restore the signal mask once we've done our setsid(). 145 */ 146 (void) sigfillset(&set); 147 (void) sigdelset(&set, SIGABRT); 148 (void) sigprocmask(SIG_BLOCK, &set, &oset); 149 150 if ((pid = fork()) == -1) { 151 openlog(arg, LOG_PID | LOG_NDELAY, LOG_DAEMON); 152 syslog(LOG_ERR, "Failed to start process in background."); 153 exit(SMF_EXIT_ERR_CONFIG); 154 } 155 156 /* If we're the parent process, exit. */ 157 if (pid != 0) { 158 _exit(0); 159 } 160 (void) setsid(); 161 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 162 (void) chdir("/"); 163 (void) umask(0); 164 } 165 166 static void 167 daemonize_fini(void) 168 { 169 int fd; 170 171 if ((fd = open("/dev/null", O_RDWR)) >= 0) { 172 (void) fcntl(fd, F_DUP2FD, STDIN_FILENO); 173 (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO); 174 (void) fcntl(fd, F_DUP2FD, STDERR_FILENO); 175 (void) close(fd); 176 } 177 } 178 179 /* 180 * main 181 * 182 * The main NDMP daemon function 183 * 184 * Parameters: 185 * argc (input) - the argument count 186 * argv (input) - command line options 187 * 188 * Returns: 189 * 0 190 */ 191 int 192 main(int argc, char *argv[]) 193 { 194 char c; 195 struct sigaction act; 196 sigset_t set; 197 void *arg = 0; 198 199 openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); 200 201 /* 202 * Check for existing ndmpd door server (make sure ndmpd is not already 203 * running) 204 */ 205 if (ndmp_door_check()) { 206 /* ndmpd is already running, exit. */ 207 return (0); 208 } 209 210 /* load ENVs */ 211 if (ndmpd_load_prop()) { 212 syslog(LOG_ERR, 213 "%s SMF properties initialization failed.", argv[0]); 214 exit(SMF_EXIT_ERR_CONFIG); 215 } 216 217 /* Global zone check */ 218 if (getzoneid() != GLOBAL_ZONEID) { 219 syslog(LOG_ERR, "Local zone not supported."); 220 exit(SMF_EXIT_ERR_FATAL); 221 } 222 223 /* Trusted Solaris check */ 224 if (is_system_labeled()) { 225 syslog(LOG_ERR, "Trusted Solaris not supported."); 226 exit(SMF_EXIT_ERR_FATAL); 227 } 228 229 opterr = 0; 230 while ((c = getopt(argc, argv, ":d")) != -1) { 231 switch (c) { 232 case 'd': 233 (void) set_debug_level(TRUE); 234 break; 235 default: 236 syslog(LOG_ERR, "%s: Invalid option -%c.", 237 argv[0], optopt); 238 syslog(LOG_ERR, "Usage: %s [-d]", argv[0]); 239 exit(SMF_EXIT_ERR_CONFIG); 240 } 241 242 } 243 244 closelog(); 245 /* 246 * close any open file descriptors which are greater 247 * than STDERR_FILENO 248 */ 249 closefrom(STDERR_FILENO + 1); 250 251 /* set up signal handler */ 252 (void) sigfillset(&set); 253 (void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */ 254 (void) sigfillset(&act.sa_mask); 255 act.sa_handler = ndmpd_sig_handler; 256 act.sa_flags = 0; 257 258 (void) sigaction(SIGTERM, &act, NULL); 259 (void) sigaction(SIGHUP, &act, NULL); 260 (void) sigaction(SIGINT, &act, NULL); 261 (void) sigaction(SIGUSR1, &act, NULL); 262 (void) sigdelset(&set, SIGTERM); 263 (void) sigdelset(&set, SIGHUP); 264 (void) sigdelset(&set, SIGINT); 265 (void) sigdelset(&set, SIGUSR1); 266 267 (void) daemonize_init(argv[0]); 268 269 openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); 270 (void) mutex_init(&log_lock, 0, NULL); 271 272 if (mod_init() != 0) { 273 syslog(LOG_ERR, "Failed to load the plugin module."); 274 exit(SMF_EXIT_ERR_CONFIG); 275 } 276 277 /* libzfs init */ 278 if ((zlibh = libzfs_init()) == NULL) { 279 syslog(LOG_ERR, "Failed to initialize ZFS library."); 280 exit(SMF_EXIT_ERR_CONFIG); 281 } 282 283 /* initialize and start the door server */ 284 if (ndmp_door_init()) { 285 syslog(LOG_ERR, "Can not start ndmpd door server."); 286 exit(SMF_EXIT_ERR_CONFIG); 287 } 288 289 (void) tlm_init(); 290 291 /* 292 * Prior to this point, we are single-threaded. We will be 293 * multi-threaded from this point on. 294 */ 295 (void) pthread_create(NULL, NULL, (funct_t)ndmpd_main, 296 (void *)&arg); 297 298 while (!ndmpd.s_shutdown_flag) { 299 (void) sigsuspend(&set); 300 301 switch (ndmpd.s_sigval) { 302 case 0: 303 break; 304 305 case SIGHUP: 306 /* Refresh SMF properties */ 307 if (ndmpd_load_prop()) 308 syslog(LOG_ERR, 309 "Service properties initialization " 310 "failed."); 311 break; 312 313 default: 314 /* 315 * Typically SIGINT or SIGTERM. 316 */ 317 ndmpd.s_shutdown_flag = 1; 318 break; 319 } 320 321 ndmpd.s_sigval = 0; 322 } 323 324 (void) mutex_destroy(&log_lock); 325 libzfs_fini(zlibh); 326 mod_fini(); 327 ndmp_door_fini(); 328 daemonize_fini(); 329 free(ndmp_log_path); 330 return (SMF_EXIT_OK); 331 } 332 333 static void 334 ndmpd_sig_handler(int sig) 335 { 336 if (ndmpd.s_sigval == 0) 337 ndmpd.s_sigval = sig; 338 } 339 340 /* 341 * Enable libumem debugging by default on DEBUG builds. 342 */ 343 #ifdef DEBUG 344 const char * 345 _umem_debug_init(void) 346 { 347 return ("default,verbose"); /* $UMEM_DEBUG setting */ 348 } 349 350 const char * 351 _umem_logging_init(void) 352 { 353 return ("fail,contents"); /* $UMEM_LOGGING setting */ 354 } 355 #endif 356