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 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 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 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 965 usage(void) 966 { 967 (void)fprintf(stderr, "%s", getopt_usage); 968 exit(1); 969 } 970 971 static void 972 nonfs(__unused int signo) 973 { 974 syslog(LOG_ERR, "missing system call: NFS not available"); 975 } 976 977 static void 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 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 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 1013 cleanup(__unused int signo) 1014 { 1015 nfsd_exit(0); 1016 } 1017 1018 /* 1019 * Cleanup child after SIGUSR1. 1020 */ 1021 static void 1022 child_cleanup(__unused int signo) 1023 { 1024 exit(0); 1025 } 1026 1027 static void 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 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 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 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 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 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 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