xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lockd/lockd.c (revision 4c28a617e3922d92a58e813a5b955eb526b9c386)
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 (c) 2012 by Delphix. All rights reserved.
25  * Copyright 2014 Nexenta Systems, Inc.  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 = 90,
94 	.retransmittimeout = 5
95 };
96 int max_servers = 256;
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 wait for clients to re-establish locks. */
176 	propname = "grace_period"; /* also -g */
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.grace = val;
185 	} else {
186 		syslog(LOG_ERR, "Reading of %s from SMF failed, using default "
187 		    "value", propname);
188 	}
189 
190 	propname = "lockd_listen_backlog"; /* also -l */
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 			listen_backlog = val;
199 	} else {
200 		syslog(LOG_ERR, "Reading of %s from SMF failed, using default "
201 		    "value", propname);
202 	}
203 
204 	propname = "lockd_servers"; /* also argv[1] */
205 	ret = nfs_smf_get_iprop(propname, &val,
206 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
207 	if (ret == SA_OK) {
208 		if (val <= 0)
209 			fprintf(stderr, gettext(
210 			    "Invalid %s from SMF"), propname);
211 		else
212 			max_servers = val;
213 	} else {
214 		syslog(LOG_ERR, "Reading of %s from SMF failed, using default "
215 		    "value", propname);
216 	}
217 
218 	propname = "lockd_retransmit_timeout"; /* also -t */
219 	ret = nfs_smf_get_iprop(propname, &val,
220 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, LOCKD);
221 	if (ret == SA_OK) {
222 		if (val <= 0)
223 			fprintf(stderr, gettext(
224 			    "Invalid %s from SMF"), propname);
225 		else
226 			lmargs.retransmittimeout = val;
227 	} else {
228 		syslog(LOG_ERR, "Reading of %s from SMF failed, using default "
229 		    "value", propname);
230 	}
231 
232 	while ((c = getopt(ac, av, "c:d:g:l:t:")) != EOF)
233 		switch (c) {
234 		case 'c': /* max_connections */
235 			if ((val = atoi(optarg)) <= 0)
236 				goto badval;
237 			max_conns_allowed = val;
238 			break;
239 
240 		case 'd': /* debug */
241 			lmargs.debug = atoi(optarg);
242 			break;
243 
244 		case 'g': /* grace_period */
245 			if ((val = atoi(optarg)) <= 0)
246 				goto badval;
247 			lmargs.grace = val;
248 			break;
249 
250 		case 'l': /* listen_backlog */
251 			if ((val = atoi(optarg)) <= 0)
252 				goto badval;
253 			listen_backlog = val;
254 			break;
255 
256 		case 't': /* retrans_timeout */
257 			if ((val = atoi(optarg)) <= 0)
258 				goto badval;
259 			lmargs.retransmittimeout = val;
260 			break;
261 
262 		badval:
263 			fprintf(stderr, gettext(
264 			    "Invalid -%c option value"), c);
265 			/* FALLTHROUGH */
266 		default:
267 			usage();
268 			/* NOTREACHED */
269 		}
270 
271 	/*
272 	 * If there is exactly one more argument, it is the number of
273 	 * servers.
274 	 */
275 	if (optind < ac) {
276 		val = atoi(av[optind]);
277 		if (val <= 0) {
278 			fprintf(stderr, gettext(
279 			    "Invalid max_servers argument"));
280 			usage();
281 		}
282 		max_servers = val;
283 		optind++;
284 	}
285 	/*
286 	 * If there are two or more arguments, then this is a usage error.
287 	 */
288 	if (optind != ac)
289 		usage();
290 
291 	if (lmargs.debug) {
292 		printf("%s: debug= %d, conn_idle_timout= %d,"
293 		    " grace_period= %d, listen_backlog= %d,"
294 		    " max_connections= %d, max_servers= %d,"
295 		    " retrans_timeout= %d\n",
296 		    MyName, lmargs.debug, lmargs.timout,
297 		    lmargs.grace, listen_backlog,
298 		    max_conns_allowed, max_servers,
299 		    lmargs.retransmittimeout);
300 	}
301 
302 	/*
303 	 * Set current dir to server root
304 	 */
305 	if (chdir(dir) < 0) {
306 		(void) fprintf(stderr, "%s:  ", MyName);
307 		perror(dir);
308 		exit(1);
309 	}
310 
311 	/* Daemonize, if not debug. */
312 	if (lmargs.debug == 0)
313 		pipe_fd = daemonize_init();
314 
315 	openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
316 
317 	/*
318 	 * establish our lock on the lock file and write our pid to it.
319 	 * exit if some other process holds the lock, or if there's any
320 	 * error in writing/locking the file.
321 	 */
322 	pid = _enter_daemon_lock(LOCKD);
323 	switch (pid) {
324 	case 0:
325 		break;
326 	case -1:
327 		fprintf(stderr, "error locking for %s: %s", LOCKD,
328 		    strerror(errno));
329 		exit(2);
330 	default:
331 		/* daemon was already running */
332 		exit(0);
333 	}
334 
335 	/*
336 	 * Block all signals till we spawn other
337 	 * threads.
338 	 */
339 	(void) sigfillset(&sgset);
340 	(void) thr_sigsetmask(SIG_BLOCK, &sgset, NULL);
341 
342 	/* Unregister any previous versions. */
343 	for (i = NLM_VERS; i < NLM4_VERS; i++) {
344 		svc_unreg(NLM_PROG, i);
345 	}
346 
347 	/*
348 	 * Set up kernel RPC thread pool for the NLM server.
349 	 */
350 	if (nlmsvcpool(max_servers)) {
351 		fprintf(stderr, "Can't set up kernel NLM service: %s. Exiting",
352 		    strerror(errno));
353 		exit(1);
354 	}
355 
356 	/*
357 	 * Set up blocked thread to do LWP creation on behalf of the kernel.
358 	 */
359 	if (svcwait(NLM_SVCPOOL_ID)) {
360 		fprintf(stderr, "Can't set up NLM pool creator: %s. Exiting",
361 		    strerror(errno));
362 		exit(1);
363 	}
364 
365 	/*
366 	 * Install atexit and sigterm handlers
367 	 */
368 	act.sa_handler = sigterm_handler;
369 	act.sa_flags = 0;
370 
371 	(void) sigaction(SIGTERM, &act, NULL);
372 	(void) atexit(shutdown_lockd);
373 
374 	/*
375 	 * Now open up for signal delivery
376 	 */
377 	(void) thr_sigsetmask(SIG_UNBLOCK, &sgset, NULL);
378 
379 	/*
380 	 * Build a protocol block list for registration.
381 	 */
382 	protobp = (struct protob *)malloc(sizeof (struct protob));
383 	protobp->serv = "NLM";
384 	protobp->versmin = NLM_VERS;
385 	protobp->versmax = NLM4_VERS;
386 	protobp->program = NLM_PROG;
387 	protobp->next = (struct protob *)NULL;
388 
389 	for (providerp = defaultproviders;
390 	    *providerp != NULL; providerp++) {
391 		provider = *providerp;
392 		do_one(provider, NULL, protobp, nlmsvc);
393 	}
394 
395 	free(protobp);
396 
397 	if (num_fds == 0) {
398 		fprintf(stderr, "Could not start NLM service for any protocol."
399 		    " Exiting");
400 		exit(1);
401 	}
402 
403 	end_listen_fds = num_fds;
404 
405 	/*
406 	 * lockd is up and running as far as we are concerned.
407 	 */
408 	if (lmargs.debug == 0)
409 		daemonize_fini(pipe_fd);
410 
411 	/*
412 	 * Get rid of unneeded privileges.
413 	 */
414 	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
415 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
416 
417 	/*
418 	 * Poll for non-data control events on the transport descriptors.
419 	 */
420 	poll_for_action();
421 
422 	/*
423 	 * If we get here, something failed in poll_for_action().
424 	 */
425 	return (1);
426 }
427 
428 static int
429 nlmsvcpool(int maxservers)
430 {
431 	struct svcpool_args npa;
432 
433 	npa.id = NLM_SVCPOOL_ID;
434 	npa.maxthreads = maxservers;
435 	npa.redline = 0;
436 	npa.qsize = 0;
437 	npa.timeout = 0;
438 	npa.stksize = 0;
439 	npa.max_same_xprt = 0;
440 	return (_nfssys(SVCPOOL_CREATE, &npa));
441 }
442 
443 static int
444 ncfmly_to_lmfmly(const char *ncfmly)
445 {
446 	if (0 == strcmp(ncfmly, NC_INET))
447 		return (LM_INET);
448 	if (0 == strcmp(ncfmly, NC_INET6))
449 		return (LM_INET6);
450 	if (0 == strcmp(ncfmly, NC_LOOPBACK))
451 		return (LM_LOOPBACK);
452 	return (-1);
453 }
454 
455 static int
456 nctype_to_lmprot(uint_t semantics)
457 {
458 	switch (semantics) {
459 	case NC_TPI_CLTS:
460 		return (LM_UDP);
461 	case NC_TPI_COTS_ORD:
462 		return (LM_TCP);
463 	}
464 	return (-1);
465 }
466 
467 static dev_t
468 ncdev_to_rdev(const char *ncdev)
469 {
470 	struct stat st;
471 
472 	if (stat(ncdev, &st) < 0)
473 		return (NODEV);
474 	return (st.st_rdev);
475 }
476 
477 static void
478 sigterm_handler(void)
479 {
480 	/* to call atexit handler */
481 	exit(0);
482 }
483 
484 static void
485 shutdown_lockd(void)
486 {
487 	(void) _nfssys(KILL_LOCKMGR, NULL);
488 }
489 
490 
491 /*
492  * Establish NLM service thread.
493  */
494 static int
495 nlmsvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
496 {
497 	struct lm_svc_args lma;
498 
499 	lma = lmargs; /* init by struct copy */
500 
501 	/*
502 	 * The kernel code needs to reconstruct a complete
503 	 * knetconfig from n_fmly, n_proto.  We use these
504 	 * two fields to convey the family and semantics.
505 	 */
506 	lma.fd = fd;
507 	lma.n_fmly = ncfmly_to_lmfmly(nconf->nc_protofmly);
508 	lma.n_proto = nctype_to_lmprot(nconf->nc_semantics);
509 	lma.n_rdev = ncdev_to_rdev(nconf->nc_device);
510 
511 	return (_nfssys(LM_SVC, &lma));
512 }
513 
514 static void
515 usage(void)
516 {
517 	(void) fprintf(stderr, gettext(
518 	    "usage: %s [options] [max_servers]\n"), MyName);
519 	(void) fprintf(stderr, gettext(
520 	    "options:  (see SMF property descriptions)\n"));
521 	/* Note: don't translate these */
522 	(void) fprintf(stderr, "\t-c max_connections\n");
523 	(void) fprintf(stderr, "\t-d debug_level\n");
524 	(void) fprintf(stderr, "\t-g grace_period\n");
525 	(void) fprintf(stderr, "\t-l listen_backlog\n");
526 	(void) fprintf(stderr, "\t-t retransmit_timeout\n");
527 
528 	exit(1);
529 }
530