xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
1 /*
2  * Copyright 2010 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 	priv_set_t *pset = priv_allocset();
124 
125 	/*
126 	 * Set effective sets privileges to 'least' required. If fails, send
127 	 * error messages to log file and proceed.
128 	 */
129 	if (pset != NULL) {
130 		priv_basicset(pset);
131 		(void) priv_addset(pset, PRIV_PROC_AUDIT);
132 		(void) priv_addset(pset, PRIV_PROC_SETID);
133 		(void) priv_addset(pset, PRIV_PROC_OWNER);
134 		(void) priv_addset(pset, PRIV_FILE_CHOWN);
135 		(void) priv_addset(pset, PRIV_FILE_CHOWN_SELF);
136 		(void) priv_addset(pset, PRIV_FILE_DAC_READ);
137 		(void) priv_addset(pset, PRIV_FILE_DAC_SEARCH);
138 		(void) priv_addset(pset, PRIV_FILE_DAC_WRITE);
139 		(void) priv_addset(pset, PRIV_FILE_OWNER);
140 		(void) priv_addset(pset, PRIV_FILE_SETID);
141 		(void) priv_addset(pset, PRIV_SYS_LINKDIR);
142 		(void) priv_addset(pset, PRIV_SYS_DEVICES);
143 		(void) priv_addset(pset, PRIV_SYS_MOUNT);
144 		(void) priv_addset(pset, PRIV_SYS_CONFIG);
145 	}
146 
147 	if (pset == NULL || setppriv(PRIV_SET, PRIV_EFFECTIVE, pset) != 0) {
148 		syslog(LOG_ERR, "Failed to set least required privileges to "
149 		    "the service.");
150 	}
151 	priv_freeset(pset);
152 
153 	/*
154 	 * Block all signals prior to the fork and leave them blocked in the
155 	 * parent so we don't get in a situation where the parent gets SIGINT
156 	 * and returns non-zero exit status and the child is actually running.
157 	 * In the child, restore the signal mask once we've done our setsid().
158 	 */
159 	(void) sigfillset(&set);
160 	(void) sigdelset(&set, SIGABRT);
161 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
162 
163 	if ((pid = fork()) == -1) {
164 		openlog(arg, LOG_PID | LOG_NDELAY, LOG_DAEMON);
165 		syslog(LOG_ERR, "Failed to start process in background.");
166 		exit(SMF_EXIT_ERR_CONFIG);
167 	}
168 
169 	/* If we're the parent process, exit. */
170 	if (pid != 0) {
171 		_exit(0);
172 	}
173 	(void) setsid();
174 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
175 	(void) chdir("/");
176 	(void) umask(0);
177 }
178 
179 static void
180 daemonize_fini(void)
181 {
182 	int fd;
183 
184 	if ((fd = open("/dev/null", O_RDWR)) >= 0) {
185 		(void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
186 		(void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
187 		(void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
188 		(void) close(fd);
189 	}
190 }
191 
192 /*
193  * main
194  *
195  * The main NDMP daemon function
196  *
197  * Parameters:
198  *   argc (input) - the argument count
199  *   argv (input) - command line options
200  *
201  * Returns:
202  *   0
203  */
204 int
205 main(int argc, char *argv[])
206 {
207 	char c;
208 	struct sigaction act;
209 	sigset_t set;
210 	void *arg = 0;
211 
212 	openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON);
213 
214 	/*
215 	 * Check for existing ndmpd door server (make sure ndmpd is not already
216 	 * running)
217 	 */
218 	if (ndmp_door_check()) {
219 		/* ndmpd is already running, exit. */
220 		return (0);
221 	}
222 
223 	/* load ENVs */
224 	if (ndmpd_load_prop()) {
225 		syslog(LOG_ERR,
226 		    "%s SMF properties initialization failed.", argv[0]);
227 		exit(SMF_EXIT_ERR_CONFIG);
228 	}
229 
230 	/* Global zone check */
231 	if (getzoneid() != GLOBAL_ZONEID) {
232 		syslog(LOG_ERR, "Local zone not supported.");
233 		exit(SMF_EXIT_ERR_FATAL);
234 	}
235 
236 	/* Trusted Solaris check */
237 	if (is_system_labeled()) {
238 		syslog(LOG_ERR, "Trusted Solaris not supported.");
239 		exit(SMF_EXIT_ERR_FATAL);
240 	}
241 
242 	opterr = 0;
243 	while ((c = getopt(argc, argv, ":d")) != -1) {
244 		switch (c) {
245 		case 'd':
246 			(void) set_debug_level(TRUE);
247 			break;
248 		default:
249 			syslog(LOG_ERR, "%s: Invalid option -%c.",
250 			    argv[0], optopt);
251 			syslog(LOG_ERR, "Usage: %s [-d]", argv[0]);
252 			exit(SMF_EXIT_ERR_CONFIG);
253 		}
254 
255 	}
256 
257 	closelog();
258 	/*
259 	 * close any open file descriptors which are greater
260 	 * than STDERR_FILENO
261 	 */
262 	closefrom(STDERR_FILENO + 1);
263 
264 	/* set up signal handler */
265 	(void) sigfillset(&set);
266 	(void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */
267 	(void) sigfillset(&act.sa_mask);
268 	act.sa_handler = ndmpd_sig_handler;
269 	act.sa_flags = 0;
270 
271 	(void) sigaction(SIGTERM, &act, NULL);
272 	(void) sigaction(SIGHUP, &act, NULL);
273 	(void) sigaction(SIGINT, &act, NULL);
274 	(void) sigaction(SIGUSR1, &act, NULL);
275 	(void) sigaction(SIGPIPE, &act, NULL);
276 	(void) sigdelset(&set, SIGTERM);
277 	(void) sigdelset(&set, SIGHUP);
278 	(void) sigdelset(&set, SIGINT);
279 	(void) sigdelset(&set, SIGUSR1);
280 	(void) sigdelset(&set, SIGPIPE);
281 
282 	(void) daemonize_init(argv[0]);
283 
284 	openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON);
285 	(void) mutex_init(&log_lock, 0, NULL);
286 
287 	if (mod_init() != 0) {
288 		syslog(LOG_ERR, "Failed to load the plugin module.");
289 		exit(SMF_EXIT_ERR_CONFIG);
290 	}
291 
292 	/* libzfs init */
293 	if ((zlibh = libzfs_init()) == NULL) {
294 		syslog(LOG_ERR, "Failed to initialize ZFS library.");
295 		exit(SMF_EXIT_ERR_CONFIG);
296 	}
297 
298 	/* initialize and start the door server */
299 	if (ndmp_door_init()) {
300 		syslog(LOG_ERR, "Can not start ndmpd door server.");
301 		exit(SMF_EXIT_ERR_CONFIG);
302 	}
303 
304 	(void) tlm_init();
305 
306 	/*
307 	 * Prior to this point, we are single-threaded. We will be
308 	 * multi-threaded from this point on.
309 	 */
310 	(void) pthread_create(NULL, NULL, (funct_t)ndmpd_main,
311 	    (void *)&arg);
312 
313 	while (!ndmpd.s_shutdown_flag) {
314 		(void) sigsuspend(&set);
315 
316 		switch (ndmpd.s_sigval) {
317 		case 0:
318 			break;
319 
320 		case SIGPIPE:
321 			break;
322 
323 		case SIGHUP:
324 			/* Refresh SMF properties */
325 			if (ndmpd_load_prop())
326 				syslog(LOG_ERR,
327 				    "Service properties initialization "
328 				    "failed.");
329 			break;
330 
331 		default:
332 			/*
333 			 * Typically SIGINT or SIGTERM.
334 			 */
335 			ndmpd.s_shutdown_flag = 1;
336 			break;
337 		}
338 
339 		ndmpd.s_sigval = 0;
340 	}
341 
342 	(void) mutex_destroy(&log_lock);
343 	libzfs_fini(zlibh);
344 	mod_fini();
345 	ndmp_door_fini();
346 	daemonize_fini();
347 	return (SMF_EXIT_OK);
348 }
349 
350 static void
351 ndmpd_sig_handler(int sig)
352 {
353 	if (ndmpd.s_sigval == 0)
354 		ndmpd.s_sigval = sig;
355 }
356 
357 /*
358  * Enable libumem debugging by default on DEBUG builds.
359  */
360 #ifdef DEBUG
361 const char *
362 _umem_debug_init(void)
363 {
364 	return ("default,verbose"); /* $UMEM_DEBUG setting */
365 }
366 
367 const char *
368 _umem_logging_init(void)
369 {
370 	return ("fail,contents"); /* $UMEM_LOGGING setting */
371 }
372 #endif
373