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