xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lockd/lockd.c (revision bbaa8b60dd95d714741fc474adad3cf710ef4efd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
25  * Copyright (c) 2012 by Delphix. All rights reserved.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T		*/
29 /*	  All Rights Reserved  	*/
30 
31 /*
32  * University Copyright- Copyright (c) 1982, 1986, 1988
33  * The Regents of the University of California
34  * All Rights Reserved
35  *
36  * University Acknowledgment- Portions of this document are derived from
37  * software developed by the University of California, Berkeley, and its
38  * contributors.
39  */
40 
41 /* LINTLIBRARY */
42 /* PROTOLIB1 */
43 
44 /*
45  * NLM server
46  *
47  * Most of this copied from ../nfsd/nfsd.c
48  * and then s:NFS:NLM: applied, etc.
49  */
50 
51 #include <sys/param.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <syslog.h>
55 #include <tiuser.h>
56 #include <rpc/rpc.h>
57 #include <errno.h>
58 #include <thread.h>
59 #include <sys/time.h>
60 #include <sys/file.h>
61 #include <nfs/nfs.h>
62 #include <nfs/nfssys.h>
63 #include <stdio.h>
64 #include <stdio_ext.h>
65 #include <stdlib.h>
66 #include <signal.h>
67 #include <netconfig.h>
68 #include <netdir.h>
69 #include <string.h>
70 #include <unistd.h>
71 #include <stropts.h>
72 #include <sys/tihdr.h>
73 #include <poll.h>
74 #include <priv_utils.h>
75 #include <sys/tiuser.h>
76 #include <netinet/tcp.h>
77 #include <deflt.h>
78 #include <rpcsvc/daemon_utils.h>
79 #include <rpcsvc/nlm_prot.h>
80 #include <libintl.h>
81 #include <libscf.h>
82 #include <libshare.h>
83 #include "nfs_tbind.h"
84 #include "thrpool.h"
85 #include "smfcfg.h"
86 
87 /* Option defaults.  See nfssys.h */
88 struct lm_svc_args lmargs = {
89 	.version = LM_SVC_CUR_VERS,
90 	/* fd, n_fmly, n_proto, n_rdev (below) */
91 	.debug = 0,
92 	.timout = 5 * 60,
93 	.grace = 60,
94 	.retransmittimeout = 15
95 };
96 int max_servers = 20;
97 
98 
99 #define	RET_OK		0	/* return code for no error */
100 #define	RET_ERR		33	/* return code for error(s) */
101 
102 static	int	nlmsvc(int fd, struct netbuf addrmask,
103 			struct netconfig *nconf);
104 static int nlmsvcpool(int max_servers);
105 static	void	usage(void);
106 
107 extern	int	_nfssys(int, void *);
108 static void sigterm_handler(void);
109 static void shutdown_lockd(void);
110 
111 extern int	daemonize_init(void);
112 extern void	daemonize_fini(int fd);
113 
114 static	char	*MyName;
115 
116 /*
117  * We want to bind to these TLI providers, and in this order,
118  * because the kernel NLM needs the loopback first for its
119  * initialization. (It uses it to talk to statd.)
120  */
121 static  NETSELDECL(defaultproviders)[] = {
122 	"/dev/ticotsord",
123 	"/dev/tcp",
124 	"/dev/udp",
125 	"/dev/tcp6",
126 	"/dev/udp6",
127 	NULL
128 };
129 
130 /*
131  * The following are all globals used by routines in nfs_tbind.c.
132  */
133 size_t	end_listen_fds;		/* used by conn_close_oldest() */
134 size_t	num_fds = 0;		/* used by multiple routines */
135 int	listen_backlog = 32;	/* used by bind_to_{provider,proto}() */
136 int	(*Mysvc)(int, struct netbuf, struct netconfig *) = nlmsvc;
137 				/* used by cots_listen_event() */
138 int	max_conns_allowed = -1;	/* used by cots_listen_event() */
139 
140 int
141 main(int ac, char *av[])
142 {
143 	char *propname = NULL;
144 	char *dir = "/";
145 	char *provider = (char *)NULL;
146 	struct protob *protobp;
147 	NETSELPDECL(providerp);
148 	sigset_t sgset;
149 	int i, c, pid, ret, val;
150 	int pipe_fd = -1;
151 	struct sigaction act;
152 
153 	MyName = *av;
154 
155 	/*
156 	 * Initializations that require more privileges than we need to run.
157 	 */
158 	(void) _create_daemon_lock(LOCKD, DAEMON_UID, DAEMON_GID);
159 	svcsetprio();
160 
161 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
162 	    DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS, NULL) == -1) {
163 		(void) fprintf(stderr, "%s should be run with"
164 		    " sufficient privileges\n", av[0]);
165 		exit(1);
166 	}
167 
168 	(void) enable_extended_FILE_stdio(-1, -1);
169 
170 	/*
171 	 * Read in the values from SMF first before we check
172 	 * command line options so the options override SMF values.
173 	 */
174 
175 	/* How long to keep idle connections. */
176 	propname = "conn_idle_timeout"; /* also -t */
177 	ret = nfs_smf_get_iprop(propname, &val,
178 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
179 	if (ret == SA_OK) {
180 		if (val <= 0)
181 			fprintf(stderr, gettext(
182 			    "Invalid %s from SMF"), propname);
183 		else
184 			lmargs.timout = val;
185 	}
186 
187 	/* Note: debug_level can only be set by args. */
188 
189 	/* How long to wait for clients to re-establish locks. */
190 	propname = "grace_period"; /* also -g */
191 	ret = nfs_smf_get_iprop(propname, &val,
192 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
193 	if (ret == SA_OK) {
194 		if (val <= 0)
195 			fprintf(stderr, gettext(
196 			    "Invalid %s from SMF"), propname);
197 		else
198 			lmargs.grace = val;
199 	}
200 
201 	propname = "listen_backlog"; /* also -l */
202 	ret = nfs_smf_get_iprop(propname, &val,
203 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
204 	if (ret == SA_OK) {
205 		if (val <= 0)
206 			fprintf(stderr, gettext(
207 			    "Invalid %s from SMF"), propname);
208 		else
209 			listen_backlog = val;
210 	}
211 
212 	propname = "max_connections"; /* also -c */
213 	ret = nfs_smf_get_iprop(propname, &val,
214 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
215 	if (ret == SA_OK) {
216 		if (val <= 0)
217 			fprintf(stderr, gettext(
218 			    "Invalid %s from SMF"), propname);
219 		else
220 			max_conns_allowed = val;
221 	}
222 
223 	propname = "max_servers"; /* also argv[1] */
224 	ret = nfs_smf_get_iprop(propname, &val,
225 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
226 	if (ret == SA_OK) {
227 		if (val <= 0)
228 			fprintf(stderr, gettext(
229 			    "Invalid %s from SMF"), propname);
230 		else
231 			max_servers = val;
232 	}
233 
234 	propname = "retrans_timeout"; /* also -r */
235 	ret = nfs_smf_get_iprop(propname, &val,
236 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
237 	if (ret == SA_OK) {
238 		if (val <= 0)
239 			fprintf(stderr, gettext(
240 			    "Invalid %s from SMF"), propname);
241 		else
242 			lmargs.retransmittimeout = val;
243 	}
244 
245 
246 	while ((c = getopt(ac, av, "c:d:g:l:r:t:")) != EOF)
247 		switch (c) {
248 		case 'c': /* max_connections */
249 			if ((val = atoi(optarg)) <= 0)
250 				goto badval;
251 			max_conns_allowed = val;
252 			break;
253 
254 		case 'd': /* debug */
255 			lmargs.debug = atoi(optarg);
256 			break;
257 
258 		case 'g': /* grace_period */
259 			if ((val = atoi(optarg)) <= 0)
260 				goto badval;
261 			lmargs.grace = val;
262 			break;
263 
264 		case 'l': /* listen_backlog */
265 			if ((val = atoi(optarg)) <= 0)
266 				goto badval;
267 			listen_backlog = val;
268 			break;
269 
270 		case 'r': /* retrans_timeout */
271 			if ((val = atoi(optarg)) <= 0)
272 				goto badval;
273 			lmargs.retransmittimeout = val;
274 			break;
275 
276 		case 't': /* conn_idle_timeout */
277 			if ((val = atoi(optarg)) <= 0)
278 				goto badval;
279 			lmargs.timout = val;
280 			break;
281 
282 		badval:
283 			fprintf(stderr, gettext(
284 			    "Invalid -%c option value"), c);
285 			/* FALLTHROUGH */
286 		default:
287 			usage();
288 			/* NOTREACHED */
289 		}
290 
291 	/*
292 	 * If there is exactly one more argument, it is the number of
293 	 * servers.
294 	 */
295 	if (optind < ac) {
296 		val = atoi(av[optind]);
297 		if (val <= 0) {
298 			fprintf(stderr, gettext(
299 			    "Invalid max_servers argument"));
300 			usage();
301 		}
302 		max_servers = val;
303 		optind++;
304 	}
305 	/*
306 	 * If there are two or more arguments, then this is a usage error.
307 	 */
308 	if (optind != ac)
309 		usage();
310 
311 	if (lmargs.debug) {
312 		printf("%s: debug= %d, conn_idle_timout= %d,"
313 		    " grace_period= %d, listen_backlog= %d,"
314 		    " max_connections= %d, max_servers= %d,"
315 		    " retrans_timeout= %d\n",
316 		    MyName, lmargs.debug, lmargs.timout,
317 		    lmargs.grace, listen_backlog,
318 		    max_conns_allowed, max_servers,
319 		    lmargs.retransmittimeout);
320 	}
321 
322 	/*
323 	 * Set current dir to server root
324 	 */
325 	if (chdir(dir) < 0) {
326 		(void) fprintf(stderr, "%s:  ", MyName);
327 		perror(dir);
328 		exit(1);
329 	}
330 
331 	/* Daemonize, if not debug. */
332 	if (lmargs.debug == 0)
333 		pipe_fd = daemonize_init();
334 
335 	openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
336 
337 	/*
338 	 * establish our lock on the lock file and write our pid to it.
339 	 * exit if some other process holds the lock, or if there's any
340 	 * error in writing/locking the file.
341 	 */
342 	pid = _enter_daemon_lock(LOCKD);
343 	switch (pid) {
344 	case 0:
345 		break;
346 	case -1:
347 		fprintf(stderr, "error locking for %s: %s", LOCKD,
348 		    strerror(errno));
349 		exit(2);
350 	default:
351 		/* daemon was already running */
352 		exit(0);
353 	}
354 
355 	/*
356 	 * Block all signals till we spawn other
357 	 * threads.
358 	 */
359 	(void) sigfillset(&sgset);
360 	(void) thr_sigsetmask(SIG_BLOCK, &sgset, NULL);
361 
362 	/* Unregister any previous versions. */
363 	for (i = NLM_VERS; i < NLM4_VERS; i++) {
364 		svc_unreg(NLM_PROG, i);
365 	}
366 
367 	/*
368 	 * Set up kernel RPC thread pool for the NLM server.
369 	 */
370 	if (nlmsvcpool(max_servers)) {
371 		fprintf(stderr, "Can't set up kernel NLM service: %s. Exiting",
372 		    strerror(errno));
373 		exit(1);
374 	}
375 
376 	/*
377 	 * Set up blocked thread to do LWP creation on behalf of the kernel.
378 	 */
379 	if (svcwait(NLM_SVCPOOL_ID)) {
380 		fprintf(stderr, "Can't set up NLM pool creator: %s. Exiting",
381 		    strerror(errno));
382 		exit(1);
383 	}
384 
385 	/*
386 	 * Install atexit and sigterm handlers
387 	 */
388 	act.sa_handler = sigterm_handler;
389 	act.sa_flags = 0;
390 
391 	(void) sigaction(SIGTERM, &act, NULL);
392 	(void) atexit(shutdown_lockd);
393 
394 	/*
395 	 * Now open up for signal delivery
396 	 */
397 	(void) thr_sigsetmask(SIG_UNBLOCK, &sgset, NULL);
398 
399 	/*
400 	 * Build a protocol block list for registration.
401 	 */
402 	protobp = (struct protob *)malloc(sizeof (struct protob));
403 	protobp->serv = "NLM";
404 	protobp->versmin = NLM_VERS;
405 	protobp->versmax = NLM4_VERS;
406 	protobp->program = NLM_PROG;
407 	protobp->next = (struct protob *)NULL;
408 
409 	for (providerp = defaultproviders;
410 	    *providerp != NULL; providerp++) {
411 		provider = *providerp;
412 		do_one(provider, NULL, protobp, nlmsvc);
413 	}
414 
415 	free(protobp);
416 
417 	if (num_fds == 0) {
418 		fprintf(stderr, "Could not start NLM service for any protocol."
419 		    " Exiting");
420 		exit(1);
421 	}
422 
423 	end_listen_fds = num_fds;
424 
425 	/*
426 	 * lockd is up and running as far as we are concerned.
427 	 */
428 	if (lmargs.debug == 0)
429 		daemonize_fini(pipe_fd);
430 
431 	/*
432 	 * Get rid of unneeded privileges.
433 	 */
434 	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
435 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
436 
437 	/*
438 	 * Poll for non-data control events on the transport descriptors.
439 	 */
440 	poll_for_action();
441 
442 	/*
443 	 * If we get here, something failed in poll_for_action().
444 	 */
445 	return (1);
446 }
447 
448 static int
449 nlmsvcpool(int maxservers)
450 {
451 	struct svcpool_args npa;
452 
453 	npa.id = NLM_SVCPOOL_ID;
454 	npa.maxthreads = maxservers;
455 	npa.redline = 0;
456 	npa.qsize = 0;
457 	npa.timeout = 0;
458 	npa.stksize = 0;
459 	npa.max_same_xprt = 0;
460 	return (_nfssys(SVCPOOL_CREATE, &npa));
461 }
462 
463 static int
464 ncfmly_to_lmfmly(const char *ncfmly)
465 {
466 	if (0 == strcmp(ncfmly, NC_INET))
467 		return (LM_INET);
468 	if (0 == strcmp(ncfmly, NC_INET6))
469 		return (LM_INET6);
470 	if (0 == strcmp(ncfmly, NC_LOOPBACK))
471 		return (LM_LOOPBACK);
472 	return (-1);
473 }
474 
475 static int
476 nctype_to_lmprot(uint_t semantics)
477 {
478 	switch (semantics) {
479 	case NC_TPI_CLTS:
480 		return (LM_UDP);
481 	case NC_TPI_COTS_ORD:
482 		return (LM_TCP);
483 	}
484 	return (-1);
485 }
486 
487 static dev_t
488 ncdev_to_rdev(const char *ncdev)
489 {
490 	struct stat st;
491 
492 	if (stat(ncdev, &st) < 0)
493 		return (NODEV);
494 	return (st.st_rdev);
495 }
496 
497 static void
498 sigterm_handler(void)
499 {
500 	/* to call atexit handler */
501 	exit(0);
502 }
503 
504 static void
505 shutdown_lockd(void)
506 {
507 	(void) _nfssys(KILL_LOCKMGR, NULL);
508 }
509 
510 
511 /*
512  * Establish NLM service thread.
513  */
514 static int
515 nlmsvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
516 {
517 	struct lm_svc_args lma;
518 
519 	lma = lmargs; /* init by struct copy */
520 
521 	/*
522 	 * The kernel code needs to reconstruct a complete
523 	 * knetconfig from n_fmly, n_proto.  We use these
524 	 * two fields to convey the family and semantics.
525 	 */
526 	lma.fd = fd;
527 	lma.n_fmly = ncfmly_to_lmfmly(nconf->nc_protofmly);
528 	lma.n_proto = nctype_to_lmprot(nconf->nc_semantics);
529 	lma.n_rdev = ncdev_to_rdev(nconf->nc_device);
530 
531 	return (_nfssys(LM_SVC, &lma));
532 }
533 
534 static void
535 usage(void)
536 {
537 	(void) fprintf(stderr, gettext(
538 	    "usage: %s [options] [max_servers]\n"), MyName);
539 	(void) fprintf(stderr, gettext(
540 	    "options:  (see SMF property descriptions)\n"));
541 	/* Note: don't translate these */
542 	(void) fprintf(stderr, "\t-c max_connections\n");
543 	(void) fprintf(stderr, "\t-d debug_level\n");
544 	(void) fprintf(stderr, "\t-g grace_period\n");
545 	(void) fprintf(stderr, "\t-l listen_backlog\n");
546 	(void) fprintf(stderr, "\t-r retrans_timeout\n");
547 	(void) fprintf(stderr, "\t-t conn_idle_timeout\n");
548 
549 	exit(1);
550 }
551