174462Salfred/*	$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $	*/
274462Salfred/*	$FreeBSD: releng/10.3/usr.sbin/rpc.lockd/lockd.c 277859 2015-01-28 21:51:34Z rstone $ */
374462Salfred
414123Speter/*
514123Speter * Copyright (c) 1995
614123Speter *	A.R. Gordon (andrew.gordon@net-tel.co.uk).  All rights reserved.
714123Speter *
814123Speter * Redistribution and use in source and binary forms, with or without
914123Speter * modification, are permitted provided that the following conditions
1014123Speter * are met:
1114123Speter * 1. Redistributions of source code must retain the above copyright
1214123Speter *    notice, this list of conditions and the following disclaimer.
1314123Speter * 2. Redistributions in binary form must reproduce the above copyright
1414123Speter *    notice, this list of conditions and the following disclaimer in the
1514123Speter *    documentation and/or other materials provided with the distribution.
1614123Speter * 3. All advertising materials mentioning features or use of this software
1714123Speter *    must display the following acknowledgement:
1814123Speter *	This product includes software developed for the FreeBSD project
1914123Speter * 4. Neither the name of the author nor the names of any co-contributors
2014123Speter *    may be used to endorse or promote products derived from this software
2114123Speter *    without specific prior written permission.
2214123Speter *
2314123Speter * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
2414123Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2514123Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2614123Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2714123Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2814123Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2914123Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3014123Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3114123Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3214123Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3314123Speter * SUCH DAMAGE.
3414123Speter *
3514123Speter */
3614123Speter
3774462Salfred#include <sys/cdefs.h>
3830376Scharnier#ifndef lint
3974462Salfred__RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $");
4074462Salfred#endif
4114123Speter
4274462Salfred/*
4374462Salfred * main() function for NFS lock daemon.  Most of the code in this
4474462Salfred * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x.
4574462Salfred *
4674462Salfred * The actual program logic is in the file lock_proc.c
4774462Salfred */
4814123Speter
49177662Sdfr#include <sys/param.h>
50177662Sdfr#include <sys/linker.h>
51177662Sdfr#include <sys/module.h>
5274462Salfred#include <sys/socket.h>
53177633Sdfr#include <sys/stat.h>
5474462Salfred
55173281Smatteo#include <netinet/in.h>
56173281Smatteo#include <arpa/inet.h>
57173281Smatteo
5830376Scharnier#include <err.h>
5974462Salfred#include <stdio.h>
6030376Scharnier#include <stdlib.h>
6174462Salfred#include <errno.h>
6274462Salfred#include <syslog.h>
6374462Salfred#include <signal.h>
6430376Scharnier#include <string.h>
6574462Salfred#include <unistd.h>
6674462Salfred#include <libutil.h>
6774462Salfred#include <netconfig.h>
68173281Smatteo#include <netdb.h>
6974462Salfred
7030376Scharnier#include <rpc/rpc.h>
71109363Smbr#include <rpc/rpc_com.h>
7274462Salfred#include <rpcsvc/sm_inter.h>
7374462Salfred
7414123Speter#include "lockd.h"
7574462Salfred#include <rpcsvc/nlm_prot.h>
7614123Speter
77222624Srmacklem#define	GETPORT_MAXTRY	20	/* Max tries to get a port # */
78222624Srmacklem
7974462Salfredint		debug_level = 0;	/* 0 = no debugging syslog() calls */
8074462Salfredint		_rpcsvcdirty = 0;
8114123Speter
8274462Salfredint grace_expired;
8375631Salfredint nsm_state;
84177633Sdfrint kernel_lockd;
85180025Sdfrint kernel_lockd_client;
8675631Salfredpid_t client_pid;
8775631Salfredstruct mon mon_host;
88173281Smatteochar **hosts, *svcport_str = NULL;
89222624Srmacklemstatic int	mallocd_svcport = 0;
90222624Srmacklemstatic int	*sock_fd;
91222624Srmacklemstatic int	sock_fdcnt;
92222624Srmacklemstatic int	sock_fdpos;
93173281Smatteoint nhosts = 0;
94173281Smatteoint xcreated = 0;
95177633Sdfrchar **addrs;			/* actually (netid, uaddr) pairs */
96177633Sdfrint naddrs;			/* count of how many (netid, uaddr) pairs */
97216603Suqschar localhost[] = "localhost";
9814123Speter
99222624Srmacklemstatic int	create_service(struct netconfig *nconf);
100222624Srmacklemstatic void	complete_service(struct netconfig *nconf, char *port_str);
101222624Srmacklemstatic void	clearout_service(void);
102177633Sdfrvoid 	lookup_addresses(struct netconfig *nconf);
10375631Salfredvoid	init_nsm(void);
10492909Salfredvoid	nlm_prog_0(struct svc_req *, SVCXPRT *);
10592909Salfredvoid	nlm_prog_1(struct svc_req *, SVCXPRT *);
10692909Salfredvoid	nlm_prog_3(struct svc_req *, SVCXPRT *);
10792909Salfredvoid	nlm_prog_4(struct svc_req *, SVCXPRT *);
108173281Smatteovoid	out_of_mem(void);
10992909Salfredvoid	usage(void);
11074462Salfred
11192909Salfredvoid sigalarm_handler(void);
11274462Salfred
113177633Sdfr/*
114177633Sdfr * XXX move to some header file.
115177633Sdfr */
116177633Sdfr#define _PATH_RPCLOCKDSOCK	"/var/run/rpclockd.sock"
117177633Sdfr
11830376Scharnierint
119173281Smatteomain(int argc, char **argv)
12014123Speter{
121173281Smatteo	int ch, i, s;
122173281Smatteo	void *nc_handle;
123173281Smatteo	char *endptr, **hosts_bak;
12487096Salfred	struct sigaction sigalarm;
12574462Salfred	int grace_period = 30;
12674462Salfred	struct netconfig *nconf;
127173281Smatteo	int have_v6 = 1;
128109363Smbr	int maxrec = RPC_MAXDATASIZE;
129168324Smatteo	in_port_t svcport = 0;
130222624Srmacklem	int attempt_cnt, port_len, port_pos, ret;
131222624Srmacklem	char **port_list;
13214123Speter
133177662Sdfr	while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) {
13474462Salfred		switch (ch) {
13574462Salfred		case 'd':
13674462Salfred			debug_level = atoi(optarg);
13774462Salfred			if (!debug_level) {
13874462Salfred				usage();
13974462Salfred				/* NOTREACHED */
14074462Salfred			}
14174462Salfred			break;
14274462Salfred		case 'g':
14374462Salfred			grace_period = atoi(optarg);
14474462Salfred			if (!grace_period) {
14574462Salfred				usage();
14674462Salfred				/* NOTREACHED */
14774462Salfred			}
14874462Salfred			break;
149173281Smatteo		case 'h':
150173281Smatteo			++nhosts;
151173281Smatteo			hosts_bak = hosts;
152173281Smatteo			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
153173281Smatteo			if (hosts_bak == NULL) {
154173281Smatteo				if (hosts != NULL) {
155173281Smatteo					for (i = 0; i < nhosts; i++)
156173281Smatteo						free(hosts[i]);
157173281Smatteo					free(hosts);
158173281Smatteo					out_of_mem();
159173281Smatteo				}
160173281Smatteo			}
161173281Smatteo			hosts = hosts_bak;
162173281Smatteo			hosts[nhosts - 1] = strdup(optarg);
163173281Smatteo			if (hosts[nhosts - 1] == NULL) {
164173281Smatteo				for (i = 0; i < (nhosts - 1); i++)
165173281Smatteo					free(hosts[i]);
166173281Smatteo				free(hosts);
167173281Smatteo				out_of_mem();
168173281Smatteo			}
169173281Smatteo			break;
170168324Smatteo		case 'p':
171168324Smatteo			endptr = NULL;
172168324Smatteo			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
173168324Smatteo			if (endptr == NULL || *endptr != '\0' ||
174168324Smatteo			    svcport == 0 || svcport >= IPPORT_MAX)
175168324Smatteo				usage();
176173281Smatteo			svcport_str = strdup(optarg);
177168324Smatteo			break;
17874462Salfred		default:
17974462Salfred		case '?':
18074462Salfred			usage();
18174462Salfred			/* NOTREACHED */
18274462Salfred		}
18374462Salfred	}
18474462Salfred	if (geteuid()) { /* This command allowed only to root */
18574462Salfred		fprintf(stderr, "Sorry. You are not superuser\n");
18674462Salfred		exit(1);
18774462Salfred        }
18814123Speter
189177662Sdfr	kernel_lockd = FALSE;
190180025Sdfr	kernel_lockd_client = FALSE;
191177662Sdfr	if (modfind("nfslockd") < 0) {
192177662Sdfr		if (kldload("nfslockd") < 0) {
193177662Sdfr			fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n");
194178066Sdfr		} else {
195178066Sdfr			kernel_lockd = TRUE;
196177662Sdfr		}
197177662Sdfr	} else {
198177662Sdfr		kernel_lockd = TRUE;
199177662Sdfr	}
200180025Sdfr	if (kernel_lockd) {
201180025Sdfr		if (getosreldate() >= 800040)
202180025Sdfr			kernel_lockd_client = TRUE;
203180025Sdfr	}
204177662Sdfr
20574462Salfred	(void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
20674462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
20774462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
20874462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);
20914123Speter
21074462Salfred	/*
21174462Salfred	 * Check if IPv6 support is present.
21274462Salfred	 */
21374462Salfred	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
21474462Salfred	if (s < 0)
215173281Smatteo		have_v6 = 0;
216173281Smatteo	else
21774462Salfred		close(s);
21814123Speter
219173281Smatteo	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
220168324Smatteo
221173281Smatteo	/*
222173281Smatteo	 * If no hosts were specified, add a wildcard entry to bind to
223173281Smatteo	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
224173281Smatteo	 * list.
225173281Smatteo	 */
226173281Smatteo	if (nhosts == 0) {
227173281Smatteo		hosts = malloc(sizeof(char**));
228173281Smatteo		if (hosts == NULL)
229173281Smatteo			out_of_mem();
230168324Smatteo
231173281Smatteo		hosts[0] = "*";
232173281Smatteo		nhosts = 1;
233173281Smatteo	} else {
234173281Smatteo		hosts_bak = hosts;
235173281Smatteo		if (have_v6) {
236173281Smatteo			hosts_bak = realloc(hosts, (nhosts + 2) *
237173281Smatteo			    sizeof(char *));
238173281Smatteo			if (hosts_bak == NULL) {
239173281Smatteo				for (i = 0; i < nhosts; i++)
240173281Smatteo					free(hosts[i]);
241173281Smatteo				free(hosts);
242173281Smatteo				out_of_mem();
243173281Smatteo			} else
244173281Smatteo				hosts = hosts_bak;
245109363Smbr
246173281Smatteo			nhosts += 2;
247173281Smatteo			hosts[nhosts - 2] = "::1";
248173281Smatteo		} else {
249173281Smatteo			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
250173281Smatteo			if (hosts_bak == NULL) {
251173281Smatteo				for (i = 0; i < nhosts; i++)
252173281Smatteo					free(hosts[i]);
25314123Speter
254173281Smatteo				free(hosts);
255173281Smatteo				out_of_mem();
256173281Smatteo			} else {
257173281Smatteo				nhosts += 1;
258173281Smatteo				hosts = hosts_bak;
259168324Smatteo			}
260168324Smatteo		}
261173281Smatteo		hosts[nhosts - 1] = "127.0.0.1";
262173281Smatteo	}
263168324Smatteo
264177633Sdfr	if (kernel_lockd) {
265180025Sdfr		if (!kernel_lockd_client) {
266180025Sdfr			/*
267180025Sdfr			 * For the case where we have a kernel lockd but it
268180025Sdfr			 * doesn't provide client locking, we run a cut-down
269180025Sdfr			 * RPC service on a local-domain socket. The kernel's
270180025Sdfr			 * RPC server will pass what it can't handle (mainly
271180025Sdfr			 * client replies) down to us.
272180025Sdfr			 */
273180025Sdfr			struct sockaddr_un sun;
274180025Sdfr			int fd, oldmask;
275180025Sdfr			SVCXPRT *xprt;
276177633Sdfr
277180025Sdfr			memset(&sun, 0, sizeof sun);
278180025Sdfr			sun.sun_family = AF_LOCAL;
279180025Sdfr			unlink(_PATH_RPCLOCKDSOCK);
280180025Sdfr			strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK);
281180025Sdfr			sun.sun_len = SUN_LEN(&sun);
282180025Sdfr			fd = socket(AF_LOCAL, SOCK_STREAM, 0);
283180025Sdfr			if (!fd) {
284180025Sdfr				err(1, "Can't create local lockd socket");
285180025Sdfr			}
286180025Sdfr			oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
287180025Sdfr			if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) {
288180025Sdfr				err(1, "Can't bind local lockd socket");
289180025Sdfr			}
290180025Sdfr			umask(oldmask);
291180025Sdfr			if (listen(fd, SOMAXCONN) < 0) {
292180025Sdfr				err(1, "Can't listen on local lockd socket");
293180025Sdfr			}
294180025Sdfr			xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
295180025Sdfr			if (!xprt) {
296180025Sdfr				err(1, "Can't create transport for local lockd socket");
297180025Sdfr			}
298180025Sdfr			if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) {
299180025Sdfr				err(1, "Can't register service for local lockd socket");
300180025Sdfr			}
301177633Sdfr		}
302177633Sdfr
303177633Sdfr		/*
304177633Sdfr		 * We need to look up the addresses so that we can
305177633Sdfr		 * hand uaddrs (ascii encoded address+port strings) to
306177633Sdfr		 * the kernel.
307177633Sdfr		 */
308177633Sdfr		nc_handle = setnetconfig();
309177633Sdfr		while ((nconf = getnetconfig(nc_handle))) {
310177633Sdfr			/* We want to listen only on udp6, tcp6, udp, tcp transports */
311177633Sdfr			if (nconf->nc_flag & NC_VISIBLE) {
312177633Sdfr				/* Skip if there's no IPv6 support */
313177633Sdfr				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
314177633Sdfr					/* DO NOTHING */
315177633Sdfr				} else {
316177633Sdfr					lookup_addresses(nconf);
317177633Sdfr				}
318173281Smatteo			}
31974462Salfred		}
320177633Sdfr		endnetconfig(nc_handle);
321177633Sdfr	} else {
322222624Srmacklem		attempt_cnt = 1;
323222624Srmacklem		sock_fdcnt = 0;
324222624Srmacklem		sock_fd = NULL;
325222624Srmacklem		port_list = NULL;
326222624Srmacklem		port_len = 0;
327177633Sdfr		nc_handle = setnetconfig();
328177633Sdfr		while ((nconf = getnetconfig(nc_handle))) {
329177633Sdfr			/* We want to listen only on udp6, tcp6, udp, tcp transports */
330177633Sdfr			if (nconf->nc_flag & NC_VISIBLE) {
331177633Sdfr				/* Skip if there's no IPv6 support */
332177633Sdfr				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
333177633Sdfr					/* DO NOTHING */
334177633Sdfr				} else {
335222624Srmacklem					ret = create_service(nconf);
336222624Srmacklem					if (ret == 1)
337222624Srmacklem						/* Ignore this call */
338222624Srmacklem						continue;
339222624Srmacklem					if (ret < 0) {
340222624Srmacklem						/*
341222624Srmacklem						 * Failed to bind port, so close
342222624Srmacklem						 * off all sockets created and
343222624Srmacklem						 * try again if the port# was
344222624Srmacklem						 * dynamically assigned via
345222624Srmacklem						 * bind(2).
346222624Srmacklem						 */
347222624Srmacklem						clearout_service();
348222624Srmacklem						if (mallocd_svcport != 0 &&
349222624Srmacklem						    attempt_cnt <
350222624Srmacklem						    GETPORT_MAXTRY) {
351222624Srmacklem							free(svcport_str);
352222624Srmacklem							svcport_str = NULL;
353222624Srmacklem							mallocd_svcport = 0;
354222624Srmacklem						} else {
355222624Srmacklem							errno = EADDRINUSE;
356222624Srmacklem							syslog(LOG_ERR,
357222624Srmacklem							 "bindresvport_sa: %m");
358222624Srmacklem							exit(1);
359222624Srmacklem						}
360222624Srmacklem
361222624Srmacklem						/*
362222624Srmacklem						 * Start over at the first
363222624Srmacklem						 * service.
364222624Srmacklem						 */
365222624Srmacklem						free(sock_fd);
366222624Srmacklem						sock_fdcnt = 0;
367222624Srmacklem						sock_fd = NULL;
368222624Srmacklem						nc_handle = setnetconfig();
369222624Srmacklem						attempt_cnt++;
370222624Srmacklem					} else if (mallocd_svcport != 0 &&
371222624Srmacklem					    attempt_cnt == GETPORT_MAXTRY) {
372222624Srmacklem						/*
373222624Srmacklem						 * For the last attempt, allow
374222624Srmacklem						 * different port #s for each
375222624Srmacklem						 * nconf by saving the
376222624Srmacklem						 * svcport_str and setting it
377222624Srmacklem						 * back to NULL.
378222624Srmacklem						 */
379222624Srmacklem						port_list = realloc(port_list,
380222624Srmacklem						    (port_len + 1) *
381222624Srmacklem						    sizeof(char *));
382222624Srmacklem						if (port_list == NULL)
383222624Srmacklem							out_of_mem();
384222624Srmacklem						port_list[port_len++] =
385222624Srmacklem						    svcport_str;
386222624Srmacklem						svcport_str = NULL;
387222624Srmacklem						mallocd_svcport = 0;
388222624Srmacklem					}
389177633Sdfr				}
390177633Sdfr			}
391177633Sdfr		}
392222624Srmacklem
393222624Srmacklem		/*
394222624Srmacklem		 * Successfully bound the ports, so call complete_service() to
395222624Srmacklem		 * do the rest of the setup on the service(s).
396222624Srmacklem		 */
397222624Srmacklem		sock_fdpos = 0;
398222624Srmacklem		port_pos = 0;
399222624Srmacklem		nc_handle = setnetconfig();
400222624Srmacklem		while ((nconf = getnetconfig(nc_handle))) {
401222624Srmacklem			/* We want to listen only on udp6, tcp6, udp, tcp transports */
402222624Srmacklem			if (nconf->nc_flag & NC_VISIBLE) {
403222624Srmacklem				/* Skip if there's no IPv6 support */
404222624Srmacklem				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
405222624Srmacklem					/* DO NOTHING */
406222624Srmacklem				} else if (port_list != NULL) {
407222624Srmacklem					if (port_pos >= port_len) {
408222624Srmacklem						syslog(LOG_ERR,
409222624Srmacklem						    "too many port#s");
410222624Srmacklem						exit(1);
411222624Srmacklem					}
412222624Srmacklem					complete_service(nconf,
413222624Srmacklem					    port_list[port_pos++]);
414222624Srmacklem				} else
415222624Srmacklem					complete_service(nconf, svcport_str);
416222624Srmacklem			}
417222624Srmacklem		}
418177633Sdfr		endnetconfig(nc_handle);
419222624Srmacklem		free(sock_fd);
420222624Srmacklem		if (port_list != NULL) {
421222624Srmacklem			for (port_pos = 0; port_pos < port_len; port_pos++)
422222624Srmacklem				free(port_list[port_pos]);
423222624Srmacklem			free(port_list);
424222624Srmacklem		}
42574462Salfred	}
42614123Speter
42774462Salfred	/*
42874462Salfred	 * Note that it is NOT sensible to run this program from inetd - the
42974462Salfred	 * protocol assumes that it will run immediately at boot time.
43074462Salfred	 */
431132254Smr	if (daemon(0, debug_level > 0)) {
43274462Salfred		err(1, "cannot fork");
43374462Salfred		/* NOTREACHED */
43474462Salfred	}
43574462Salfred
43674462Salfred	openlog("rpc.lockd", 0, LOG_DAEMON);
43774462Salfred	if (debug_level)
43874462Salfred		syslog(LOG_INFO, "Starting, debug level %d", debug_level);
43974462Salfred	else
44074462Salfred		syslog(LOG_INFO, "Starting");
44174462Salfred
44286319Salfred	sigalarm.sa_handler = (sig_t) sigalarm_handler;
44374462Salfred	sigemptyset(&sigalarm.sa_mask);
44474462Salfred	sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
44574462Salfred	sigalarm.sa_flags |= SA_RESTART;
44674462Salfred	if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
44774462Salfred		syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
44874462Salfred		    strerror(errno));
44974462Salfred		exit(1);
45074462Salfred	}
45174462Salfred
452177633Sdfr	if (kernel_lockd) {
453180025Sdfr		if (!kernel_lockd_client) {
454180025Sdfr			init_nsm();
455180025Sdfr			client_pid = client_request();
45675631Salfred
457180025Sdfr			/*
458180025Sdfr			 * Create a child process to enter the kernel and then
459180025Sdfr			 * wait for RPCs on our local domain socket.
460180025Sdfr			 */
461180025Sdfr			if (!fork())
462180025Sdfr				nlm_syscall(debug_level, grace_period,
463180025Sdfr				    naddrs, addrs);
464180025Sdfr			else
465180025Sdfr				svc_run();
466180025Sdfr		} else {
467180025Sdfr			/*
468180025Sdfr			 * The kernel lockd implementation provides
469180025Sdfr			 * both client and server so we don't need to
470180025Sdfr			 * do anything else.
471180025Sdfr			 */
472177633Sdfr			nlm_syscall(debug_level, grace_period, naddrs, addrs);
473180025Sdfr		}
474177633Sdfr	} else {
475177633Sdfr		grace_expired = 0;
476177633Sdfr		alarm(grace_period);
47775631Salfred
478177633Sdfr		init_nsm();
479177633Sdfr
480177633Sdfr		client_pid = client_request();
481177633Sdfr
482177633Sdfr		svc_run();		/* Should never return */
483177633Sdfr	}
48474462Salfred	exit(1);
48514123Speter}
48630376Scharnier
487173281Smatteo/*
488173281Smatteo * This routine creates and binds sockets on the appropriate
489222624Srmacklem * addresses. It gets called one time for each transport.
490222624Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate
491222624Srmacklem * bind failed with EADDRINUSE.
492222624Srmacklem * Any file descriptors that have been created are stored in sock_fd and
493222624Srmacklem * the total count of them is maintained in sock_fdcnt.
494173281Smatteo */
495222624Srmacklemstatic int
496173281Smatteocreate_service(struct netconfig *nconf)
497173281Smatteo{
498173281Smatteo	struct addrinfo hints, *res = NULL;
499173281Smatteo	struct sockaddr_in *sin;
500173281Smatteo	struct sockaddr_in6 *sin6;
501173281Smatteo	struct __rpc_sockinfo si;
502173281Smatteo	int aicode;
503173281Smatteo	int fd;
504173281Smatteo	int nhostsbak;
505173281Smatteo	int r;
506173281Smatteo	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
507222624Srmacklem	int mallocd_res;
508173281Smatteo
509173281Smatteo	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
510173281Smatteo	    (nconf->nc_semantics != NC_TPI_COTS) &&
511173281Smatteo	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
512222624Srmacklem		return (1);	/* not my type */
513173281Smatteo
514173281Smatteo	/*
515173281Smatteo	 * XXX - using RPC library internal functions.
516173281Smatteo	 */
517173281Smatteo	if (!__rpc_nconf2sockinfo(nconf, &si)) {
518173281Smatteo		syslog(LOG_ERR, "cannot get information for %s",
519173281Smatteo		    nconf->nc_netid);
520222624Srmacklem		return (1);
521173281Smatteo	}
522173281Smatteo
523173281Smatteo	/* Get rpc.statd's address on this transport */
524173281Smatteo	memset(&hints, 0, sizeof hints);
525173281Smatteo	hints.ai_family = si.si_af;
526173281Smatteo	hints.ai_socktype = si.si_socktype;
527173281Smatteo	hints.ai_protocol = si.si_proto;
528173281Smatteo
529173281Smatteo	/*
530173281Smatteo	 * Bind to specific IPs if asked to
531173281Smatteo	 */
532173281Smatteo	nhostsbak = nhosts;
533173281Smatteo	while (nhostsbak > 0) {
534173281Smatteo		--nhostsbak;
535222624Srmacklem		sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
536222624Srmacklem		if (sock_fd == NULL)
537222624Srmacklem			out_of_mem();
538222624Srmacklem		sock_fd[sock_fdcnt++] = -1;	/* Set invalid for now. */
539222624Srmacklem		mallocd_res = 0;
540277859Srstone		hints.ai_flags = AI_PASSIVE;
541173281Smatteo
542173281Smatteo		/*
543173281Smatteo		 * XXX - using RPC library internal functions.
544173281Smatteo		 */
545173281Smatteo		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
546173281Smatteo			syslog(LOG_ERR, "cannot create socket for %s",
547173281Smatteo			    nconf->nc_netid);
548173281Smatteo			continue;
549173281Smatteo		}
550173281Smatteo
551173281Smatteo		switch (hints.ai_family) {
552173281Smatteo			case AF_INET:
553173281Smatteo				if (inet_pton(AF_INET, hosts[nhostsbak],
554173281Smatteo				    host_addr) == 1) {
555222624Srmacklem					hints.ai_flags |= AI_NUMERICHOST;
556173281Smatteo				} else {
557173281Smatteo					/*
558173281Smatteo					 * Skip if we have an AF_INET6 address.
559173281Smatteo					 */
560173281Smatteo					if (inet_pton(AF_INET6, hosts[nhostsbak],
561173281Smatteo					    host_addr) == 1) {
562173281Smatteo						close(fd);
563173281Smatteo						continue;
564173281Smatteo					}
565173281Smatteo				}
566173281Smatteo				break;
567173281Smatteo			case AF_INET6:
568173281Smatteo				if (inet_pton(AF_INET6, hosts[nhostsbak],
569173281Smatteo				    host_addr) == 1) {
570222624Srmacklem					hints.ai_flags |= AI_NUMERICHOST;
571173281Smatteo				} else {
572173281Smatteo					/*
573173281Smatteo					 * Skip if we have an AF_INET address.
574173281Smatteo					 */
575173281Smatteo					if (inet_pton(AF_INET, hosts[nhostsbak],
576173281Smatteo					    host_addr) == 1) {
577173281Smatteo						close(fd);
578173281Smatteo						continue;
579173281Smatteo					}
580173281Smatteo				}
581173281Smatteo				break;
582173281Smatteo			default:
583173281Smatteo				break;
584173281Smatteo		}
585173281Smatteo
586173281Smatteo		/*
587173281Smatteo		 * If no hosts were specified, just bind to INADDR_ANY
588173281Smatteo		 */
589173281Smatteo		if (strcmp("*", hosts[nhostsbak]) == 0) {
590173281Smatteo			if (svcport_str == NULL) {
591173281Smatteo				res = malloc(sizeof(struct addrinfo));
592173281Smatteo				if (res == NULL)
593173281Smatteo					out_of_mem();
594222624Srmacklem				mallocd_res = 1;
595173281Smatteo				res->ai_flags = hints.ai_flags;
596173281Smatteo				res->ai_family = hints.ai_family;
597173281Smatteo				res->ai_protocol = hints.ai_protocol;
598173281Smatteo				switch (res->ai_family) {
599173281Smatteo					case AF_INET:
600173281Smatteo						sin = malloc(sizeof(struct sockaddr_in));
601173281Smatteo						if (sin == NULL)
602173281Smatteo							out_of_mem();
603173281Smatteo						sin->sin_family = AF_INET;
604173281Smatteo						sin->sin_port = htons(0);
605173281Smatteo						sin->sin_addr.s_addr = htonl(INADDR_ANY);
606173281Smatteo						res->ai_addr = (struct sockaddr*) sin;
607173281Smatteo						res->ai_addrlen = (socklen_t)
608222624Srmacklem						    sizeof(struct sockaddr_in);
609173281Smatteo						break;
610173281Smatteo					case AF_INET6:
611173281Smatteo						sin6 = malloc(sizeof(struct sockaddr_in6));
612173411Smatteo						if (sin6 == NULL)
613173281Smatteo							out_of_mem();
614173281Smatteo						sin6->sin6_family = AF_INET6;
615173281Smatteo						sin6->sin6_port = htons(0);
616173281Smatteo						sin6->sin6_addr = in6addr_any;
617173281Smatteo						res->ai_addr = (struct sockaddr*) sin6;
618222624Srmacklem						res->ai_addrlen = (socklen_t)
619222624Srmacklem						    sizeof(struct sockaddr_in6);
620173281Smatteo						break;
621173281Smatteo					default:
622222624Srmacklem						syslog(LOG_ERR,
623222624Srmacklem						    "bad addr fam %d",
624222624Srmacklem						    res->ai_family);
625222624Srmacklem						exit(1);
626173281Smatteo				}
627173281Smatteo			} else {
628173281Smatteo				if ((aicode = getaddrinfo(NULL, svcport_str,
629173281Smatteo				    &hints, &res)) != 0) {
630173281Smatteo					syslog(LOG_ERR,
631173281Smatteo					    "cannot get local address for %s: %s",
632173281Smatteo					    nconf->nc_netid,
633173281Smatteo					    gai_strerror(aicode));
634222624Srmacklem					close(fd);
635173281Smatteo					continue;
636173281Smatteo				}
637173281Smatteo			}
638173281Smatteo		} else {
639173281Smatteo			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
640173281Smatteo			    &hints, &res)) != 0) {
641173281Smatteo				syslog(LOG_ERR,
642173281Smatteo				    "cannot get local address for %s: %s",
643173281Smatteo				    nconf->nc_netid, gai_strerror(aicode));
644222624Srmacklem				close(fd);
645173281Smatteo				continue;
646173281Smatteo			}
647173281Smatteo		}
648173281Smatteo
649222624Srmacklem
650222624Srmacklem		/* Store the fd. */
651222624Srmacklem		sock_fd[sock_fdcnt - 1] = fd;
652222624Srmacklem
653222624Srmacklem		/* Now, attempt the bind. */
654173281Smatteo		r = bindresvport_sa(fd, res->ai_addr);
655173281Smatteo		if (r != 0) {
656222624Srmacklem			if (errno == EADDRINUSE && mallocd_svcport != 0) {
657222624Srmacklem				if (mallocd_res != 0) {
658222624Srmacklem					free(res->ai_addr);
659222624Srmacklem					free(res);
660222624Srmacklem				} else
661222624Srmacklem					freeaddrinfo(res);
662222624Srmacklem				return (-1);
663222624Srmacklem			}
664173281Smatteo			syslog(LOG_ERR, "bindresvport_sa: %m");
665173281Smatteo			exit(1);
666173281Smatteo		}
667173281Smatteo
668222624Srmacklem		if (svcport_str == NULL) {
669222624Srmacklem			svcport_str = malloc(NI_MAXSERV * sizeof(char));
670222624Srmacklem			if (svcport_str == NULL)
671222624Srmacklem				out_of_mem();
672222624Srmacklem			mallocd_svcport = 1;
673222624Srmacklem
674222624Srmacklem			if (getnameinfo(res->ai_addr,
675222624Srmacklem			    res->ai_addr->sa_len, NULL, NI_MAXHOST,
676222624Srmacklem			    svcport_str, NI_MAXSERV * sizeof(char),
677222624Srmacklem			    NI_NUMERICHOST | NI_NUMERICSERV))
678222624Srmacklem				errx(1, "Cannot get port number");
679222624Srmacklem		}
680222624Srmacklem		if (mallocd_res != 0) {
681222624Srmacklem			free(res->ai_addr);
682222624Srmacklem			free(res);
683222624Srmacklem		} else
684222624Srmacklem			freeaddrinfo(res);
685222624Srmacklem		res = NULL;
686222624Srmacklem	}
687222624Srmacklem	return (0);
688222624Srmacklem}
689222624Srmacklem
690222624Srmacklem/*
691222624Srmacklem * Called after all the create_service() calls have succeeded, to complete
692222624Srmacklem * the setup and registration.
693222624Srmacklem */
694222624Srmacklemstatic void
695222624Srmacklemcomplete_service(struct netconfig *nconf, char *port_str)
696222624Srmacklem{
697222624Srmacklem	struct addrinfo hints, *res = NULL;
698222624Srmacklem	struct __rpc_sockinfo si;
699222624Srmacklem	struct netbuf servaddr;
700222624Srmacklem	SVCXPRT	*transp = NULL;
701222624Srmacklem	int aicode, fd, nhostsbak;
702222624Srmacklem	int registered = 0;
703222624Srmacklem
704222624Srmacklem	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
705222624Srmacklem	    (nconf->nc_semantics != NC_TPI_COTS) &&
706222624Srmacklem	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
707222624Srmacklem		return;	/* not my type */
708222624Srmacklem
709222624Srmacklem	/*
710222624Srmacklem	 * XXX - using RPC library internal functions.
711222624Srmacklem	 */
712222624Srmacklem	if (!__rpc_nconf2sockinfo(nconf, &si)) {
713222624Srmacklem		syslog(LOG_ERR, "cannot get information for %s",
714222624Srmacklem		    nconf->nc_netid);
715222624Srmacklem		return;
716222624Srmacklem	}
717222624Srmacklem
718222624Srmacklem	nhostsbak = nhosts;
719222624Srmacklem	while (nhostsbak > 0) {
720222624Srmacklem		--nhostsbak;
721222624Srmacklem		if (sock_fdpos >= sock_fdcnt) {
722222624Srmacklem			/* Should never happen. */
723222624Srmacklem			syslog(LOG_ERR, "Ran out of socket fd's");
724222624Srmacklem			return;
725222624Srmacklem		}
726222624Srmacklem		fd = sock_fd[sock_fdpos++];
727222624Srmacklem		if (fd < 0)
728222624Srmacklem			continue;
729222624Srmacklem
730177950Sdfr		if (nconf->nc_semantics != NC_TPI_CLTS)
731177950Sdfr		    listen(fd, SOMAXCONN);
732177950Sdfr
733173281Smatteo		transp = svc_tli_create(fd, nconf, NULL,
734173281Smatteo		    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
735173281Smatteo
736173281Smatteo		if (transp != (SVCXPRT *) NULL) {
737173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0,
738173281Smatteo			    NULL))
739173281Smatteo				syslog(LOG_ERR,
740173281Smatteo				    "can't register %s NLM_PROG, NLM_SM service",
741173281Smatteo				    nconf->nc_netid);
742173281Smatteo
743173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1,
744173281Smatteo			    NULL))
745173281Smatteo				syslog(LOG_ERR,
746173281Smatteo				    "can't register %s NLM_PROG, NLM_VERS service",
747173281Smatteo				    nconf->nc_netid);
748173281Smatteo
749173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3,
750173281Smatteo			    NULL))
751173281Smatteo				syslog(LOG_ERR,
752173281Smatteo				    "can't register %s NLM_PROG, NLM_VERSX service",
753173281Smatteo				    nconf->nc_netid);
754173281Smatteo
755173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4,
756173281Smatteo			    NULL))
757173281Smatteo				syslog(LOG_ERR,
758173281Smatteo				    "can't register %s NLM_PROG, NLM_VERS4 service",
759173281Smatteo				    nconf->nc_netid);
760173281Smatteo
761173281Smatteo		} else
762173281Smatteo			syslog(LOG_WARNING, "can't create %s services",
763173281Smatteo			    nconf->nc_netid);
764173281Smatteo
765173281Smatteo		if (registered == 0) {
766173281Smatteo			registered = 1;
767173281Smatteo			memset(&hints, 0, sizeof hints);
768173281Smatteo			hints.ai_flags = AI_PASSIVE;
769173281Smatteo			hints.ai_family = si.si_af;
770173281Smatteo			hints.ai_socktype = si.si_socktype;
771173281Smatteo			hints.ai_protocol = si.si_proto;
772173281Smatteo
773222624Srmacklem			if ((aicode = getaddrinfo(NULL, port_str, &hints,
774173281Smatteo			    &res)) != 0) {
775173281Smatteo				syslog(LOG_ERR, "cannot get local address: %s",
776173281Smatteo				    gai_strerror(aicode));
777173281Smatteo				exit(1);
778173281Smatteo			}
779173281Smatteo
780173281Smatteo			servaddr.buf = malloc(res->ai_addrlen);
781173281Smatteo			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
782173281Smatteo			servaddr.len = res->ai_addrlen;
783173281Smatteo
784173281Smatteo			rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr);
785173281Smatteo			rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr);
786173281Smatteo			rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr);
787173281Smatteo			rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr);
788173281Smatteo
789173281Smatteo			xcreated++;
790173281Smatteo			freeaddrinfo(res);
791173281Smatteo		}
792173281Smatteo	} /* end while */
793173281Smatteo}
794173281Smatteo
795177633Sdfr/*
796222624Srmacklem * Clear out sockets after a failure to bind one of them, so that the
797222624Srmacklem * cycle of socket creation/binding can start anew.
798222624Srmacklem */
799222624Srmacklemstatic void
800222624Srmacklemclearout_service(void)
801222624Srmacklem{
802222624Srmacklem	int i;
803222624Srmacklem
804222624Srmacklem	for (i = 0; i < sock_fdcnt; i++) {
805222624Srmacklem		if (sock_fd[i] >= 0) {
806222624Srmacklem			shutdown(sock_fd[i], SHUT_RDWR);
807222624Srmacklem			close(sock_fd[i]);
808222624Srmacklem		}
809222624Srmacklem	}
810222624Srmacklem}
811222624Srmacklem
812222624Srmacklem/*
813177633Sdfr * Look up addresses for the kernel to create transports for.
814177633Sdfr */
815173281Smatteovoid
816177633Sdfrlookup_addresses(struct netconfig *nconf)
817177633Sdfr{
818177633Sdfr	struct addrinfo hints, *res = NULL;
819177633Sdfr	struct sockaddr_in *sin;
820177633Sdfr	struct sockaddr_in6 *sin6;
821177633Sdfr	struct __rpc_sockinfo si;
822177633Sdfr	struct netbuf servaddr;
823177633Sdfr	int aicode;
824177633Sdfr	int nhostsbak;
825177633Sdfr	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
826177633Sdfr	char *uaddr;
827177633Sdfr
828177633Sdfr	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
829177633Sdfr	    (nconf->nc_semantics != NC_TPI_COTS) &&
830177633Sdfr	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
831177633Sdfr		return;	/* not my type */
832177633Sdfr
833177633Sdfr	/*
834177633Sdfr	 * XXX - using RPC library internal functions.
835177633Sdfr	 */
836177633Sdfr	if (!__rpc_nconf2sockinfo(nconf, &si)) {
837177633Sdfr		syslog(LOG_ERR, "cannot get information for %s",
838177633Sdfr		    nconf->nc_netid);
839177633Sdfr		return;
840177633Sdfr	}
841177633Sdfr
842177633Sdfr	/* Get rpc.statd's address on this transport */
843177633Sdfr	memset(&hints, 0, sizeof hints);
844177633Sdfr	hints.ai_flags = AI_PASSIVE;
845177633Sdfr	hints.ai_family = si.si_af;
846177633Sdfr	hints.ai_socktype = si.si_socktype;
847177633Sdfr	hints.ai_protocol = si.si_proto;
848177633Sdfr
849177633Sdfr	/*
850177633Sdfr	 * Bind to specific IPs if asked to
851177633Sdfr	 */
852177633Sdfr	nhostsbak = nhosts;
853177633Sdfr	while (nhostsbak > 0) {
854177633Sdfr		--nhostsbak;
855177633Sdfr
856177633Sdfr		switch (hints.ai_family) {
857177633Sdfr			case AF_INET:
858177633Sdfr				if (inet_pton(AF_INET, hosts[nhostsbak],
859177633Sdfr				    host_addr) == 1) {
860177633Sdfr					hints.ai_flags &= AI_NUMERICHOST;
861177633Sdfr				} else {
862177633Sdfr					/*
863177633Sdfr					 * Skip if we have an AF_INET6 address.
864177633Sdfr					 */
865177633Sdfr					if (inet_pton(AF_INET6, hosts[nhostsbak],
866177633Sdfr					    host_addr) == 1) {
867177633Sdfr						continue;
868177633Sdfr					}
869177633Sdfr				}
870177633Sdfr				break;
871177633Sdfr			case AF_INET6:
872177633Sdfr				if (inet_pton(AF_INET6, hosts[nhostsbak],
873177633Sdfr				    host_addr) == 1) {
874177633Sdfr					hints.ai_flags &= AI_NUMERICHOST;
875177633Sdfr				} else {
876177633Sdfr					/*
877177633Sdfr					 * Skip if we have an AF_INET address.
878177633Sdfr					 */
879177633Sdfr					if (inet_pton(AF_INET, hosts[nhostsbak],
880177633Sdfr					    host_addr) == 1) {
881177633Sdfr						continue;
882177633Sdfr					}
883177633Sdfr				}
884177633Sdfr				break;
885177633Sdfr			default:
886177633Sdfr				break;
887177633Sdfr		}
888177633Sdfr
889177633Sdfr		/*
890177633Sdfr		 * If no hosts were specified, just bind to INADDR_ANY
891177633Sdfr		 */
892177633Sdfr		if (strcmp("*", hosts[nhostsbak]) == 0) {
893177633Sdfr			if (svcport_str == NULL) {
894177633Sdfr				res = malloc(sizeof(struct addrinfo));
895177633Sdfr				if (res == NULL)
896177633Sdfr					out_of_mem();
897177633Sdfr				res->ai_flags = hints.ai_flags;
898177633Sdfr				res->ai_family = hints.ai_family;
899177633Sdfr				res->ai_protocol = hints.ai_protocol;
900177633Sdfr				switch (res->ai_family) {
901177633Sdfr					case AF_INET:
902177633Sdfr						sin = malloc(sizeof(struct sockaddr_in));
903177633Sdfr						if (sin == NULL)
904177633Sdfr							out_of_mem();
905177633Sdfr						sin->sin_family = AF_INET;
906177633Sdfr						sin->sin_port = htons(0);
907177633Sdfr						sin->sin_addr.s_addr = htonl(INADDR_ANY);
908177633Sdfr						res->ai_addr = (struct sockaddr*) sin;
909177633Sdfr						res->ai_addrlen = (socklen_t)
910177633Sdfr						    sizeof(res->ai_addr);
911177633Sdfr						break;
912177633Sdfr					case AF_INET6:
913177633Sdfr						sin6 = malloc(sizeof(struct sockaddr_in6));
914177633Sdfr						if (sin6 == NULL)
915177633Sdfr							out_of_mem();
916177633Sdfr						sin6->sin6_family = AF_INET6;
917177633Sdfr						sin6->sin6_port = htons(0);
918177633Sdfr						sin6->sin6_addr = in6addr_any;
919177633Sdfr						res->ai_addr = (struct sockaddr*) sin6;
920177633Sdfr						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
921177633Sdfr						break;
922177633Sdfr					default:
923177633Sdfr						break;
924177633Sdfr				}
925177633Sdfr			} else {
926177633Sdfr				if ((aicode = getaddrinfo(NULL, svcport_str,
927177633Sdfr				    &hints, &res)) != 0) {
928177633Sdfr					syslog(LOG_ERR,
929177633Sdfr					    "cannot get local address for %s: %s",
930177633Sdfr					    nconf->nc_netid,
931177633Sdfr					    gai_strerror(aicode));
932177633Sdfr					continue;
933177633Sdfr				}
934177633Sdfr			}
935177633Sdfr		} else {
936177633Sdfr			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
937177633Sdfr			    &hints, &res)) != 0) {
938177633Sdfr				syslog(LOG_ERR,
939177633Sdfr				    "cannot get local address for %s: %s",
940177633Sdfr				    nconf->nc_netid, gai_strerror(aicode));
941177633Sdfr				continue;
942177633Sdfr			}
943177633Sdfr		}
944177633Sdfr
945177633Sdfr		servaddr.len = servaddr.maxlen = res->ai_addr->sa_len;
946177633Sdfr		servaddr.buf = res->ai_addr;
947177633Sdfr		uaddr = taddr2uaddr(nconf, &servaddr);
948177633Sdfr
949177633Sdfr		addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *));
950177633Sdfr		if (!addrs)
951177633Sdfr			out_of_mem();
952177633Sdfr		addrs[2 * naddrs] = strdup(nconf->nc_netid);
953177633Sdfr		addrs[2 * naddrs + 1] = uaddr;
954177633Sdfr		naddrs++;
955177633Sdfr	} /* end while */
956177633Sdfr}
957177633Sdfr
958177633Sdfrvoid
95986319Salfredsigalarm_handler(void)
96074462Salfred{
96186319Salfred
96274462Salfred	grace_expired = 1;
96374462Salfred}
96474462Salfred
96574462Salfredvoid
96630376Scharnierusage()
96730376Scharnier{
968177666Sdfr	errx(1, "usage: rpc.lockd [-d <debuglevel>]"
969173281Smatteo	    " [-g <grace period>] [-h <bindip>] [-p <port>]");
97030376Scharnier}
97175631Salfred
97275631Salfred/*
97375631Salfred * init_nsm --
97475631Salfred *	Reset the NSM state-of-the-world and acquire its state.
97575631Salfred */
97675631Salfredvoid
97775631Salfredinit_nsm(void)
97875631Salfred{
97975631Salfred	enum clnt_stat ret;
98075631Salfred	my_id id;
98175631Salfred	sm_stat stat;
98292978Salfred	char name[] = "NFS NLM";
98375631Salfred
98475631Salfred	/*
98575631Salfred	 * !!!
98675631Salfred	 * The my_id structure isn't used by the SM_UNMON_ALL call, as far
98775631Salfred	 * as I know.  Leave it empty for now.
98875631Salfred	 */
98975631Salfred	memset(&id, 0, sizeof(id));
99092978Salfred	id.my_name = name;
99175631Salfred
99275631Salfred	/*
99375631Salfred	 * !!!
99475631Salfred	 * The statd program must already be registered when lockd runs.
99575631Salfred	 */
99675631Salfred	do {
99775631Salfred		ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
998121558Speter		    (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat);
99975631Salfred		if (ret == RPC_PROGUNAVAIL) {
1000113971Sghelmer			syslog(LOG_WARNING, "%lu %s", SM_PROG,
1001113971Sghelmer			    clnt_sperrno(ret));
100275631Salfred			sleep(2);
100375631Salfred			continue;
100475631Salfred		}
100575631Salfred		break;
100675631Salfred	} while (0);
100775631Salfred
100875631Salfred	if (ret != 0) {
1009113971Sghelmer		syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
1010113971Sghelmer		exit(1);
101175631Salfred	}
101275631Salfred
101375631Salfred	nsm_state = stat.state;
101475631Salfred
101575631Salfred	/* setup constant data for SM_MON calls */
101692978Salfred	mon_host.mon_id.my_id.my_name = localhost;
101775631Salfred	mon_host.mon_id.my_id.my_prog = NLM_PROG;
101875631Salfred	mon_host.mon_id.my_id.my_vers = NLM_SM;
101975631Salfred	mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
102075631Salfred}
1021173281Smatteo
1022173281Smatteo/*
1023173281Smatteo * Out of memory, fatal
1024173281Smatteo */
1025173281Smatteovoid out_of_mem()
1026173281Smatteo{
1027173281Smatteo	syslog(LOG_ERR, "out of memory");
1028173281Smatteo	exit(2);
1029173281Smatteo}
1030