xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c (revision a6bde1a23b60f140c7ed78df979c2e22b1ed9b2c)
1 /*
2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
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 
79 	plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
80 	if (plname == NULL || *plname == '\0')
81 		return (0);
82 
83 	if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) {
84 		NDMP_LOG(LOG_ERR, "Error loading the plug-in %s: %s",
85 		    plname, dlerror());
86 		return (0);
87 	}
88 
89 	plugin_init = (ndmp_plugin_t *(*)(int))dlsym(mod_plp, "_ndmp_init");
90 	if (plugin_init == NULL) {
91 		(void) dlclose(mod_plp);
92 		return (0);
93 	}
94 	if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) {
95 		NDMP_LOG(LOG_ERR, "Error loading the plug-in %s", plname);
96 		return (-1);
97 	}
98 	return (0);
99 }
100 
101 /*
102  * Unload
103  */
104 static void
105 mod_fini()
106 {
107 	if (ndmp_pl == NULL)
108 		return;
109 
110 	void (*plugin_fini)(ndmp_plugin_t *);
111 
112 	plugin_fini = (void (*)(ndmp_plugin_t *))dlsym(mod_plp, "_ndmp_fini");
113 	if (plugin_fini == NULL) {
114 		(void) dlclose(mod_plp);
115 		return;
116 	}
117 	plugin_fini(ndmp_pl);
118 	(void) dlclose(mod_plp);
119 }
120 
121 static void
122 set_privileges(void)
123 {
124 	priv_set_t *pset = priv_allocset();
125 
126 	/*
127 	 * Set effective sets privileges to 'least' required. If fails, send
128 	 * error messages to log file and proceed.
129 	 */
130 	if (pset != NULL) {
131 		priv_basicset(pset);
132 		(void) priv_addset(pset, PRIV_PROC_AUDIT);
133 		(void) priv_addset(pset, PRIV_PROC_SETID);
134 		(void) priv_addset(pset, PRIV_PROC_OWNER);
135 		(void) priv_addset(pset, PRIV_FILE_CHOWN);
136 		(void) priv_addset(pset, PRIV_FILE_CHOWN_SELF);
137 		(void) priv_addset(pset, PRIV_FILE_DAC_READ);
138 		(void) priv_addset(pset, PRIV_FILE_DAC_SEARCH);
139 		(void) priv_addset(pset, PRIV_FILE_DAC_WRITE);
140 		(void) priv_addset(pset, PRIV_FILE_OWNER);
141 		(void) priv_addset(pset, PRIV_FILE_SETID);
142 		(void) priv_addset(pset, PRIV_SYS_LINKDIR);
143 		(void) priv_addset(pset, PRIV_SYS_DEVICES);
144 		(void) priv_addset(pset, PRIV_SYS_MOUNT);
145 		(void) priv_addset(pset, PRIV_SYS_CONFIG);
146 	}
147 
148 	if (pset == NULL || setppriv(PRIV_SET, PRIV_EFFECTIVE, pset) != 0) {
149 		(void) fprintf(stderr,
150 		    "Failed to set least required privileges to the service\n");
151 	}
152 	priv_freeset(pset);
153 }
154 
155 static void
156 daemonize_init(void)
157 {
158 	sigset_t set, oset;
159 	pid_t pid;
160 
161 	/*
162 	 * Block all signals prior to the fork and leave them blocked in the
163 	 * parent so we don't get in a situation where the parent gets SIGINT
164 	 * and returns non-zero exit status and the child is actually running.
165 	 * In the child, restore the signal mask once we've done our setsid().
166 	 */
167 	(void) sigfillset(&set);
168 	(void) sigdelset(&set, SIGABRT);
169 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
170 
171 	if ((pid = fork()) == -1) {
172 		(void) fprintf(stderr,
173 		    "Failed to start process in background.\n");
174 		exit(SMF_EXIT_ERR_CONFIG);
175 	}
176 
177 	/* If we're the parent process, exit. */
178 	if (pid != 0) {
179 		_exit(0);
180 	}
181 	(void) setsid();
182 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
183 	(void) chdir("/");
184 }
185 
186 /*
187  * main
188  *
189  * The main NDMP daemon function
190  *
191  * Parameters:
192  *   argc (input) - the argument count
193  *   argv (input) - command line options
194  *
195  * Returns:
196  *   0
197  */
198 int
199 main(int argc, char *argv[])
200 {
201 	struct sigaction act;
202 	sigset_t set;
203 	char c;
204 	void *arg = NULL;
205 	boolean_t run_in_foreground = B_FALSE;
206 	boolean_t override_debug = B_FALSE;
207 
208 	/*
209 	 * Check for existing ndmpd door server (make sure ndmpd is not already
210 	 * running)
211 	 */
212 	if (ndmp_door_check()) {
213 		/* ndmpd is already running, exit. */
214 		(void) fprintf(stderr, "ndmpd is already running.\n");
215 		return (0);
216 	}
217 
218 	/* Global zone check */
219 	if (getzoneid() != GLOBAL_ZONEID) {
220 		(void) fprintf(stderr, "Non-global zone not supported.\n");
221 		exit(SMF_EXIT_ERR_FATAL);
222 	}
223 
224 	/* Trusted Solaris check */
225 	if (is_system_labeled()) {
226 		(void) fprintf(stderr, "Trusted Solaris not supported.\n");
227 		exit(SMF_EXIT_ERR_FATAL);
228 	}
229 
230 	/* load SMF configuration */
231 	if (ndmpd_load_prop()) {
232 		(void) fprintf(stderr,
233 		    "SMF properties initialization failed.\n");
234 		exit(SMF_EXIT_ERR_CONFIG);
235 	}
236 
237 	opterr = 0;
238 	while ((c = getopt(argc, argv, "df")) != -1) {
239 		switch (c) {
240 		case 'd':
241 			override_debug = B_TRUE;
242 			break;
243 		case 'f':
244 			run_in_foreground = B_TRUE;
245 			break;
246 		default:
247 			(void) fprintf(stderr, "%s: Invalid option -%c.\n",
248 			    argv[0], optopt);
249 			(void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
250 			exit(SMF_EXIT_ERR_CONFIG);
251 		}
252 	}
253 
254 	/* set up signal handler */
255 	(void) sigfillset(&set);
256 	(void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */
257 	(void) sigfillset(&act.sa_mask);
258 	act.sa_handler = ndmpd_sig_handler;
259 	act.sa_flags = 0;
260 
261 	(void) sigaction(SIGTERM, &act, NULL);
262 	(void) sigaction(SIGHUP, &act, NULL);
263 	(void) sigaction(SIGINT, &act, NULL);
264 	(void) sigaction(SIGUSR1, &act, NULL);
265 	(void) sigaction(SIGPIPE, &act, NULL);
266 	(void) sigdelset(&set, SIGTERM);
267 	(void) sigdelset(&set, SIGHUP);
268 	(void) sigdelset(&set, SIGINT);
269 	(void) sigdelset(&set, SIGUSR1);
270 	(void) sigdelset(&set, SIGPIPE);
271 
272 	set_privileges();
273 	(void) umask(077);
274 	openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON);
275 
276 	/*
277 	 * Open log file before we detach from terminal in case that open
278 	 * fails and error message is printed to stderr.
279 	 */
280 	if (ndmp_log_open_file(run_in_foreground, override_debug) != 0)
281 		exit(SMF_EXIT_ERR_FATAL);
282 
283 	if (!run_in_foreground)
284 		daemonize_init();
285 
286 	(void) mutex_init(&ndmpd_zfs_fd_lock, 0, NULL);
287 
288 	if (mod_init() != 0) {
289 		NDMP_LOG(LOG_ERR, "Failed to load the plugin module.");
290 		exit(SMF_EXIT_ERR_CONFIG);
291 	}
292 
293 	/* libzfs init */
294 	if ((zlibh = libzfs_init()) == NULL) {
295 		NDMP_LOG(LOG_ERR, "Failed to initialize ZFS library.");
296 		exit(SMF_EXIT_ERR_CONFIG);
297 	}
298 
299 	/* initialize and start the door server */
300 	if (ndmp_door_init()) {
301 		NDMP_LOG(LOG_ERR, "Can not start ndmpd door server.");
302 		exit(SMF_EXIT_ERR_CONFIG);
303 	}
304 
305 	if (tlm_init() == -1) {
306 		NDMP_LOG(LOG_ERR, "Failed to initialize tape manager.");
307 		exit(SMF_EXIT_ERR_CONFIG);
308 	}
309 
310 	/*
311 	 * Prior to this point, we are single-threaded. We will be
312 	 * multi-threaded from this point on.
313 	 */
314 	(void) pthread_create(NULL, NULL, (funct_t)ndmpd_main,
315 	    (void *)&arg);
316 
317 	while (!ndmpd.s_shutdown_flag) {
318 		(void) sigsuspend(&set);
319 
320 		switch (ndmpd.s_sigval) {
321 		case 0:
322 			break;
323 
324 		case SIGPIPE:
325 			break;
326 
327 		case SIGHUP:
328 			/* Refresh SMF properties */
329 			if (ndmpd_load_prop())
330 				NDMP_LOG(LOG_ERR,
331 				    "Service properties initialization "
332 				    "failed.");
333 			break;
334 
335 		default:
336 			/*
337 			 * Typically SIGINT or SIGTERM.
338 			 */
339 			ndmpd.s_shutdown_flag = 1;
340 			break;
341 		}
342 
343 		ndmpd.s_sigval = 0;
344 	}
345 
346 	(void) mutex_destroy(&ndmpd_zfs_fd_lock);
347 	libzfs_fini(zlibh);
348 	mod_fini();
349 	ndmp_door_fini();
350 	ndmp_log_close_file();
351 
352 	return (SMF_EXIT_OK);
353 }
354 
355 static void
356 ndmpd_sig_handler(int sig)
357 {
358 	if (ndmpd.s_sigval == 0)
359 		ndmpd.s_sigval = sig;
360 }
361 
362 /*
363  * Enable libumem debugging by default on DEBUG builds.
364  */
365 #ifdef DEBUG
366 const char *
367 _umem_debug_init(void)
368 {
369 	return ("default,verbose"); /* $UMEM_DEBUG setting */
370 }
371 
372 const char *
373 _umem_logging_init(void)
374 {
375 	return ("fail,contents"); /* $UMEM_LOGGING setting */
376 }
377 #endif
378