11558Srgrimes/* 21558Srgrimes * Copyright (c) 1989, 1993, 1994 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Rick Macklem at The University of Guelph. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 4. Neither the name of the University nor the names of its contributors 171558Srgrimes * may be used to endorse or promote products derived from this software 181558Srgrimes * without specific prior written permission. 191558Srgrimes * 201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301558Srgrimes * SUCH DAMAGE. 311558Srgrimes */ 321558Srgrimes 331558Srgrimes#ifndef lint 3437666Scharnierstatic const char copyright[] = 351558Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\ 361558Srgrimes The Regents of the University of California. All rights reserved.\n"; 3795861Speter#endif /* not lint */ 381558Srgrimes 391558Srgrimes#ifndef lint 4037666Scharnier#if 0 4123684Speterstatic char sccsid[] = "@(#)nfsd.c 8.9 (Berkeley) 3/29/95"; 4237666Scharnier#endif 4337666Scharnierstatic const char rcsid[] = 4450476Speter "$FreeBSD$"; 4595861Speter#endif /* not lint */ 461558Srgrimes 471558Srgrimes#include <sys/param.h> 481558Srgrimes#include <sys/syslog.h> 491558Srgrimes#include <sys/wait.h> 501558Srgrimes#include <sys/mount.h> 51192674Srmacklem#include <sys/fcntl.h> 5285034Siedowse#include <sys/linker.h> 5385034Siedowse#include <sys/module.h> 54220510Srmacklem#include <sys/types.h> 55220510Srmacklem#include <sys/stat.h> 56243637Salfred#include <sys/sysctl.h> 57220510Srmacklem#include <sys/ucred.h> 581558Srgrimes 591558Srgrimes#include <rpc/rpc.h> 601558Srgrimes#include <rpc/pmap_clnt.h> 61194880Sdfr#include <rpcsvc/nfs_prot.h> 621558Srgrimes 6353096Sdillon#include <netdb.h> 6453096Sdillon#include <arpa/inet.h> 6583653Speter#include <nfsserver/nfs.h> 66192674Srmacklem#include <nfs/nfssvc.h> 671558Srgrimes 681558Srgrimes#include <err.h> 691558Srgrimes#include <errno.h> 7085034Siedowse#include <signal.h> 711558Srgrimes#include <stdio.h> 721558Srgrimes#include <stdlib.h> 7395861Speter#include <string.h> 741558Srgrimes#include <unistd.h> 75243637Salfred#include <sysexits.h> 761558Srgrimes 77243637Salfred#include <getopt.h> 78243637Salfred 79241737Sedstatic int debug = 0; 801558Srgrimes 81192674Srmacklem#define NFSD_STABLERESTART "/var/db/nfs-stablerestart" 82220510Srmacklem#define NFSD_STABLEBACKUP "/var/db/nfs-stablerestart.bak" 83140679Srwatson#define MAXNFSDCNT 256 8474462Salfred#define DEFNFSDCNT 4 85241737Sedstatic pid_t children[MAXNFSDCNT]; /* PIDs of children */ 86241737Sedstatic int nfsdcnt; /* number of children */ 87243637Salfredstatic int nfsdcnt_set; 88243637Salfredstatic int minthreads; 89243637Salfredstatic int maxthreads; 90241737Sedstatic int new_syscall; 91241737Sedstatic int run_v4server = 1; /* Force running of nfsv4 server */ 92241737Sedstatic int nfssvc_nfsd; /* Set to correct NFSSVC_xxx flag */ 93241737Sedstatic int stablefd = -1; /* Fd for the stable restart file */ 94241737Sedstatic int backupfd; /* Fd for the backup stable restart file */ 95243637Salfredstatic const char *getopt_shortopts; 96243637Salfredstatic const char *getopt_usage; 9774462Salfred 98243637Salfredstatic int minthreads_set; 99243637Salfredstatic int maxthreads_set; 100243637Salfred 101243637Salfredstatic struct option longopts[] = { 102243637Salfred { "debug", no_argument, &debug, 1 }, 103243637Salfred { "minthreads", required_argument, &minthreads_set, 1 }, 104243637Salfred { "maxthreads", required_argument, &maxthreads_set, 1 }, 105243637Salfred { NULL, 0, NULL, 0} 106243637Salfred}; 107243637Salfred 108246778Sdelphijstatic void cleanup(int); 109246778Sdelphijstatic void child_cleanup(int); 110246778Sdelphijstatic void killchildren(void); 111246778Sdelphijstatic void nfsd_exit(int); 112246778Sdelphijstatic void nonfs(int); 113246778Sdelphijstatic void reapchild(int); 114246778Sdelphijstatic int setbindhost(struct addrinfo **ia, const char *bindhost, 115246778Sdelphij struct addrinfo hints); 116246778Sdelphijstatic void start_server(int); 117246778Sdelphijstatic void unregistration(void); 118246778Sdelphijstatic void usage(void); 119246778Sdelphijstatic void open_stable(int *, int *); 120246778Sdelphijstatic void copy_stable(int, int); 121246778Sdelphijstatic void backup_stable(int); 122246780Sdelphijstatic void set_nfsdcnt(int); 1231558Srgrimes 1241558Srgrimes/* 1251558Srgrimes * Nfs server daemon mostly just a user context for nfssvc() 1261558Srgrimes * 1271558Srgrimes * 1 - do file descriptor and signal cleanup 1281558Srgrimes * 2 - fork the nfsd(s) 1291558Srgrimes * 3 - create server socket(s) 13074462Salfred * 4 - register socket with rpcbind 1311558Srgrimes * 1321558Srgrimes * For connectionless protocols, just pass the socket into the kernel via. 1331558Srgrimes * nfssvc(). 1341558Srgrimes * For connection based sockets, loop doing accepts. When you get a new 1351558Srgrimes * socket from accept, pass the msgsock into the kernel via. nfssvc(). 1361558Srgrimes * The arguments are: 13774462Salfred * -r - reregister with rpcbind 13874462Salfred * -d - unregister with rpcbind 1391558Srgrimes * -t - support tcp nfs clients 1401558Srgrimes * -u - support udp nfs clients 141192993Srmacklem * -e - forces it to run a server that supports nfsv4 1421558Srgrimes * followed by "n" which is the number of nfsds' to fork off 1431558Srgrimes */ 1441558Srgrimesint 145137319Sdelphijmain(int argc, char **argv) 1461558Srgrimes{ 147184588Sdfr struct nfsd_addsock_args addsockargs; 14874462Salfred struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints; 14974462Salfred struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6; 15074462Salfred struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6; 15174462Salfred struct sockaddr_in inetpeer; 15274462Salfred struct sockaddr_in6 inet6peer; 1531558Srgrimes fd_set ready, sockbits; 15474462Salfred fd_set v4bits, v6bits; 155153590Sdelphij int ch, connect_type_cnt, i, maxsock, msgsock; 156153609Sdelphij socklen_t len; 15785034Siedowse int on = 1, unregister, reregister, sock; 15874462Salfred int tcp6sock, ip6flag, tcpflag, tcpsock; 159218777Sjhb int udpflag, ecode, error, s, srvcnt; 16085034Siedowse int bindhostc, bindanyflag, rpcbreg, rpcbregcnt; 161220510Srmacklem int nfssvc_addsock; 162243637Salfred int longindex = 0; 163243637Salfred const char *lopt; 16453096Sdillon char **bindhost = NULL; 16574462Salfred pid_t pid; 1661558Srgrimes 1671558Srgrimes nfsdcnt = DEFNFSDCNT; 16885034Siedowse unregister = reregister = tcpflag = maxsock = 0; 16985034Siedowse bindanyflag = udpflag = connect_type_cnt = bindhostc = 0; 170243637Salfred getopt_shortopts = "ah:n:rdtueo"; 171243637Salfred getopt_usage = 172243637Salfred "usage:\n" 173243637Salfred " nfsd [-ardtueo] [-h bindip]\n" 174243637Salfred " [-n numservers] [--minthreads #] [--maxthreads #]\n"; 175243637Salfred while ((ch = getopt_long(argc, argv, getopt_shortopts, longopts, 176243637Salfred &longindex)) != -1) 1771558Srgrimes switch (ch) { 17853096Sdillon case 'a': 17953096Sdillon bindanyflag = 1; 18053096Sdillon break; 1811558Srgrimes case 'n': 182246780Sdelphij set_nfsdcnt(atoi(optarg)); 1831558Srgrimes break; 18453096Sdillon case 'h': 18553096Sdillon bindhostc++; 18653096Sdillon bindhost = realloc(bindhost,sizeof(char *)*bindhostc); 18753096Sdillon if (bindhost == NULL) 18853096Sdillon errx(1, "Out of memory"); 18953096Sdillon bindhost[bindhostc-1] = strdup(optarg); 19053096Sdillon if (bindhost[bindhostc-1] == NULL) 19153096Sdillon errx(1, "Out of memory"); 19253096Sdillon break; 1931558Srgrimes case 'r': 1941558Srgrimes reregister = 1; 1951558Srgrimes break; 19674462Salfred case 'd': 19774462Salfred unregister = 1; 19874462Salfred break; 1991558Srgrimes case 't': 2001558Srgrimes tcpflag = 1; 2011558Srgrimes break; 2021558Srgrimes case 'u': 2031558Srgrimes udpflag = 1; 2041558Srgrimes break; 205192993Srmacklem case 'e': 206220980Srmacklem /* now a no-op, since this is the default */ 207192674Srmacklem break; 208220980Srmacklem case 'o': 209220980Srmacklem run_v4server = 0; 210220980Srmacklem break; 211243637Salfred case 0: 212243637Salfred lopt = longopts[longindex].name; 213243637Salfred if (!strcmp(lopt, "minthreads")) { 214243637Salfred minthreads = atoi(optarg); 215243637Salfred } else if (!strcmp(lopt, "maxthreads")) { 216243637Salfred maxthreads = atoi(optarg); 217243637Salfred } 218243637Salfred break; 2191558Srgrimes default: 2201558Srgrimes case '?': 2211558Srgrimes usage(); 2221558Srgrimes }; 22315496Sbde if (!tcpflag && !udpflag) 22415496Sbde udpflag = 1; 2251558Srgrimes argv += optind; 2261558Srgrimes argc -= optind; 227243645Salfred if (minthreads_set && maxthreads_set && minthreads > maxthreads) 228243645Salfred errx(EX_USAGE, 229243645Salfred "error: minthreads(%d) can't be greater than " 230243645Salfred "maxthreads(%d)", minthreads, maxthreads); 2311558Srgrimes 2321558Srgrimes /* 2331558Srgrimes * XXX 2341558Srgrimes * Backward compatibility, trailing number is the count of daemons. 2351558Srgrimes */ 2361558Srgrimes if (argc > 1) 2371558Srgrimes usage(); 238246780Sdelphij if (argc == 1) 239246780Sdelphij set_nfsdcnt(atoi(argv[0])); 24074800Salfred 241192674Srmacklem /* 242220980Srmacklem * Unless the "-o" option was specified, try and run "nfsd". 243220980Srmacklem * If "-o" was specified, try and run "nfsserver". 244192674Srmacklem */ 245192674Srmacklem if (run_v4server > 0) { 246192674Srmacklem if (modfind("nfsd") < 0) { 247192674Srmacklem /* Not present in kernel, try loading it */ 248192674Srmacklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 249192674Srmacklem errx(1, "NFS server is not available"); 250192674Srmacklem } 251192674Srmacklem } else if (modfind("nfsserver") < 0) { 252192674Srmacklem /* Not present in kernel, try loading it */ 253192674Srmacklem if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 254192674Srmacklem errx(1, "NFS server is not available"); 255192674Srmacklem } 256192674Srmacklem 25774462Salfred ip6flag = 1; 25874462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 25974800Salfred if (s == -1) { 260244447Srmacklem if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT) 26174800Salfred err(1, "socket"); 26274462Salfred ip6flag = 0; 26374800Salfred } else if (getnetconfigent("udp6") == NULL || 26474800Salfred getnetconfigent("tcp6") == NULL) { 26574800Salfred ip6flag = 0; 26674800Salfred } 26774800Salfred if (s != -1) 26874462Salfred close(s); 2691558Srgrimes 27053096Sdillon if (bindhostc == 0 || bindanyflag) { 27153096Sdillon bindhostc++; 27253096Sdillon bindhost = realloc(bindhost,sizeof(char *)*bindhostc); 27353096Sdillon if (bindhost == NULL) 27453096Sdillon errx(1, "Out of memory"); 27553096Sdillon bindhost[bindhostc-1] = strdup("*"); 27653096Sdillon if (bindhost[bindhostc-1] == NULL) 27753096Sdillon errx(1, "Out of memory"); 27853096Sdillon } 27953096Sdillon 28074462Salfred if (unregister) { 28174462Salfred unregistration(); 28274462Salfred exit (0); 28374462Salfred } 2841558Srgrimes if (reregister) { 28574462Salfred if (udpflag) { 28674462Salfred memset(&hints, 0, sizeof hints); 28774462Salfred hints.ai_flags = AI_PASSIVE; 28874462Salfred hints.ai_family = AF_INET; 28974462Salfred hints.ai_socktype = SOCK_DGRAM; 29074462Salfred hints.ai_protocol = IPPROTO_UDP; 29174462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); 29274800Salfred if (ecode != 0) 29374800Salfred err(1, "getaddrinfo udp: %s", gai_strerror(ecode)); 29474462Salfred nconf_udp = getnetconfigent("udp"); 29574462Salfred if (nconf_udp == NULL) 29674462Salfred err(1, "getnetconfigent udp failed"); 29774462Salfred nb_udp.buf = ai_udp->ai_addr; 29874462Salfred nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; 299194880Sdfr if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) || 300194880Sdfr (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp))) 30174462Salfred err(1, "rpcb_set udp failed"); 30274462Salfred freeaddrinfo(ai_udp); 30374462Salfred } 30474462Salfred if (udpflag && ip6flag) { 30574462Salfred memset(&hints, 0, sizeof hints); 30674462Salfred hints.ai_flags = AI_PASSIVE; 30774462Salfred hints.ai_family = AF_INET6; 30874462Salfred hints.ai_socktype = SOCK_DGRAM; 30974462Salfred hints.ai_protocol = IPPROTO_UDP; 31074462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); 31174800Salfred if (ecode != 0) 31274800Salfred err(1, "getaddrinfo udp6: %s", gai_strerror(ecode)); 31374462Salfred nconf_udp6 = getnetconfigent("udp6"); 31474462Salfred if (nconf_udp6 == NULL) 31574462Salfred err(1, "getnetconfigent udp6 failed"); 31674462Salfred nb_udp6.buf = ai_udp6->ai_addr; 31774462Salfred nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; 318194880Sdfr if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) || 319194880Sdfr (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6))) 32074462Salfred err(1, "rpcb_set udp6 failed"); 32174462Salfred freeaddrinfo(ai_udp6); 32274462Salfred } 32374462Salfred if (tcpflag) { 32474462Salfred memset(&hints, 0, sizeof hints); 32574462Salfred hints.ai_flags = AI_PASSIVE; 32674462Salfred hints.ai_family = AF_INET; 32774462Salfred hints.ai_socktype = SOCK_STREAM; 32874462Salfred hints.ai_protocol = IPPROTO_TCP; 32974462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp); 33074800Salfred if (ecode != 0) 33174800Salfred err(1, "getaddrinfo tcp: %s", gai_strerror(ecode)); 33274462Salfred nconf_tcp = getnetconfigent("tcp"); 33374462Salfred if (nconf_tcp == NULL) 33474462Salfred err(1, "getnetconfigent tcp failed"); 33574462Salfred nb_tcp.buf = ai_tcp->ai_addr; 33674462Salfred nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; 337194880Sdfr if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp, &nb_tcp)) || 338194880Sdfr (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp, &nb_tcp))) 33974462Salfred err(1, "rpcb_set tcp failed"); 34074462Salfred freeaddrinfo(ai_tcp); 34174462Salfred } 34274462Salfred if (tcpflag && ip6flag) { 34374462Salfred memset(&hints, 0, sizeof hints); 34474462Salfred hints.ai_flags = AI_PASSIVE; 34574462Salfred hints.ai_family = AF_INET6; 34674462Salfred hints.ai_socktype = SOCK_STREAM; 34774462Salfred hints.ai_protocol = IPPROTO_TCP; 34874462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); 34974800Salfred if (ecode != 0) 35074800Salfred err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode)); 35174462Salfred nconf_tcp6 = getnetconfigent("tcp6"); 35274462Salfred if (nconf_tcp6 == NULL) 35374462Salfred err(1, "getnetconfigent tcp6 failed"); 35474462Salfred nb_tcp6.buf = ai_tcp6->ai_addr; 35574462Salfred nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; 356194880Sdfr if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) || 357194880Sdfr (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6))) 35874462Salfred err(1, "rpcb_set tcp6 failed"); 35974462Salfred freeaddrinfo(ai_tcp6); 36074462Salfred } 36174462Salfred exit (0); 3621558Srgrimes } 36374800Salfred if (debug == 0) { 36474800Salfred daemon(0, 0); 36574800Salfred (void)signal(SIGHUP, SIG_IGN); 36674800Salfred (void)signal(SIGINT, SIG_IGN); 36774800Salfred /* 36874800Salfred * nfsd sits in the kernel most of the time. It needs 36974800Salfred * to ignore SIGTERM/SIGQUIT in order to stay alive as long 37074800Salfred * as possible during a shutdown, otherwise loopback 37174800Salfred * mounts will not be able to unmount. 37274800Salfred */ 37374800Salfred (void)signal(SIGTERM, SIG_IGN); 37474800Salfred (void)signal(SIGQUIT, SIG_IGN); 37574800Salfred } 37685034Siedowse (void)signal(SIGSYS, nonfs); 37774800Salfred (void)signal(SIGCHLD, reapchild); 378220510Srmacklem (void)signal(SIGUSR2, backup_stable); 37974462Salfred 380243637Salfred openlog("nfsd", LOG_PID | (debug ? LOG_PERROR : 0), LOG_DAEMON); 3811558Srgrimes 382184588Sdfr /* 383192674Srmacklem * For V4, we open the stablerestart file and call nfssvc() 384192674Srmacklem * to get it loaded. This is done before the daemons do the 385192674Srmacklem * regular nfssvc() call to service NFS requests. 386192674Srmacklem * (This way the file remains open until the last nfsd is killed 387192674Srmacklem * off.) 388220510Srmacklem * It and the backup copy will be created as empty files 389220510Srmacklem * the first time this nfsd is started and should never be 390220510Srmacklem * deleted/replaced if at all possible. It should live on a 391192674Srmacklem * local, non-volatile storage device that does not do hardware 392192674Srmacklem * level write-back caching. (See SCSI doc for more information 393192674Srmacklem * on how to prevent write-back caching on SCSI disks.) 394184588Sdfr */ 395192674Srmacklem if (run_v4server > 0) { 396220510Srmacklem open_stable(&stablefd, &backupfd); 397192674Srmacklem if (stablefd < 0) { 398243637Salfred syslog(LOG_ERR, "Can't open %s: %m\n", NFSD_STABLERESTART); 399192674Srmacklem exit(1); 400192674Srmacklem } 401220510Srmacklem /* This system call will fail for old kernels, but that's ok. */ 402220510Srmacklem nfssvc(NFSSVC_BACKUPSTABLE, NULL); 403192674Srmacklem if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) { 404243637Salfred syslog(LOG_ERR, "Can't read stable storage file: %m\n"); 405192674Srmacklem exit(1); 406192674Srmacklem } 407192674Srmacklem nfssvc_addsock = NFSSVC_NFSDADDSOCK; 408192674Srmacklem nfssvc_nfsd = NFSSVC_NFSDNFSD; 409184588Sdfr new_syscall = TRUE; 410192674Srmacklem } else { 411192674Srmacklem nfssvc_addsock = NFSSVC_ADDSOCK; 412192674Srmacklem nfssvc_nfsd = NFSSVC_NFSD; 413192674Srmacklem /* 414192674Srmacklem * Figure out if the kernel supports the new-style 415192674Srmacklem * NFSSVC_NFSD. Old kernels will return ENXIO because they 416192674Srmacklem * don't recognise the flag value, new ones will return EINVAL 417192674Srmacklem * because argp is NULL. 418192674Srmacklem */ 419192674Srmacklem new_syscall = FALSE; 420192674Srmacklem if (nfssvc(NFSSVC_NFSD, NULL) < 0 && errno == EINVAL) 421192674Srmacklem new_syscall = TRUE; 422192674Srmacklem } 423184588Sdfr 424184588Sdfr if (!new_syscall) { 425184588Sdfr /* If we use UDP only, we start the last server below. */ 426184588Sdfr srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1; 427184588Sdfr for (i = 0; i < srvcnt; i++) { 428184588Sdfr switch ((pid = fork())) { 429184588Sdfr case -1: 430184588Sdfr syslog(LOG_ERR, "fork: %m"); 431184588Sdfr nfsd_exit(1); 432184588Sdfr case 0: 433184588Sdfr break; 434184588Sdfr default: 435184588Sdfr children[i] = pid; 436184588Sdfr continue; 437184588Sdfr } 438184588Sdfr (void)signal(SIGUSR1, child_cleanup); 439184588Sdfr setproctitle("server"); 440184588Sdfr 441184588Sdfr start_server(0); 442184588Sdfr } 443184588Sdfr } else if (tcpflag) { 444184588Sdfr /* 445184588Sdfr * For TCP mode, we fork once to start the first 446184588Sdfr * kernel nfsd thread. The kernel will add more 447184588Sdfr * threads as needed. 448184588Sdfr */ 449184588Sdfr pid = fork(); 450184588Sdfr if (pid == -1) { 4511558Srgrimes syslog(LOG_ERR, "fork: %m"); 45285034Siedowse nfsd_exit(1); 4531558Srgrimes } 454184588Sdfr if (pid) { 455184588Sdfr children[0] = pid; 456184588Sdfr } else { 457184588Sdfr (void)signal(SIGUSR1, child_cleanup); 458184588Sdfr setproctitle("server"); 459184588Sdfr start_server(0); 460184588Sdfr } 4611558Srgrimes } 4621558Srgrimes 46385034Siedowse (void)signal(SIGUSR1, cleanup); 46474462Salfred FD_ZERO(&v4bits); 46574462Salfred FD_ZERO(&v6bits); 466100499Skan FD_ZERO(&sockbits); 46774462Salfred 46874462Salfred rpcbregcnt = 0; 46974462Salfred /* Set up the socket for udp and rpcb register it. */ 47074462Salfred if (udpflag) { 47174462Salfred rpcbreg = 0; 47274462Salfred for (i = 0; i < bindhostc; i++) { 47374462Salfred memset(&hints, 0, sizeof hints); 47474462Salfred hints.ai_flags = AI_PASSIVE; 47574462Salfred hints.ai_family = AF_INET; 47674462Salfred hints.ai_socktype = SOCK_DGRAM; 47774462Salfred hints.ai_protocol = IPPROTO_UDP; 47874462Salfred if (setbindhost(&ai_udp, bindhost[i], hints) == 0) { 47974462Salfred rpcbreg = 1; 48074462Salfred rpcbregcnt++; 48174462Salfred if ((sock = socket(ai_udp->ai_family, 48274462Salfred ai_udp->ai_socktype, 48374462Salfred ai_udp->ai_protocol)) < 0) { 48474462Salfred syslog(LOG_ERR, 48574462Salfred "can't create udp socket"); 48685034Siedowse nfsd_exit(1); 48774462Salfred } 48874462Salfred if (bind(sock, ai_udp->ai_addr, 48974462Salfred ai_udp->ai_addrlen) < 0) { 49074462Salfred syslog(LOG_ERR, 49174462Salfred "can't bind udp addr %s: %m", 49274462Salfred bindhost[i]); 49385034Siedowse nfsd_exit(1); 49474462Salfred } 49574462Salfred freeaddrinfo(ai_udp); 496184588Sdfr addsockargs.sock = sock; 497184588Sdfr addsockargs.name = NULL; 498184588Sdfr addsockargs.namelen = 0; 499192674Srmacklem if (nfssvc(nfssvc_addsock, &addsockargs) < 0) { 50074462Salfred syslog(LOG_ERR, "can't Add UDP socket"); 50185034Siedowse nfsd_exit(1); 50274462Salfred } 50374462Salfred (void)close(sock); 50474462Salfred } 5051558Srgrimes } 50674462Salfred if (rpcbreg == 1) { 50774462Salfred memset(&hints, 0, sizeof hints); 50874462Salfred hints.ai_flags = AI_PASSIVE; 50974462Salfred hints.ai_family = AF_INET; 51074462Salfred hints.ai_socktype = SOCK_DGRAM; 51174462Salfred hints.ai_protocol = IPPROTO_UDP; 51274462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); 51374462Salfred if (ecode != 0) { 51474462Salfred syslog(LOG_ERR, "getaddrinfo udp: %s", 51574462Salfred gai_strerror(ecode)); 51685034Siedowse nfsd_exit(1); 51774462Salfred } 51874462Salfred nconf_udp = getnetconfigent("udp"); 51974462Salfred if (nconf_udp == NULL) 52074462Salfred err(1, "getnetconfigent udp failed"); 52174462Salfred nb_udp.buf = ai_udp->ai_addr; 52274462Salfred nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; 523194880Sdfr if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) || 524194880Sdfr (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp))) 52574462Salfred err(1, "rpcb_set udp failed"); 52674462Salfred freeaddrinfo(ai_udp); 5271558Srgrimes } 5281558Srgrimes } 5291558Srgrimes 53074462Salfred /* Set up the socket for udp6 and rpcb register it. */ 53174462Salfred if (udpflag && ip6flag) { 53274462Salfred rpcbreg = 0; 53374462Salfred for (i = 0; i < bindhostc; i++) { 53474462Salfred memset(&hints, 0, sizeof hints); 53574462Salfred hints.ai_flags = AI_PASSIVE; 53674462Salfred hints.ai_family = AF_INET6; 53774462Salfred hints.ai_socktype = SOCK_DGRAM; 53874462Salfred hints.ai_protocol = IPPROTO_UDP; 53974462Salfred if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) { 54074462Salfred rpcbreg = 1; 54174462Salfred rpcbregcnt++; 54274462Salfred if ((sock = socket(ai_udp6->ai_family, 54374462Salfred ai_udp6->ai_socktype, 54474462Salfred ai_udp6->ai_protocol)) < 0) { 54574462Salfred syslog(LOG_ERR, 54674462Salfred "can't create udp6 socket"); 54785034Siedowse nfsd_exit(1); 54874462Salfred } 549100505Sume if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, 55074462Salfred &on, sizeof on) < 0) { 55174462Salfred syslog(LOG_ERR, 55274462Salfred "can't set v6-only binding for " 55374462Salfred "udp6 socket: %m"); 55485034Siedowse nfsd_exit(1); 55574462Salfred } 55674462Salfred if (bind(sock, ai_udp6->ai_addr, 55774462Salfred ai_udp6->ai_addrlen) < 0) { 55874462Salfred syslog(LOG_ERR, 55974462Salfred "can't bind udp6 addr %s: %m", 56074462Salfred bindhost[i]); 56185034Siedowse nfsd_exit(1); 56274462Salfred } 56374462Salfred freeaddrinfo(ai_udp6); 564184588Sdfr addsockargs.sock = sock; 565184588Sdfr addsockargs.name = NULL; 566184588Sdfr addsockargs.namelen = 0; 567192674Srmacklem if (nfssvc(nfssvc_addsock, &addsockargs) < 0) { 56874462Salfred syslog(LOG_ERR, 56974462Salfred "can't add UDP6 socket"); 57085034Siedowse nfsd_exit(1); 57174462Salfred } 57274462Salfred (void)close(sock); 57374462Salfred } 5741558Srgrimes } 57574462Salfred if (rpcbreg == 1) { 57674462Salfred memset(&hints, 0, sizeof hints); 57774462Salfred hints.ai_flags = AI_PASSIVE; 57874462Salfred hints.ai_family = AF_INET6; 57974462Salfred hints.ai_socktype = SOCK_DGRAM; 58074462Salfred hints.ai_protocol = IPPROTO_UDP; 58174462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); 58274462Salfred if (ecode != 0) { 58374462Salfred syslog(LOG_ERR, "getaddrinfo udp6: %s", 58474462Salfred gai_strerror(ecode)); 58585034Siedowse nfsd_exit(1); 58674462Salfred } 58774462Salfred nconf_udp6 = getnetconfigent("udp6"); 58874462Salfred if (nconf_udp6 == NULL) 58974462Salfred err(1, "getnetconfigent udp6 failed"); 59074462Salfred nb_udp6.buf = ai_udp6->ai_addr; 59174462Salfred nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; 592194880Sdfr if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) || 593194880Sdfr (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6))) 59474462Salfred err(1, "rpcb_set udp6 failed"); 59574462Salfred freeaddrinfo(ai_udp6); 5961558Srgrimes } 5971558Srgrimes } 5981558Srgrimes 59974462Salfred /* Set up the socket for tcp and rpcb register it. */ 60074462Salfred if (tcpflag) { 60174462Salfred rpcbreg = 0; 60274462Salfred for (i = 0; i < bindhostc; i++) { 60374462Salfred memset(&hints, 0, sizeof hints); 60474462Salfred hints.ai_flags = AI_PASSIVE; 60574462Salfred hints.ai_family = AF_INET; 60674462Salfred hints.ai_socktype = SOCK_STREAM; 60774462Salfred hints.ai_protocol = IPPROTO_TCP; 60874462Salfred if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) { 60974462Salfred rpcbreg = 1; 61074462Salfred rpcbregcnt++; 61174462Salfred if ((tcpsock = socket(AF_INET, SOCK_STREAM, 61274462Salfred 0)) < 0) { 61374462Salfred syslog(LOG_ERR, 614241849Seadler "can't create tcp socket"); 61585034Siedowse nfsd_exit(1); 61674462Salfred } 61774462Salfred if (setsockopt(tcpsock, SOL_SOCKET, 61874462Salfred SO_REUSEADDR, 61974462Salfred (char *)&on, sizeof(on)) < 0) 62074462Salfred syslog(LOG_ERR, 62174462Salfred "setsockopt SO_REUSEADDR: %m"); 62274462Salfred if (bind(tcpsock, ai_tcp->ai_addr, 62374462Salfred ai_tcp->ai_addrlen) < 0) { 62474462Salfred syslog(LOG_ERR, 62574462Salfred "can't bind tcp addr %s: %m", 62674462Salfred bindhost[i]); 62785034Siedowse nfsd_exit(1); 62874462Salfred } 62974462Salfred if (listen(tcpsock, 5) < 0) { 63074462Salfred syslog(LOG_ERR, "listen failed"); 63185034Siedowse nfsd_exit(1); 63274462Salfred } 63374462Salfred freeaddrinfo(ai_tcp); 63474462Salfred FD_SET(tcpsock, &sockbits); 63574462Salfred FD_SET(tcpsock, &v4bits); 63674462Salfred maxsock = tcpsock; 63774462Salfred connect_type_cnt++; 63874462Salfred } 6391558Srgrimes } 64074462Salfred if (rpcbreg == 1) { 64174462Salfred memset(&hints, 0, sizeof hints); 64274462Salfred hints.ai_flags = AI_PASSIVE; 64374462Salfred hints.ai_family = AF_INET; 64474462Salfred hints.ai_socktype = SOCK_STREAM; 64574462Salfred hints.ai_protocol = IPPROTO_TCP; 64674462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, 64774462Salfred &ai_tcp); 64874462Salfred if (ecode != 0) { 64974462Salfred syslog(LOG_ERR, "getaddrinfo tcp: %s", 65074462Salfred gai_strerror(ecode)); 65185034Siedowse nfsd_exit(1); 65274462Salfred } 65374462Salfred nconf_tcp = getnetconfigent("tcp"); 65474462Salfred if (nconf_tcp == NULL) 65574462Salfred err(1, "getnetconfigent tcp failed"); 65674462Salfred nb_tcp.buf = ai_tcp->ai_addr; 65774462Salfred nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; 658194880Sdfr if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp, 659194880Sdfr &nb_tcp)) || (!rpcb_set(NFS_PROGRAM, 3, 66074462Salfred nconf_tcp, &nb_tcp))) 66174462Salfred err(1, "rpcb_set tcp failed"); 66274462Salfred freeaddrinfo(ai_tcp); 6631558Srgrimes } 6641558Srgrimes } 6651558Srgrimes 66674462Salfred /* Set up the socket for tcp6 and rpcb register it. */ 66774462Salfred if (tcpflag && ip6flag) { 66874462Salfred rpcbreg = 0; 66974462Salfred for (i = 0; i < bindhostc; i++) { 67074462Salfred memset(&hints, 0, sizeof hints); 67174462Salfred hints.ai_flags = AI_PASSIVE; 67274462Salfred hints.ai_family = AF_INET6; 67374462Salfred hints.ai_socktype = SOCK_STREAM; 67474462Salfred hints.ai_protocol = IPPROTO_TCP; 67574462Salfred if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) { 67674462Salfred rpcbreg = 1; 67774462Salfred rpcbregcnt++; 67874462Salfred if ((tcp6sock = socket(ai_tcp6->ai_family, 67974462Salfred ai_tcp6->ai_socktype, 68074462Salfred ai_tcp6->ai_protocol)) < 0) { 68174462Salfred syslog(LOG_ERR, 68274462Salfred "can't create tcp6 socket"); 68385034Siedowse nfsd_exit(1); 68474462Salfred } 68574462Salfred if (setsockopt(tcp6sock, SOL_SOCKET, 68674462Salfred SO_REUSEADDR, 68774462Salfred (char *)&on, sizeof(on)) < 0) 68874462Salfred syslog(LOG_ERR, 68974462Salfred "setsockopt SO_REUSEADDR: %m"); 69074462Salfred if (setsockopt(tcp6sock, IPPROTO_IPV6, 691100505Sume IPV6_V6ONLY, &on, sizeof on) < 0) { 69274462Salfred syslog(LOG_ERR, 69374462Salfred "can't set v6-only binding for tcp6 " 69474462Salfred "socket: %m"); 69585034Siedowse nfsd_exit(1); 69674462Salfred } 69774462Salfred if (bind(tcp6sock, ai_tcp6->ai_addr, 69874462Salfred ai_tcp6->ai_addrlen) < 0) { 69974462Salfred syslog(LOG_ERR, 70074462Salfred "can't bind tcp6 addr %s: %m", 70174462Salfred bindhost[i]); 70285034Siedowse nfsd_exit(1); 70374462Salfred } 70474462Salfred if (listen(tcp6sock, 5) < 0) { 70574462Salfred syslog(LOG_ERR, "listen failed"); 70685034Siedowse nfsd_exit(1); 70774462Salfred } 70874462Salfred freeaddrinfo(ai_tcp6); 70974462Salfred FD_SET(tcp6sock, &sockbits); 71074462Salfred FD_SET(tcp6sock, &v6bits); 71174462Salfred if (maxsock < tcp6sock) 71274462Salfred maxsock = tcp6sock; 71374462Salfred connect_type_cnt++; 71474462Salfred } 7151558Srgrimes } 71674462Salfred if (rpcbreg == 1) { 71774462Salfred memset(&hints, 0, sizeof hints); 71874462Salfred hints.ai_flags = AI_PASSIVE; 71974462Salfred hints.ai_family = AF_INET6; 72074462Salfred hints.ai_socktype = SOCK_STREAM; 72174462Salfred hints.ai_protocol = IPPROTO_TCP; 72274462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); 72374462Salfred if (ecode != 0) { 72474462Salfred syslog(LOG_ERR, "getaddrinfo tcp6: %s", 72574462Salfred gai_strerror(ecode)); 72685034Siedowse nfsd_exit(1); 72774462Salfred } 72874462Salfred nconf_tcp6 = getnetconfigent("tcp6"); 72974462Salfred if (nconf_tcp6 == NULL) 73074462Salfred err(1, "getnetconfigent tcp6 failed"); 73174462Salfred nb_tcp6.buf = ai_tcp6->ai_addr; 73274462Salfred nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; 733194880Sdfr if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) || 734194880Sdfr (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6))) 73574462Salfred err(1, "rpcb_set tcp6 failed"); 73674462Salfred freeaddrinfo(ai_tcp6); 7371558Srgrimes } 7381558Srgrimes } 7391558Srgrimes 74074462Salfred if (rpcbregcnt == 0) { 74174462Salfred syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m"); 74285034Siedowse nfsd_exit(1); 7431558Srgrimes } 7441558Srgrimes 74585034Siedowse if (tcpflag && connect_type_cnt == 0) { 74674462Salfred syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m"); 74785034Siedowse nfsd_exit(1); 74874462Salfred } 7491558Srgrimes 7509336Sdfr setproctitle("master"); 75185034Siedowse /* 75285034Siedowse * We always want a master to have a clean way to to shut nfsd down 75385034Siedowse * (with unregistration): if the master is killed, it unregisters and 75485034Siedowse * kills all children. If we run for UDP only (and so do not have to 75585034Siedowse * loop waiting waiting for accept), we instead make the parent 75685034Siedowse * a "server" too. start_server will not return. 75785034Siedowse */ 75885034Siedowse if (!tcpflag) 75985034Siedowse start_server(1); 7601558Srgrimes 7611558Srgrimes /* 7621558Srgrimes * Loop forever accepting connections and passing the sockets 7631558Srgrimes * into the kernel for the mounts. 7641558Srgrimes */ 7651558Srgrimes for (;;) { 7661558Srgrimes ready = sockbits; 7671558Srgrimes if (connect_type_cnt > 1) { 7681558Srgrimes if (select(maxsock + 1, 7691558Srgrimes &ready, NULL, NULL, NULL) < 1) { 770218777Sjhb error = errno; 771218777Sjhb if (error == EINTR) 772124357Srwatson continue; 773220510Srmacklem syslog(LOG_ERR, "select failed: %m"); 77485034Siedowse nfsd_exit(1); 7751558Srgrimes } 7761558Srgrimes } 77774462Salfred for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) { 77874462Salfred if (FD_ISSET(tcpsock, &ready)) { 77974462Salfred if (FD_ISSET(tcpsock, &v4bits)) { 78074462Salfred len = sizeof(inetpeer); 78174462Salfred if ((msgsock = accept(tcpsock, 78274462Salfred (struct sockaddr *)&inetpeer, &len)) < 0) { 783218777Sjhb error = errno; 78474462Salfred syslog(LOG_ERR, "accept failed: %m"); 785218777Sjhb if (error == ECONNABORTED || 786218777Sjhb error == EINTR) 787124357Srwatson continue; 78885034Siedowse nfsd_exit(1); 78974462Salfred } 79074462Salfred memset(inetpeer.sin_zero, 0, 79174462Salfred sizeof(inetpeer.sin_zero)); 79274462Salfred if (setsockopt(msgsock, SOL_SOCKET, 79374462Salfred SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) 79474462Salfred syslog(LOG_ERR, 79574462Salfred "setsockopt SO_KEEPALIVE: %m"); 796184588Sdfr addsockargs.sock = msgsock; 797184588Sdfr addsockargs.name = (caddr_t)&inetpeer; 798184588Sdfr addsockargs.namelen = len; 799192674Srmacklem nfssvc(nfssvc_addsock, &addsockargs); 80074462Salfred (void)close(msgsock); 80174462Salfred } else if (FD_ISSET(tcpsock, &v6bits)) { 80274462Salfred len = sizeof(inet6peer); 80374462Salfred if ((msgsock = accept(tcpsock, 80474462Salfred (struct sockaddr *)&inet6peer, 80574462Salfred &len)) < 0) { 806218777Sjhb error = errno; 80774462Salfred syslog(LOG_ERR, 80874462Salfred "accept failed: %m"); 809218777Sjhb if (error == ECONNABORTED || 810218777Sjhb error == EINTR) 811124357Srwatson continue; 81285034Siedowse nfsd_exit(1); 81374462Salfred } 81474462Salfred if (setsockopt(msgsock, SOL_SOCKET, 81574462Salfred SO_KEEPALIVE, (char *)&on, 81674462Salfred sizeof(on)) < 0) 81774462Salfred syslog(LOG_ERR, "setsockopt " 81874462Salfred "SO_KEEPALIVE: %m"); 819184588Sdfr addsockargs.sock = msgsock; 820184588Sdfr addsockargs.name = (caddr_t)&inet6peer; 821184588Sdfr addsockargs.namelen = len; 822192674Srmacklem nfssvc(nfssvc_addsock, &addsockargs); 82374462Salfred (void)close(msgsock); 82474462Salfred } 8251558Srgrimes } 8261558Srgrimes } 8271558Srgrimes } 8281558Srgrimes} 8291558Srgrimes 830246778Sdelphijstatic int 83174462Salfredsetbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints) 83253096Sdillon{ 83374462Salfred int ecode; 83474462Salfred u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 83574462Salfred const char *hostptr; 83653096Sdillon 83774462Salfred if (bindhost == NULL || strcmp("*", bindhost) == 0) 83874462Salfred hostptr = NULL; 83974462Salfred else 84074462Salfred hostptr = bindhost; 84174462Salfred 84274462Salfred if (hostptr != NULL) { 84374462Salfred switch (hints.ai_family) { 84474462Salfred case AF_INET: 84574462Salfred if (inet_pton(AF_INET, hostptr, host_addr) == 1) { 84674462Salfred hints.ai_flags = AI_NUMERICHOST; 84774462Salfred } else { 84874462Salfred if (inet_pton(AF_INET6, hostptr, 84974462Salfred host_addr) == 1) 85074462Salfred return (1); 85153096Sdillon } 85274462Salfred break; 85374462Salfred case AF_INET6: 85474462Salfred if (inet_pton(AF_INET6, hostptr, host_addr) == 1) { 85574462Salfred hints.ai_flags = AI_NUMERICHOST; 85674462Salfred } else { 85774462Salfred if (inet_pton(AF_INET, hostptr, 85874462Salfred host_addr) == 1) 85974462Salfred return (1); 86074462Salfred } 86174462Salfred break; 86274462Salfred default: 86395861Speter break; 86453096Sdillon } 86553096Sdillon } 86674462Salfred 86774462Salfred ecode = getaddrinfo(hostptr, "nfs", &hints, ai); 86874462Salfred if (ecode != 0) { 86974462Salfred syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost, 87074462Salfred gai_strerror(ecode)); 87174462Salfred return (1); 87274462Salfred } 87374462Salfred return (0); 87453096Sdillon} 87553096Sdillon 876246778Sdelphijstatic void 877246780Sdelphijset_nfsdcnt(int proposed) 878246780Sdelphij{ 879246780Sdelphij 880246780Sdelphij if (proposed < 1) { 881246780Sdelphij warnx("nfsd count too low %d; reset to %d", proposed, 882246780Sdelphij DEFNFSDCNT); 883246780Sdelphij nfsdcnt = DEFNFSDCNT; 884246780Sdelphij } else if (proposed > MAXNFSDCNT) { 885246780Sdelphij warnx("nfsd count too high %d; truncated to %d", proposed, 886246780Sdelphij MAXNFSDCNT); 887246780Sdelphij nfsdcnt = MAXNFSDCNT; 888246780Sdelphij } else 889246780Sdelphij nfsdcnt = proposed; 890246780Sdelphij nfsdcnt_set = 1; 891246780Sdelphij} 892246780Sdelphij 893246780Sdelphijstatic void 894201227Sedusage(void) 8951558Srgrimes{ 896243637Salfred (void)fprintf(stderr, "%s", getopt_usage); 8971558Srgrimes exit(1); 8981558Srgrimes} 8991558Srgrimes 900246778Sdelphijstatic void 901137319Sdelphijnonfs(__unused int signo) 9021558Srgrimes{ 90337666Scharnier syslog(LOG_ERR, "missing system call: NFS not available"); 9041558Srgrimes} 9051558Srgrimes 906246778Sdelphijstatic void 907137319Sdelphijreapchild(__unused int signo) 9081558Srgrimes{ 90985034Siedowse pid_t pid; 91085034Siedowse int i; 9111558Srgrimes 91285034Siedowse while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) { 91385034Siedowse for (i = 0; i < nfsdcnt; i++) 91485034Siedowse if (pid == children[i]) 91585034Siedowse children[i] = -1; 91685034Siedowse } 9171558Srgrimes} 9181558Srgrimes 919246778Sdelphijstatic void 920201227Sedunregistration(void) 92174462Salfred{ 922194880Sdfr if ((!rpcb_unset(NFS_PROGRAM, 2, NULL)) || 923194880Sdfr (!rpcb_unset(NFS_PROGRAM, 3, NULL))) 92474462Salfred syslog(LOG_ERR, "rpcb_unset failed"); 92574462Salfred} 92674462Salfred 927246778Sdelphijstatic void 928201227Sedkillchildren(void) 92974462Salfred{ 93074462Salfred int i; 93174462Salfred 93274462Salfred for (i = 0; i < nfsdcnt; i++) { 93374462Salfred if (children[i] > 0) 93474462Salfred kill(children[i], SIGKILL); 93574462Salfred } 93674462Salfred} 93774462Salfred 93885034Siedowse/* 93985034Siedowse * Cleanup master after SIGUSR1. 94085034Siedowse */ 941246778Sdelphijstatic void 942137319Sdelphijcleanup(__unused int signo) 94374462Salfred{ 94485034Siedowse nfsd_exit(0); 94585034Siedowse} 94685034Siedowse 94785034Siedowse/* 94885034Siedowse * Cleanup child after SIGUSR1. 94985034Siedowse */ 950246778Sdelphijstatic void 951137319Sdelphijchild_cleanup(__unused int signo) 95285034Siedowse{ 95385034Siedowse exit(0); 95485034Siedowse} 95585034Siedowse 956246778Sdelphijstatic void 95785034Siedowsenfsd_exit(int status) 95885034Siedowse{ 95974462Salfred killchildren(); 96085034Siedowse unregistration(); 96185034Siedowse exit(status); 96274462Salfred} 96385034Siedowse 964243637Salfredstatic int 965243637Salfredget_tuned_nfsdcount(void) 966243637Salfred{ 967243637Salfred int ncpu, error, tuned_nfsdcnt; 968243637Salfred size_t ncpu_size; 969243637Salfred 970243637Salfred ncpu_size = sizeof(ncpu); 971243637Salfred error = sysctlbyname("hw.ncpu", &ncpu, &ncpu_size, NULL, 0); 972243637Salfred if (error) { 973243637Salfred warnx("sysctlbyname(hw.ncpu) failed defaulting to %d nfs servers", 974243637Salfred DEFNFSDCNT); 975243637Salfred tuned_nfsdcnt = DEFNFSDCNT; 976243637Salfred } else { 977243637Salfred tuned_nfsdcnt = ncpu * 8; 978243637Salfred } 979243637Salfred if (!new_syscall && tuned_nfsdcnt > MAXNFSDCNT) { 980243637Salfred warnx("nfsd count %d; truncated to %d", tuned_nfsdcnt, 981243637Salfred MAXNFSDCNT); 982243637Salfred tuned_nfsdcnt = MAXNFSDCNT; 983243637Salfred } 984243637Salfred return tuned_nfsdcnt; 985243637Salfred} 986243637Salfred 987246778Sdelphijstatic void 98885034Siedowsestart_server(int master) 98985034Siedowse{ 990192674Srmacklem char principal[MAXHOSTNAMELEN + 5]; 991184588Sdfr struct nfsd_nfsd_args nfsdargs; 992192674Srmacklem int status, error; 993192674Srmacklem char hostname[MAXHOSTNAMELEN + 1], *cp; 994192674Srmacklem struct addrinfo *aip, hints; 99585034Siedowse 99685034Siedowse status = 0; 997184588Sdfr if (new_syscall) { 998192674Srmacklem gethostname(hostname, sizeof (hostname)); 999192674Srmacklem snprintf(principal, sizeof (principal), "nfs@%s", hostname); 1000192674Srmacklem if ((cp = strchr(hostname, '.')) == NULL || 1001192674Srmacklem *(cp + 1) == '\0') { 1002192674Srmacklem /* If not fully qualified, try getaddrinfo() */ 1003192674Srmacklem memset((void *)&hints, 0, sizeof (hints)); 1004192674Srmacklem hints.ai_flags = AI_CANONNAME; 1005192674Srmacklem error = getaddrinfo(hostname, NULL, &hints, &aip); 1006192674Srmacklem if (error == 0) { 1007192674Srmacklem if (aip->ai_canonname != NULL && 1008192674Srmacklem (cp = strchr(aip->ai_canonname, '.')) != 1009192674Srmacklem NULL && *(cp + 1) != '\0') 1010192674Srmacklem snprintf(principal, sizeof (principal), 1011192674Srmacklem "nfs@%s", aip->ai_canonname); 1012192674Srmacklem freeaddrinfo(aip); 1013192674Srmacklem } 1014192674Srmacklem } 1015184588Sdfr nfsdargs.principal = principal; 1016243637Salfred 1017246781Sdelphij if (nfsdcnt_set) 1018246781Sdelphij nfsdargs.minthreads = nfsdargs.maxthreads = nfsdcnt; 1019246781Sdelphij else { 1020246781Sdelphij nfsdargs.minthreads = minthreads_set ? minthreads : get_tuned_nfsdcount(); 1021246781Sdelphij nfsdargs.maxthreads = maxthreads_set ? maxthreads : nfsdargs.minthreads; 1022246781Sdelphij if (nfsdargs.maxthreads < nfsdargs.minthreads) 1023246781Sdelphij nfsdargs.maxthreads = nfsdargs.minthreads; 1024243637Salfred } 1025192674Srmacklem error = nfssvc(nfssvc_nfsd, &nfsdargs); 1026192674Srmacklem if (error < 0 && errno == EAUTH) { 1027192674Srmacklem /* 1028192674Srmacklem * This indicates that it could not register the 1029192674Srmacklem * rpcsec_gss credentials, usually because the 1030192674Srmacklem * gssd daemon isn't running. 1031192674Srmacklem * (only the experimental server with nfsv4) 1032192674Srmacklem */ 1033192674Srmacklem syslog(LOG_ERR, "No gssd, using AUTH_SYS only"); 1034192674Srmacklem principal[0] = '\0'; 1035192674Srmacklem error = nfssvc(nfssvc_nfsd, &nfsdargs); 1036192674Srmacklem } 1037192674Srmacklem if (error < 0) { 1038184588Sdfr syslog(LOG_ERR, "nfssvc: %m"); 1039184588Sdfr status = 1; 1040184588Sdfr } 1041184588Sdfr } else { 1042184588Sdfr if (nfssvc(NFSSVC_OLDNFSD, NULL) < 0) { 1043184588Sdfr syslog(LOG_ERR, "nfssvc: %m"); 1044184588Sdfr status = 1; 1045184588Sdfr } 104685034Siedowse } 104785034Siedowse if (master) 104885034Siedowse nfsd_exit(status); 104985034Siedowse else 105085034Siedowse exit(status); 105185034Siedowse} 1052220510Srmacklem 1053220510Srmacklem/* 1054220510Srmacklem * Open the stable restart file and return the file descriptor for it. 1055220510Srmacklem */ 1056246778Sdelphijstatic void 1057220510Srmacklemopen_stable(int *stable_fdp, int *backup_fdp) 1058220510Srmacklem{ 1059220510Srmacklem int stable_fd, backup_fd = -1, ret; 1060220510Srmacklem struct stat st, backup_st; 1061220510Srmacklem 1062220510Srmacklem /* Open and stat the stable restart file. */ 1063220510Srmacklem stable_fd = open(NFSD_STABLERESTART, O_RDWR, 0); 1064220510Srmacklem if (stable_fd < 0) 1065220510Srmacklem stable_fd = open(NFSD_STABLERESTART, O_RDWR | O_CREAT, 0600); 1066220510Srmacklem if (stable_fd >= 0) { 1067220510Srmacklem ret = fstat(stable_fd, &st); 1068220510Srmacklem if (ret < 0) { 1069220510Srmacklem close(stable_fd); 1070220510Srmacklem stable_fd = -1; 1071220510Srmacklem } 1072220510Srmacklem } 1073220510Srmacklem 1074220510Srmacklem /* Open and stat the backup stable restart file. */ 1075220510Srmacklem if (stable_fd >= 0) { 1076220510Srmacklem backup_fd = open(NFSD_STABLEBACKUP, O_RDWR, 0); 1077220510Srmacklem if (backup_fd < 0) 1078220510Srmacklem backup_fd = open(NFSD_STABLEBACKUP, O_RDWR | O_CREAT, 1079220510Srmacklem 0600); 1080220510Srmacklem if (backup_fd >= 0) { 1081220510Srmacklem ret = fstat(backup_fd, &backup_st); 1082220510Srmacklem if (ret < 0) { 1083220510Srmacklem close(backup_fd); 1084220510Srmacklem backup_fd = -1; 1085220510Srmacklem } 1086220510Srmacklem } 1087220510Srmacklem if (backup_fd < 0) { 1088220510Srmacklem close(stable_fd); 1089220510Srmacklem stable_fd = -1; 1090220510Srmacklem } 1091220510Srmacklem } 1092220510Srmacklem 1093220510Srmacklem *stable_fdp = stable_fd; 1094220510Srmacklem *backup_fdp = backup_fd; 1095220510Srmacklem if (stable_fd < 0) 1096220510Srmacklem return; 1097220510Srmacklem 1098220510Srmacklem /* Sync up the 2 files, as required. */ 1099220510Srmacklem if (st.st_size > 0) 1100220510Srmacklem copy_stable(stable_fd, backup_fd); 1101220510Srmacklem else if (backup_st.st_size > 0) 1102220510Srmacklem copy_stable(backup_fd, stable_fd); 1103220510Srmacklem} 1104220510Srmacklem 1105220510Srmacklem/* 1106220510Srmacklem * Copy the stable restart file to the backup or vice versa. 1107220510Srmacklem */ 1108246778Sdelphijstatic void 1109220510Srmacklemcopy_stable(int from_fd, int to_fd) 1110220510Srmacklem{ 1111220510Srmacklem int cnt, ret; 1112220510Srmacklem static char buf[1024]; 1113220510Srmacklem 1114220510Srmacklem ret = lseek(from_fd, (off_t)0, SEEK_SET); 1115220510Srmacklem if (ret >= 0) 1116220510Srmacklem ret = lseek(to_fd, (off_t)0, SEEK_SET); 1117220510Srmacklem if (ret >= 0) 1118220510Srmacklem ret = ftruncate(to_fd, (off_t)0); 1119220510Srmacklem if (ret >= 0) 1120220510Srmacklem do { 1121220510Srmacklem cnt = read(from_fd, buf, 1024); 1122220510Srmacklem if (cnt > 0) 1123220510Srmacklem ret = write(to_fd, buf, cnt); 1124220510Srmacklem else if (cnt < 0) 1125220510Srmacklem ret = cnt; 1126220510Srmacklem } while (cnt > 0 && ret >= 0); 1127220510Srmacklem if (ret >= 0) 1128220510Srmacklem ret = fsync(to_fd); 1129220510Srmacklem if (ret < 0) 1130220510Srmacklem syslog(LOG_ERR, "stable restart copy failure: %m"); 1131220510Srmacklem} 1132220510Srmacklem 1133220510Srmacklem/* 1134220510Srmacklem * Back up the stable restart file when indicated by the kernel. 1135220510Srmacklem */ 1136246778Sdelphijstatic void 1137220510Srmacklembackup_stable(__unused int signo) 1138220510Srmacklem{ 1139220510Srmacklem 1140220510Srmacklem if (stablefd >= 0) 1141220510Srmacklem copy_stable(stablefd, backupfd); 1142220510Srmacklem} 1143220510Srmacklem 1144