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