xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c (revision 2654012f83cec5dc15b61dfe3e4a4915f186e7a6)
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