nfsd.c revision 95861
11558Srgrimes/*
21558Srgrimes * Copyright (c) 1989, 1993, 1994
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * This code is derived from software contributed to Berkeley by
61558Srgrimes * Rick Macklem at The University of Guelph.
71558Srgrimes *
81558Srgrimes * Redistribution and use in source and binary forms, with or without
91558Srgrimes * modification, are permitted provided that the following conditions
101558Srgrimes * are met:
111558Srgrimes * 1. Redistributions of source code must retain the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer.
131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141558Srgrimes *    notice, this list of conditions and the following disclaimer in the
151558Srgrimes *    documentation and/or other materials provided with the distribution.
161558Srgrimes * 3. All advertising materials mentioning features or use of this software
171558Srgrimes *    must display the following acknowledgement:
181558Srgrimes *	This product includes software developed by the University of
191558Srgrimes *	California, Berkeley and its contributors.
201558Srgrimes * 4. Neither the name of the University nor the names of its contributors
211558Srgrimes *    may be used to endorse or promote products derived from this software
221558Srgrimes *    without specific prior written permission.
231558Srgrimes *
241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341558Srgrimes * SUCH DAMAGE.
351558Srgrimes */
361558Srgrimes
371558Srgrimes#ifndef lint
3837666Scharnierstatic const char copyright[] =
391558Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\
401558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
4195861Speter#endif /* not lint */
421558Srgrimes
431558Srgrimes#ifndef lint
4437666Scharnier#if 0
4523684Speterstatic char sccsid[] = "@(#)nfsd.c	8.9 (Berkeley) 3/29/95";
4637666Scharnier#endif
4737666Scharnierstatic const char rcsid[] =
4850476Speter  "$FreeBSD: head/usr.sbin/nfsd/nfsd.c 95861 2002-05-01 06:49:43Z peter $";
4995861Speter#endif /* not lint */
501558Srgrimes
511558Srgrimes#include <sys/param.h>
521558Srgrimes#include <sys/syslog.h>
531558Srgrimes#include <sys/wait.h>
541558Srgrimes#include <sys/mount.h>
5585034Siedowse#include <sys/linker.h>
5685034Siedowse#include <sys/module.h>
571558Srgrimes
581558Srgrimes#include <rpc/rpc.h>
591558Srgrimes#include <rpc/pmap_clnt.h>
601558Srgrimes
6153096Sdillon#include <netdb.h>
6253096Sdillon#include <arpa/inet.h>
631558Srgrimes#include <nfs/rpcv2.h>
649336Sdfr#include <nfs/nfsproto.h>
6583653Speter#include <nfsserver/nfs.h>
661558Srgrimes
671558Srgrimes#include <err.h>
681558Srgrimes#include <errno.h>
6985034Siedowse#include <signal.h>
701558Srgrimes#include <stdio.h>
711558Srgrimes#include <stdlib.h>
7295861Speter#include <string.h>
731558Srgrimes#include <unistd.h>
7474462Salfred#include <netdb.h>
751558Srgrimes
761558Srgrimes/* Global defs */
771558Srgrimes#ifdef DEBUG
7893233Spb#define	syslog(e, s...)	fprintf(stderr,s)
791558Srgrimesint	debug = 1;
801558Srgrimes#else
811558Srgrimesint	debug = 0;
821558Srgrimes#endif
831558Srgrimes
841558Srgrimesstruct	nfsd_srvargs nsd;
851558Srgrimes
8674462Salfred#define	MAXNFSDCNT	20
8774462Salfred#define	DEFNFSDCNT	 4
8874462Salfredpid_t	children[MAXNFSDCNT];	/* PIDs of children */
8974462Salfredint	nfsdcnt;		/* number of children */
9074462Salfred
9174462Salfredvoid	cleanup(int);
9285034Siedowsevoid	child_cleanup(int);
9374462Salfredvoid	killchildren(void);
9485034Siedowsevoid	nfsd_exit(int);
9585034Siedowsevoid	nonfs(int);
9685034Siedowsevoid	reapchild(int);
9785034Siedowseint	setbindhost(struct addrinfo **ia, const char *bindhost,
9885034Siedowse	    struct addrinfo hints);
9985034Siedowsevoid	start_server(int);
10085034Siedowsevoid	unregistration(void);
10185034Siedowsevoid	usage(void);
1021558Srgrimes
1031558Srgrimes/*
1041558Srgrimes * Nfs server daemon mostly just a user context for nfssvc()
1051558Srgrimes *
1061558Srgrimes * 1 - do file descriptor and signal cleanup
1071558Srgrimes * 2 - fork the nfsd(s)
1081558Srgrimes * 3 - create server socket(s)
10974462Salfred * 4 - register socket with rpcbind
1101558Srgrimes *
1111558Srgrimes * For connectionless protocols, just pass the socket into the kernel via.
1121558Srgrimes * nfssvc().
1131558Srgrimes * For connection based sockets, loop doing accepts. When you get a new
1141558Srgrimes * socket from accept, pass the msgsock into the kernel via. nfssvc().
1151558Srgrimes * The arguments are:
11674462Salfred *	-r - reregister with rpcbind
11774462Salfred *	-d - unregister with rpcbind
1181558Srgrimes *	-t - support tcp nfs clients
1191558Srgrimes *	-u - support udp nfs clients
1201558Srgrimes * followed by "n" which is the number of nfsds' to fork off
1211558Srgrimes */
1221558Srgrimesint
1231558Srgrimesmain(argc, argv, envp)
1241558Srgrimes	int argc;
1251558Srgrimes	char *argv[], *envp[];
1261558Srgrimes{
1271558Srgrimes	struct nfsd_args nfsdargs;
12874462Salfred	struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
12974462Salfred	struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
13074462Salfred	struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
13174462Salfred	struct sockaddr_in inetpeer;
13274462Salfred	struct sockaddr_in6 inet6peer;
1331558Srgrimes	fd_set ready, sockbits;
13474462Salfred	fd_set v4bits, v6bits;
13583653Speter	int ch, connect_type_cnt, i, len, maxsock, msgsock;
13685034Siedowse	int on = 1, unregister, reregister, sock;
13774462Salfred	int tcp6sock, ip6flag, tcpflag, tcpsock;
13885034Siedowse	int udpflag, ecode, s, srvcnt;
13985034Siedowse	int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
14053096Sdillon	char **bindhost = NULL;
14174462Salfred	pid_t pid;
1421558Srgrimes
14383688Speter	if (modfind("nfsserver") < 0) {
14483688Speter		/* Not present in kernel, try loading it */
14583688Speter		if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
14683688Speter			errx(1, "NFS serveris not available");
1472999Swollman	}
1482999Swollman
1491558Srgrimes	nfsdcnt = DEFNFSDCNT;
15085034Siedowse	unregister = reregister = tcpflag = maxsock = 0;
15185034Siedowse	bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
15274462Salfred#define	GETOPT	"ah:n:rdtu"
15374462Salfred#define	USAGE	"[-ardtu] [-n num_servers] [-h bindip]"
15424359Simp	while ((ch = getopt(argc, argv, GETOPT)) != -1)
1551558Srgrimes		switch (ch) {
15653096Sdillon		case 'a':
15753096Sdillon			bindanyflag = 1;
15853096Sdillon			break;
1591558Srgrimes		case 'n':
1601558Srgrimes			nfsdcnt = atoi(optarg);
1611558Srgrimes			if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
16231206Sjdp				warnx("nfsd count %d; reset to %d", nfsdcnt,
16331206Sjdp				    DEFNFSDCNT);
1641558Srgrimes				nfsdcnt = DEFNFSDCNT;
1651558Srgrimes			}
1661558Srgrimes			break;
16753096Sdillon		case 'h':
16853096Sdillon			bindhostc++;
16953096Sdillon			bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
17053096Sdillon			if (bindhost == NULL)
17153096Sdillon				errx(1, "Out of memory");
17253096Sdillon			bindhost[bindhostc-1] = strdup(optarg);
17353096Sdillon			if (bindhost[bindhostc-1] == NULL)
17453096Sdillon				errx(1, "Out of memory");
17553096Sdillon			break;
1761558Srgrimes		case 'r':
1771558Srgrimes			reregister = 1;
1781558Srgrimes			break;
17974462Salfred		case 'd':
18074462Salfred			unregister = 1;
18174462Salfred			break;
1821558Srgrimes		case 't':
1831558Srgrimes			tcpflag = 1;
1841558Srgrimes			break;
1851558Srgrimes		case 'u':
1861558Srgrimes			udpflag = 1;
1871558Srgrimes			break;
1881558Srgrimes		default:
1891558Srgrimes		case '?':
1901558Srgrimes			usage();
1911558Srgrimes		};
19215496Sbde	if (!tcpflag && !udpflag)
19315496Sbde		udpflag = 1;
1941558Srgrimes	argv += optind;
1951558Srgrimes	argc -= optind;
1961558Srgrimes
1971558Srgrimes	/*
1981558Srgrimes	 * XXX
1991558Srgrimes	 * Backward compatibility, trailing number is the count of daemons.
2001558Srgrimes	 */
2011558Srgrimes	if (argc > 1)
2021558Srgrimes		usage();
2031558Srgrimes	if (argc == 1) {
2041558Srgrimes		nfsdcnt = atoi(argv[0]);
2051558Srgrimes		if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
20631206Sjdp			warnx("nfsd count %d; reset to %d", nfsdcnt,
20731206Sjdp			    DEFNFSDCNT);
2081558Srgrimes			nfsdcnt = DEFNFSDCNT;
2091558Srgrimes		}
2101558Srgrimes	}
21174800Salfred
21274462Salfred	ip6flag = 1;
21374462Salfred	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
21474800Salfred	if (s == -1) {
21574800Salfred		if (errno != EPROTONOSUPPORT)
21674800Salfred			err(1, "socket");
21774462Salfred		ip6flag = 0;
21874800Salfred	} else if (getnetconfigent("udp6") == NULL ||
21974800Salfred		getnetconfigent("tcp6") == NULL) {
22074800Salfred		ip6flag = 0;
22174800Salfred	}
22274800Salfred	if (s != -1)
22374462Salfred		close(s);
2241558Srgrimes
22553096Sdillon	if (bindhostc == 0 || bindanyflag) {
22653096Sdillon		bindhostc++;
22753096Sdillon		bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
22853096Sdillon		if (bindhost == NULL)
22953096Sdillon			errx(1, "Out of memory");
23053096Sdillon		bindhost[bindhostc-1] = strdup("*");
23153096Sdillon		if (bindhost[bindhostc-1] == NULL)
23253096Sdillon			errx(1, "Out of memory");
23353096Sdillon	}
23453096Sdillon
23574462Salfred	if (unregister) {
23674462Salfred		unregistration();
23774462Salfred		exit (0);
23874462Salfred	}
2391558Srgrimes	if (reregister) {
24074462Salfred		if (udpflag) {
24174462Salfred			memset(&hints, 0, sizeof hints);
24274462Salfred			hints.ai_flags = AI_PASSIVE;
24374462Salfred			hints.ai_family = AF_INET;
24474462Salfred			hints.ai_socktype = SOCK_DGRAM;
24574462Salfred			hints.ai_protocol = IPPROTO_UDP;
24674462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
24774800Salfred			if (ecode != 0)
24874800Salfred				err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
24974462Salfred			nconf_udp = getnetconfigent("udp");
25074462Salfred			if (nconf_udp == NULL)
25174462Salfred				err(1, "getnetconfigent udp failed");
25274462Salfred			nb_udp.buf = ai_udp->ai_addr;
25374462Salfred			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
25474462Salfred			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
25574462Salfred			    (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
25674462Salfred				err(1, "rpcb_set udp failed");
25774462Salfred			freeaddrinfo(ai_udp);
25874462Salfred		}
25974462Salfred		if (udpflag && ip6flag) {
26074462Salfred			memset(&hints, 0, sizeof hints);
26174462Salfred			hints.ai_flags = AI_PASSIVE;
26274462Salfred			hints.ai_family = AF_INET6;
26374462Salfred			hints.ai_socktype = SOCK_DGRAM;
26474462Salfred			hints.ai_protocol = IPPROTO_UDP;
26574462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
26674800Salfred			if (ecode != 0)
26774800Salfred				err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
26874462Salfred			nconf_udp6 = getnetconfigent("udp6");
26974462Salfred			if (nconf_udp6 == NULL)
27074462Salfred				err(1, "getnetconfigent udp6 failed");
27174462Salfred			nb_udp6.buf = ai_udp6->ai_addr;
27274462Salfred			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
27374462Salfred			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
27474462Salfred			    (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
27574462Salfred				err(1, "rpcb_set udp6 failed");
27674462Salfred			freeaddrinfo(ai_udp6);
27774462Salfred		}
27874462Salfred		if (tcpflag) {
27974462Salfred			memset(&hints, 0, sizeof hints);
28074462Salfred			hints.ai_flags = AI_PASSIVE;
28174462Salfred			hints.ai_family = AF_INET;
28274462Salfred			hints.ai_socktype = SOCK_STREAM;
28374462Salfred			hints.ai_protocol = IPPROTO_TCP;
28474462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
28574800Salfred			if (ecode != 0)
28674800Salfred				err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
28774462Salfred			nconf_tcp = getnetconfigent("tcp");
28874462Salfred			if (nconf_tcp == NULL)
28974462Salfred				err(1, "getnetconfigent tcp failed");
29074462Salfred			nb_tcp.buf = ai_tcp->ai_addr;
29174462Salfred			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
29274462Salfred			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) ||
29374462Salfred			    (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)))
29474462Salfred				err(1, "rpcb_set tcp failed");
29574462Salfred			freeaddrinfo(ai_tcp);
29674462Salfred		}
29774462Salfred		if (tcpflag && ip6flag) {
29874462Salfred			memset(&hints, 0, sizeof hints);
29974462Salfred			hints.ai_flags = AI_PASSIVE;
30074462Salfred			hints.ai_family = AF_INET6;
30174462Salfred			hints.ai_socktype = SOCK_STREAM;
30274462Salfred			hints.ai_protocol = IPPROTO_TCP;
30374462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
30474800Salfred			if (ecode != 0)
30574800Salfred				err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
30674462Salfred			nconf_tcp6 = getnetconfigent("tcp6");
30774462Salfred			if (nconf_tcp6 == NULL)
30874462Salfred				err(1, "getnetconfigent tcp6 failed");
30974462Salfred			nb_tcp6.buf = ai_tcp6->ai_addr;
31074462Salfred			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
31174462Salfred			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
31274462Salfred			    (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
31374462Salfred				err(1, "rpcb_set tcp6 failed");
31474462Salfred			freeaddrinfo(ai_tcp6);
31574462Salfred		}
31674462Salfred		exit (0);
3171558Srgrimes	}
31874800Salfred	if (debug == 0) {
31974800Salfred		daemon(0, 0);
32074800Salfred		(void)signal(SIGHUP, SIG_IGN);
32174800Salfred		(void)signal(SIGINT, SIG_IGN);
32274800Salfred		/*
32374800Salfred		 * nfsd sits in the kernel most of the time.  It needs
32474800Salfred		 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
32574800Salfred		 * as possible during a shutdown, otherwise loopback
32674800Salfred		 * mounts will not be able to unmount.
32774800Salfred		 */
32874800Salfred		(void)signal(SIGTERM, SIG_IGN);
32974800Salfred		(void)signal(SIGQUIT, SIG_IGN);
33074800Salfred	}
33185034Siedowse	(void)signal(SIGSYS, nonfs);
33274800Salfred	(void)signal(SIGCHLD, reapchild);
33374462Salfred
33485034Siedowse	openlog("nfsd", LOG_PID, LOG_DAEMON);
3351558Srgrimes
33685034Siedowse	/* If we use UDP only, we start the last server below. */
33785034Siedowse	srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1;
33885034Siedowse	for (i = 0; i < srvcnt; i++) {
33974462Salfred		switch ((pid = fork())) {
3401558Srgrimes		case -1:
3411558Srgrimes			syslog(LOG_ERR, "fork: %m");
34285034Siedowse			nfsd_exit(1);
3431558Srgrimes		case 0:
3441558Srgrimes			break;
3451558Srgrimes		default:
34674462Salfred			children[i] = pid;
3471558Srgrimes			continue;
3481558Srgrimes		}
34985034Siedowse		(void)signal(SIGUSR1, child_cleanup);
35085034Siedowse		setproctitle("server");
3511558Srgrimes
35285034Siedowse		start_server(0);
3531558Srgrimes	}
3541558Srgrimes
35585034Siedowse	(void)signal(SIGUSR1, cleanup);
35674462Salfred	FD_ZERO(&v4bits);
35774462Salfred	FD_ZERO(&v6bits);
35874462Salfred
35974462Salfred	rpcbregcnt = 0;
36074462Salfred	/* Set up the socket for udp and rpcb register it. */
36174462Salfred	if (udpflag) {
36274462Salfred		rpcbreg = 0;
36374462Salfred		for (i = 0; i < bindhostc; i++) {
36474462Salfred			memset(&hints, 0, sizeof hints);
36574462Salfred			hints.ai_flags = AI_PASSIVE;
36674462Salfred			hints.ai_family = AF_INET;
36774462Salfred			hints.ai_socktype = SOCK_DGRAM;
36874462Salfred			hints.ai_protocol = IPPROTO_UDP;
36974462Salfred			if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
37074462Salfred				rpcbreg = 1;
37174462Salfred				rpcbregcnt++;
37274462Salfred				if ((sock = socket(ai_udp->ai_family,
37374462Salfred				    ai_udp->ai_socktype,
37474462Salfred				    ai_udp->ai_protocol)) < 0) {
37574462Salfred					syslog(LOG_ERR,
37674462Salfred					    "can't create udp socket");
37785034Siedowse					nfsd_exit(1);
37874462Salfred				}
37974462Salfred				if (bind(sock, ai_udp->ai_addr,
38074462Salfred				    ai_udp->ai_addrlen) < 0) {
38174462Salfred					syslog(LOG_ERR,
38274462Salfred					    "can't bind udp addr %s: %m",
38374462Salfred					    bindhost[i]);
38485034Siedowse					nfsd_exit(1);
38574462Salfred				}
38674462Salfred				freeaddrinfo(ai_udp);
38774462Salfred				nfsdargs.sock = sock;
38874462Salfred				nfsdargs.name = NULL;
38974462Salfred				nfsdargs.namelen = 0;
39074462Salfred				if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
39174462Salfred					syslog(LOG_ERR, "can't Add UDP socket");
39285034Siedowse					nfsd_exit(1);
39374462Salfred				}
39474462Salfred				(void)close(sock);
39574462Salfred			}
3961558Srgrimes		}
39774462Salfred		if (rpcbreg == 1) {
39874462Salfred			memset(&hints, 0, sizeof hints);
39974462Salfred			hints.ai_flags = AI_PASSIVE;
40074462Salfred			hints.ai_family = AF_INET;
40174462Salfred			hints.ai_socktype = SOCK_DGRAM;
40274462Salfred			hints.ai_protocol = IPPROTO_UDP;
40374462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
40474462Salfred			if (ecode != 0) {
40574462Salfred				syslog(LOG_ERR, "getaddrinfo udp: %s",
40674462Salfred				   gai_strerror(ecode));
40785034Siedowse				nfsd_exit(1);
40874462Salfred			}
40974462Salfred			nconf_udp = getnetconfigent("udp");
41074462Salfred			if (nconf_udp == NULL)
41174462Salfred				err(1, "getnetconfigent udp failed");
41274462Salfred			nb_udp.buf = ai_udp->ai_addr;
41374462Salfred			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
41474462Salfred			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
41574462Salfred			    (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
41674462Salfred				err(1, "rpcb_set udp failed");
41774462Salfred			freeaddrinfo(ai_udp);
4181558Srgrimes		}
4191558Srgrimes	}
4201558Srgrimes
42174462Salfred	/* Set up the socket for udp6 and rpcb register it. */
42274462Salfred	if (udpflag && ip6flag) {
42374462Salfred		rpcbreg = 0;
42474462Salfred		for (i = 0; i < bindhostc; i++) {
42574462Salfred			memset(&hints, 0, sizeof hints);
42674462Salfred			hints.ai_flags = AI_PASSIVE;
42774462Salfred			hints.ai_family = AF_INET6;
42874462Salfred			hints.ai_socktype = SOCK_DGRAM;
42974462Salfred			hints.ai_protocol = IPPROTO_UDP;
43074462Salfred			if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
43174462Salfred				rpcbreg = 1;
43274462Salfred				rpcbregcnt++;
43374462Salfred				if ((sock = socket(ai_udp6->ai_family,
43474462Salfred				    ai_udp6->ai_socktype,
43574462Salfred				    ai_udp6->ai_protocol)) < 0) {
43674462Salfred					syslog(LOG_ERR,
43774462Salfred						"can't create udp6 socket");
43885034Siedowse					nfsd_exit(1);
43974462Salfred				}
44074462Salfred				if (setsockopt(sock, IPPROTO_IPV6,
44174462Salfred				    IPV6_BINDV6ONLY,
44274462Salfred				    &on, sizeof on) < 0) {
44374462Salfred					syslog(LOG_ERR,
44474462Salfred					    "can't set v6-only binding for "
44574462Salfred					    "udp6 socket: %m");
44685034Siedowse					nfsd_exit(1);
44774462Salfred				}
44874462Salfred				if (bind(sock, ai_udp6->ai_addr,
44974462Salfred				    ai_udp6->ai_addrlen) < 0) {
45074462Salfred					syslog(LOG_ERR,
45174462Salfred					    "can't bind udp6 addr %s: %m",
45274462Salfred					    bindhost[i]);
45385034Siedowse					nfsd_exit(1);
45474462Salfred				}
45574462Salfred				freeaddrinfo(ai_udp6);
45674462Salfred				nfsdargs.sock = sock;
45774462Salfred				nfsdargs.name = NULL;
45874462Salfred				nfsdargs.namelen = 0;
45974462Salfred				if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
46074462Salfred					syslog(LOG_ERR,
46174462Salfred					    "can't add UDP6 socket");
46285034Siedowse					nfsd_exit(1);
46374462Salfred				}
46474462Salfred				(void)close(sock);
46574462Salfred			}
4661558Srgrimes		}
46774462Salfred		if (rpcbreg == 1) {
46874462Salfred			memset(&hints, 0, sizeof hints);
46974462Salfred			hints.ai_flags = AI_PASSIVE;
47074462Salfred			hints.ai_family = AF_INET6;
47174462Salfred			hints.ai_socktype = SOCK_DGRAM;
47274462Salfred			hints.ai_protocol = IPPROTO_UDP;
47374462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
47474462Salfred			if (ecode != 0) {
47574462Salfred				syslog(LOG_ERR, "getaddrinfo udp6: %s",
47674462Salfred				   gai_strerror(ecode));
47785034Siedowse				nfsd_exit(1);
47874462Salfred			}
47974462Salfred			nconf_udp6 = getnetconfigent("udp6");
48074462Salfred			if (nconf_udp6 == NULL)
48174462Salfred				err(1, "getnetconfigent udp6 failed");
48274462Salfred			nb_udp6.buf = ai_udp6->ai_addr;
48374462Salfred			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
48474462Salfred			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
48574462Salfred			    (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
48674462Salfred				err(1, "rpcb_set udp6 failed");
48774462Salfred			freeaddrinfo(ai_udp6);
4881558Srgrimes		}
4891558Srgrimes	}
4901558Srgrimes
49174462Salfred	/* Set up the socket for tcp and rpcb register it. */
49274462Salfred	if (tcpflag) {
49374462Salfred		rpcbreg = 0;
49474462Salfred		for (i = 0; i < bindhostc; i++) {
49574462Salfred			memset(&hints, 0, sizeof hints);
49674462Salfred			hints.ai_flags = AI_PASSIVE;
49774462Salfred			hints.ai_family = AF_INET;
49874462Salfred			hints.ai_socktype = SOCK_STREAM;
49974462Salfred			hints.ai_protocol = IPPROTO_TCP;
50074462Salfred			if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
50174462Salfred				rpcbreg = 1;
50274462Salfred				rpcbregcnt++;
50374462Salfred				if ((tcpsock = socket(AF_INET, SOCK_STREAM,
50474462Salfred				    0)) < 0) {
50574462Salfred					syslog(LOG_ERR,
50674462Salfred					    "can't create tpc socket");
50785034Siedowse					nfsd_exit(1);
50874462Salfred				}
50974462Salfred				if (setsockopt(tcpsock, SOL_SOCKET,
51074462Salfred				    SO_REUSEADDR,
51174462Salfred				    (char *)&on, sizeof(on)) < 0)
51274462Salfred					syslog(LOG_ERR,
51374462Salfred					     "setsockopt SO_REUSEADDR: %m");
51474462Salfred				if (bind(tcpsock, ai_tcp->ai_addr,
51574462Salfred				    ai_tcp->ai_addrlen) < 0) {
51674462Salfred					syslog(LOG_ERR,
51774462Salfred					    "can't bind tcp addr %s: %m",
51874462Salfred					    bindhost[i]);
51985034Siedowse					nfsd_exit(1);
52074462Salfred				}
52174462Salfred				if (listen(tcpsock, 5) < 0) {
52274462Salfred					syslog(LOG_ERR, "listen failed");
52385034Siedowse					nfsd_exit(1);
52474462Salfred				}
52574462Salfred				freeaddrinfo(ai_tcp);
52674462Salfred				FD_SET(tcpsock, &sockbits);
52774462Salfred				FD_SET(tcpsock, &v4bits);
52874462Salfred				maxsock = tcpsock;
52974462Salfred				connect_type_cnt++;
53074462Salfred			}
5311558Srgrimes		}
53274462Salfred		if (rpcbreg == 1) {
53374462Salfred			memset(&hints, 0, sizeof hints);
53474462Salfred			hints.ai_flags = AI_PASSIVE;
53574462Salfred			hints.ai_family = AF_INET;
53674462Salfred			hints.ai_socktype = SOCK_STREAM;
53774462Salfred			hints.ai_protocol = IPPROTO_TCP;
53874462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints,
53974462Salfred			     &ai_tcp);
54074462Salfred			if (ecode != 0) {
54174462Salfred				syslog(LOG_ERR, "getaddrinfo tcp: %s",
54274462Salfred				   gai_strerror(ecode));
54385034Siedowse				nfsd_exit(1);
54474462Salfred			}
54574462Salfred			nconf_tcp = getnetconfigent("tcp");
54674462Salfred			if (nconf_tcp == NULL)
54774462Salfred				err(1, "getnetconfigent tcp failed");
54874462Salfred			nb_tcp.buf = ai_tcp->ai_addr;
54974462Salfred			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
55074462Salfred			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp,
55174462Salfred			    &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3,
55274462Salfred			    nconf_tcp, &nb_tcp)))
55374462Salfred				err(1, "rpcb_set tcp failed");
55474462Salfred			freeaddrinfo(ai_tcp);
5551558Srgrimes		}
5561558Srgrimes	}
5571558Srgrimes
55874462Salfred	/* Set up the socket for tcp6 and rpcb register it. */
55974462Salfred	if (tcpflag && ip6flag) {
56074462Salfred		rpcbreg = 0;
56174462Salfred		for (i = 0; i < bindhostc; i++) {
56274462Salfred			memset(&hints, 0, sizeof hints);
56374462Salfred			hints.ai_flags = AI_PASSIVE;
56474462Salfred			hints.ai_family = AF_INET6;
56574462Salfred			hints.ai_socktype = SOCK_STREAM;
56674462Salfred			hints.ai_protocol = IPPROTO_TCP;
56774462Salfred			if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
56874462Salfred				rpcbreg = 1;
56974462Salfred				rpcbregcnt++;
57074462Salfred				if ((tcp6sock = socket(ai_tcp6->ai_family,
57174462Salfred				    ai_tcp6->ai_socktype,
57274462Salfred				    ai_tcp6->ai_protocol)) < 0) {
57374462Salfred					syslog(LOG_ERR,
57474462Salfred					    "can't create tcp6 socket");
57585034Siedowse					nfsd_exit(1);
57674462Salfred				}
57774462Salfred				if (setsockopt(tcp6sock, SOL_SOCKET,
57874462Salfred				    SO_REUSEADDR,
57974462Salfred				    (char *)&on, sizeof(on)) < 0)
58074462Salfred					syslog(LOG_ERR,
58174462Salfred					    "setsockopt SO_REUSEADDR: %m");
58274462Salfred				if (setsockopt(tcp6sock, IPPROTO_IPV6,
58374462Salfred				    IPV6_BINDV6ONLY, &on, sizeof on) < 0) {
58474462Salfred					syslog(LOG_ERR,
58574462Salfred					"can't set v6-only binding for tcp6 "
58674462Salfred					    "socket: %m");
58785034Siedowse					nfsd_exit(1);
58874462Salfred				}
58974462Salfred				if (bind(tcp6sock, ai_tcp6->ai_addr,
59074462Salfred				    ai_tcp6->ai_addrlen) < 0) {
59174462Salfred					syslog(LOG_ERR,
59274462Salfred					    "can't bind tcp6 addr %s: %m",
59374462Salfred					    bindhost[i]);
59485034Siedowse					nfsd_exit(1);
59574462Salfred				}
59674462Salfred				if (listen(tcp6sock, 5) < 0) {
59774462Salfred					syslog(LOG_ERR, "listen failed");
59885034Siedowse					nfsd_exit(1);
59974462Salfred				}
60074462Salfred				freeaddrinfo(ai_tcp6);
60174462Salfred				FD_SET(tcp6sock, &sockbits);
60274462Salfred				FD_SET(tcp6sock, &v6bits);
60374462Salfred				if (maxsock < tcp6sock)
60474462Salfred					maxsock = tcp6sock;
60574462Salfred				connect_type_cnt++;
60674462Salfred			}
6071558Srgrimes		}
60874462Salfred		if (rpcbreg == 1) {
60974462Salfred			memset(&hints, 0, sizeof hints);
61074462Salfred			hints.ai_flags = AI_PASSIVE;
61174462Salfred			hints.ai_family = AF_INET6;
61274462Salfred			hints.ai_socktype = SOCK_STREAM;
61374462Salfred			hints.ai_protocol = IPPROTO_TCP;
61474462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
61574462Salfred			if (ecode != 0) {
61674462Salfred				syslog(LOG_ERR, "getaddrinfo tcp6: %s",
61774462Salfred				   gai_strerror(ecode));
61885034Siedowse				nfsd_exit(1);
61974462Salfred			}
62074462Salfred			nconf_tcp6 = getnetconfigent("tcp6");
62174462Salfred			if (nconf_tcp6 == NULL)
62274462Salfred				err(1, "getnetconfigent tcp6 failed");
62374462Salfred			nb_tcp6.buf = ai_tcp6->ai_addr;
62474462Salfred			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
62574462Salfred			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
62674462Salfred			    (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
62774462Salfred				err(1, "rpcb_set tcp6 failed");
62874462Salfred			freeaddrinfo(ai_tcp6);
6291558Srgrimes		}
6301558Srgrimes	}
6311558Srgrimes
63274462Salfred	if (rpcbregcnt == 0) {
63374462Salfred		syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
63485034Siedowse		nfsd_exit(1);
6351558Srgrimes	}
6361558Srgrimes
63785034Siedowse	if (tcpflag && connect_type_cnt == 0) {
63874462Salfred		syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
63985034Siedowse		nfsd_exit(1);
64074462Salfred	}
6411558Srgrimes
6429336Sdfr	setproctitle("master");
64385034Siedowse	/*
64485034Siedowse	 * We always want a master to have a clean way to to shut nfsd down
64585034Siedowse	 * (with unregistration): if the master is killed, it unregisters and
64685034Siedowse	 * kills all children. If we run for UDP only (and so do not have to
64785034Siedowse	 * loop waiting waiting for accept), we instead make the parent
64885034Siedowse	 * a "server" too. start_server will not return.
64985034Siedowse	 */
65085034Siedowse	if (!tcpflag)
65185034Siedowse		start_server(1);
6521558Srgrimes
6531558Srgrimes	/*
6541558Srgrimes	 * Loop forever accepting connections and passing the sockets
6551558Srgrimes	 * into the kernel for the mounts.
6561558Srgrimes	 */
6571558Srgrimes	for (;;) {
6581558Srgrimes		ready = sockbits;
6591558Srgrimes		if (connect_type_cnt > 1) {
6601558Srgrimes			if (select(maxsock + 1,
6611558Srgrimes			    &ready, NULL, NULL, NULL) < 1) {
6621558Srgrimes				syslog(LOG_ERR, "select failed: %m");
66385034Siedowse				nfsd_exit(1);
6641558Srgrimes			}
6651558Srgrimes		}
66674462Salfred		for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
66774462Salfred			if (FD_ISSET(tcpsock, &ready)) {
66874462Salfred				if (FD_ISSET(tcpsock, &v4bits)) {
66974462Salfred					len = sizeof(inetpeer);
67074462Salfred					if ((msgsock = accept(tcpsock,
67174462Salfred					    (struct sockaddr *)&inetpeer, &len)) < 0) {
67274462Salfred						syslog(LOG_ERR, "accept failed: %m");
67385034Siedowse						nfsd_exit(1);
67474462Salfred					}
67574462Salfred					memset(inetpeer.sin_zero, 0,
67674462Salfred						sizeof(inetpeer.sin_zero));
67774462Salfred					if (setsockopt(msgsock, SOL_SOCKET,
67874462Salfred					    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
67974462Salfred						syslog(LOG_ERR,
68074462Salfred						    "setsockopt SO_KEEPALIVE: %m");
68174462Salfred					nfsdargs.sock = msgsock;
68274462Salfred					nfsdargs.name = (caddr_t)&inetpeer;
68385034Siedowse					nfsdargs.namelen = len;
68474462Salfred					nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
68574462Salfred					(void)close(msgsock);
68674462Salfred				} else if (FD_ISSET(tcpsock, &v6bits)) {
68774462Salfred					len = sizeof(inet6peer);
68874462Salfred					if ((msgsock = accept(tcpsock,
68974462Salfred					    (struct sockaddr *)&inet6peer,
69074462Salfred					    &len)) < 0) {
69174462Salfred						syslog(LOG_ERR,
69274462Salfred						     "accept failed: %m");
69385034Siedowse						nfsd_exit(1);
69474462Salfred					}
69574462Salfred					if (setsockopt(msgsock, SOL_SOCKET,
69674462Salfred					    SO_KEEPALIVE, (char *)&on,
69774462Salfred					    sizeof(on)) < 0)
69874462Salfred						syslog(LOG_ERR, "setsockopt "
69974462Salfred						    "SO_KEEPALIVE: %m");
70074462Salfred					nfsdargs.sock = msgsock;
70174462Salfred					nfsdargs.name = (caddr_t)&inet6peer;
70285034Siedowse					nfsdargs.namelen = len;
70374462Salfred					nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
70474462Salfred					(void)close(msgsock);
70574462Salfred				}
7061558Srgrimes			}
7071558Srgrimes		}
7081558Srgrimes	}
7091558Srgrimes}
7101558Srgrimes
71174462Salfredint
71274462Salfredsetbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints)
71353096Sdillon{
71474462Salfred	int ecode;
71574462Salfred	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
71674462Salfred	const char *hostptr;
71753096Sdillon
71874462Salfred	if (bindhost == NULL || strcmp("*", bindhost) == 0)
71974462Salfred		hostptr = NULL;
72074462Salfred	else
72174462Salfred		hostptr = bindhost;
72274462Salfred
72374462Salfred	if (hostptr != NULL) {
72474462Salfred		switch (hints.ai_family) {
72574462Salfred		case AF_INET:
72674462Salfred			if (inet_pton(AF_INET, hostptr, host_addr) == 1) {
72774462Salfred				hints.ai_flags = AI_NUMERICHOST;
72874462Salfred			} else {
72974462Salfred				if (inet_pton(AF_INET6, hostptr,
73074462Salfred				    host_addr) == 1)
73174462Salfred					return (1);
73253096Sdillon			}
73374462Salfred			break;
73474462Salfred		case AF_INET6:
73574462Salfred			if (inet_pton(AF_INET6, hostptr, host_addr) == 1) {
73674462Salfred				hints.ai_flags = AI_NUMERICHOST;
73774462Salfred			} else {
73874462Salfred				if (inet_pton(AF_INET, hostptr,
73974462Salfred				    host_addr) == 1)
74074462Salfred					return (1);
74174462Salfred			}
74274462Salfred			break;
74374462Salfred		default:
74495861Speter			break;
74553096Sdillon		}
74653096Sdillon	}
74774462Salfred
74874462Salfred	ecode = getaddrinfo(hostptr, "nfs", &hints, ai);
74974462Salfred	if (ecode != 0) {
75074462Salfred		syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost,
75174462Salfred		    gai_strerror(ecode));
75274462Salfred		return (1);
75374462Salfred	}
75474462Salfred	return (0);
75553096Sdillon}
75653096Sdillon
75753096Sdillonvoid
7581558Srgrimesusage()
7591558Srgrimes{
7609336Sdfr	(void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
7611558Srgrimes	exit(1);
7621558Srgrimes}
7631558Srgrimes
7641558Srgrimesvoid
7651558Srgrimesnonfs(signo)
7661558Srgrimes	int signo;
7671558Srgrimes{
76837666Scharnier	syslog(LOG_ERR, "missing system call: NFS not available");
7691558Srgrimes}
7701558Srgrimes
7711558Srgrimesvoid
7721558Srgrimesreapchild(signo)
7731558Srgrimes	int signo;
7741558Srgrimes{
77585034Siedowse	pid_t pid;
77685034Siedowse	int i;
7771558Srgrimes
77885034Siedowse	while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) {
77985034Siedowse		for (i = 0; i < nfsdcnt; i++)
78085034Siedowse			if (pid == children[i])
78185034Siedowse				children[i] = -1;
78285034Siedowse	}
7831558Srgrimes}
7841558Srgrimes
78574462Salfredvoid
78674462Salfredunregistration()
78774462Salfred{
78874462Salfred	if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) ||
78974462Salfred	    (!rpcb_unset(RPCPROG_NFS, 3, NULL)))
79074462Salfred		syslog(LOG_ERR, "rpcb_unset failed");
79174462Salfred}
79274462Salfred
79374462Salfredvoid
79474462Salfredkillchildren()
79574462Salfred{
79674462Salfred	int i;
79774462Salfred
79874462Salfred	for (i = 0; i < nfsdcnt; i++) {
79974462Salfred		if (children[i] > 0)
80074462Salfred			kill(children[i], SIGKILL);
80174462Salfred	}
80274462Salfred}
80374462Salfred
80485034Siedowse/*
80585034Siedowse * Cleanup master after SIGUSR1.
80685034Siedowse */
80774462Salfredvoid
80874462Salfredcleanup(signo)
80974462Salfred{
81085034Siedowse	nfsd_exit(0);
81185034Siedowse}
81285034Siedowse
81385034Siedowse/*
81485034Siedowse * Cleanup child after SIGUSR1.
81585034Siedowse */
81685034Siedowsevoid
81785034Siedowsechild_cleanup(signo)
81885034Siedowse{
81985034Siedowse	exit(0);
82085034Siedowse}
82185034Siedowse
82285034Siedowsevoid
82385034Siedowsenfsd_exit(int status)
82485034Siedowse{
82574462Salfred	killchildren();
82685034Siedowse	unregistration();
82785034Siedowse	exit(status);
82874462Salfred}
82985034Siedowse
83085034Siedowsevoid
83185034Siedowsestart_server(int master)
83285034Siedowse{
83385034Siedowse	int status;
83485034Siedowse
83585034Siedowse	status = 0;
83685034Siedowse	nsd.nsd_nfsd = NULL;
83785034Siedowse	if (nfssvc(NFSSVC_NFSD, &nsd) < 0) {
83885034Siedowse		syslog(LOG_ERR, "nfssvc: %m");
83985034Siedowse		status = 1;
84085034Siedowse	}
84185034Siedowse	if (master)
84285034Siedowse		nfsd_exit(status);
84385034Siedowse	else
84485034Siedowse		exit(status);
84585034Siedowse}
846