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