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 * 4. Neither the name of the University nor the names of its contributors
171558Srgrimes *    may be used to endorse or promote products derived from this software
181558Srgrimes *    without specific prior written permission.
191558Srgrimes *
201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301558Srgrimes * SUCH DAMAGE.
311558Srgrimes */
321558Srgrimes
331558Srgrimes#ifndef lint
3437666Scharnierstatic const char copyright[] =
351558Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\
361558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
3795861Speter#endif /* not lint */
381558Srgrimes
391558Srgrimes#ifndef lint
4037666Scharnier#if 0
4123684Speterstatic char sccsid[] = "@(#)nfsd.c	8.9 (Berkeley) 3/29/95";
4237666Scharnier#endif
4337666Scharnierstatic const char rcsid[] =
4450476Speter  "$FreeBSD$";
4595861Speter#endif /* not lint */
461558Srgrimes
471558Srgrimes#include <sys/param.h>
481558Srgrimes#include <sys/syslog.h>
491558Srgrimes#include <sys/wait.h>
501558Srgrimes#include <sys/mount.h>
51192674Srmacklem#include <sys/fcntl.h>
5285034Siedowse#include <sys/linker.h>
5385034Siedowse#include <sys/module.h>
54220510Srmacklem#include <sys/types.h>
55220510Srmacklem#include <sys/stat.h>
56243637Salfred#include <sys/sysctl.h>
57220510Srmacklem#include <sys/ucred.h>
581558Srgrimes
591558Srgrimes#include <rpc/rpc.h>
601558Srgrimes#include <rpc/pmap_clnt.h>
61194880Sdfr#include <rpcsvc/nfs_prot.h>
621558Srgrimes
6353096Sdillon#include <netdb.h>
6453096Sdillon#include <arpa/inet.h>
6583653Speter#include <nfsserver/nfs.h>
66192674Srmacklem#include <nfs/nfssvc.h>
671558Srgrimes
681558Srgrimes#include <err.h>
691558Srgrimes#include <errno.h>
7085034Siedowse#include <signal.h>
711558Srgrimes#include <stdio.h>
721558Srgrimes#include <stdlib.h>
7395861Speter#include <string.h>
741558Srgrimes#include <unistd.h>
75243637Salfred#include <sysexits.h>
761558Srgrimes
77243637Salfred#include <getopt.h>
78243637Salfred
79241737Sedstatic int	debug = 0;
801558Srgrimes
81192674Srmacklem#define	NFSD_STABLERESTART	"/var/db/nfs-stablerestart"
82220510Srmacklem#define	NFSD_STABLEBACKUP	"/var/db/nfs-stablerestart.bak"
83140679Srwatson#define	MAXNFSDCNT	256
8474462Salfred#define	DEFNFSDCNT	 4
85241737Sedstatic pid_t children[MAXNFSDCNT]; /* PIDs of children */
86241737Sedstatic int nfsdcnt;		/* number of children */
87243637Salfredstatic int nfsdcnt_set;
88243637Salfredstatic int minthreads;
89243637Salfredstatic int maxthreads;
90241737Sedstatic int new_syscall;
91241737Sedstatic int run_v4server = 1;	/* Force running of nfsv4 server */
92241737Sedstatic int nfssvc_nfsd;		/* Set to correct NFSSVC_xxx flag */
93241737Sedstatic int stablefd = -1;	/* Fd for the stable restart file */
94241737Sedstatic int backupfd;		/* Fd for the backup stable restart file */
95243637Salfredstatic const char *getopt_shortopts;
96243637Salfredstatic const char *getopt_usage;
9774462Salfred
98243637Salfredstatic int minthreads_set;
99243637Salfredstatic int maxthreads_set;
100243637Salfred
101243637Salfredstatic struct option longopts[] = {
102243637Salfred	{ "debug", no_argument, &debug, 1 },
103243637Salfred	{ "minthreads", required_argument, &minthreads_set, 1 },
104243637Salfred	{ "maxthreads", required_argument, &maxthreads_set, 1 },
105243637Salfred	{ NULL, 0, NULL, 0}
106243637Salfred};
107243637Salfred
108246778Sdelphijstatic void	cleanup(int);
109246778Sdelphijstatic void	child_cleanup(int);
110246778Sdelphijstatic void	killchildren(void);
111246778Sdelphijstatic void	nfsd_exit(int);
112246778Sdelphijstatic void	nonfs(int);
113246778Sdelphijstatic void	reapchild(int);
114246778Sdelphijstatic int	setbindhost(struct addrinfo **ia, const char *bindhost,
115246778Sdelphij		    struct addrinfo hints);
116246778Sdelphijstatic void	start_server(int);
117246778Sdelphijstatic void	unregistration(void);
118246778Sdelphijstatic void	usage(void);
119246778Sdelphijstatic void	open_stable(int *, int *);
120246778Sdelphijstatic void	copy_stable(int, int);
121246778Sdelphijstatic void	backup_stable(int);
122246780Sdelphijstatic void	set_nfsdcnt(int);
1231558Srgrimes
1241558Srgrimes/*
1251558Srgrimes * Nfs server daemon mostly just a user context for nfssvc()
1261558Srgrimes *
1271558Srgrimes * 1 - do file descriptor and signal cleanup
1281558Srgrimes * 2 - fork the nfsd(s)
1291558Srgrimes * 3 - create server socket(s)
13074462Salfred * 4 - register socket with rpcbind
1311558Srgrimes *
1321558Srgrimes * For connectionless protocols, just pass the socket into the kernel via.
1331558Srgrimes * nfssvc().
1341558Srgrimes * For connection based sockets, loop doing accepts. When you get a new
1351558Srgrimes * socket from accept, pass the msgsock into the kernel via. nfssvc().
1361558Srgrimes * The arguments are:
13774462Salfred *	-r - reregister with rpcbind
13874462Salfred *	-d - unregister with rpcbind
1391558Srgrimes *	-t - support tcp nfs clients
1401558Srgrimes *	-u - support udp nfs clients
141192993Srmacklem *	-e - forces it to run a server that supports nfsv4
1421558Srgrimes * followed by "n" which is the number of nfsds' to fork off
1431558Srgrimes */
1441558Srgrimesint
145137319Sdelphijmain(int argc, char **argv)
1461558Srgrimes{
147184588Sdfr	struct nfsd_addsock_args addsockargs;
14874462Salfred	struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
14974462Salfred	struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
15074462Salfred	struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
15174462Salfred	struct sockaddr_in inetpeer;
15274462Salfred	struct sockaddr_in6 inet6peer;
1531558Srgrimes	fd_set ready, sockbits;
15474462Salfred	fd_set v4bits, v6bits;
155153590Sdelphij	int ch, connect_type_cnt, i, maxsock, msgsock;
156153609Sdelphij	socklen_t len;
15785034Siedowse	int on = 1, unregister, reregister, sock;
15874462Salfred	int tcp6sock, ip6flag, tcpflag, tcpsock;
159218777Sjhb	int udpflag, ecode, error, s, srvcnt;
16085034Siedowse	int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
161220510Srmacklem	int nfssvc_addsock;
162243637Salfred	int longindex = 0;
163243637Salfred	const char *lopt;
16453096Sdillon	char **bindhost = NULL;
16574462Salfred	pid_t pid;
1661558Srgrimes
1671558Srgrimes	nfsdcnt = DEFNFSDCNT;
16885034Siedowse	unregister = reregister = tcpflag = maxsock = 0;
16985034Siedowse	bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
170243637Salfred	getopt_shortopts = "ah:n:rdtueo";
171243637Salfred	getopt_usage =
172243637Salfred	    "usage:\n"
173243637Salfred	    "  nfsd [-ardtueo] [-h bindip]\n"
174243637Salfred	    "       [-n numservers] [--minthreads #] [--maxthreads #]\n";
175243637Salfred	while ((ch = getopt_long(argc, argv, getopt_shortopts, longopts,
176243637Salfred		    &longindex)) != -1)
1771558Srgrimes		switch (ch) {
17853096Sdillon		case 'a':
17953096Sdillon			bindanyflag = 1;
18053096Sdillon			break;
1811558Srgrimes		case 'n':
182246780Sdelphij			set_nfsdcnt(atoi(optarg));
1831558Srgrimes			break;
18453096Sdillon		case 'h':
18553096Sdillon			bindhostc++;
18653096Sdillon			bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
18753096Sdillon			if (bindhost == NULL)
18853096Sdillon				errx(1, "Out of memory");
18953096Sdillon			bindhost[bindhostc-1] = strdup(optarg);
19053096Sdillon			if (bindhost[bindhostc-1] == NULL)
19153096Sdillon				errx(1, "Out of memory");
19253096Sdillon			break;
1931558Srgrimes		case 'r':
1941558Srgrimes			reregister = 1;
1951558Srgrimes			break;
19674462Salfred		case 'd':
19774462Salfred			unregister = 1;
19874462Salfred			break;
1991558Srgrimes		case 't':
2001558Srgrimes			tcpflag = 1;
2011558Srgrimes			break;
2021558Srgrimes		case 'u':
2031558Srgrimes			udpflag = 1;
2041558Srgrimes			break;
205192993Srmacklem		case 'e':
206220980Srmacklem			/* now a no-op, since this is the default */
207192674Srmacklem			break;
208220980Srmacklem		case 'o':
209220980Srmacklem			run_v4server = 0;
210220980Srmacklem			break;
211243637Salfred		case 0:
212243637Salfred			lopt = longopts[longindex].name;
213243637Salfred			if (!strcmp(lopt, "minthreads")) {
214243637Salfred				minthreads = atoi(optarg);
215243637Salfred			} else if (!strcmp(lopt, "maxthreads")) {
216243637Salfred				maxthreads = atoi(optarg);
217243637Salfred			}
218243637Salfred			break;
2191558Srgrimes		default:
2201558Srgrimes		case '?':
2211558Srgrimes			usage();
2221558Srgrimes		};
22315496Sbde	if (!tcpflag && !udpflag)
22415496Sbde		udpflag = 1;
2251558Srgrimes	argv += optind;
2261558Srgrimes	argc -= optind;
227243645Salfred	if (minthreads_set && maxthreads_set && minthreads > maxthreads)
228243645Salfred		errx(EX_USAGE,
229243645Salfred		    "error: minthreads(%d) can't be greater than "
230243645Salfred		    "maxthreads(%d)", minthreads, maxthreads);
2311558Srgrimes
2321558Srgrimes	/*
2331558Srgrimes	 * XXX
2341558Srgrimes	 * Backward compatibility, trailing number is the count of daemons.
2351558Srgrimes	 */
2361558Srgrimes	if (argc > 1)
2371558Srgrimes		usage();
238246780Sdelphij	if (argc == 1)
239246780Sdelphij		set_nfsdcnt(atoi(argv[0]));
24074800Salfred
241192674Srmacklem	/*
242220980Srmacklem	 * Unless the "-o" option was specified, try and run "nfsd".
243220980Srmacklem	 * If "-o" was specified, try and run "nfsserver".
244192674Srmacklem	 */
245192674Srmacklem	if (run_v4server > 0) {
246192674Srmacklem		if (modfind("nfsd") < 0) {
247192674Srmacklem			/* Not present in kernel, try loading it */
248192674Srmacklem			if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
249192674Srmacklem				errx(1, "NFS server is not available");
250192674Srmacklem		}
251192674Srmacklem	} else if (modfind("nfsserver") < 0) {
252192674Srmacklem		/* Not present in kernel, try loading it */
253192674Srmacklem		if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
254192674Srmacklem			errx(1, "NFS server is not available");
255192674Srmacklem	}
256192674Srmacklem
25774462Salfred	ip6flag = 1;
25874462Salfred	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
25974800Salfred	if (s == -1) {
260244447Srmacklem		if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
26174800Salfred			err(1, "socket");
26274462Salfred		ip6flag = 0;
26374800Salfred	} else if (getnetconfigent("udp6") == NULL ||
26474800Salfred		getnetconfigent("tcp6") == NULL) {
26574800Salfred		ip6flag = 0;
26674800Salfred	}
26774800Salfred	if (s != -1)
26874462Salfred		close(s);
2691558Srgrimes
27053096Sdillon	if (bindhostc == 0 || bindanyflag) {
27153096Sdillon		bindhostc++;
27253096Sdillon		bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
27353096Sdillon		if (bindhost == NULL)
27453096Sdillon			errx(1, "Out of memory");
27553096Sdillon		bindhost[bindhostc-1] = strdup("*");
27653096Sdillon		if (bindhost[bindhostc-1] == NULL)
27753096Sdillon			errx(1, "Out of memory");
27853096Sdillon	}
27953096Sdillon
28074462Salfred	if (unregister) {
28174462Salfred		unregistration();
28274462Salfred		exit (0);
28374462Salfred	}
2841558Srgrimes	if (reregister) {
28574462Salfred		if (udpflag) {
28674462Salfred			memset(&hints, 0, sizeof hints);
28774462Salfred			hints.ai_flags = AI_PASSIVE;
28874462Salfred			hints.ai_family = AF_INET;
28974462Salfred			hints.ai_socktype = SOCK_DGRAM;
29074462Salfred			hints.ai_protocol = IPPROTO_UDP;
29174462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
29274800Salfred			if (ecode != 0)
29374800Salfred				err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
29474462Salfred			nconf_udp = getnetconfigent("udp");
29574462Salfred			if (nconf_udp == NULL)
29674462Salfred				err(1, "getnetconfigent udp failed");
29774462Salfred			nb_udp.buf = ai_udp->ai_addr;
29874462Salfred			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
299194880Sdfr			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) ||
300194880Sdfr			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp)))
30174462Salfred				err(1, "rpcb_set udp failed");
30274462Salfred			freeaddrinfo(ai_udp);
30374462Salfred		}
30474462Salfred		if (udpflag && ip6flag) {
30574462Salfred			memset(&hints, 0, sizeof hints);
30674462Salfred			hints.ai_flags = AI_PASSIVE;
30774462Salfred			hints.ai_family = AF_INET6;
30874462Salfred			hints.ai_socktype = SOCK_DGRAM;
30974462Salfred			hints.ai_protocol = IPPROTO_UDP;
31074462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
31174800Salfred			if (ecode != 0)
31274800Salfred				err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
31374462Salfred			nconf_udp6 = getnetconfigent("udp6");
31474462Salfred			if (nconf_udp6 == NULL)
31574462Salfred				err(1, "getnetconfigent udp6 failed");
31674462Salfred			nb_udp6.buf = ai_udp6->ai_addr;
31774462Salfred			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
318194880Sdfr			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) ||
319194880Sdfr			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6)))
32074462Salfred				err(1, "rpcb_set udp6 failed");
32174462Salfred			freeaddrinfo(ai_udp6);
32274462Salfred		}
32374462Salfred		if (tcpflag) {
32474462Salfred			memset(&hints, 0, sizeof hints);
32574462Salfred			hints.ai_flags = AI_PASSIVE;
32674462Salfred			hints.ai_family = AF_INET;
32774462Salfred			hints.ai_socktype = SOCK_STREAM;
32874462Salfred			hints.ai_protocol = IPPROTO_TCP;
32974462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
33074800Salfred			if (ecode != 0)
33174800Salfred				err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
33274462Salfred			nconf_tcp = getnetconfigent("tcp");
33374462Salfred			if (nconf_tcp == NULL)
33474462Salfred				err(1, "getnetconfigent tcp failed");
33574462Salfred			nb_tcp.buf = ai_tcp->ai_addr;
33674462Salfred			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
337194880Sdfr			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp, &nb_tcp)) ||
338194880Sdfr			    (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp, &nb_tcp)))
33974462Salfred				err(1, "rpcb_set tcp failed");
34074462Salfred			freeaddrinfo(ai_tcp);
34174462Salfred		}
34274462Salfred		if (tcpflag && ip6flag) {
34374462Salfred			memset(&hints, 0, sizeof hints);
34474462Salfred			hints.ai_flags = AI_PASSIVE;
34574462Salfred			hints.ai_family = AF_INET6;
34674462Salfred			hints.ai_socktype = SOCK_STREAM;
34774462Salfred			hints.ai_protocol = IPPROTO_TCP;
34874462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
34974800Salfred			if (ecode != 0)
35074800Salfred				err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
35174462Salfred			nconf_tcp6 = getnetconfigent("tcp6");
35274462Salfred			if (nconf_tcp6 == NULL)
35374462Salfred				err(1, "getnetconfigent tcp6 failed");
35474462Salfred			nb_tcp6.buf = ai_tcp6->ai_addr;
35574462Salfred			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
356194880Sdfr			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) ||
357194880Sdfr			    (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6)))
35874462Salfred				err(1, "rpcb_set tcp6 failed");
35974462Salfred			freeaddrinfo(ai_tcp6);
36074462Salfred		}
36174462Salfred		exit (0);
3621558Srgrimes	}
36374800Salfred	if (debug == 0) {
36474800Salfred		daemon(0, 0);
36574800Salfred		(void)signal(SIGHUP, SIG_IGN);
36674800Salfred		(void)signal(SIGINT, SIG_IGN);
36774800Salfred		/*
36874800Salfred		 * nfsd sits in the kernel most of the time.  It needs
36974800Salfred		 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
37074800Salfred		 * as possible during a shutdown, otherwise loopback
37174800Salfred		 * mounts will not be able to unmount.
37274800Salfred		 */
37374800Salfred		(void)signal(SIGTERM, SIG_IGN);
37474800Salfred		(void)signal(SIGQUIT, SIG_IGN);
37574800Salfred	}
37685034Siedowse	(void)signal(SIGSYS, nonfs);
37774800Salfred	(void)signal(SIGCHLD, reapchild);
378220510Srmacklem	(void)signal(SIGUSR2, backup_stable);
37974462Salfred
380243637Salfred	openlog("nfsd", LOG_PID | (debug ? LOG_PERROR : 0), LOG_DAEMON);
3811558Srgrimes
382184588Sdfr	/*
383192674Srmacklem	 * For V4, we open the stablerestart file and call nfssvc()
384192674Srmacklem	 * to get it loaded. This is done before the daemons do the
385192674Srmacklem	 * regular nfssvc() call to service NFS requests.
386192674Srmacklem	 * (This way the file remains open until the last nfsd is killed
387192674Srmacklem	 *  off.)
388220510Srmacklem	 * It and the backup copy will be created as empty files
389220510Srmacklem	 * the first time this nfsd is started and should never be
390220510Srmacklem	 * deleted/replaced if at all possible. It should live on a
391192674Srmacklem	 * local, non-volatile storage device that does not do hardware
392192674Srmacklem	 * level write-back caching. (See SCSI doc for more information
393192674Srmacklem	 * on how to prevent write-back caching on SCSI disks.)
394184588Sdfr	 */
395192674Srmacklem	if (run_v4server > 0) {
396220510Srmacklem		open_stable(&stablefd, &backupfd);
397192674Srmacklem		if (stablefd < 0) {
398243637Salfred			syslog(LOG_ERR, "Can't open %s: %m\n", NFSD_STABLERESTART);
399192674Srmacklem			exit(1);
400192674Srmacklem		}
401220510Srmacklem		/* This system call will fail for old kernels, but that's ok. */
402220510Srmacklem		nfssvc(NFSSVC_BACKUPSTABLE, NULL);
403192674Srmacklem		if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) {
404243637Salfred			syslog(LOG_ERR, "Can't read stable storage file: %m\n");
405192674Srmacklem			exit(1);
406192674Srmacklem		}
407192674Srmacklem		nfssvc_addsock = NFSSVC_NFSDADDSOCK;
408192674Srmacklem		nfssvc_nfsd = NFSSVC_NFSDNFSD;
409184588Sdfr		new_syscall = TRUE;
410192674Srmacklem	} else {
411192674Srmacklem		nfssvc_addsock = NFSSVC_ADDSOCK;
412192674Srmacklem		nfssvc_nfsd = NFSSVC_NFSD;
413192674Srmacklem		/*
414192674Srmacklem		 * Figure out if the kernel supports the new-style
415192674Srmacklem		 * NFSSVC_NFSD. Old kernels will return ENXIO because they
416192674Srmacklem		 * don't recognise the flag value, new ones will return EINVAL
417192674Srmacklem		 * because argp is NULL.
418192674Srmacklem		 */
419192674Srmacklem		new_syscall = FALSE;
420192674Srmacklem		if (nfssvc(NFSSVC_NFSD, NULL) < 0 && errno == EINVAL)
421192674Srmacklem			new_syscall = TRUE;
422192674Srmacklem	}
423184588Sdfr
424184588Sdfr	if (!new_syscall) {
425184588Sdfr		/* If we use UDP only, we start the last server below. */
426184588Sdfr		srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1;
427184588Sdfr		for (i = 0; i < srvcnt; i++) {
428184588Sdfr			switch ((pid = fork())) {
429184588Sdfr			case -1:
430184588Sdfr				syslog(LOG_ERR, "fork: %m");
431184588Sdfr				nfsd_exit(1);
432184588Sdfr			case 0:
433184588Sdfr				break;
434184588Sdfr			default:
435184588Sdfr				children[i] = pid;
436184588Sdfr				continue;
437184588Sdfr			}
438184588Sdfr			(void)signal(SIGUSR1, child_cleanup);
439184588Sdfr			setproctitle("server");
440184588Sdfr
441184588Sdfr			start_server(0);
442184588Sdfr		}
443184588Sdfr	} else if (tcpflag) {
444184588Sdfr		/*
445184588Sdfr		 * For TCP mode, we fork once to start the first
446184588Sdfr		 * kernel nfsd thread. The kernel will add more
447184588Sdfr		 * threads as needed.
448184588Sdfr		 */
449184588Sdfr		pid = fork();
450184588Sdfr		if (pid == -1) {
4511558Srgrimes			syslog(LOG_ERR, "fork: %m");
45285034Siedowse			nfsd_exit(1);
4531558Srgrimes		}
454184588Sdfr		if (pid) {
455184588Sdfr			children[0] = pid;
456184588Sdfr		} else {
457184588Sdfr			(void)signal(SIGUSR1, child_cleanup);
458184588Sdfr			setproctitle("server");
459184588Sdfr			start_server(0);
460184588Sdfr		}
4611558Srgrimes	}
4621558Srgrimes
46385034Siedowse	(void)signal(SIGUSR1, cleanup);
46474462Salfred	FD_ZERO(&v4bits);
46574462Salfred	FD_ZERO(&v6bits);
466100499Skan	FD_ZERO(&sockbits);
46774462Salfred
46874462Salfred	rpcbregcnt = 0;
46974462Salfred	/* Set up the socket for udp and rpcb register it. */
47074462Salfred	if (udpflag) {
47174462Salfred		rpcbreg = 0;
47274462Salfred		for (i = 0; i < bindhostc; i++) {
47374462Salfred			memset(&hints, 0, sizeof hints);
47474462Salfred			hints.ai_flags = AI_PASSIVE;
47574462Salfred			hints.ai_family = AF_INET;
47674462Salfred			hints.ai_socktype = SOCK_DGRAM;
47774462Salfred			hints.ai_protocol = IPPROTO_UDP;
47874462Salfred			if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
47974462Salfred				rpcbreg = 1;
48074462Salfred				rpcbregcnt++;
48174462Salfred				if ((sock = socket(ai_udp->ai_family,
48274462Salfred				    ai_udp->ai_socktype,
48374462Salfred				    ai_udp->ai_protocol)) < 0) {
48474462Salfred					syslog(LOG_ERR,
48574462Salfred					    "can't create udp socket");
48685034Siedowse					nfsd_exit(1);
48774462Salfred				}
48874462Salfred				if (bind(sock, ai_udp->ai_addr,
48974462Salfred				    ai_udp->ai_addrlen) < 0) {
49074462Salfred					syslog(LOG_ERR,
49174462Salfred					    "can't bind udp addr %s: %m",
49274462Salfred					    bindhost[i]);
49385034Siedowse					nfsd_exit(1);
49474462Salfred				}
49574462Salfred				freeaddrinfo(ai_udp);
496184588Sdfr				addsockargs.sock = sock;
497184588Sdfr				addsockargs.name = NULL;
498184588Sdfr				addsockargs.namelen = 0;
499192674Srmacklem				if (nfssvc(nfssvc_addsock, &addsockargs) < 0) {
50074462Salfred					syslog(LOG_ERR, "can't Add UDP socket");
50185034Siedowse					nfsd_exit(1);
50274462Salfred				}
50374462Salfred				(void)close(sock);
50474462Salfred			}
5051558Srgrimes		}
50674462Salfred		if (rpcbreg == 1) {
50774462Salfred			memset(&hints, 0, sizeof hints);
50874462Salfred			hints.ai_flags = AI_PASSIVE;
50974462Salfred			hints.ai_family = AF_INET;
51074462Salfred			hints.ai_socktype = SOCK_DGRAM;
51174462Salfred			hints.ai_protocol = IPPROTO_UDP;
51274462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
51374462Salfred			if (ecode != 0) {
51474462Salfred				syslog(LOG_ERR, "getaddrinfo udp: %s",
51574462Salfred				   gai_strerror(ecode));
51685034Siedowse				nfsd_exit(1);
51774462Salfred			}
51874462Salfred			nconf_udp = getnetconfigent("udp");
51974462Salfred			if (nconf_udp == NULL)
52074462Salfred				err(1, "getnetconfigent udp failed");
52174462Salfred			nb_udp.buf = ai_udp->ai_addr;
52274462Salfred			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
523194880Sdfr			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) ||
524194880Sdfr			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp)))
52574462Salfred				err(1, "rpcb_set udp failed");
52674462Salfred			freeaddrinfo(ai_udp);
5271558Srgrimes		}
5281558Srgrimes	}
5291558Srgrimes
53074462Salfred	/* Set up the socket for udp6 and rpcb register it. */
53174462Salfred	if (udpflag && ip6flag) {
53274462Salfred		rpcbreg = 0;
53374462Salfred		for (i = 0; i < bindhostc; i++) {
53474462Salfred			memset(&hints, 0, sizeof hints);
53574462Salfred			hints.ai_flags = AI_PASSIVE;
53674462Salfred			hints.ai_family = AF_INET6;
53774462Salfred			hints.ai_socktype = SOCK_DGRAM;
53874462Salfred			hints.ai_protocol = IPPROTO_UDP;
53974462Salfred			if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
54074462Salfred				rpcbreg = 1;
54174462Salfred				rpcbregcnt++;
54274462Salfred				if ((sock = socket(ai_udp6->ai_family,
54374462Salfred				    ai_udp6->ai_socktype,
54474462Salfred				    ai_udp6->ai_protocol)) < 0) {
54574462Salfred					syslog(LOG_ERR,
54674462Salfred						"can't create udp6 socket");
54785034Siedowse					nfsd_exit(1);
54874462Salfred				}
549100505Sume				if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
55074462Salfred				    &on, sizeof on) < 0) {
55174462Salfred					syslog(LOG_ERR,
55274462Salfred					    "can't set v6-only binding for "
55374462Salfred					    "udp6 socket: %m");
55485034Siedowse					nfsd_exit(1);
55574462Salfred				}
55674462Salfred				if (bind(sock, ai_udp6->ai_addr,
55774462Salfred				    ai_udp6->ai_addrlen) < 0) {
55874462Salfred					syslog(LOG_ERR,
55974462Salfred					    "can't bind udp6 addr %s: %m",
56074462Salfred					    bindhost[i]);
56185034Siedowse					nfsd_exit(1);
56274462Salfred				}
56374462Salfred				freeaddrinfo(ai_udp6);
564184588Sdfr				addsockargs.sock = sock;
565184588Sdfr				addsockargs.name = NULL;
566184588Sdfr				addsockargs.namelen = 0;
567192674Srmacklem				if (nfssvc(nfssvc_addsock, &addsockargs) < 0) {
56874462Salfred					syslog(LOG_ERR,
56974462Salfred					    "can't add UDP6 socket");
57085034Siedowse					nfsd_exit(1);
57174462Salfred				}
57274462Salfred				(void)close(sock);
57374462Salfred			}
5741558Srgrimes		}
57574462Salfred		if (rpcbreg == 1) {
57674462Salfred			memset(&hints, 0, sizeof hints);
57774462Salfred			hints.ai_flags = AI_PASSIVE;
57874462Salfred			hints.ai_family = AF_INET6;
57974462Salfred			hints.ai_socktype = SOCK_DGRAM;
58074462Salfred			hints.ai_protocol = IPPROTO_UDP;
58174462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
58274462Salfred			if (ecode != 0) {
58374462Salfred				syslog(LOG_ERR, "getaddrinfo udp6: %s",
58474462Salfred				   gai_strerror(ecode));
58585034Siedowse				nfsd_exit(1);
58674462Salfred			}
58774462Salfred			nconf_udp6 = getnetconfigent("udp6");
58874462Salfred			if (nconf_udp6 == NULL)
58974462Salfred				err(1, "getnetconfigent udp6 failed");
59074462Salfred			nb_udp6.buf = ai_udp6->ai_addr;
59174462Salfred			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
592194880Sdfr			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) ||
593194880Sdfr			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6)))
59474462Salfred				err(1, "rpcb_set udp6 failed");
59574462Salfred			freeaddrinfo(ai_udp6);
5961558Srgrimes		}
5971558Srgrimes	}
5981558Srgrimes
59974462Salfred	/* Set up the socket for tcp and rpcb register it. */
60074462Salfred	if (tcpflag) {
60174462Salfred		rpcbreg = 0;
60274462Salfred		for (i = 0; i < bindhostc; i++) {
60374462Salfred			memset(&hints, 0, sizeof hints);
60474462Salfred			hints.ai_flags = AI_PASSIVE;
60574462Salfred			hints.ai_family = AF_INET;
60674462Salfred			hints.ai_socktype = SOCK_STREAM;
60774462Salfred			hints.ai_protocol = IPPROTO_TCP;
60874462Salfred			if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
60974462Salfred				rpcbreg = 1;
61074462Salfred				rpcbregcnt++;
61174462Salfred				if ((tcpsock = socket(AF_INET, SOCK_STREAM,
61274462Salfred				    0)) < 0) {
61374462Salfred					syslog(LOG_ERR,
614241849Seadler					    "can't create tcp socket");
61585034Siedowse					nfsd_exit(1);
61674462Salfred				}
61774462Salfred				if (setsockopt(tcpsock, SOL_SOCKET,
61874462Salfred				    SO_REUSEADDR,
61974462Salfred				    (char *)&on, sizeof(on)) < 0)
62074462Salfred					syslog(LOG_ERR,
62174462Salfred					     "setsockopt SO_REUSEADDR: %m");
62274462Salfred				if (bind(tcpsock, ai_tcp->ai_addr,
62374462Salfred				    ai_tcp->ai_addrlen) < 0) {
62474462Salfred					syslog(LOG_ERR,
62574462Salfred					    "can't bind tcp addr %s: %m",
62674462Salfred					    bindhost[i]);
62785034Siedowse					nfsd_exit(1);
62874462Salfred				}
62974462Salfred				if (listen(tcpsock, 5) < 0) {
63074462Salfred					syslog(LOG_ERR, "listen failed");
63185034Siedowse					nfsd_exit(1);
63274462Salfred				}
63374462Salfred				freeaddrinfo(ai_tcp);
63474462Salfred				FD_SET(tcpsock, &sockbits);
63574462Salfred				FD_SET(tcpsock, &v4bits);
63674462Salfred				maxsock = tcpsock;
63774462Salfred				connect_type_cnt++;
63874462Salfred			}
6391558Srgrimes		}
64074462Salfred		if (rpcbreg == 1) {
64174462Salfred			memset(&hints, 0, sizeof hints);
64274462Salfred			hints.ai_flags = AI_PASSIVE;
64374462Salfred			hints.ai_family = AF_INET;
64474462Salfred			hints.ai_socktype = SOCK_STREAM;
64574462Salfred			hints.ai_protocol = IPPROTO_TCP;
64674462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints,
64774462Salfred			     &ai_tcp);
64874462Salfred			if (ecode != 0) {
64974462Salfred				syslog(LOG_ERR, "getaddrinfo tcp: %s",
65074462Salfred				   gai_strerror(ecode));
65185034Siedowse				nfsd_exit(1);
65274462Salfred			}
65374462Salfred			nconf_tcp = getnetconfigent("tcp");
65474462Salfred			if (nconf_tcp == NULL)
65574462Salfred				err(1, "getnetconfigent tcp failed");
65674462Salfred			nb_tcp.buf = ai_tcp->ai_addr;
65774462Salfred			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
658194880Sdfr			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp,
659194880Sdfr			    &nb_tcp)) || (!rpcb_set(NFS_PROGRAM, 3,
66074462Salfred			    nconf_tcp, &nb_tcp)))
66174462Salfred				err(1, "rpcb_set tcp failed");
66274462Salfred			freeaddrinfo(ai_tcp);
6631558Srgrimes		}
6641558Srgrimes	}
6651558Srgrimes
66674462Salfred	/* Set up the socket for tcp6 and rpcb register it. */
66774462Salfred	if (tcpflag && ip6flag) {
66874462Salfred		rpcbreg = 0;
66974462Salfred		for (i = 0; i < bindhostc; i++) {
67074462Salfred			memset(&hints, 0, sizeof hints);
67174462Salfred			hints.ai_flags = AI_PASSIVE;
67274462Salfred			hints.ai_family = AF_INET6;
67374462Salfred			hints.ai_socktype = SOCK_STREAM;
67474462Salfred			hints.ai_protocol = IPPROTO_TCP;
67574462Salfred			if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
67674462Salfred				rpcbreg = 1;
67774462Salfred				rpcbregcnt++;
67874462Salfred				if ((tcp6sock = socket(ai_tcp6->ai_family,
67974462Salfred				    ai_tcp6->ai_socktype,
68074462Salfred				    ai_tcp6->ai_protocol)) < 0) {
68174462Salfred					syslog(LOG_ERR,
68274462Salfred					    "can't create tcp6 socket");
68385034Siedowse					nfsd_exit(1);
68474462Salfred				}
68574462Salfred				if (setsockopt(tcp6sock, SOL_SOCKET,
68674462Salfred				    SO_REUSEADDR,
68774462Salfred				    (char *)&on, sizeof(on)) < 0)
68874462Salfred					syslog(LOG_ERR,
68974462Salfred					    "setsockopt SO_REUSEADDR: %m");
69074462Salfred				if (setsockopt(tcp6sock, IPPROTO_IPV6,
691100505Sume				    IPV6_V6ONLY, &on, sizeof on) < 0) {
69274462Salfred					syslog(LOG_ERR,
69374462Salfred					"can't set v6-only binding for tcp6 "
69474462Salfred					    "socket: %m");
69585034Siedowse					nfsd_exit(1);
69674462Salfred				}
69774462Salfred				if (bind(tcp6sock, ai_tcp6->ai_addr,
69874462Salfred				    ai_tcp6->ai_addrlen) < 0) {
69974462Salfred					syslog(LOG_ERR,
70074462Salfred					    "can't bind tcp6 addr %s: %m",
70174462Salfred					    bindhost[i]);
70285034Siedowse					nfsd_exit(1);
70374462Salfred				}
70474462Salfred				if (listen(tcp6sock, 5) < 0) {
70574462Salfred					syslog(LOG_ERR, "listen failed");
70685034Siedowse					nfsd_exit(1);
70774462Salfred				}
70874462Salfred				freeaddrinfo(ai_tcp6);
70974462Salfred				FD_SET(tcp6sock, &sockbits);
71074462Salfred				FD_SET(tcp6sock, &v6bits);
71174462Salfred				if (maxsock < tcp6sock)
71274462Salfred					maxsock = tcp6sock;
71374462Salfred				connect_type_cnt++;
71474462Salfred			}
7151558Srgrimes		}
71674462Salfred		if (rpcbreg == 1) {
71774462Salfred			memset(&hints, 0, sizeof hints);
71874462Salfred			hints.ai_flags = AI_PASSIVE;
71974462Salfred			hints.ai_family = AF_INET6;
72074462Salfred			hints.ai_socktype = SOCK_STREAM;
72174462Salfred			hints.ai_protocol = IPPROTO_TCP;
72274462Salfred			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
72374462Salfred			if (ecode != 0) {
72474462Salfred				syslog(LOG_ERR, "getaddrinfo tcp6: %s",
72574462Salfred				   gai_strerror(ecode));
72685034Siedowse				nfsd_exit(1);
72774462Salfred			}
72874462Salfred			nconf_tcp6 = getnetconfigent("tcp6");
72974462Salfred			if (nconf_tcp6 == NULL)
73074462Salfred				err(1, "getnetconfigent tcp6 failed");
73174462Salfred			nb_tcp6.buf = ai_tcp6->ai_addr;
73274462Salfred			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
733194880Sdfr			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) ||
734194880Sdfr			    (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6)))
73574462Salfred				err(1, "rpcb_set tcp6 failed");
73674462Salfred			freeaddrinfo(ai_tcp6);
7371558Srgrimes		}
7381558Srgrimes	}
7391558Srgrimes
74074462Salfred	if (rpcbregcnt == 0) {
74174462Salfred		syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
74285034Siedowse		nfsd_exit(1);
7431558Srgrimes	}
7441558Srgrimes
74585034Siedowse	if (tcpflag && connect_type_cnt == 0) {
74674462Salfred		syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
74785034Siedowse		nfsd_exit(1);
74874462Salfred	}
7491558Srgrimes
7509336Sdfr	setproctitle("master");
75185034Siedowse	/*
75285034Siedowse	 * We always want a master to have a clean way to to shut nfsd down
75385034Siedowse	 * (with unregistration): if the master is killed, it unregisters and
75485034Siedowse	 * kills all children. If we run for UDP only (and so do not have to
75585034Siedowse	 * loop waiting waiting for accept), we instead make the parent
75685034Siedowse	 * a "server" too. start_server will not return.
75785034Siedowse	 */
75885034Siedowse	if (!tcpflag)
75985034Siedowse		start_server(1);
7601558Srgrimes
7611558Srgrimes	/*
7621558Srgrimes	 * Loop forever accepting connections and passing the sockets
7631558Srgrimes	 * into the kernel for the mounts.
7641558Srgrimes	 */
7651558Srgrimes	for (;;) {
7661558Srgrimes		ready = sockbits;
7671558Srgrimes		if (connect_type_cnt > 1) {
7681558Srgrimes			if (select(maxsock + 1,
7691558Srgrimes			    &ready, NULL, NULL, NULL) < 1) {
770218777Sjhb				error = errno;
771218777Sjhb				if (error == EINTR)
772124357Srwatson					continue;
773220510Srmacklem				syslog(LOG_ERR, "select failed: %m");
77485034Siedowse				nfsd_exit(1);
7751558Srgrimes			}
7761558Srgrimes		}
77774462Salfred		for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
77874462Salfred			if (FD_ISSET(tcpsock, &ready)) {
77974462Salfred				if (FD_ISSET(tcpsock, &v4bits)) {
78074462Salfred					len = sizeof(inetpeer);
78174462Salfred					if ((msgsock = accept(tcpsock,
78274462Salfred					    (struct sockaddr *)&inetpeer, &len)) < 0) {
783218777Sjhb						error = errno;
78474462Salfred						syslog(LOG_ERR, "accept failed: %m");
785218777Sjhb						if (error == ECONNABORTED ||
786218777Sjhb						    error == EINTR)
787124357Srwatson							continue;
78885034Siedowse						nfsd_exit(1);
78974462Salfred					}
79074462Salfred					memset(inetpeer.sin_zero, 0,
79174462Salfred						sizeof(inetpeer.sin_zero));
79274462Salfred					if (setsockopt(msgsock, SOL_SOCKET,
79374462Salfred					    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
79474462Salfred						syslog(LOG_ERR,
79574462Salfred						    "setsockopt SO_KEEPALIVE: %m");
796184588Sdfr					addsockargs.sock = msgsock;
797184588Sdfr					addsockargs.name = (caddr_t)&inetpeer;
798184588Sdfr					addsockargs.namelen = len;
799192674Srmacklem					nfssvc(nfssvc_addsock, &addsockargs);
80074462Salfred					(void)close(msgsock);
80174462Salfred				} else if (FD_ISSET(tcpsock, &v6bits)) {
80274462Salfred					len = sizeof(inet6peer);
80374462Salfred					if ((msgsock = accept(tcpsock,
80474462Salfred					    (struct sockaddr *)&inet6peer,
80574462Salfred					    &len)) < 0) {
806218777Sjhb						error = errno;
80774462Salfred						syslog(LOG_ERR,
80874462Salfred						     "accept failed: %m");
809218777Sjhb						if (error == ECONNABORTED ||
810218777Sjhb						    error == EINTR)
811124357Srwatson							continue;
81285034Siedowse						nfsd_exit(1);
81374462Salfred					}
81474462Salfred					if (setsockopt(msgsock, SOL_SOCKET,
81574462Salfred					    SO_KEEPALIVE, (char *)&on,
81674462Salfred					    sizeof(on)) < 0)
81774462Salfred						syslog(LOG_ERR, "setsockopt "
81874462Salfred						    "SO_KEEPALIVE: %m");
819184588Sdfr					addsockargs.sock = msgsock;
820184588Sdfr					addsockargs.name = (caddr_t)&inet6peer;
821184588Sdfr					addsockargs.namelen = len;
822192674Srmacklem					nfssvc(nfssvc_addsock, &addsockargs);
82374462Salfred					(void)close(msgsock);
82474462Salfred				}
8251558Srgrimes			}
8261558Srgrimes		}
8271558Srgrimes	}
8281558Srgrimes}
8291558Srgrimes
830246778Sdelphijstatic int
83174462Salfredsetbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints)
83253096Sdillon{
83374462Salfred	int ecode;
83474462Salfred	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
83574462Salfred	const char *hostptr;
83653096Sdillon
83774462Salfred	if (bindhost == NULL || strcmp("*", bindhost) == 0)
83874462Salfred		hostptr = NULL;
83974462Salfred	else
84074462Salfred		hostptr = bindhost;
84174462Salfred
84274462Salfred	if (hostptr != NULL) {
84374462Salfred		switch (hints.ai_family) {
84474462Salfred		case AF_INET:
84574462Salfred			if (inet_pton(AF_INET, hostptr, host_addr) == 1) {
84674462Salfred				hints.ai_flags = AI_NUMERICHOST;
84774462Salfred			} else {
84874462Salfred				if (inet_pton(AF_INET6, hostptr,
84974462Salfred				    host_addr) == 1)
85074462Salfred					return (1);
85153096Sdillon			}
85274462Salfred			break;
85374462Salfred		case AF_INET6:
85474462Salfred			if (inet_pton(AF_INET6, hostptr, host_addr) == 1) {
85574462Salfred				hints.ai_flags = AI_NUMERICHOST;
85674462Salfred			} else {
85774462Salfred				if (inet_pton(AF_INET, hostptr,
85874462Salfred				    host_addr) == 1)
85974462Salfred					return (1);
86074462Salfred			}
86174462Salfred			break;
86274462Salfred		default:
86395861Speter			break;
86453096Sdillon		}
86553096Sdillon	}
86674462Salfred
86774462Salfred	ecode = getaddrinfo(hostptr, "nfs", &hints, ai);
86874462Salfred	if (ecode != 0) {
86974462Salfred		syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost,
87074462Salfred		    gai_strerror(ecode));
87174462Salfred		return (1);
87274462Salfred	}
87374462Salfred	return (0);
87453096Sdillon}
87553096Sdillon
876246778Sdelphijstatic void
877246780Sdelphijset_nfsdcnt(int proposed)
878246780Sdelphij{
879246780Sdelphij
880246780Sdelphij	if (proposed < 1) {
881246780Sdelphij		warnx("nfsd count too low %d; reset to %d", proposed,
882246780Sdelphij		    DEFNFSDCNT);
883246780Sdelphij		nfsdcnt = DEFNFSDCNT;
884246780Sdelphij	} else if (proposed > MAXNFSDCNT) {
885246780Sdelphij		warnx("nfsd count too high %d; truncated to %d", proposed,
886246780Sdelphij		    MAXNFSDCNT);
887246780Sdelphij		nfsdcnt = MAXNFSDCNT;
888246780Sdelphij	} else
889246780Sdelphij		nfsdcnt = proposed;
890246780Sdelphij	nfsdcnt_set = 1;
891246780Sdelphij}
892246780Sdelphij
893246780Sdelphijstatic void
894201227Sedusage(void)
8951558Srgrimes{
896243637Salfred	(void)fprintf(stderr, "%s", getopt_usage);
8971558Srgrimes	exit(1);
8981558Srgrimes}
8991558Srgrimes
900246778Sdelphijstatic void
901137319Sdelphijnonfs(__unused int signo)
9021558Srgrimes{
90337666Scharnier	syslog(LOG_ERR, "missing system call: NFS not available");
9041558Srgrimes}
9051558Srgrimes
906246778Sdelphijstatic void
907137319Sdelphijreapchild(__unused int signo)
9081558Srgrimes{
90985034Siedowse	pid_t pid;
91085034Siedowse	int i;
9111558Srgrimes
91285034Siedowse	while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) {
91385034Siedowse		for (i = 0; i < nfsdcnt; i++)
91485034Siedowse			if (pid == children[i])
91585034Siedowse				children[i] = -1;
91685034Siedowse	}
9171558Srgrimes}
9181558Srgrimes
919246778Sdelphijstatic void
920201227Sedunregistration(void)
92174462Salfred{
922194880Sdfr	if ((!rpcb_unset(NFS_PROGRAM, 2, NULL)) ||
923194880Sdfr	    (!rpcb_unset(NFS_PROGRAM, 3, NULL)))
92474462Salfred		syslog(LOG_ERR, "rpcb_unset failed");
92574462Salfred}
92674462Salfred
927246778Sdelphijstatic void
928201227Sedkillchildren(void)
92974462Salfred{
93074462Salfred	int i;
93174462Salfred
93274462Salfred	for (i = 0; i < nfsdcnt; i++) {
93374462Salfred		if (children[i] > 0)
93474462Salfred			kill(children[i], SIGKILL);
93574462Salfred	}
93674462Salfred}
93774462Salfred
93885034Siedowse/*
93985034Siedowse * Cleanup master after SIGUSR1.
94085034Siedowse */
941246778Sdelphijstatic void
942137319Sdelphijcleanup(__unused int signo)
94374462Salfred{
94485034Siedowse	nfsd_exit(0);
94585034Siedowse}
94685034Siedowse
94785034Siedowse/*
94885034Siedowse * Cleanup child after SIGUSR1.
94985034Siedowse */
950246778Sdelphijstatic void
951137319Sdelphijchild_cleanup(__unused int signo)
95285034Siedowse{
95385034Siedowse	exit(0);
95485034Siedowse}
95585034Siedowse
956246778Sdelphijstatic void
95785034Siedowsenfsd_exit(int status)
95885034Siedowse{
95974462Salfred	killchildren();
96085034Siedowse	unregistration();
96185034Siedowse	exit(status);
96274462Salfred}
96385034Siedowse
964243637Salfredstatic int
965243637Salfredget_tuned_nfsdcount(void)
966243637Salfred{
967243637Salfred	int ncpu, error, tuned_nfsdcnt;
968243637Salfred	size_t ncpu_size;
969243637Salfred
970243637Salfred	ncpu_size = sizeof(ncpu);
971243637Salfred	error = sysctlbyname("hw.ncpu", &ncpu, &ncpu_size, NULL, 0);
972243637Salfred	if (error) {
973243637Salfred		warnx("sysctlbyname(hw.ncpu) failed defaulting to %d nfs servers",
974243637Salfred		    DEFNFSDCNT);
975243637Salfred		tuned_nfsdcnt = DEFNFSDCNT;
976243637Salfred	} else {
977243637Salfred		tuned_nfsdcnt = ncpu * 8;
978243637Salfred	}
979243637Salfred	if (!new_syscall && tuned_nfsdcnt > MAXNFSDCNT) {
980243637Salfred		warnx("nfsd count %d; truncated to %d", tuned_nfsdcnt,
981243637Salfred		    MAXNFSDCNT);
982243637Salfred		tuned_nfsdcnt = MAXNFSDCNT;
983243637Salfred	}
984243637Salfred	return tuned_nfsdcnt;
985243637Salfred}
986243637Salfred
987246778Sdelphijstatic void
98885034Siedowsestart_server(int master)
98985034Siedowse{
990192674Srmacklem	char principal[MAXHOSTNAMELEN + 5];
991184588Sdfr	struct nfsd_nfsd_args nfsdargs;
992192674Srmacklem	int status, error;
993192674Srmacklem	char hostname[MAXHOSTNAMELEN + 1], *cp;
994192674Srmacklem	struct addrinfo *aip, hints;
99585034Siedowse
99685034Siedowse	status = 0;
997184588Sdfr	if (new_syscall) {
998192674Srmacklem		gethostname(hostname, sizeof (hostname));
999192674Srmacklem		snprintf(principal, sizeof (principal), "nfs@%s", hostname);
1000192674Srmacklem		if ((cp = strchr(hostname, '.')) == NULL ||
1001192674Srmacklem		    *(cp + 1) == '\0') {
1002192674Srmacklem			/* If not fully qualified, try getaddrinfo() */
1003192674Srmacklem			memset((void *)&hints, 0, sizeof (hints));
1004192674Srmacklem			hints.ai_flags = AI_CANONNAME;
1005192674Srmacklem			error = getaddrinfo(hostname, NULL, &hints, &aip);
1006192674Srmacklem			if (error == 0) {
1007192674Srmacklem				if (aip->ai_canonname != NULL &&
1008192674Srmacklem				    (cp = strchr(aip->ai_canonname, '.')) !=
1009192674Srmacklem				    NULL && *(cp + 1) != '\0')
1010192674Srmacklem					snprintf(principal, sizeof (principal),
1011192674Srmacklem					    "nfs@%s", aip->ai_canonname);
1012192674Srmacklem				freeaddrinfo(aip);
1013192674Srmacklem			}
1014192674Srmacklem		}
1015184588Sdfr		nfsdargs.principal = principal;
1016243637Salfred
1017246781Sdelphij		if (nfsdcnt_set)
1018246781Sdelphij			nfsdargs.minthreads = nfsdargs.maxthreads = nfsdcnt;
1019246781Sdelphij		else {
1020246781Sdelphij			nfsdargs.minthreads = minthreads_set ? minthreads : get_tuned_nfsdcount();
1021246781Sdelphij			nfsdargs.maxthreads = maxthreads_set ? maxthreads : nfsdargs.minthreads;
1022246781Sdelphij			if (nfsdargs.maxthreads < nfsdargs.minthreads)
1023246781Sdelphij				nfsdargs.maxthreads = nfsdargs.minthreads;
1024243637Salfred		}
1025192674Srmacklem		error = nfssvc(nfssvc_nfsd, &nfsdargs);
1026192674Srmacklem		if (error < 0 && errno == EAUTH) {
1027192674Srmacklem			/*
1028192674Srmacklem			 * This indicates that it could not register the
1029192674Srmacklem			 * rpcsec_gss credentials, usually because the
1030192674Srmacklem			 * gssd daemon isn't running.
1031192674Srmacklem			 * (only the experimental server with nfsv4)
1032192674Srmacklem			 */
1033192674Srmacklem			syslog(LOG_ERR, "No gssd, using AUTH_SYS only");
1034192674Srmacklem			principal[0] = '\0';
1035192674Srmacklem			error = nfssvc(nfssvc_nfsd, &nfsdargs);
1036192674Srmacklem		}
1037192674Srmacklem		if (error < 0) {
1038184588Sdfr			syslog(LOG_ERR, "nfssvc: %m");
1039184588Sdfr			status = 1;
1040184588Sdfr		}
1041184588Sdfr	} else {
1042184588Sdfr		if (nfssvc(NFSSVC_OLDNFSD, NULL) < 0) {
1043184588Sdfr			syslog(LOG_ERR, "nfssvc: %m");
1044184588Sdfr			status = 1;
1045184588Sdfr		}
104685034Siedowse	}
104785034Siedowse	if (master)
104885034Siedowse		nfsd_exit(status);
104985034Siedowse	else
105085034Siedowse		exit(status);
105185034Siedowse}
1052220510Srmacklem
1053220510Srmacklem/*
1054220510Srmacklem * Open the stable restart file and return the file descriptor for it.
1055220510Srmacklem */
1056246778Sdelphijstatic void
1057220510Srmacklemopen_stable(int *stable_fdp, int *backup_fdp)
1058220510Srmacklem{
1059220510Srmacklem	int stable_fd, backup_fd = -1, ret;
1060220510Srmacklem	struct stat st, backup_st;
1061220510Srmacklem
1062220510Srmacklem	/* Open and stat the stable restart file. */
1063220510Srmacklem	stable_fd = open(NFSD_STABLERESTART, O_RDWR, 0);
1064220510Srmacklem	if (stable_fd < 0)
1065220510Srmacklem		stable_fd = open(NFSD_STABLERESTART, O_RDWR | O_CREAT, 0600);
1066220510Srmacklem	if (stable_fd >= 0) {
1067220510Srmacklem		ret = fstat(stable_fd, &st);
1068220510Srmacklem		if (ret < 0) {
1069220510Srmacklem			close(stable_fd);
1070220510Srmacklem			stable_fd = -1;
1071220510Srmacklem		}
1072220510Srmacklem	}
1073220510Srmacklem
1074220510Srmacklem	/* Open and stat the backup stable restart file. */
1075220510Srmacklem	if (stable_fd >= 0) {
1076220510Srmacklem		backup_fd = open(NFSD_STABLEBACKUP, O_RDWR, 0);
1077220510Srmacklem		if (backup_fd < 0)
1078220510Srmacklem			backup_fd = open(NFSD_STABLEBACKUP, O_RDWR | O_CREAT,
1079220510Srmacklem			    0600);
1080220510Srmacklem		if (backup_fd >= 0) {
1081220510Srmacklem			ret = fstat(backup_fd, &backup_st);
1082220510Srmacklem			if (ret < 0) {
1083220510Srmacklem				close(backup_fd);
1084220510Srmacklem				backup_fd = -1;
1085220510Srmacklem			}
1086220510Srmacklem		}
1087220510Srmacklem		if (backup_fd < 0) {
1088220510Srmacklem			close(stable_fd);
1089220510Srmacklem			stable_fd = -1;
1090220510Srmacklem		}
1091220510Srmacklem	}
1092220510Srmacklem
1093220510Srmacklem	*stable_fdp = stable_fd;
1094220510Srmacklem	*backup_fdp = backup_fd;
1095220510Srmacklem	if (stable_fd < 0)
1096220510Srmacklem		return;
1097220510Srmacklem
1098220510Srmacklem	/* Sync up the 2 files, as required. */
1099220510Srmacklem	if (st.st_size > 0)
1100220510Srmacklem		copy_stable(stable_fd, backup_fd);
1101220510Srmacklem	else if (backup_st.st_size > 0)
1102220510Srmacklem		copy_stable(backup_fd, stable_fd);
1103220510Srmacklem}
1104220510Srmacklem
1105220510Srmacklem/*
1106220510Srmacklem * Copy the stable restart file to the backup or vice versa.
1107220510Srmacklem */
1108246778Sdelphijstatic void
1109220510Srmacklemcopy_stable(int from_fd, int to_fd)
1110220510Srmacklem{
1111220510Srmacklem	int cnt, ret;
1112220510Srmacklem	static char buf[1024];
1113220510Srmacklem
1114220510Srmacklem	ret = lseek(from_fd, (off_t)0, SEEK_SET);
1115220510Srmacklem	if (ret >= 0)
1116220510Srmacklem		ret = lseek(to_fd, (off_t)0, SEEK_SET);
1117220510Srmacklem	if (ret >= 0)
1118220510Srmacklem		ret = ftruncate(to_fd, (off_t)0);
1119220510Srmacklem	if (ret >= 0)
1120220510Srmacklem		do {
1121220510Srmacklem			cnt = read(from_fd, buf, 1024);
1122220510Srmacklem			if (cnt > 0)
1123220510Srmacklem				ret = write(to_fd, buf, cnt);
1124220510Srmacklem			else if (cnt < 0)
1125220510Srmacklem				ret = cnt;
1126220510Srmacklem		} while (cnt > 0 && ret >= 0);
1127220510Srmacklem	if (ret >= 0)
1128220510Srmacklem		ret = fsync(to_fd);
1129220510Srmacklem	if (ret < 0)
1130220510Srmacklem		syslog(LOG_ERR, "stable restart copy failure: %m");
1131220510Srmacklem}
1132220510Srmacklem
1133220510Srmacklem/*
1134220510Srmacklem * Back up the stable restart file when indicated by the kernel.
1135220510Srmacklem */
1136246778Sdelphijstatic void
1137220510Srmacklembackup_stable(__unused int signo)
1138220510Srmacklem{
1139220510Srmacklem
1140220510Srmacklem	if (stablefd >= 0)
1141220510Srmacklem		copy_stable(stablefd, backupfd);
1142220510Srmacklem}
1143220510Srmacklem
1144