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