]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/nfsd/nfsd.c
zfs: merge openzfs/zfs@2e6b3c4d9
[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 #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
70 static 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
79 static pid_t children[MAXNFSDCNT]; /* PIDs of children */
80 static pid_t masterpid;            /* PID of master/parent */
81 static int nfsdcnt;             /* number of children */
82 static int nfsdcnt_set;
83 static int minthreads;
84 static int maxthreads;
85 static int nfssvc_nfsd;         /* Set to correct NFSSVC_xxx flag */
86 static int stablefd = -1;       /* Fd for the stable restart file */
87 static int backupfd;            /* Fd for the backup stable restart file */
88 static const char *getopt_shortopts;
89 static const char *getopt_usage;
90 static int nfs_minvers = NFS_VER2;
91
92 static int minthreads_set;
93 static int maxthreads_set;
94
95 static 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
104 static void     cleanup(int);
105 static void     child_cleanup(int);
106 static void     killchildren(void);
107 static void     nfsd_exit(int);
108 static void     nonfs(int);
109 static void     reapchild(int);
110 static int      setbindhost(struct addrinfo **ia, const char *bindhost,
111                     struct addrinfo hints);
112 static void     start_server(int, struct nfsd_nfsd_args *, const char *vhost);
113 static void     unregistration(void);
114 static void     usage(void);
115 static void     open_stable(int *, int *);
116 static void     copy_stable(int, int);
117 static void     backup_stable(int);
118 static void     set_nfsdcnt(int);
119 static 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  */
143 int
144 main(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
852 static int
853 setbindhost(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
898 static void
899 set_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
915 static void
916 usage(void)
917 {
918         (void)fprintf(stderr, "%s", getopt_usage);
919         exit(1);
920 }
921
922 static void
923 nonfs(__unused int signo)
924 {
925         syslog(LOG_ERR, "missing system call: NFS not available");
926 }
927
928 static void
929 reapchild(__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
941 static void
942 unregistration(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
949 static void
950 killchildren(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  */
963 static void
964 cleanup(__unused int signo)
965 {
966         nfsd_exit(0);
967 }
968
969 /*
970  * Cleanup child after SIGUSR1.
971  */
972 static void
973 child_cleanup(__unused int signo)
974 {
975         exit(0);
976 }
977
978 static void
979 nfsd_exit(int status)
980 {
981         killchildren();
982         unregistration();
983         exit(status);
984 }
985
986 static int
987 get_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
1004 static void
1005 start_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  */
1073 static void
1074 open_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  */
1125 static void
1126 copy_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  */
1153 static void
1154 backup_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  */
1164 static void
1165 parse_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