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#include <sys/param.h>
36#include <sys/syslog.h>
37#include <sys/wait.h>
38#include <sys/mount.h>
39#include <sys/fcntl.h>
40#include <sys/linker.h>
41#include <sys/module.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <sys/sysctl.h>
45#include <sys/ucred.h>
46
47#include <rpc/rpc.h>
48#include <rpc/pmap_clnt.h>
49#include <rpcsvc/nfs_prot.h>
50
51#include <netdb.h>
52#include <arpa/inet.h>
53#include <nfs/nfssvc.h>
54
55#include <fs/nfs/nfsproto.h>
56#include <fs/nfs/nfskpiport.h>
57#include <fs/nfs/nfs.h>
58
59#include <err.h>
60#include <errno.h>
61#include <signal.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <unistd.h>
66#include <sysexits.h>
67
68#include <getopt.h>
69
70static int	debug = 0;
71
72#define	NFSD_STABLERESTART	"/var/db/nfs-stablerestart"
73#define	NFSD_STABLEBACKUP	"/var/db/nfs-stablerestart.bak"
74#define	MAXNFSDCNT	256
75#define	DEFNFSDCNT	 4
76#define	NFS_VER2	 2
77#define NFS_VER3	 3
78#define NFS_VER4	 4
79static pid_t children[MAXNFSDCNT]; /* PIDs of children */
80static pid_t masterpid;		   /* PID of master/parent */
81static int nfsdcnt;		/* number of children */
82static int nfsdcnt_set;
83static int minthreads;
84static int maxthreads;
85static int nfssvc_nfsd;		/* Set to correct NFSSVC_xxx flag */
86static int stablefd = -1;	/* Fd for the stable restart file */
87static int backupfd;		/* Fd for the backup stable restart file */
88static const char *getopt_shortopts;
89static const char *getopt_usage;
90static int nfs_minvers = NFS_VER2;
91
92static int minthreads_set;
93static int maxthreads_set;
94
95static struct option longopts[] = {
96	{ "debug", no_argument, &debug, 1 },
97	{ "minthreads", required_argument, &minthreads_set, 1 },
98	{ "maxthreads", required_argument, &maxthreads_set, 1 },
99	{ "pnfs", required_argument, NULL, 'p' },
100	{ "mirror", required_argument, NULL, 'm' },
101	{ NULL, 0, NULL, 0}
102};
103
104static void	cleanup(int);
105static void	child_cleanup(int);
106static void	killchildren(void);
107static void	nfsd_exit(int);
108static void	nonfs(int);
109static void	reapchild(int);
110static int	setbindhost(struct addrinfo **ia, const char *bindhost,
111		    struct addrinfo hints);
112static void	start_server(int, struct nfsd_nfsd_args *, const char *vhost);
113static void	unregistration(void);
114static void	usage(void);
115static void	open_stable(int *, int *);
116static void	copy_stable(int, int);
117static void	backup_stable(int);
118static void	set_nfsdcnt(int);
119static void	parse_dsserver(const char *, struct nfsd_nfsd_args *);
120
121/*
122 * Nfs server daemon mostly just a user context for nfssvc()
123 *
124 * 1 - do file descriptor and signal cleanup
125 * 2 - fork the nfsd(s)
126 * 3 - create server socket(s)
127 * 4 - register socket with rpcbind
128 *
129 * For connectionless protocols, just pass the socket into the kernel via.
130 * nfssvc().
131 * For connection based sockets, loop doing accepts. When you get a new
132 * socket from accept, pass the msgsock into the kernel via. nfssvc().
133 * The arguments are:
134 *	-r - reregister with rpcbind
135 *	-d - unregister with rpcbind
136 *	-t - support tcp nfs clients
137 *	-u - support udp nfs clients
138 *	-e - forces it to run a server that supports nfsv4
139 *	-p - enable a pNFS service
140 *	-m - set the mirroring level for a pNFS service
141 * followed by "n" which is the number of nfsds' to fork off
142 */
143int
144main(int argc, char **argv)
145{
146	struct nfsd_addsock_args addsockargs;
147	struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
148	struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
149	struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
150	struct sockaddr_storage peer;
151	fd_set ready, sockbits;
152	int ch, connect_type_cnt, i, maxsock, msgsock;
153	socklen_t len;
154	int on = 1, unregister, reregister, sock;
155	int tcp6sock, ip6flag, tcpflag, tcpsock;
156	int udpflag, ecode, error, s;
157	int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
158	int nfssvc_addsock;
159	int jailed, longindex = 0;
160	size_t jailed_size, nfs_minvers_size;
161	const char *lopt;
162	char **bindhost = NULL;
163	pid_t pid;
164	struct nfsd_nfsd_args nfsdargs;
165	const char *vhostname = NULL;
166
167	nfsdargs.mirrorcnt = 1;
168	nfsdargs.addr = NULL;
169	nfsdargs.addrlen = 0;
170	nfsdcnt = DEFNFSDCNT;
171	unregister = reregister = tcpflag = maxsock = 0;
172	bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
173	getopt_shortopts = "ah:n:rdtuep:m:V:";
174	getopt_usage =
175	    "usage:\n"
176	    "  nfsd [-ardtue] [-h bindip]\n"
177	    "       [-n numservers] [--minthreads #] [--maxthreads #]\n"
178	    "       [-p/--pnfs dsserver0:/dsserver0-mounted-on-dir,...,"
179	    "dsserverN:/dsserverN-mounted-on-dir] [-m mirrorlevel]\n"
180	    "       [-V virtual_hostname]\n";
181	while ((ch = getopt_long(argc, argv, getopt_shortopts, longopts,
182		    &longindex)) != -1)
183		switch (ch) {
184		case 'V':
185			if (strlen(optarg) <= MAXHOSTNAMELEN)
186				vhostname = optarg;
187			else
188				warnx("Virtual host name (%s) is too long",
189				    optarg);
190			break;
191		case 'a':
192			bindanyflag = 1;
193			break;
194		case 'n':
195			set_nfsdcnt(atoi(optarg));
196			break;
197		case 'h':
198			bindhostc++;
199			bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
200			if (bindhost == NULL)
201				errx(1, "Out of memory");
202			bindhost[bindhostc-1] = strdup(optarg);
203			if (bindhost[bindhostc-1] == NULL)
204				errx(1, "Out of memory");
205			break;
206		case 'r':
207			reregister = 1;
208			break;
209		case 'd':
210			unregister = 1;
211			break;
212		case 't':
213			tcpflag = 1;
214			break;
215		case 'u':
216			udpflag = 1;
217			break;
218		case 'e':
219			/* now a no-op, since this is the default */
220			break;
221		case 'p':
222			/* Parse out the DS server host names and mount pts. */
223			parse_dsserver(optarg, &nfsdargs);
224			break;
225		case 'm':
226			/* Set the mirror level for a pNFS service. */
227			i = atoi(optarg);
228			if (i < 2 || i > NFSDEV_MAXMIRRORS)
229				errx(1, "Mirror level out of range 2<-->%d",
230				    NFSDEV_MAXMIRRORS);
231			nfsdargs.mirrorcnt = i;
232			break;
233		case 0:
234			lopt = longopts[longindex].name;
235			if (!strcmp(lopt, "minthreads")) {
236				minthreads = atoi(optarg);
237			} else if (!strcmp(lopt, "maxthreads")) {
238				maxthreads = atoi(optarg);
239			}
240			break;
241		default:
242		case '?':
243			usage();
244		}
245	if (!tcpflag && !udpflag)
246		udpflag = 1;
247	argv += optind;
248	argc -= optind;
249	if (minthreads_set && maxthreads_set && minthreads > maxthreads)
250		errx(EX_USAGE,
251		    "error: minthreads(%d) can't be greater than "
252		    "maxthreads(%d)", minthreads, maxthreads);
253
254	/*
255	 * XXX
256	 * Backward compatibility, trailing number is the count of daemons.
257	 */
258	if (argc > 1)
259		usage();
260	if (argc == 1)
261		set_nfsdcnt(atoi(argv[0]));
262
263	/*
264	 * Unless the "-o" option was specified, try and run "nfsd".
265	 * If "-o" was specified, try and run "nfsserver".
266	 */
267	if (modfind("nfsd") < 0) {
268		/* Not present in kernel, try loading it */
269		if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
270			errx(1, "NFS server is not available");
271	}
272
273	ip6flag = 1;
274	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
275	if (s == -1) {
276		if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
277			err(1, "socket");
278		ip6flag = 0;
279	} else if (getnetconfigent("udp6") == NULL ||
280		getnetconfigent("tcp6") == NULL) {
281		ip6flag = 0;
282	}
283	if (s != -1)
284		close(s);
285
286	if (bindhostc == 0 || bindanyflag) {
287		bindhostc++;
288		bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
289		if (bindhost == NULL)
290			errx(1, "Out of memory");
291		bindhost[bindhostc-1] = strdup("*");
292		if (bindhost[bindhostc-1] == NULL)
293			errx(1, "Out of memory");
294	}
295
296	if (unregister) {
297		/*
298		 * Unregister before setting nfs_minvers, in case the
299		 * value of vfs.nfsd.server_min_nfsvers has changed
300		 * since registering with rpcbind.
301		 */
302		unregistration();
303		exit (0);
304	}
305
306	nfs_minvers_size = sizeof(nfs_minvers);
307	error = sysctlbyname("vfs.nfsd.server_min_nfsvers", &nfs_minvers,
308	    &nfs_minvers_size, NULL, 0);
309	if (error != 0 || nfs_minvers < NFS_VER2 || nfs_minvers > NFS_VER4) {
310		warnx("sysctlbyname(vfs.nfsd.server_min_nfsvers) failed,"
311		    " defaulting to NFSv2");
312		nfs_minvers = NFS_VER2;
313	}
314
315	if (reregister) {
316		if (udpflag) {
317			memset(&hints, 0, sizeof hints);
318			hints.ai_flags = AI_PASSIVE;
319			hints.ai_family = AF_INET;
320			hints.ai_socktype = SOCK_DGRAM;
321			hints.ai_protocol = IPPROTO_UDP;
322			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
323			if (ecode != 0)
324				err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
325			nconf_udp = getnetconfigent("udp");
326			if (nconf_udp == NULL)
327				err(1, "getnetconfigent udp failed");
328			nb_udp.buf = ai_udp->ai_addr;
329			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
330			if (nfs_minvers == NFS_VER2)
331				if (!rpcb_set(NFS_PROGRAM, 2, nconf_udp,
332				    &nb_udp))
333					err(1, "rpcb_set udp failed");
334			if (nfs_minvers <= NFS_VER3)
335				if (!rpcb_set(NFS_PROGRAM, 3, nconf_udp,
336				    &nb_udp))
337					err(1, "rpcb_set udp failed");
338			freeaddrinfo(ai_udp);
339		}
340		if (udpflag && ip6flag) {
341			memset(&hints, 0, sizeof hints);
342			hints.ai_flags = AI_PASSIVE;
343			hints.ai_family = AF_INET6;
344			hints.ai_socktype = SOCK_DGRAM;
345			hints.ai_protocol = IPPROTO_UDP;
346			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
347			if (ecode != 0)
348				err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
349			nconf_udp6 = getnetconfigent("udp6");
350			if (nconf_udp6 == NULL)
351				err(1, "getnetconfigent udp6 failed");
352			nb_udp6.buf = ai_udp6->ai_addr;
353			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
354			if (nfs_minvers == NFS_VER2)
355				if (!rpcb_set(NFS_PROGRAM, 2, nconf_udp6,
356				    &nb_udp6))
357					err(1, "rpcb_set udp6 failed");
358			if (nfs_minvers <= NFS_VER3)
359				if (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6,
360				    &nb_udp6))
361					err(1, "rpcb_set udp6 failed");
362			freeaddrinfo(ai_udp6);
363		}
364		if (tcpflag) {
365			memset(&hints, 0, sizeof hints);
366			hints.ai_flags = AI_PASSIVE;
367			hints.ai_family = AF_INET;
368			hints.ai_socktype = SOCK_STREAM;
369			hints.ai_protocol = IPPROTO_TCP;
370			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
371			if (ecode != 0)
372				err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
373			nconf_tcp = getnetconfigent("tcp");
374			if (nconf_tcp == NULL)
375				err(1, "getnetconfigent tcp failed");
376			nb_tcp.buf = ai_tcp->ai_addr;
377			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
378			if (nfs_minvers == NFS_VER2)
379				if (!rpcb_set(NFS_PROGRAM, 2, nconf_tcp,
380				    &nb_tcp))
381					err(1, "rpcb_set tcp failed");
382			if (nfs_minvers <= NFS_VER3)
383				if (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp,
384				    &nb_tcp))
385					err(1, "rpcb_set tcp failed");
386			freeaddrinfo(ai_tcp);
387		}
388		if (tcpflag && ip6flag) {
389			memset(&hints, 0, sizeof hints);
390			hints.ai_flags = AI_PASSIVE;
391			hints.ai_family = AF_INET6;
392			hints.ai_socktype = SOCK_STREAM;
393			hints.ai_protocol = IPPROTO_TCP;
394			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
395			if (ecode != 0)
396				err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
397			nconf_tcp6 = getnetconfigent("tcp6");
398			if (nconf_tcp6 == NULL)
399				err(1, "getnetconfigent tcp6 failed");
400			nb_tcp6.buf = ai_tcp6->ai_addr;
401			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
402			if (nfs_minvers == NFS_VER2)
403				if (!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6,
404				    &nb_tcp6))
405					err(1, "rpcb_set tcp6 failed");
406			if (nfs_minvers <= NFS_VER3)
407				if (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6,
408				   &nb_tcp6))
409					err(1, "rpcb_set tcp6 failed");
410			freeaddrinfo(ai_tcp6);
411		}
412		exit (0);
413	}
414	if (debug == 0) {
415		daemon(0, 0);
416		(void)signal(SIGHUP, SIG_IGN);
417		(void)signal(SIGINT, SIG_IGN);
418		/*
419		 * nfsd sits in the kernel most of the time.  It needs
420		 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
421		 * as possible during a shutdown, otherwise loopback
422		 * mounts will not be able to unmount.
423		 */
424		(void)signal(SIGTERM, SIG_IGN);
425		(void)signal(SIGQUIT, SIG_IGN);
426	}
427	(void)signal(SIGSYS, nonfs);
428	(void)signal(SIGCHLD, reapchild);
429	(void)signal(SIGUSR2, backup_stable);
430
431	openlog("nfsd", LOG_PID | (debug ? LOG_PERROR : 0), LOG_DAEMON);
432
433	/*
434	 * For V4, we open the stablerestart file and call nfssvc()
435	 * to get it loaded. This is done before the daemons do the
436	 * regular nfssvc() call to service NFS requests.
437	 * (This way the file remains open until the last nfsd is killed
438	 *  off.)
439	 * It and the backup copy will be created as empty files
440	 * the first time this nfsd is started and should never be
441	 * deleted/replaced if at all possible. It should live on a
442	 * local, non-volatile storage device that does not do hardware
443	 * level write-back caching. (See SCSI doc for more information
444	 * on how to prevent write-back caching on SCSI disks.)
445	 */
446	open_stable(&stablefd, &backupfd);
447	if (stablefd < 0) {
448		syslog(LOG_ERR, "Can't open %s: %m\n", NFSD_STABLERESTART);
449		exit(1);
450	}
451	/* This system call will fail for old kernels, but that's ok. */
452	nfssvc(NFSSVC_BACKUPSTABLE, NULL);
453	if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) {
454		if (errno == EPERM) {
455			jailed = 0;
456			jailed_size = sizeof(jailed);
457			sysctlbyname("security.jail.jailed", &jailed,
458			    &jailed_size, NULL, 0);
459			if (jailed != 0)
460				syslog(LOG_ERR, "nfssvc stablerestart failed: "
461				    "allow.nfsd might not be configured");
462			else
463				syslog(LOG_ERR, "nfssvc stablerestart failed");
464		} else if (errno == ENXIO)
465			syslog(LOG_ERR, "nfssvc stablerestart failed: is nfsd "
466			    "already running?");
467		else
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