1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1989, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
36static const char copyright[] =
37"@(#) Copyright (c) 1989, 1993, 1994\n\
38	The Regents of the University of California.  All rights reserved.\n";
39#endif /* not lint */
40
41#ifndef lint
42#if 0
43static char sccsid[] = "@(#)nfsd.c	8.9 (Berkeley) 3/29/95";
44#endif
45static const char rcsid[] =
46  "$FreeBSD$";
47#endif /* not lint */
48
49#include <sys/param.h>
50#include <sys/syslog.h>
51#include <sys/wait.h>
52#include <sys/mount.h>
53#include <sys/fcntl.h>
54#include <sys/linker.h>
55#include <sys/module.h>
56#include <sys/types.h>
57#include <sys/stat.h>
58#include <sys/sysctl.h>
59#include <sys/ucred.h>
60
61#include <rpc/rpc.h>
62#include <rpc/pmap_clnt.h>
63#include <rpcsvc/nfs_prot.h>
64
65#include <netdb.h>
66#include <arpa/inet.h>
67#include <nfs/nfssvc.h>
68
69#include <fs/nfs/nfsproto.h>
70#include <fs/nfs/nfskpiport.h>
71#include <fs/nfs/nfs.h>
72
73#include <err.h>
74#include <errno.h>
75#include <signal.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <string.h>
79#include <unistd.h>
80#include <sysexits.h>
81
82#include <getopt.h>
83
84static int	debug = 0;
85
86#define	NFSD_STABLERESTART	"/var/db/nfs-stablerestart"
87#define	NFSD_STABLEBACKUP	"/var/db/nfs-stablerestart.bak"
88#define	MAXNFSDCNT	256
89#define	DEFNFSDCNT	 4
90#define	NFS_VER2	 2
91#define NFS_VER3	 3
92#define NFS_VER4	 4
93static pid_t children[MAXNFSDCNT]; /* PIDs of children */
94static pid_t masterpid;		   /* PID of master/parent */
95static int nfsdcnt;		/* number of children */
96static int nfsdcnt_set;
97static int minthreads;
98static int maxthreads;
99static int nfssvc_nfsd;		/* Set to correct NFSSVC_xxx flag */
100static int stablefd = -1;	/* Fd for the stable restart file */
101static int backupfd;		/* Fd for the backup stable restart file */
102static const char *getopt_shortopts;
103static const char *getopt_usage;
104static int nfs_minvers = NFS_VER2;
105
106static int minthreads_set;
107static int maxthreads_set;
108
109static struct option longopts[] = {
110	{ "debug", no_argument, &debug, 1 },
111	{ "minthreads", required_argument, &minthreads_set, 1 },
112	{ "maxthreads", required_argument, &maxthreads_set, 1 },
113	{ "pnfs", required_argument, NULL, 'p' },
114	{ "mirror", required_argument, NULL, 'm' },
115	{ NULL, 0, NULL, 0}
116};
117
118static void	cleanup(int);
119static void	child_cleanup(int);
120static void	killchildren(void);
121static void	nfsd_exit(int);
122static void	nonfs(int);
123static void	reapchild(int);
124static int	setbindhost(struct addrinfo **ia, const char *bindhost,
125		    struct addrinfo hints);
126static void	start_server(int, struct nfsd_nfsd_args *, const char *vhost);
127static void	unregistration(void);
128static void	usage(void);
129static void	open_stable(int *, int *);
130static void	copy_stable(int, int);
131static void	backup_stable(int);
132static void	set_nfsdcnt(int);
133static void	parse_dsserver(const char *, struct nfsd_nfsd_args *);
134
135/*
136 * Nfs server daemon mostly just a user context for nfssvc()
137 *
138 * 1 - do file descriptor and signal cleanup
139 * 2 - fork the nfsd(s)
140 * 3 - create server socket(s)
141 * 4 - register socket with rpcbind
142 *
143 * For connectionless protocols, just pass the socket into the kernel via.
144 * nfssvc().
145 * For connection based sockets, loop doing accepts. When you get a new
146 * socket from accept, pass the msgsock into the kernel via. nfssvc().
147 * The arguments are:
148 *	-r - reregister with rpcbind
149 *	-d - unregister with rpcbind
150 *	-t - support tcp nfs clients
151 *	-u - support udp nfs clients
152 *	-e - forces it to run a server that supports nfsv4
153 *	-p - enable a pNFS service
154 *	-m - set the mirroring level for a pNFS service
155 * followed by "n" which is the number of nfsds' to fork off
156 */
157int
158main(int argc, char **argv)
159{
160	struct nfsd_addsock_args addsockargs;
161	struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
162	struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
163	struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
164	struct sockaddr_storage peer;
165	fd_set ready, sockbits;
166	int ch, connect_type_cnt, i, maxsock, msgsock;
167	socklen_t len;
168	int on = 1, unregister, reregister, sock;
169	int tcp6sock, ip6flag, tcpflag, tcpsock;
170	int udpflag, ecode, error, s;
171	int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
172	int nfssvc_addsock;
173	int longindex = 0;
174	size_t nfs_minvers_size;
175	const char *lopt;
176	char **bindhost = NULL;
177	pid_t pid;
178	struct nfsd_nfsd_args nfsdargs;
179	const char *vhostname = NULL;
180
181	nfsdargs.mirrorcnt = 1;
182	nfsdargs.addr = NULL;
183	nfsdargs.addrlen = 0;
184	nfsdcnt = DEFNFSDCNT;
185	unregister = reregister = tcpflag = maxsock = 0;
186	bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
187	getopt_shortopts = "ah:n:rdtuep:m:V:";
188	getopt_usage =
189	    "usage:\n"
190	    "  nfsd [-ardtue] [-h bindip]\n"
191	    "       [-n numservers] [--minthreads #] [--maxthreads #]\n"
192	    "       [-p/--pnfs dsserver0:/dsserver0-mounted-on-dir,...,\n"
193	    "       [-V virtual_hostname]\n"
194	    "       dsserverN:/dsserverN-mounted-on-dir] [-m mirrorlevel]\n";
195	while ((ch = getopt_long(argc, argv, getopt_shortopts, longopts,
196		    &longindex)) != -1)
197		switch (ch) {
198		case 'V':
199			if (strlen(optarg) <= MAXHOSTNAMELEN)
200				vhostname = optarg;
201			else
202				warnx("Virtual host name (%s) is too long",
203				    optarg);
204			break;
205		case 'a':
206			bindanyflag = 1;
207			break;
208		case 'n':
209			set_nfsdcnt(atoi(optarg));
210			break;
211		case 'h':
212			bindhostc++;
213			bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
214			if (bindhost == NULL)
215				errx(1, "Out of memory");
216			bindhost[bindhostc-1] = strdup(optarg);
217			if (bindhost[bindhostc-1] == NULL)
218				errx(1, "Out of memory");
219			break;
220		case 'r':
221			reregister = 1;
222			break;
223		case 'd':
224			unregister = 1;
225			break;
226		case 't':
227			tcpflag = 1;
228			break;
229		case 'u':
230			udpflag = 1;
231			break;
232		case 'e':
233			/* now a no-op, since this is the default */
234			break;
235		case 'p':
236			/* Parse out the DS server host names and mount pts. */
237			parse_dsserver(optarg, &nfsdargs);
238			break;
239		case 'm':
240			/* Set the mirror level for a pNFS service. */
241			i = atoi(optarg);
242			if (i < 2 || i > NFSDEV_MAXMIRRORS)
243				errx(1, "Mirror level out of range 2<-->%d",
244				    NFSDEV_MAXMIRRORS);
245			nfsdargs.mirrorcnt = i;
246			break;
247		case 0:
248			lopt = longopts[longindex].name;
249			if (!strcmp(lopt, "minthreads")) {
250				minthreads = atoi(optarg);
251			} else if (!strcmp(lopt, "maxthreads")) {
252				maxthreads = atoi(optarg);
253			}
254			break;
255		default:
256		case '?':
257			usage();
258		}
259	if (!tcpflag && !udpflag)
260		udpflag = 1;
261	argv += optind;
262	argc -= optind;
263	if (minthreads_set && maxthreads_set && minthreads > maxthreads)
264		errx(EX_USAGE,
265		    "error: minthreads(%d) can't be greater than "
266		    "maxthreads(%d)", minthreads, maxthreads);
267
268	/*
269	 * XXX
270	 * Backward compatibility, trailing number is the count of daemons.
271	 */
272	if (argc > 1)
273		usage();
274	if (argc == 1)
275		set_nfsdcnt(atoi(argv[0]));
276
277	/*
278	 * Unless the "-o" option was specified, try and run "nfsd".
279	 * If "-o" was specified, try and run "nfsserver".
280	 */
281	if (modfind("nfsd") < 0) {
282		/* Not present in kernel, try loading it */
283		if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
284			errx(1, "NFS server is not available");
285	}
286
287	ip6flag = 1;
288	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
289	if (s == -1) {
290		if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
291			err(1, "socket");
292		ip6flag = 0;
293	} else if (getnetconfigent("udp6") == NULL ||
294		getnetconfigent("tcp6") == NULL) {
295		ip6flag = 0;
296	}
297	if (s != -1)
298		close(s);
299
300	if (bindhostc == 0 || bindanyflag) {
301		bindhostc++;
302		bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
303		if (bindhost == NULL)
304			errx(1, "Out of memory");
305		bindhost[bindhostc-1] = strdup("*");
306		if (bindhost[bindhostc-1] == NULL)
307			errx(1, "Out of memory");
308	}
309
310	if (unregister) {
311		/*
312		 * Unregister before setting nfs_minvers, in case the
313		 * value of vfs.nfsd.server_min_nfsvers has changed
314		 * since registering with rpcbind.
315		 */
316		unregistration();
317		exit (0);
318	}
319
320	nfs_minvers_size = sizeof(nfs_minvers);
321	error = sysctlbyname("vfs.nfsd.server_min_nfsvers", &nfs_minvers,
322	    &nfs_minvers_size, NULL, 0);
323	if (error != 0 || nfs_minvers < NFS_VER2 || nfs_minvers > NFS_VER4) {
324		warnx("sysctlbyname(vfs.nfsd.server_min_nfsvers) failed,"
325		    " defaulting to NFSv2");
326		nfs_minvers = NFS_VER2;
327	}
328
329	if (reregister) {
330		if (udpflag) {
331			memset(&hints, 0, sizeof hints);
332			hints.ai_flags = AI_PASSIVE;
333			hints.ai_family = AF_INET;
334			hints.ai_socktype = SOCK_DGRAM;
335			hints.ai_protocol = IPPROTO_UDP;
336			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
337			if (ecode != 0)
338				err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
339			nconf_udp = getnetconfigent("udp");
340			if (nconf_udp == NULL)
341				err(1, "getnetconfigent udp failed");
342			nb_udp.buf = ai_udp->ai_addr;
343			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
344			if (nfs_minvers == NFS_VER2)
345				if (!rpcb_set(NFS_PROGRAM, 2, nconf_udp,
346				    &nb_udp))
347					err(1, "rpcb_set udp failed");
348			if (nfs_minvers <= NFS_VER3)
349				if (!rpcb_set(NFS_PROGRAM, 3, nconf_udp,
350				    &nb_udp))
351					err(1, "rpcb_set udp failed");
352			freeaddrinfo(ai_udp);
353		}
354		if (udpflag && ip6flag) {
355			memset(&hints, 0, sizeof hints);
356			hints.ai_flags = AI_PASSIVE;
357			hints.ai_family = AF_INET6;
358			hints.ai_socktype = SOCK_DGRAM;
359			hints.ai_protocol = IPPROTO_UDP;
360			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
361			if (ecode != 0)
362				err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
363			nconf_udp6 = getnetconfigent("udp6");
364			if (nconf_udp6 == NULL)
365				err(1, "getnetconfigent udp6 failed");
366			nb_udp6.buf = ai_udp6->ai_addr;
367			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
368			if (nfs_minvers == NFS_VER2)
369				if (!rpcb_set(NFS_PROGRAM, 2, nconf_udp6,
370				    &nb_udp6))
371					err(1, "rpcb_set udp6 failed");
372			if (nfs_minvers <= NFS_VER3)
373				if (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6,
374				    &nb_udp6))
375					err(1, "rpcb_set udp6 failed");
376			freeaddrinfo(ai_udp6);
377		}
378		if (tcpflag) {
379			memset(&hints, 0, sizeof hints);
380			hints.ai_flags = AI_PASSIVE;
381			hints.ai_family = AF_INET;
382			hints.ai_socktype = SOCK_STREAM;
383			hints.ai_protocol = IPPROTO_TCP;
384			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
385			if (ecode != 0)
386				err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
387			nconf_tcp = getnetconfigent("tcp");
388			if (nconf_tcp == NULL)
389				err(1, "getnetconfigent tcp failed");
390			nb_tcp.buf = ai_tcp->ai_addr;
391			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
392			if (nfs_minvers == NFS_VER2)
393				if (!rpcb_set(NFS_PROGRAM, 2, nconf_tcp,
394				    &nb_tcp))
395					err(1, "rpcb_set tcp failed");
396			if (nfs_minvers <= NFS_VER3)
397				if (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp,
398				    &nb_tcp))
399					err(1, "rpcb_set tcp failed");
400			freeaddrinfo(ai_tcp);
401		}
402		if (tcpflag && ip6flag) {
403			memset(&hints, 0, sizeof hints);
404			hints.ai_flags = AI_PASSIVE;
405			hints.ai_family = AF_INET6;
406			hints.ai_socktype = SOCK_STREAM;
407			hints.ai_protocol = IPPROTO_TCP;
408			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
409			if (ecode != 0)
410				err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
411			nconf_tcp6 = getnetconfigent("tcp6");
412			if (nconf_tcp6 == NULL)
413				err(1, "getnetconfigent tcp6 failed");
414			nb_tcp6.buf = ai_tcp6->ai_addr;
415			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
416			if (nfs_minvers == NFS_VER2)
417				if (!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6,
418				    &nb_tcp6))
419					err(1, "rpcb_set tcp6 failed");
420			if (nfs_minvers <= NFS_VER3)
421				if (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6,
422				   &nb_tcp6))
423					err(1, "rpcb_set tcp6 failed");
424			freeaddrinfo(ai_tcp6);
425		}
426		exit (0);
427	}
428	if (debug == 0) {
429		daemon(0, 0);
430		(void)signal(SIGHUP, SIG_IGN);
431		(void)signal(SIGINT, SIG_IGN);
432		/*
433		 * nfsd sits in the kernel most of the time.  It needs
434		 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
435		 * as possible during a shutdown, otherwise loopback
436		 * mounts will not be able to unmount.
437		 */
438		(void)signal(SIGTERM, SIG_IGN);
439		(void)signal(SIGQUIT, SIG_IGN);
440	}
441	(void)signal(SIGSYS, nonfs);
442	(void)signal(SIGCHLD, reapchild);
443	(void)signal(SIGUSR2, backup_stable);
444
445	openlog("nfsd", LOG_PID | (debug ? LOG_PERROR : 0), LOG_DAEMON);
446
447	/*
448	 * For V4, we open the stablerestart file and call nfssvc()
449	 * to get it loaded. This is done before the daemons do the
450	 * regular nfssvc() call to service NFS requests.
451	 * (This way the file remains open until the last nfsd is killed
452	 *  off.)
453	 * It and the backup copy will be created as empty files
454	 * the first time this nfsd is started and should never be
455	 * deleted/replaced if at all possible. It should live on a
456	 * local, non-volatile storage device that does not do hardware
457	 * level write-back caching. (See SCSI doc for more information
458	 * on how to prevent write-back caching on SCSI disks.)
459	 */
460	open_stable(&stablefd, &backupfd);
461	if (stablefd < 0) {
462		syslog(LOG_ERR, "Can't open %s: %m\n", NFSD_STABLERESTART);
463		exit(1);
464	}
465	/* This system call will fail for old kernels, but that's ok. */
466	nfssvc(NFSSVC_BACKUPSTABLE, NULL);
467	if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) {
468		syslog(LOG_ERR, "Can't read stable storage file: %m\n");
469		exit(1);
470	}
471	nfssvc_addsock = NFSSVC_NFSDADDSOCK;
472	nfssvc_nfsd = NFSSVC_NFSDNFSD | NFSSVC_NEWSTRUCT;
473
474	if (tcpflag) {
475		/*
476		 * For TCP mode, we fork once to start the first
477		 * kernel nfsd thread. The kernel will add more
478		 * threads as needed.
479		 */
480		masterpid = getpid();
481		pid = fork();
482		if (pid == -1) {
483			syslog(LOG_ERR, "fork: %m");
484			nfsd_exit(1);
485		}
486		if (pid) {
487			children[0] = pid;
488		} else {
489			(void)signal(SIGUSR1, child_cleanup);
490			setproctitle("server");
491			start_server(0, &nfsdargs, vhostname);
492		}
493	}
494
495	(void)signal(SIGUSR1, cleanup);
496	FD_ZERO(&sockbits);
497
498	rpcbregcnt = 0;
499	/* Set up the socket for udp and rpcb register it. */
500	if (udpflag) {
501		rpcbreg = 0;
502		for (i = 0; i < bindhostc; i++) {
503			memset(&hints, 0, sizeof hints);
504			hints.ai_flags = AI_PASSIVE;
505			hints.ai_family = AF_INET;
506			hints.ai_socktype = SOCK_DGRAM;
507			hints.ai_protocol = IPPROTO_UDP;
508			if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
509				rpcbreg = 1;
510				rpcbregcnt++;
511				if ((sock = socket(ai_udp->ai_family,
512				    ai_udp->ai_socktype,
513				    ai_udp->ai_protocol)) < 0) {
514					syslog(LOG_ERR,
515					    "can't create udp socket");
516					nfsd_exit(1);
517				}
518				if (bind(sock, ai_udp->ai_addr,
519				    ai_udp->ai_addrlen) < 0) {
520					syslog(LOG_ERR,
521					    "can't bind udp addr %s: %m",
522					    bindhost[i]);
523					nfsd_exit(1);
524				}
525				freeaddrinfo(ai_udp);
526				addsockargs.sock = sock;
527				addsockargs.name = NULL;
528				addsockargs.namelen = 0;
529				if (nfssvc(nfssvc_addsock, &addsockargs) < 0) {
530					syslog(LOG_ERR, "can't Add UDP socket");
531					nfsd_exit(1);
532				}
533				(void)close(sock);
534			}
535		}
536		if (rpcbreg == 1) {
537			memset(&hints, 0, sizeof hints);
538			hints.ai_flags = AI_PASSIVE;
539			hints.ai_family = AF_INET;
540			hints.ai_socktype = SOCK_DGRAM;
541			hints.ai_protocol = IPPROTO_UDP;
542			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
543			if (ecode != 0) {
544				syslog(LOG_ERR, "getaddrinfo udp: %s",
545				   gai_strerror(ecode));
546				nfsd_exit(1);
547			}
548			nconf_udp = getnetconfigent("udp");
549			if (nconf_udp == NULL)
550				err(1, "getnetconfigent udp failed");
551			nb_udp.buf = ai_udp->ai_addr;
552			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
553			if (nfs_minvers == NFS_VER2)
554				if (!rpcb_set(NFS_PROGRAM, 2, nconf_udp,
555				    &nb_udp))
556					err(1, "rpcb_set udp failed");
557			if (nfs_minvers <= NFS_VER3)
558				if (!rpcb_set(NFS_PROGRAM, 3, nconf_udp,
559				    &nb_udp))
560					err(1, "rpcb_set udp failed");
561			freeaddrinfo(ai_udp);
562		}
563	}
564
565	/* Set up the socket for udp6 and rpcb register it. */
566	if (udpflag && ip6flag) {
567		rpcbreg = 0;
568		for (i = 0; i < bindhostc; i++) {
569			memset(&hints, 0, sizeof hints);
570			hints.ai_flags = AI_PASSIVE;
571			hints.ai_family = AF_INET6;
572			hints.ai_socktype = SOCK_DGRAM;
573			hints.ai_protocol = IPPROTO_UDP;
574			if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
575				rpcbreg = 1;
576				rpcbregcnt++;
577				if ((sock = socket(ai_udp6->ai_family,
578				    ai_udp6->ai_socktype,
579				    ai_udp6->ai_protocol)) < 0) {
580					syslog(LOG_ERR,
581						"can't create udp6 socket");
582					nfsd_exit(1);
583				}
584				if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
585				    &on, sizeof on) < 0) {
586					syslog(LOG_ERR,
587					    "can't set v6-only binding for "
588					    "udp6 socket: %m");
589					nfsd_exit(1);
590				}
591				if (bind(sock, ai_udp6->ai_addr,
592				    ai_udp6->ai_addrlen) < 0) {
593					syslog(LOG_ERR,
594					    "can't bind udp6 addr %s: %m",
595					    bindhost[i]);
596					nfsd_exit(1);
597				}
598				freeaddrinfo(ai_udp6);
599				addsockargs.sock = sock;
600				addsockargs.name = NULL;
601				addsockargs.namelen = 0;
602				if (nfssvc(nfssvc_addsock, &addsockargs) < 0) {
603					syslog(LOG_ERR,
604					    "can't add UDP6 socket");
605					nfsd_exit(1);
606				}
607				(void)close(sock);
608			}
609		}
610		if (rpcbreg == 1) {
611			memset(&hints, 0, sizeof hints);
612			hints.ai_flags = AI_PASSIVE;
613			hints.ai_family = AF_INET6;
614			hints.ai_socktype = SOCK_DGRAM;
615			hints.ai_protocol = IPPROTO_UDP;
616			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
617			if (ecode != 0) {
618				syslog(LOG_ERR, "getaddrinfo udp6: %s",
619				   gai_strerror(ecode));
620				nfsd_exit(1);
621			}
622			nconf_udp6 = getnetconfigent("udp6");
623			if (nconf_udp6 == NULL)
624				err(1, "getnetconfigent udp6 failed");
625			nb_udp6.buf = ai_udp6->ai_addr;
626			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
627			if (nfs_minvers == NFS_VER2)
628				if (!rpcb_set(NFS_PROGRAM, 2, nconf_udp6,
629				    &nb_udp6))
630					err(1,
631					    "rpcb_set udp6 failed");
632			if (nfs_minvers <= NFS_VER3)
633				if (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6,
634				    &nb_udp6))
635					err(1,
636					    "rpcb_set udp6 failed");
637			freeaddrinfo(ai_udp6);
638		}
639	}
640
641	/* Set up the socket for tcp and rpcb register it. */
642	if (tcpflag) {
643		rpcbreg = 0;
644		for (i = 0; i < bindhostc; i++) {
645			memset(&hints, 0, sizeof hints);
646			hints.ai_flags = AI_PASSIVE;
647			hints.ai_family = AF_INET;
648			hints.ai_socktype = SOCK_STREAM;
649			hints.ai_protocol = IPPROTO_TCP;
650			if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
651				rpcbreg = 1;
652				rpcbregcnt++;
653				if ((tcpsock = socket(AF_INET, SOCK_STREAM,
654				    0)) < 0) {
655					syslog(LOG_ERR,
656					    "can't create tcp socket");
657					nfsd_exit(1);
658				}
659				if (setsockopt(tcpsock, SOL_SOCKET,
660				    SO_REUSEADDR,
661				    (char *)&on, sizeof(on)) < 0)
662					syslog(LOG_ERR,
663					     "setsockopt SO_REUSEADDR: %m");
664				if (bind(tcpsock, ai_tcp->ai_addr,
665				    ai_tcp->ai_addrlen) < 0) {
666					syslog(LOG_ERR,
667					    "can't bind tcp addr %s: %m",
668					    bindhost[i]);
669					nfsd_exit(1);
670				}
671				if (listen(tcpsock, -1) < 0) {
672					syslog(LOG_ERR, "listen failed");
673					nfsd_exit(1);
674				}
675				freeaddrinfo(ai_tcp);
676				FD_SET(tcpsock, &sockbits);
677				maxsock = tcpsock;
678				connect_type_cnt++;
679			}
680		}
681		if (rpcbreg == 1) {
682			memset(&hints, 0, sizeof hints);
683			hints.ai_flags = AI_PASSIVE;
684			hints.ai_family = AF_INET;
685			hints.ai_socktype = SOCK_STREAM;
686			hints.ai_protocol = IPPROTO_TCP;
687			ecode = getaddrinfo(NULL, "nfs", &hints,
688			     &ai_tcp);
689			if (ecode != 0) {
690				syslog(LOG_ERR, "getaddrinfo tcp: %s",
691				   gai_strerror(ecode));
692				nfsd_exit(1);
693			}
694			nconf_tcp = getnetconfigent("tcp");
695			if (nconf_tcp == NULL)
696				err(1, "getnetconfigent tcp failed");
697			nb_tcp.buf = ai_tcp->ai_addr;
698			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
699			if (nfs_minvers == NFS_VER2)
700				if (!rpcb_set(NFS_PROGRAM, 2, nconf_tcp,
701				    &nb_tcp))
702					err(1, "rpcb_set tcp failed");
703			if (nfs_minvers <= NFS_VER3)
704				if (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp,
705				    &nb_tcp))
706					err(1, "rpcb_set tcp failed");
707			freeaddrinfo(ai_tcp);
708		}
709	}
710
711	/* Set up the socket for tcp6 and rpcb register it. */
712	if (tcpflag && ip6flag) {
713		rpcbreg = 0;
714		for (i = 0; i < bindhostc; i++) {
715			memset(&hints, 0, sizeof hints);
716			hints.ai_flags = AI_PASSIVE;
717			hints.ai_family = AF_INET6;
718			hints.ai_socktype = SOCK_STREAM;
719			hints.ai_protocol = IPPROTO_TCP;
720			if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
721				rpcbreg = 1;
722				rpcbregcnt++;
723				if ((tcp6sock = socket(ai_tcp6->ai_family,
724				    ai_tcp6->ai_socktype,
725				    ai_tcp6->ai_protocol)) < 0) {
726					syslog(LOG_ERR,
727					    "can't create tcp6 socket");
728					nfsd_exit(1);
729				}
730				if (setsockopt(tcp6sock, SOL_SOCKET,
731				    SO_REUSEADDR,
732				    (char *)&on, sizeof(on)) < 0)
733					syslog(LOG_ERR,
734					    "setsockopt SO_REUSEADDR: %m");
735				if (setsockopt(tcp6sock, IPPROTO_IPV6,
736				    IPV6_V6ONLY, &on, sizeof on) < 0) {
737					syslog(LOG_ERR,
738					"can't set v6-only binding for tcp6 "
739					    "socket: %m");
740					nfsd_exit(1);
741				}
742				if (bind(tcp6sock, ai_tcp6->ai_addr,
743				    ai_tcp6->ai_addrlen) < 0) {
744					syslog(LOG_ERR,
745					    "can't bind tcp6 addr %s: %m",
746					    bindhost[i]);
747					nfsd_exit(1);
748				}
749				if (listen(tcp6sock, -1) < 0) {
750					syslog(LOG_ERR, "listen failed");
751					nfsd_exit(1);
752				}
753				freeaddrinfo(ai_tcp6);
754				FD_SET(tcp6sock, &sockbits);
755				if (maxsock < tcp6sock)
756					maxsock = tcp6sock;
757				connect_type_cnt++;
758			}
759		}
760		if (rpcbreg == 1) {
761			memset(&hints, 0, sizeof hints);
762			hints.ai_flags = AI_PASSIVE;
763			hints.ai_family = AF_INET6;
764			hints.ai_socktype = SOCK_STREAM;
765			hints.ai_protocol = IPPROTO_TCP;
766			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
767			if (ecode != 0) {
768				syslog(LOG_ERR, "getaddrinfo tcp6: %s",
769				   gai_strerror(ecode));
770				nfsd_exit(1);
771			}
772			nconf_tcp6 = getnetconfigent("tcp6");
773			if (nconf_tcp6 == NULL)
774				err(1, "getnetconfigent tcp6 failed");
775			nb_tcp6.buf = ai_tcp6->ai_addr;
776			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
777			if (nfs_minvers == NFS_VER2)
778				if (!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6,
779				    &nb_tcp6))
780					err(1, "rpcb_set tcp6 failed");
781			if (nfs_minvers <= NFS_VER3)
782				if (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6,
783				    &nb_tcp6))
784					err(1, "rpcb_set tcp6 failed");
785			freeaddrinfo(ai_tcp6);
786		}
787	}
788
789	if (rpcbregcnt == 0) {
790		syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
791		nfsd_exit(1);
792	}
793
794	if (tcpflag && connect_type_cnt == 0) {
795		syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
796		nfsd_exit(1);
797	}
798
799	setproctitle("master");
800	/*
801	 * We always want a master to have a clean way to shut nfsd down
802	 * (with unregistration): if the master is killed, it unregisters and
803	 * kills all children. If we run for UDP only (and so do not have to
804	 * loop waiting for accept), we instead make the parent
805	 * a "server" too. start_server will not return.
806	 */
807	if (!tcpflag)
808		start_server(1, &nfsdargs, vhostname);
809
810	/*
811	 * Loop forever accepting connections and passing the sockets
812	 * into the kernel for the mounts.
813	 */
814	for (;;) {
815		ready = sockbits;
816		if (connect_type_cnt > 1) {
817			if (select(maxsock + 1,
818			    &ready, NULL, NULL, NULL) < 1) {
819				error = errno;
820				if (error == EINTR)
821					continue;
822				syslog(LOG_ERR, "select failed: %m");
823				nfsd_exit(1);
824			}
825		}
826		for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
827			if (FD_ISSET(tcpsock, &ready)) {
828				len = sizeof(peer);
829				if ((msgsock = accept(tcpsock,
830				    (struct sockaddr *)&peer, &len)) < 0) {
831					error = errno;
832					syslog(LOG_ERR, "accept failed: %m");
833					if (error == ECONNABORTED ||
834					    error == EINTR)
835						continue;
836					nfsd_exit(1);
837				}
838				if (setsockopt(msgsock, SOL_SOCKET,
839				    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
840					syslog(LOG_ERR,
841					    "setsockopt SO_KEEPALIVE: %m");
842				addsockargs.sock = msgsock;
843				addsockargs.name = (caddr_t)&peer;
844				addsockargs.namelen = len;
845				nfssvc(nfssvc_addsock, &addsockargs);
846				(void)close(msgsock);
847			}
848		}
849	}
850}
851
852static int
853setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints)
854{
855	int ecode;
856	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
857	const char *hostptr;
858
859	if (bindhost == NULL || strcmp("*", bindhost) == 0)
860		hostptr = NULL;
861	else
862		hostptr = bindhost;
863
864	if (hostptr != NULL) {
865		switch (hints.ai_family) {
866		case AF_INET:
867			if (inet_pton(AF_INET, hostptr, host_addr) == 1) {
868				hints.ai_flags = AI_NUMERICHOST;
869			} else {
870				if (inet_pton(AF_INET6, hostptr,
871				    host_addr) == 1)
872					return (1);
873			}
874			break;
875		case AF_INET6:
876			if (inet_pton(AF_INET6, hostptr, host_addr) == 1) {
877				hints.ai_flags = AI_NUMERICHOST;
878			} else {
879				if (inet_pton(AF_INET, hostptr,
880				    host_addr) == 1)
881					return (1);
882			}
883			break;
884		default:
885			break;
886		}
887	}
888
889	ecode = getaddrinfo(hostptr, "nfs", &hints, ai);
890	if (ecode != 0) {
891		syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost,
892		    gai_strerror(ecode));
893		return (1);
894	}
895	return (0);
896}
897
898static void
899set_nfsdcnt(int proposed)
900{
901
902	if (proposed < 1) {
903		warnx("nfsd count too low %d; reset to %d", proposed,
904		    DEFNFSDCNT);
905		nfsdcnt = DEFNFSDCNT;
906	} else if (proposed > MAXNFSDCNT) {
907		warnx("nfsd count too high %d; truncated to %d", proposed,
908		    MAXNFSDCNT);
909		nfsdcnt = MAXNFSDCNT;
910	} else
911		nfsdcnt = proposed;
912	nfsdcnt_set = 1;
913}
914
915static void
916usage(void)
917{
918	(void)fprintf(stderr, "%s", getopt_usage);
919	exit(1);
920}
921
922static void
923nonfs(__unused int signo)
924{
925	syslog(LOG_ERR, "missing system call: NFS not available");
926}
927
928static void
929reapchild(__unused int signo)
930{
931	pid_t pid;
932	int i;
933
934	while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) {
935		for (i = 0; i < nfsdcnt; i++)
936			if (pid == children[i])
937				children[i] = -1;
938	}
939}
940
941static void
942unregistration(void)
943{
944	if ((nfs_minvers == NFS_VER2 && !rpcb_unset(NFS_PROGRAM, 2, NULL)) ||
945	    (nfs_minvers <= NFS_VER3 && !rpcb_unset(NFS_PROGRAM, 3, NULL)))
946		syslog(LOG_ERR, "rpcb_unset failed");
947}
948
949static void
950killchildren(void)
951{
952	int i;
953
954	for (i = 0; i < nfsdcnt; i++) {
955		if (children[i] > 0)
956			kill(children[i], SIGKILL);
957	}
958}
959
960/*
961 * Cleanup master after SIGUSR1.
962 */
963static void
964cleanup(__unused int signo)
965{
966	nfsd_exit(0);
967}
968
969/*
970 * Cleanup child after SIGUSR1.
971 */
972static void
973child_cleanup(__unused int signo)
974{
975	exit(0);
976}
977
978static void
979nfsd_exit(int status)
980{
981	killchildren();
982	unregistration();
983	exit(status);
984}
985
986static int
987get_tuned_nfsdcount(void)
988{
989	int ncpu, error, tuned_nfsdcnt;
990	size_t ncpu_size;
991
992	ncpu_size = sizeof(ncpu);
993	error = sysctlbyname("hw.ncpu", &ncpu, &ncpu_size, NULL, 0);
994	if (error) {
995		warnx("sysctlbyname(hw.ncpu) failed defaulting to %d nfs servers",
996		    DEFNFSDCNT);
997		tuned_nfsdcnt = DEFNFSDCNT;
998	} else {
999		tuned_nfsdcnt = ncpu * 8;
1000	}
1001	return tuned_nfsdcnt;
1002}
1003
1004static void
1005start_server(int master, struct nfsd_nfsd_args *nfsdargp, const char *vhost)
1006{
1007	char principal[MAXHOSTNAMELEN + 5];
1008	int status, error;
1009	char hostname[MAXHOSTNAMELEN + 1], *cp;
1010	struct addrinfo *aip, hints;
1011
1012	status = 0;
1013	if (vhost == NULL)
1014		gethostname(hostname, sizeof (hostname));
1015	else
1016		strlcpy(hostname, vhost, sizeof (hostname));
1017	snprintf(principal, sizeof (principal), "nfs@%s", hostname);
1018	if ((cp = strchr(hostname, '.')) == NULL ||
1019	    *(cp + 1) == '\0') {
1020		/* If not fully qualified, try getaddrinfo() */
1021		memset((void *)&hints, 0, sizeof (hints));
1022		hints.ai_flags = AI_CANONNAME;
1023		error = getaddrinfo(hostname, NULL, &hints, &aip);
1024		if (error == 0) {
1025			if (aip->ai_canonname != NULL &&
1026			    (cp = strchr(aip->ai_canonname, '.')) !=
1027			    NULL && *(cp + 1) != '\0')
1028				snprintf(principal, sizeof (principal),
1029				    "nfs@%s", aip->ai_canonname);
1030			freeaddrinfo(aip);
1031		}
1032	}
1033	nfsdargp->principal = principal;
1034
1035	if (nfsdcnt_set)
1036		nfsdargp->minthreads = nfsdargp->maxthreads = nfsdcnt;
1037	else {
1038		nfsdargp->minthreads = minthreads_set ? minthreads : get_tuned_nfsdcount();
1039		nfsdargp->maxthreads = maxthreads_set ? maxthreads : nfsdargp->minthreads;
1040		if (nfsdargp->maxthreads < nfsdargp->minthreads)
1041			nfsdargp->maxthreads = nfsdargp->minthreads;
1042	}
1043	error = nfssvc(nfssvc_nfsd, nfsdargp);
1044	if (error < 0 && errno == EAUTH) {
1045		/*
1046		 * This indicates that it could not register the
1047		 * rpcsec_gss credentials, usually because the
1048		 * gssd daemon isn't running.
1049		 * (only the experimental server with nfsv4)
1050		 */
1051		syslog(LOG_ERR, "No gssd, using AUTH_SYS only");
1052		principal[0] = '\0';
1053		error = nfssvc(nfssvc_nfsd, nfsdargp);
1054	}
1055	if (error < 0) {
1056		if (errno == ENXIO) {
1057			syslog(LOG_ERR, "Bad -p option, cannot run");
1058			if (masterpid != 0 && master == 0)
1059				kill(masterpid, SIGUSR1);
1060		} else
1061			syslog(LOG_ERR, "nfssvc: %m");
1062		status = 1;
1063	}
1064	if (master)
1065		nfsd_exit(status);
1066	else
1067		exit(status);
1068}
1069
1070/*
1071 * Open the stable restart file and return the file descriptor for it.
1072 */
1073static void
1074open_stable(int *stable_fdp, int *backup_fdp)
1075{
1076	int stable_fd, backup_fd = -1, ret;
1077	struct stat st, backup_st;
1078
1079	/* Open and stat the stable restart file. */
1080	stable_fd = open(NFSD_STABLERESTART, O_RDWR, 0);
1081	if (stable_fd < 0)
1082		stable_fd = open(NFSD_STABLERESTART, O_RDWR | O_CREAT, 0600);
1083	if (stable_fd >= 0) {
1084		ret = fstat(stable_fd, &st);
1085		if (ret < 0) {
1086			close(stable_fd);
1087			stable_fd = -1;
1088		}
1089	}
1090
1091	/* Open and stat the backup stable restart file. */
1092	if (stable_fd >= 0) {
1093		backup_fd = open(NFSD_STABLEBACKUP, O_RDWR, 0);
1094		if (backup_fd < 0)
1095			backup_fd = open(NFSD_STABLEBACKUP, O_RDWR | O_CREAT,
1096			    0600);
1097		if (backup_fd >= 0) {
1098			ret = fstat(backup_fd, &backup_st);
1099			if (ret < 0) {
1100				close(backup_fd);
1101				backup_fd = -1;
1102			}
1103		}
1104		if (backup_fd < 0) {
1105			close(stable_fd);
1106			stable_fd = -1;
1107		}
1108	}
1109
1110	*stable_fdp = stable_fd;
1111	*backup_fdp = backup_fd;
1112	if (stable_fd < 0)
1113		return;
1114
1115	/* Sync up the 2 files, as required. */
1116	if (st.st_size > 0)
1117		copy_stable(stable_fd, backup_fd);
1118	else if (backup_st.st_size > 0)
1119		copy_stable(backup_fd, stable_fd);
1120}
1121
1122/*
1123 * Copy the stable restart file to the backup or vice versa.
1124 */
1125static void
1126copy_stable(int from_fd, int to_fd)
1127{
1128	int cnt, ret;
1129	static char buf[1024];
1130
1131	ret = lseek(from_fd, (off_t)0, SEEK_SET);
1132	if (ret >= 0)
1133		ret = lseek(to_fd, (off_t)0, SEEK_SET);
1134	if (ret >= 0)
1135		ret = ftruncate(to_fd, (off_t)0);
1136	if (ret >= 0)
1137		do {
1138			cnt = read(from_fd, buf, 1024);
1139			if (cnt > 0)
1140				ret = write(to_fd, buf, cnt);
1141			else if (cnt < 0)
1142				ret = cnt;
1143		} while (cnt > 0 && ret >= 0);
1144	if (ret >= 0)
1145		ret = fsync(to_fd);
1146	if (ret < 0)
1147		syslog(LOG_ERR, "stable restart copy failure: %m");
1148}
1149
1150/*
1151 * Back up the stable restart file when indicated by the kernel.
1152 */
1153static void
1154backup_stable(__unused int signo)
1155{
1156
1157	if (stablefd >= 0)
1158		copy_stable(stablefd, backupfd);
1159}
1160
1161/*
1162 * Parse the pNFS string and extract the DS servers and ports numbers.
1163 */
1164static void
1165parse_dsserver(const char *optionarg, struct nfsd_nfsd_args *nfsdargp)
1166{
1167	char *cp, *cp2, *dsaddr, *dshost, *dspath, *dsvol, nfsprt[9];
1168	char *mdspath, *mdsp, ip6[INET6_ADDRSTRLEN];
1169	const char *ad;
1170	int ecode;
1171	u_int adsiz, dsaddrcnt, dshostcnt, dspathcnt, hostsiz, pathsiz;
1172	u_int mdspathcnt;
1173	size_t dsaddrsiz, dshostsiz, dspathsiz, nfsprtsiz, mdspathsiz;
1174	struct addrinfo hints, *ai_tcp, *res;
1175	struct sockaddr_in sin;
1176	struct sockaddr_in6 sin6;
1177
1178	cp = strdup(optionarg);
1179	if (cp == NULL)
1180		errx(1, "Out of memory");
1181
1182	/* Now, do the host names. */
1183	dspathsiz = 1024;
1184	dspathcnt = 0;
1185	dspath = malloc(dspathsiz);
1186	if (dspath == NULL)
1187		errx(1, "Out of memory");
1188	dshostsiz = 1024;
1189	dshostcnt = 0;
1190	dshost = malloc(dshostsiz);
1191	if (dshost == NULL)
1192		errx(1, "Out of memory");
1193	dsaddrsiz = 1024;
1194	dsaddrcnt = 0;
1195	dsaddr = malloc(dsaddrsiz);
1196	if (dsaddr == NULL)
1197		errx(1, "Out of memory");
1198	mdspathsiz = 1024;
1199	mdspathcnt = 0;
1200	mdspath = malloc(mdspathsiz);
1201	if (mdspath == NULL)
1202		errx(1, "Out of memory");
1203
1204	/* Put the NFS port# in "." form. */
1205	snprintf(nfsprt, 9, ".%d.%d", 2049 >> 8, 2049 & 0xff);
1206	nfsprtsiz = strlen(nfsprt);
1207
1208	ai_tcp = NULL;
1209	/* Loop around for each DS server name. */
1210	do {
1211		cp2 = strchr(cp, ',');
1212		if (cp2 != NULL) {
1213			/* Not the last DS in the list. */
1214			*cp2++ = '\0';
1215			if (*cp2 == '\0')
1216				usage();
1217		}
1218
1219		dsvol = strchr(cp, ':');
1220		if (dsvol == NULL || *(dsvol + 1) == '\0')
1221			usage();
1222		*dsvol++ = '\0';
1223
1224		/* Optional path for MDS file system to be stored on DS. */
1225		mdsp = strchr(dsvol, '#');
1226		if (mdsp != NULL) {
1227			if (*(mdsp + 1) == '\0' || mdsp <= dsvol)
1228				usage();
1229			*mdsp++ = '\0';
1230		}
1231
1232		/* Append this pathname to dspath. */
1233		pathsiz = strlen(dsvol);
1234		if (dspathcnt + pathsiz + 1 > dspathsiz) {
1235			dspathsiz *= 2;
1236			dspath = realloc(dspath, dspathsiz);
1237			if (dspath == NULL)
1238				errx(1, "Out of memory");
1239		}
1240		strcpy(&dspath[dspathcnt], dsvol);
1241		dspathcnt += pathsiz + 1;
1242
1243		/* Append this pathname to mdspath. */
1244		if (mdsp != NULL)
1245			pathsiz = strlen(mdsp);
1246		else
1247			pathsiz = 0;
1248		if (mdspathcnt + pathsiz + 1 > mdspathsiz) {
1249			mdspathsiz *= 2;
1250			mdspath = realloc(mdspath, mdspathsiz);
1251			if (mdspath == NULL)
1252				errx(1, "Out of memory");
1253		}
1254		if (mdsp != NULL)
1255			strcpy(&mdspath[mdspathcnt], mdsp);
1256		else
1257			mdspath[mdspathcnt] = '\0';
1258		mdspathcnt += pathsiz + 1;
1259
1260		if (ai_tcp != NULL)
1261			freeaddrinfo(ai_tcp);
1262
1263		/* Get the fully qualified domain name and IP address. */
1264		memset(&hints, 0, sizeof(hints));
1265		hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
1266		hints.ai_family = PF_UNSPEC;
1267		hints.ai_socktype = SOCK_STREAM;
1268		hints.ai_protocol = IPPROTO_TCP;
1269		ecode = getaddrinfo(cp, NULL, &hints, &ai_tcp);
1270		if (ecode != 0)
1271			err(1, "getaddrinfo pnfs: %s %s", cp,
1272			    gai_strerror(ecode));
1273		ad = NULL;
1274		for (res = ai_tcp; res != NULL; res = res->ai_next) {
1275			if (res->ai_addr->sa_family == AF_INET) {
1276				if (res->ai_addrlen < sizeof(sin))
1277					err(1, "getaddrinfo() returned "
1278					    "undersized IPv4 address");
1279				/*
1280				 * Mips cares about sockaddr_in alignment,
1281				 * so copy the address.
1282				 */
1283				memcpy(&sin, res->ai_addr, sizeof(sin));
1284				ad = inet_ntoa(sin.sin_addr);
1285				break;
1286			} else if (res->ai_family == AF_INET6) {
1287				if (res->ai_addrlen < sizeof(sin6))
1288					err(1, "getaddrinfo() returned "
1289					    "undersized IPv6 address");
1290				/*
1291				 * Mips cares about sockaddr_in6 alignment,
1292				 * so copy the address.
1293				 */
1294				memcpy(&sin6, res->ai_addr, sizeof(sin6));
1295				ad = inet_ntop(AF_INET6, &sin6.sin6_addr, ip6,
1296				    sizeof(ip6));
1297
1298				/*
1299				 * XXX
1300				 * Since a link local address will only
1301				 * work if the client and DS are in the
1302				 * same scope zone, only use it if it is
1303				 * the only address.
1304				 */
1305				if (ad != NULL &&
1306				    !IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
1307					break;
1308			}
1309		}
1310		if (ad == NULL)
1311			err(1, "No IP address for %s", cp);
1312
1313		/* Append this address to dsaddr. */
1314		adsiz = strlen(ad);
1315		if (dsaddrcnt + adsiz + nfsprtsiz + 1 > dsaddrsiz) {
1316			dsaddrsiz *= 2;
1317			dsaddr = realloc(dsaddr, dsaddrsiz);
1318			if (dsaddr == NULL)
1319				errx(1, "Out of memory");
1320		}
1321		strcpy(&dsaddr[dsaddrcnt], ad);
1322		strcat(&dsaddr[dsaddrcnt], nfsprt);
1323		dsaddrcnt += adsiz + nfsprtsiz + 1;
1324
1325		/* Append this hostname to dshost. */
1326		hostsiz = strlen(ai_tcp->ai_canonname);
1327		if (dshostcnt + hostsiz + 1 > dshostsiz) {
1328			dshostsiz *= 2;
1329			dshost = realloc(dshost, dshostsiz);
1330			if (dshost == NULL)
1331				errx(1, "Out of memory");
1332		}
1333		strcpy(&dshost[dshostcnt], ai_tcp->ai_canonname);
1334		dshostcnt += hostsiz + 1;
1335
1336		cp = cp2;
1337	} while (cp != NULL);
1338
1339	nfsdargp->addr = dsaddr;
1340	nfsdargp->addrlen = dsaddrcnt;
1341	nfsdargp->dnshost = dshost;
1342	nfsdargp->dnshostlen = dshostcnt;
1343	nfsdargp->dspath = dspath;
1344	nfsdargp->dspathlen = dspathcnt;
1345	nfsdargp->mdspath = mdspath;
1346	nfsdargp->mdspathlen = mdspathcnt;
1347	freeaddrinfo(ai_tcp);
1348}
1349
1350