lockd.c revision 173281
174462Salfred/*	$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $	*/
274462Salfred/*	$FreeBSD: head/usr.sbin/rpc.lockd/lockd.c 173281 2007-11-02 14:51:53Z matteo $ */
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
4974462Salfred#include <sys/types.h>
5074462Salfred#include <sys/socket.h>
5174462Salfred
52173281Smatteo#include <netinet/in.h>
53173281Smatteo#include <arpa/inet.h>
54173281Smatteo
5530376Scharnier#include <err.h>
5674462Salfred#include <stdio.h>
5730376Scharnier#include <stdlib.h>
5874462Salfred#include <errno.h>
5974462Salfred#include <syslog.h>
6074462Salfred#include <signal.h>
6130376Scharnier#include <string.h>
6274462Salfred#include <unistd.h>
6374462Salfred#include <libutil.h>
6474462Salfred#include <netconfig.h>
65173281Smatteo#include <netdb.h>
6674462Salfred
6730376Scharnier#include <rpc/rpc.h>
68109363Smbr#include <rpc/rpc_com.h>
6974462Salfred#include <rpcsvc/sm_inter.h>
7074462Salfred
7114123Speter#include "lockd.h"
7274462Salfred#include <rpcsvc/nlm_prot.h>
7314123Speter
7474462Salfredint		debug_level = 0;	/* 0 = no debugging syslog() calls */
7574462Salfredint		_rpcsvcdirty = 0;
7614123Speter
7774462Salfredint grace_expired;
7875631Salfredint nsm_state;
7975631Salfredpid_t client_pid;
8075631Salfredstruct mon mon_host;
81173281Smatteochar **hosts, *svcport_str = NULL;
82173281Smatteoint nhosts = 0;
83173281Smatteoint xcreated = 0;
8414123Speter
85173281Smatteovoid 	create_service(struct netconfig *nconf);
8675631Salfredvoid	init_nsm(void);
8792909Salfredvoid	nlm_prog_0(struct svc_req *, SVCXPRT *);
8892909Salfredvoid	nlm_prog_1(struct svc_req *, SVCXPRT *);
8992909Salfredvoid	nlm_prog_3(struct svc_req *, SVCXPRT *);
9092909Salfredvoid	nlm_prog_4(struct svc_req *, SVCXPRT *);
91173281Smatteovoid	out_of_mem(void);
9292909Salfredvoid	usage(void);
9374462Salfred
9492909Salfredvoid sigalarm_handler(void);
9574462Salfred
9630376Scharnierint
97173281Smatteomain(int argc, char **argv)
9814123Speter{
99173281Smatteo	int ch, i, s;
100173281Smatteo	void *nc_handle;
101173281Smatteo	char *endptr, **hosts_bak;
10287096Salfred	struct sigaction sigalarm;
10374462Salfred	int grace_period = 30;
10474462Salfred	struct netconfig *nconf;
105173281Smatteo	int have_v6 = 1;
106109363Smbr	int maxrec = RPC_MAXDATASIZE;
107168324Smatteo	in_port_t svcport = 0;
10814123Speter
109173281Smatteo	while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) {
11074462Salfred		switch (ch) {
11174462Salfred		case 'd':
11274462Salfred			debug_level = atoi(optarg);
11374462Salfred			if (!debug_level) {
11474462Salfred				usage();
11574462Salfred				/* NOTREACHED */
11674462Salfred			}
11774462Salfred			break;
11874462Salfred		case 'g':
11974462Salfred			grace_period = atoi(optarg);
12074462Salfred			if (!grace_period) {
12174462Salfred				usage();
12274462Salfred				/* NOTREACHED */
12374462Salfred			}
12474462Salfred			break;
125173281Smatteo		case 'h':
126173281Smatteo			++nhosts;
127173281Smatteo			hosts_bak = hosts;
128173281Smatteo			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
129173281Smatteo			if (hosts_bak == NULL) {
130173281Smatteo				if (hosts != NULL) {
131173281Smatteo					for (i = 0; i < nhosts; i++)
132173281Smatteo						free(hosts[i]);
133173281Smatteo					free(hosts);
134173281Smatteo					out_of_mem();
135173281Smatteo				}
136173281Smatteo			}
137173281Smatteo			hosts = hosts_bak;
138173281Smatteo			hosts[nhosts - 1] = strdup(optarg);
139173281Smatteo			if (hosts[nhosts - 1] == NULL) {
140173281Smatteo				for (i = 0; i < (nhosts - 1); i++)
141173281Smatteo					free(hosts[i]);
142173281Smatteo				free(hosts);
143173281Smatteo				out_of_mem();
144173281Smatteo			}
145173281Smatteo			break;
146168324Smatteo		case 'p':
147168324Smatteo			endptr = NULL;
148168324Smatteo			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
149168324Smatteo			if (endptr == NULL || *endptr != '\0' ||
150168324Smatteo			    svcport == 0 || svcport >= IPPORT_MAX)
151168324Smatteo				usage();
152173281Smatteo			svcport_str = strdup(optarg);
153168324Smatteo			break;
15474462Salfred		default:
15574462Salfred		case '?':
15674462Salfred			usage();
15774462Salfred			/* NOTREACHED */
15874462Salfred		}
15974462Salfred	}
16074462Salfred	if (geteuid()) { /* This command allowed only to root */
16174462Salfred		fprintf(stderr, "Sorry. You are not superuser\n");
16274462Salfred		exit(1);
16374462Salfred        }
16414123Speter
16574462Salfred	(void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
16674462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
16774462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
16874462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);
16914123Speter
17074462Salfred	/*
17174462Salfred	 * Check if IPv6 support is present.
17274462Salfred	 */
17374462Salfred	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
17474462Salfred	if (s < 0)
175173281Smatteo		have_v6 = 0;
176173281Smatteo	else
17774462Salfred		close(s);
17814123Speter
179173281Smatteo	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
180168324Smatteo
181173281Smatteo	/*
182173281Smatteo	 * If no hosts were specified, add a wildcard entry to bind to
183173281Smatteo	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
184173281Smatteo	 * list.
185173281Smatteo	 */
186173281Smatteo	if (nhosts == 0) {
187173281Smatteo		hosts = malloc(sizeof(char**));
188173281Smatteo		if (hosts == NULL)
189173281Smatteo			out_of_mem();
190168324Smatteo
191173281Smatteo		hosts[0] = "*";
192173281Smatteo		nhosts = 1;
193173281Smatteo	} else {
194173281Smatteo		hosts_bak = hosts;
195173281Smatteo		if (have_v6) {
196173281Smatteo			hosts_bak = realloc(hosts, (nhosts + 2) *
197173281Smatteo			    sizeof(char *));
198173281Smatteo			if (hosts_bak == NULL) {
199173281Smatteo				for (i = 0; i < nhosts; i++)
200173281Smatteo					free(hosts[i]);
201173281Smatteo				free(hosts);
202173281Smatteo				out_of_mem();
203173281Smatteo			} else
204173281Smatteo				hosts = hosts_bak;
205109363Smbr
206173281Smatteo			nhosts += 2;
207173281Smatteo			hosts[nhosts - 2] = "::1";
208173281Smatteo		} else {
209173281Smatteo			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
210173281Smatteo			if (hosts_bak == NULL) {
211173281Smatteo				for (i = 0; i < nhosts; i++)
212173281Smatteo					free(hosts[i]);
21314123Speter
214173281Smatteo				free(hosts);
215173281Smatteo				out_of_mem();
216173281Smatteo			} else {
217173281Smatteo				nhosts += 1;
218173281Smatteo				hosts = hosts_bak;
219168324Smatteo			}
220168324Smatteo		}
221173281Smatteo		hosts[nhosts - 1] = "127.0.0.1";
222173281Smatteo	}
223168324Smatteo
224173281Smatteo	nc_handle = setnetconfig();
225173281Smatteo	while ((nconf = getnetconfig(nc_handle))) {
226173281Smatteo		/* We want to listen only on udp6, tcp6, udp, tcp transports */
227173281Smatteo		if (nconf->nc_flag & NC_VISIBLE) {
228173281Smatteo			/* Skip if there's no IPv6 support */
229173281Smatteo			if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
230173281Smatteo				/* DO NOTHING */
231173281Smatteo			} else {
232173281Smatteo				create_service(nconf);
233173281Smatteo			}
23474462Salfred		}
23574462Salfred	}
236173281Smatteo	endnetconfig(nc_handle);
23714123Speter
23874462Salfred	/*
23974462Salfred	 * Note that it is NOT sensible to run this program from inetd - the
24074462Salfred	 * protocol assumes that it will run immediately at boot time.
24174462Salfred	 */
242132254Smr	if (daemon(0, debug_level > 0)) {
24374462Salfred		err(1, "cannot fork");
24474462Salfred		/* NOTREACHED */
24574462Salfred	}
24674462Salfred
24774462Salfred	openlog("rpc.lockd", 0, LOG_DAEMON);
24874462Salfred	if (debug_level)
24974462Salfred		syslog(LOG_INFO, "Starting, debug level %d", debug_level);
25074462Salfred	else
25174462Salfred		syslog(LOG_INFO, "Starting");
25274462Salfred
25386319Salfred	sigalarm.sa_handler = (sig_t) sigalarm_handler;
25474462Salfred	sigemptyset(&sigalarm.sa_mask);
25574462Salfred	sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
25674462Salfred	sigalarm.sa_flags |= SA_RESTART;
25774462Salfred	if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
25874462Salfred		syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
25974462Salfred		    strerror(errno));
26074462Salfred		exit(1);
26174462Salfred	}
26274462Salfred	grace_expired = 0;
263161552Sthomas	alarm(grace_period);
26474462Salfred
26575631Salfred	init_nsm();
26675631Salfred
26775631Salfred	client_pid = client_request();
26875631Salfred
26974462Salfred	svc_run();		/* Should never return */
27074462Salfred	exit(1);
27114123Speter}
27230376Scharnier
273173281Smatteo/*
274173281Smatteo * This routine creates and binds sockets on the appropriate
275173281Smatteo * addresses. It gets called one time for each transport and
276173281Smatteo * registrates the service with rpcbind on that trasport.
277173281Smatteo */
27874462Salfredvoid
279173281Smatteocreate_service(struct netconfig *nconf)
280173281Smatteo{
281173281Smatteo	struct addrinfo hints, *res = NULL;
282173281Smatteo	struct sockaddr_in *sin;
283173281Smatteo	struct sockaddr_in6 *sin6;
284173281Smatteo	struct __rpc_sockinfo si;
285173281Smatteo	struct netbuf servaddr;
286173281Smatteo	SVCXPRT	*transp = NULL;
287173281Smatteo	int aicode;
288173281Smatteo	int fd;
289173281Smatteo	int nhostsbak;
290173281Smatteo	int r;
291173281Smatteo	int registered = 0;
292173281Smatteo	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
293173281Smatteo
294173281Smatteo	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
295173281Smatteo	    (nconf->nc_semantics != NC_TPI_COTS) &&
296173281Smatteo	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
297173281Smatteo		return;	/* not my type */
298173281Smatteo
299173281Smatteo	/*
300173281Smatteo	 * XXX - using RPC library internal functions.
301173281Smatteo	 */
302173281Smatteo	if (!__rpc_nconf2sockinfo(nconf, &si)) {
303173281Smatteo		syslog(LOG_ERR, "cannot get information for %s",
304173281Smatteo		    nconf->nc_netid);
305173281Smatteo		return;
306173281Smatteo	}
307173281Smatteo
308173281Smatteo	/* Get rpc.statd's address on this transport */
309173281Smatteo	memset(&hints, 0, sizeof hints);
310173281Smatteo	hints.ai_flags = AI_PASSIVE;
311173281Smatteo	hints.ai_family = si.si_af;
312173281Smatteo	hints.ai_socktype = si.si_socktype;
313173281Smatteo	hints.ai_protocol = si.si_proto;
314173281Smatteo
315173281Smatteo	/*
316173281Smatteo	 * Bind to specific IPs if asked to
317173281Smatteo	 */
318173281Smatteo	nhostsbak = nhosts;
319173281Smatteo	while (nhostsbak > 0) {
320173281Smatteo		--nhostsbak;
321173281Smatteo
322173281Smatteo		/*
323173281Smatteo		 * XXX - using RPC library internal functions.
324173281Smatteo		 */
325173281Smatteo		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
326173281Smatteo			syslog(LOG_ERR, "cannot create socket for %s",
327173281Smatteo			    nconf->nc_netid);
328173281Smatteo			continue;
329173281Smatteo		}
330173281Smatteo
331173281Smatteo		switch (hints.ai_family) {
332173281Smatteo			case AF_INET:
333173281Smatteo				if (inet_pton(AF_INET, hosts[nhostsbak],
334173281Smatteo				    host_addr) == 1) {
335173281Smatteo					hints.ai_flags &= AI_NUMERICHOST;
336173281Smatteo				} else {
337173281Smatteo					/*
338173281Smatteo					 * Skip if we have an AF_INET6 address.
339173281Smatteo					 */
340173281Smatteo					if (inet_pton(AF_INET6, hosts[nhostsbak],
341173281Smatteo					    host_addr) == 1) {
342173281Smatteo						close(fd);
343173281Smatteo						continue;
344173281Smatteo					}
345173281Smatteo				}
346173281Smatteo				break;
347173281Smatteo			case AF_INET6:
348173281Smatteo				if (inet_pton(AF_INET6, hosts[nhostsbak],
349173281Smatteo				    host_addr) == 1) {
350173281Smatteo					hints.ai_flags &= AI_NUMERICHOST;
351173281Smatteo				} else {
352173281Smatteo					/*
353173281Smatteo					 * Skip if we have an AF_INET address.
354173281Smatteo					 */
355173281Smatteo					if (inet_pton(AF_INET, hosts[nhostsbak],
356173281Smatteo					    host_addr) == 1) {
357173281Smatteo						close(fd);
358173281Smatteo						continue;
359173281Smatteo					}
360173281Smatteo				}
361173281Smatteo				break;
362173281Smatteo			default:
363173281Smatteo				break;
364173281Smatteo		}
365173281Smatteo
366173281Smatteo		/*
367173281Smatteo		 * If no hosts were specified, just bind to INADDR_ANY
368173281Smatteo		 */
369173281Smatteo		if (strcmp("*", hosts[nhostsbak]) == 0) {
370173281Smatteo			if (svcport_str == NULL) {
371173281Smatteo				res = malloc(sizeof(struct addrinfo));
372173281Smatteo				if (res == NULL)
373173281Smatteo					out_of_mem();
374173281Smatteo				res->ai_flags = hints.ai_flags;
375173281Smatteo				res->ai_family = hints.ai_family;
376173281Smatteo				res->ai_protocol = hints.ai_protocol;
377173281Smatteo				switch (res->ai_family) {
378173281Smatteo					case AF_INET:
379173281Smatteo						sin = malloc(sizeof(struct sockaddr_in));
380173281Smatteo						if (sin == NULL)
381173281Smatteo							out_of_mem();
382173281Smatteo						sin->sin_family = AF_INET;
383173281Smatteo						sin->sin_port = htons(0);
384173281Smatteo						sin->sin_addr.s_addr = htonl(INADDR_ANY);
385173281Smatteo						res->ai_addr = (struct sockaddr*) sin;
386173281Smatteo						res->ai_addrlen = (socklen_t)
387173281Smatteo						    sizeof(res->ai_addr);
388173281Smatteo						break;
389173281Smatteo					case AF_INET6:
390173281Smatteo						sin6 = malloc(sizeof(struct sockaddr_in6));
391173281Smatteo						if (res->ai_addr == NULL)
392173281Smatteo							out_of_mem();
393173281Smatteo						sin6->sin6_family = AF_INET6;
394173281Smatteo						sin6->sin6_port = htons(0);
395173281Smatteo						sin6->sin6_addr = in6addr_any;
396173281Smatteo						res->ai_addr = (struct sockaddr*) sin6;
397173281Smatteo						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
398173281Smatteo						break;
399173281Smatteo					default:
400173281Smatteo						break;
401173281Smatteo				}
402173281Smatteo			} else {
403173281Smatteo				if ((aicode = getaddrinfo(NULL, svcport_str,
404173281Smatteo				    &hints, &res)) != 0) {
405173281Smatteo					syslog(LOG_ERR,
406173281Smatteo					    "cannot get local address for %s: %s",
407173281Smatteo					    nconf->nc_netid,
408173281Smatteo					    gai_strerror(aicode));
409173281Smatteo					continue;
410173281Smatteo				}
411173281Smatteo			}
412173281Smatteo		} else {
413173281Smatteo			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
414173281Smatteo			    &hints, &res)) != 0) {
415173281Smatteo				syslog(LOG_ERR,
416173281Smatteo				    "cannot get local address for %s: %s",
417173281Smatteo				    nconf->nc_netid, gai_strerror(aicode));
418173281Smatteo				continue;
419173281Smatteo			}
420173281Smatteo		}
421173281Smatteo
422173281Smatteo		r = bindresvport_sa(fd, res->ai_addr);
423173281Smatteo		if (r != 0) {
424173281Smatteo			syslog(LOG_ERR, "bindresvport_sa: %m");
425173281Smatteo			exit(1);
426173281Smatteo		}
427173281Smatteo
428173281Smatteo		transp = svc_tli_create(fd, nconf, NULL,
429173281Smatteo		    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
430173281Smatteo
431173281Smatteo		if (transp != (SVCXPRT *) NULL) {
432173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0,
433173281Smatteo			    NULL))
434173281Smatteo				syslog(LOG_ERR,
435173281Smatteo				    "can't register %s NLM_PROG, NLM_SM service",
436173281Smatteo				    nconf->nc_netid);
437173281Smatteo
438173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1,
439173281Smatteo			    NULL))
440173281Smatteo				syslog(LOG_ERR,
441173281Smatteo				    "can't register %s NLM_PROG, NLM_VERS service",
442173281Smatteo				    nconf->nc_netid);
443173281Smatteo
444173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3,
445173281Smatteo			    NULL))
446173281Smatteo				syslog(LOG_ERR,
447173281Smatteo				    "can't register %s NLM_PROG, NLM_VERSX service",
448173281Smatteo				    nconf->nc_netid);
449173281Smatteo
450173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4,
451173281Smatteo			    NULL))
452173281Smatteo				syslog(LOG_ERR,
453173281Smatteo				    "can't register %s NLM_PROG, NLM_VERS4 service",
454173281Smatteo				    nconf->nc_netid);
455173281Smatteo
456173281Smatteo		} else
457173281Smatteo			syslog(LOG_WARNING, "can't create %s services",
458173281Smatteo			    nconf->nc_netid);
459173281Smatteo
460173281Smatteo		if (registered == 0) {
461173281Smatteo			registered = 1;
462173281Smatteo			memset(&hints, 0, sizeof hints);
463173281Smatteo			hints.ai_flags = AI_PASSIVE;
464173281Smatteo			hints.ai_family = si.si_af;
465173281Smatteo			hints.ai_socktype = si.si_socktype;
466173281Smatteo			hints.ai_protocol = si.si_proto;
467173281Smatteo
468173281Smatteo			if (svcport_str == NULL) {
469173281Smatteo				svcport_str = malloc(NI_MAXSERV * sizeof(char));
470173281Smatteo				if (svcport_str == NULL)
471173281Smatteo					out_of_mem();
472173281Smatteo
473173281Smatteo				if (getnameinfo(res->ai_addr,
474173281Smatteo				    res->ai_addr->sa_len, NULL, NI_MAXHOST,
475173281Smatteo				    svcport_str, NI_MAXSERV * sizeof(char),
476173281Smatteo				    NI_NUMERICHOST | NI_NUMERICSERV))
477173281Smatteo					errx(1, "Cannot get port number");
478173281Smatteo			}
479173281Smatteo
480173281Smatteo			if((aicode = getaddrinfo(NULL, svcport_str, &hints,
481173281Smatteo			    &res)) != 0) {
482173281Smatteo				syslog(LOG_ERR, "cannot get local address: %s",
483173281Smatteo				    gai_strerror(aicode));
484173281Smatteo				exit(1);
485173281Smatteo			}
486173281Smatteo
487173281Smatteo			servaddr.buf = malloc(res->ai_addrlen);
488173281Smatteo			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
489173281Smatteo			servaddr.len = res->ai_addrlen;
490173281Smatteo
491173281Smatteo			rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr);
492173281Smatteo			rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr);
493173281Smatteo			rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr);
494173281Smatteo			rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr);
495173281Smatteo
496173281Smatteo			xcreated++;
497173281Smatteo			freeaddrinfo(res);
498173281Smatteo		}
499173281Smatteo	} /* end while */
500173281Smatteo}
501173281Smatteo
502173281Smatteovoid
50386319Salfredsigalarm_handler(void)
50474462Salfred{
50586319Salfred
50674462Salfred	grace_expired = 1;
50774462Salfred}
50874462Salfred
50974462Salfredvoid
51030376Scharnierusage()
51130376Scharnier{
512168324Smatteo	errx(1, "usage: rpc.lockd [-d <debuglevel>]"
513173281Smatteo	    " [-g <grace period>] [-h <bindip>] [-p <port>]");
51430376Scharnier}
51575631Salfred
51675631Salfred/*
51775631Salfred * init_nsm --
51875631Salfred *	Reset the NSM state-of-the-world and acquire its state.
51975631Salfred */
52075631Salfredvoid
52175631Salfredinit_nsm(void)
52275631Salfred{
52375631Salfred	enum clnt_stat ret;
52475631Salfred	my_id id;
52575631Salfred	sm_stat stat;
52692978Salfred	char name[] = "NFS NLM";
52792978Salfred	char localhost[] = "localhost";
52875631Salfred
52975631Salfred	/*
53075631Salfred	 * !!!
53175631Salfred	 * The my_id structure isn't used by the SM_UNMON_ALL call, as far
53275631Salfred	 * as I know.  Leave it empty for now.
53375631Salfred	 */
53475631Salfred	memset(&id, 0, sizeof(id));
53592978Salfred	id.my_name = name;
53675631Salfred
53775631Salfred	/*
53875631Salfred	 * !!!
53975631Salfred	 * The statd program must already be registered when lockd runs.
54075631Salfred	 */
54175631Salfred	do {
54275631Salfred		ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
543121558Speter		    (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat);
54475631Salfred		if (ret == RPC_PROGUNAVAIL) {
545113971Sghelmer			syslog(LOG_WARNING, "%lu %s", SM_PROG,
546113971Sghelmer			    clnt_sperrno(ret));
54775631Salfred			sleep(2);
54875631Salfred			continue;
54975631Salfred		}
55075631Salfred		break;
55175631Salfred	} while (0);
55275631Salfred
55375631Salfred	if (ret != 0) {
554113971Sghelmer		syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
555113971Sghelmer		exit(1);
55675631Salfred	}
55775631Salfred
55875631Salfred	nsm_state = stat.state;
55975631Salfred
56075631Salfred	/* setup constant data for SM_MON calls */
56192978Salfred	mon_host.mon_id.my_id.my_name = localhost;
56275631Salfred	mon_host.mon_id.my_id.my_prog = NLM_PROG;
56375631Salfred	mon_host.mon_id.my_id.my_vers = NLM_SM;
56475631Salfred	mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
56575631Salfred}
566173281Smatteo
567173281Smatteo/*
568173281Smatteo * Out of memory, fatal
569173281Smatteo */
570173281Smatteovoid out_of_mem()
571173281Smatteo{
572173281Smatteo	syslog(LOG_ERR, "out of memory");
573173281Smatteo	exit(2);
574173281Smatteo}
575