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