18fae3551SRodney W. Grimes /* 28fae3551SRodney W. Grimes * Copyright (c) 1989, 1993, 1994 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by 68fae3551SRodney W. Grimes * Rick Macklem at The University of Guelph. 78fae3551SRodney W. Grimes * 88fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 98fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 108fae3551SRodney W. Grimes * are met: 118fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 128fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 138fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 148fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 158fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 168fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 178fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 188fae3551SRodney W. Grimes * without specific prior written permission. 198fae3551SRodney W. Grimes * 208fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 218fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 228fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 238fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 248fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 258fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 268fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 278fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 288fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 298fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 308fae3551SRodney W. Grimes * SUCH DAMAGE. 318fae3551SRodney W. Grimes */ 328fae3551SRodney W. Grimes 338fae3551SRodney W. Grimes #ifndef lint 349b4d716bSPhilippe Charnier static const char copyright[] = 358fae3551SRodney W. Grimes "@(#) Copyright (c) 1989, 1993, 1994\n\ 368fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 3737436e40SPeter Wemm #endif /* not lint */ 388fae3551SRodney W. Grimes 398fae3551SRodney W. Grimes #ifndef lint 409b4d716bSPhilippe Charnier #if 0 4108966bd5SPeter Wemm static char sccsid[] = "@(#)nfsd.c 8.9 (Berkeley) 3/29/95"; 429b4d716bSPhilippe Charnier #endif 439b4d716bSPhilippe Charnier static const char rcsid[] = 447f3dea24SPeter Wemm "$FreeBSD$"; 4537436e40SPeter Wemm #endif /* not lint */ 468fae3551SRodney W. Grimes 478fae3551SRodney W. Grimes #include <sys/param.h> 488fae3551SRodney W. Grimes #include <sys/syslog.h> 498fae3551SRodney W. Grimes #include <sys/wait.h> 508fae3551SRodney W. Grimes #include <sys/mount.h> 5120d0a5e5SRick Macklem #include <sys/fcntl.h> 52fef7dd5aSIan Dowse #include <sys/linker.h> 53fef7dd5aSIan Dowse #include <sys/module.h> 548fae3551SRodney W. Grimes 558fae3551SRodney W. Grimes #include <rpc/rpc.h> 568fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h> 570775314bSDoug Rabson #include <rpcsvc/nfs_prot.h> 588fae3551SRodney W. Grimes 5992fc2acfSMatthew Dillon #include <netdb.h> 6092fc2acfSMatthew Dillon #include <arpa/inet.h> 6191196234SPeter Wemm #include <nfsserver/nfs.h> 6220d0a5e5SRick Macklem #include <nfs/nfssvc.h> 638fae3551SRodney W. Grimes 648fae3551SRodney W. Grimes #include <err.h> 658fae3551SRodney W. Grimes #include <errno.h> 66fef7dd5aSIan Dowse #include <signal.h> 678fae3551SRodney W. Grimes #include <stdio.h> 688fae3551SRodney W. Grimes #include <stdlib.h> 6937436e40SPeter Wemm #include <string.h> 708fae3551SRodney W. Grimes #include <unistd.h> 718360efbdSAlfred Perlstein #include <netdb.h> 728fae3551SRodney W. Grimes 738fae3551SRodney W. Grimes /* Global defs */ 748fae3551SRodney W. Grimes #ifdef DEBUG 7585554bf8SPierre Beyssac #define syslog(e, s...) fprintf(stderr,s) 768fae3551SRodney W. Grimes int debug = 1; 778fae3551SRodney W. Grimes #else 788fae3551SRodney W. Grimes int debug = 0; 798fae3551SRodney W. Grimes #endif 808fae3551SRodney W. Grimes 8120d0a5e5SRick Macklem #define NFSD_STABLERESTART "/var/db/nfs-stablerestart" 823f7c86a8SRobert Watson #define MAXNFSDCNT 256 838360efbdSAlfred Perlstein #define DEFNFSDCNT 4 848360efbdSAlfred Perlstein pid_t children[MAXNFSDCNT]; /* PIDs of children */ 858360efbdSAlfred Perlstein int nfsdcnt; /* number of children */ 86a9148abdSDoug Rabson int new_syscall; 8720d0a5e5SRick Macklem int run_v4server = 0; /* Force running of nfsv4 server */ 8820d0a5e5SRick Macklem int nfssvc_nfsd; /* Set to correct NFSSVC_xxx flag */ 898360efbdSAlfred Perlstein 908360efbdSAlfred Perlstein void cleanup(int); 91fef7dd5aSIan Dowse void child_cleanup(int); 928360efbdSAlfred Perlstein void killchildren(void); 93fef7dd5aSIan Dowse void nfsd_exit(int); 948360efbdSAlfred Perlstein void nonfs(int); 958360efbdSAlfred Perlstein void reapchild(int); 96fef7dd5aSIan Dowse int setbindhost(struct addrinfo **ia, const char *bindhost, 97fef7dd5aSIan Dowse struct addrinfo hints); 98fef7dd5aSIan Dowse void start_server(int); 998360efbdSAlfred Perlstein void unregistration(void); 1008360efbdSAlfred Perlstein void usage(void); 1018fae3551SRodney W. Grimes 1028fae3551SRodney W. Grimes /* 1038fae3551SRodney W. Grimes * Nfs server daemon mostly just a user context for nfssvc() 1048fae3551SRodney W. Grimes * 1058fae3551SRodney W. Grimes * 1 - do file descriptor and signal cleanup 1068fae3551SRodney W. Grimes * 2 - fork the nfsd(s) 1078fae3551SRodney W. Grimes * 3 - create server socket(s) 1088360efbdSAlfred Perlstein * 4 - register socket with rpcbind 1098fae3551SRodney W. Grimes * 1108fae3551SRodney W. Grimes * For connectionless protocols, just pass the socket into the kernel via. 1118fae3551SRodney W. Grimes * nfssvc(). 1128fae3551SRodney W. Grimes * For connection based sockets, loop doing accepts. When you get a new 1138fae3551SRodney W. Grimes * socket from accept, pass the msgsock into the kernel via. nfssvc(). 1148fae3551SRodney W. Grimes * The arguments are: 1158360efbdSAlfred Perlstein * -r - reregister with rpcbind 1168360efbdSAlfred Perlstein * -d - unregister with rpcbind 1178fae3551SRodney W. Grimes * -t - support tcp nfs clients 1188fae3551SRodney W. Grimes * -u - support udp nfs clients 1192179ae1eSRick Macklem * -e - forces it to run a server that supports nfsv4 1208fae3551SRodney W. Grimes * followed by "n" which is the number of nfsds' to fork off 1218fae3551SRodney W. Grimes */ 1228fae3551SRodney W. Grimes int 1236f52836bSXin LI main(int argc, char **argv) 1248fae3551SRodney W. Grimes { 125a9148abdSDoug Rabson struct nfsd_addsock_args addsockargs; 1268360efbdSAlfred Perlstein struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints; 1278360efbdSAlfred Perlstein struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6; 1288360efbdSAlfred Perlstein struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6; 1298360efbdSAlfred Perlstein struct sockaddr_in inetpeer; 1308360efbdSAlfred Perlstein struct sockaddr_in6 inet6peer; 1318fae3551SRodney W. Grimes fd_set ready, sockbits; 1328360efbdSAlfred Perlstein fd_set v4bits, v6bits; 1336f229bd3SXin LI int ch, connect_type_cnt, i, maxsock, msgsock; 134487e8667SXin LI socklen_t len; 135fef7dd5aSIan Dowse int on = 1, unregister, reregister, sock; 1368360efbdSAlfred Perlstein int tcp6sock, ip6flag, tcpflag, tcpsock; 137*873ec24aSJohn Baldwin int udpflag, ecode, error, s, srvcnt; 138fef7dd5aSIan Dowse int bindhostc, bindanyflag, rpcbreg, rpcbregcnt; 13920d0a5e5SRick Macklem int stablefd, nfssvc_addsock; 14092fc2acfSMatthew Dillon char **bindhost = NULL; 1418360efbdSAlfred Perlstein pid_t pid; 142d599144dSGarrett Wollman 1438fae3551SRodney W. Grimes nfsdcnt = DEFNFSDCNT; 144fef7dd5aSIan Dowse unregister = reregister = tcpflag = maxsock = 0; 145fef7dd5aSIan Dowse bindanyflag = udpflag = connect_type_cnt = bindhostc = 0; 1462179ae1eSRick Macklem #define GETOPT "ah:n:rdtue" 1472179ae1eSRick Macklem #define USAGE "[-ardtue] [-n num_servers] [-h bindip]" 1488d64695cSWarner Losh while ((ch = getopt(argc, argv, GETOPT)) != -1) 1498fae3551SRodney W. Grimes switch (ch) { 15092fc2acfSMatthew Dillon case 'a': 15192fc2acfSMatthew Dillon bindanyflag = 1; 15292fc2acfSMatthew Dillon break; 1538fae3551SRodney W. Grimes case 'n': 1548fae3551SRodney W. Grimes nfsdcnt = atoi(optarg); 1558fae3551SRodney W. Grimes if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) { 1563e83b874SJohn Polstra warnx("nfsd count %d; reset to %d", nfsdcnt, 1573e83b874SJohn Polstra DEFNFSDCNT); 1588fae3551SRodney W. Grimes nfsdcnt = DEFNFSDCNT; 1598fae3551SRodney W. Grimes } 1608fae3551SRodney W. Grimes break; 16192fc2acfSMatthew Dillon case 'h': 16292fc2acfSMatthew Dillon bindhostc++; 16392fc2acfSMatthew Dillon bindhost = realloc(bindhost,sizeof(char *)*bindhostc); 16492fc2acfSMatthew Dillon if (bindhost == NULL) 16592fc2acfSMatthew Dillon errx(1, "Out of memory"); 16692fc2acfSMatthew Dillon bindhost[bindhostc-1] = strdup(optarg); 16792fc2acfSMatthew Dillon if (bindhost[bindhostc-1] == NULL) 16892fc2acfSMatthew Dillon errx(1, "Out of memory"); 16992fc2acfSMatthew Dillon break; 1708fae3551SRodney W. Grimes case 'r': 1718fae3551SRodney W. Grimes reregister = 1; 1728fae3551SRodney W. Grimes break; 1738360efbdSAlfred Perlstein case 'd': 1748360efbdSAlfred Perlstein unregister = 1; 1758360efbdSAlfred Perlstein break; 1768fae3551SRodney W. Grimes case 't': 1778fae3551SRodney W. Grimes tcpflag = 1; 1788fae3551SRodney W. Grimes break; 1798fae3551SRodney W. Grimes case 'u': 1808fae3551SRodney W. Grimes udpflag = 1; 1818fae3551SRodney W. Grimes break; 1822179ae1eSRick Macklem case 'e': 18320d0a5e5SRick Macklem run_v4server = 1; 18420d0a5e5SRick Macklem break; 1858fae3551SRodney W. Grimes default: 1868fae3551SRodney W. Grimes case '?': 1878fae3551SRodney W. Grimes usage(); 1888fae3551SRodney W. Grimes }; 18952efa6c1SBruce Evans if (!tcpflag && !udpflag) 19052efa6c1SBruce Evans udpflag = 1; 1918fae3551SRodney W. Grimes argv += optind; 1928fae3551SRodney W. Grimes argc -= optind; 1938fae3551SRodney W. Grimes 1948fae3551SRodney W. Grimes /* 1958fae3551SRodney W. Grimes * XXX 1968fae3551SRodney W. Grimes * Backward compatibility, trailing number is the count of daemons. 1978fae3551SRodney W. Grimes */ 1988fae3551SRodney W. Grimes if (argc > 1) 1998fae3551SRodney W. Grimes usage(); 2008fae3551SRodney W. Grimes if (argc == 1) { 2018fae3551SRodney W. Grimes nfsdcnt = atoi(argv[0]); 2028fae3551SRodney W. Grimes if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) { 2033e83b874SJohn Polstra warnx("nfsd count %d; reset to %d", nfsdcnt, 2043e83b874SJohn Polstra DEFNFSDCNT); 2058fae3551SRodney W. Grimes nfsdcnt = DEFNFSDCNT; 2068fae3551SRodney W. Grimes } 2078fae3551SRodney W. Grimes } 208e0a509bbSAlfred Perlstein 20920d0a5e5SRick Macklem /* 2102179ae1eSRick Macklem * If the "-e" option was specified OR only the nfsd module is 21120d0a5e5SRick Macklem * found in the server, run "nfsd". 21220d0a5e5SRick Macklem * Otherwise, try and run "nfsserver". 21320d0a5e5SRick Macklem */ 21420d0a5e5SRick Macklem if (run_v4server > 0) { 21520d0a5e5SRick Macklem if (modfind("nfsd") < 0) { 21620d0a5e5SRick Macklem /* Not present in kernel, try loading it */ 21720d0a5e5SRick Macklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 21820d0a5e5SRick Macklem errx(1, "NFS server is not available"); 21920d0a5e5SRick Macklem } 22020d0a5e5SRick Macklem } else if (modfind("nfsserver") < 0 && modfind("nfsd") >= 0) { 22120d0a5e5SRick Macklem run_v4server = 1; 22220d0a5e5SRick Macklem } else if (modfind("nfsserver") < 0) { 22320d0a5e5SRick Macklem /* Not present in kernel, try loading it */ 22420d0a5e5SRick Macklem if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 22520d0a5e5SRick Macklem errx(1, "NFS server is not available"); 22620d0a5e5SRick Macklem } 22720d0a5e5SRick Macklem 2288360efbdSAlfred Perlstein ip6flag = 1; 2298360efbdSAlfred Perlstein s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 230e0a509bbSAlfred Perlstein if (s == -1) { 231e0a509bbSAlfred Perlstein if (errno != EPROTONOSUPPORT) 232e0a509bbSAlfred Perlstein err(1, "socket"); 2338360efbdSAlfred Perlstein ip6flag = 0; 234e0a509bbSAlfred Perlstein } else if (getnetconfigent("udp6") == NULL || 235e0a509bbSAlfred Perlstein getnetconfigent("tcp6") == NULL) { 236e0a509bbSAlfred Perlstein ip6flag = 0; 237e0a509bbSAlfred Perlstein } 238e0a509bbSAlfred Perlstein if (s != -1) 2398360efbdSAlfred Perlstein close(s); 2408fae3551SRodney W. Grimes 24192fc2acfSMatthew Dillon if (bindhostc == 0 || bindanyflag) { 24292fc2acfSMatthew Dillon bindhostc++; 24392fc2acfSMatthew Dillon bindhost = realloc(bindhost,sizeof(char *)*bindhostc); 24492fc2acfSMatthew Dillon if (bindhost == NULL) 24592fc2acfSMatthew Dillon errx(1, "Out of memory"); 24692fc2acfSMatthew Dillon bindhost[bindhostc-1] = strdup("*"); 24792fc2acfSMatthew Dillon if (bindhost[bindhostc-1] == NULL) 24892fc2acfSMatthew Dillon errx(1, "Out of memory"); 24992fc2acfSMatthew Dillon } 25092fc2acfSMatthew Dillon 2518360efbdSAlfred Perlstein if (unregister) { 2528360efbdSAlfred Perlstein unregistration(); 2538fae3551SRodney W. Grimes exit (0); 2548fae3551SRodney W. Grimes } 2558360efbdSAlfred Perlstein if (reregister) { 2568360efbdSAlfred Perlstein if (udpflag) { 2578360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 2588360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 2598360efbdSAlfred Perlstein hints.ai_family = AF_INET; 2608360efbdSAlfred Perlstein hints.ai_socktype = SOCK_DGRAM; 2618360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 2628360efbdSAlfred Perlstein ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); 263e0a509bbSAlfred Perlstein if (ecode != 0) 264e0a509bbSAlfred Perlstein err(1, "getaddrinfo udp: %s", gai_strerror(ecode)); 2658360efbdSAlfred Perlstein nconf_udp = getnetconfigent("udp"); 2668360efbdSAlfred Perlstein if (nconf_udp == NULL) 2678360efbdSAlfred Perlstein err(1, "getnetconfigent udp failed"); 2688360efbdSAlfred Perlstein nb_udp.buf = ai_udp->ai_addr; 2698360efbdSAlfred Perlstein nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; 2700775314bSDoug Rabson if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) || 2710775314bSDoug Rabson (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp))) 2728360efbdSAlfred Perlstein err(1, "rpcb_set udp failed"); 2738360efbdSAlfred Perlstein freeaddrinfo(ai_udp); 2748360efbdSAlfred Perlstein } 2758360efbdSAlfred Perlstein if (udpflag && ip6flag) { 2768360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 2778360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 2788360efbdSAlfred Perlstein hints.ai_family = AF_INET6; 2798360efbdSAlfred Perlstein hints.ai_socktype = SOCK_DGRAM; 2808360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 2818360efbdSAlfred Perlstein ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); 282e0a509bbSAlfred Perlstein if (ecode != 0) 283e0a509bbSAlfred Perlstein err(1, "getaddrinfo udp6: %s", gai_strerror(ecode)); 2848360efbdSAlfred Perlstein nconf_udp6 = getnetconfigent("udp6"); 2858360efbdSAlfred Perlstein if (nconf_udp6 == NULL) 2868360efbdSAlfred Perlstein err(1, "getnetconfigent udp6 failed"); 2878360efbdSAlfred Perlstein nb_udp6.buf = ai_udp6->ai_addr; 2888360efbdSAlfred Perlstein nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; 2890775314bSDoug Rabson if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) || 2900775314bSDoug Rabson (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6))) 2918360efbdSAlfred Perlstein err(1, "rpcb_set udp6 failed"); 2928360efbdSAlfred Perlstein freeaddrinfo(ai_udp6); 2938360efbdSAlfred Perlstein } 2948360efbdSAlfred Perlstein if (tcpflag) { 2958360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 2968360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 2978360efbdSAlfred Perlstein hints.ai_family = AF_INET; 2988360efbdSAlfred Perlstein hints.ai_socktype = SOCK_STREAM; 2998360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_TCP; 3008360efbdSAlfred Perlstein ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp); 301e0a509bbSAlfred Perlstein if (ecode != 0) 302e0a509bbSAlfred Perlstein err(1, "getaddrinfo tcp: %s", gai_strerror(ecode)); 3038360efbdSAlfred Perlstein nconf_tcp = getnetconfigent("tcp"); 3048360efbdSAlfred Perlstein if (nconf_tcp == NULL) 3058360efbdSAlfred Perlstein err(1, "getnetconfigent tcp failed"); 3068360efbdSAlfred Perlstein nb_tcp.buf = ai_tcp->ai_addr; 3078360efbdSAlfred Perlstein nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; 3080775314bSDoug Rabson if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp, &nb_tcp)) || 3090775314bSDoug Rabson (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp, &nb_tcp))) 3108360efbdSAlfred Perlstein err(1, "rpcb_set tcp failed"); 3118360efbdSAlfred Perlstein freeaddrinfo(ai_tcp); 3128360efbdSAlfred Perlstein } 3138360efbdSAlfred Perlstein if (tcpflag && ip6flag) { 3148360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 3158360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 3168360efbdSAlfred Perlstein hints.ai_family = AF_INET6; 3178360efbdSAlfred Perlstein hints.ai_socktype = SOCK_STREAM; 3188360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_TCP; 3198360efbdSAlfred Perlstein ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); 320e0a509bbSAlfred Perlstein if (ecode != 0) 321e0a509bbSAlfred Perlstein err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode)); 3228360efbdSAlfred Perlstein nconf_tcp6 = getnetconfigent("tcp6"); 3238360efbdSAlfred Perlstein if (nconf_tcp6 == NULL) 3248360efbdSAlfred Perlstein err(1, "getnetconfigent tcp6 failed"); 3258360efbdSAlfred Perlstein nb_tcp6.buf = ai_tcp6->ai_addr; 3268360efbdSAlfred Perlstein nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; 3270775314bSDoug Rabson if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) || 3280775314bSDoug Rabson (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6))) 3298360efbdSAlfred Perlstein err(1, "rpcb_set tcp6 failed"); 3308360efbdSAlfred Perlstein freeaddrinfo(ai_tcp6); 3318360efbdSAlfred Perlstein } 3328360efbdSAlfred Perlstein exit (0); 3338360efbdSAlfred Perlstein } 334e0a509bbSAlfred Perlstein if (debug == 0) { 335e0a509bbSAlfred Perlstein daemon(0, 0); 336e0a509bbSAlfred Perlstein (void)signal(SIGHUP, SIG_IGN); 337e0a509bbSAlfred Perlstein (void)signal(SIGINT, SIG_IGN); 338e0a509bbSAlfred Perlstein /* 339e0a509bbSAlfred Perlstein * nfsd sits in the kernel most of the time. It needs 340e0a509bbSAlfred Perlstein * to ignore SIGTERM/SIGQUIT in order to stay alive as long 341e0a509bbSAlfred Perlstein * as possible during a shutdown, otherwise loopback 342e0a509bbSAlfred Perlstein * mounts will not be able to unmount. 343e0a509bbSAlfred Perlstein */ 344e0a509bbSAlfred Perlstein (void)signal(SIGTERM, SIG_IGN); 345e0a509bbSAlfred Perlstein (void)signal(SIGQUIT, SIG_IGN); 346e0a509bbSAlfred Perlstein } 347fef7dd5aSIan Dowse (void)signal(SIGSYS, nonfs); 348e0a509bbSAlfred Perlstein (void)signal(SIGCHLD, reapchild); 3498360efbdSAlfred Perlstein 350fef7dd5aSIan Dowse openlog("nfsd", LOG_PID, LOG_DAEMON); 3518fae3551SRodney W. Grimes 352a9148abdSDoug Rabson /* 35320d0a5e5SRick Macklem * For V4, we open the stablerestart file and call nfssvc() 35420d0a5e5SRick Macklem * to get it loaded. This is done before the daemons do the 35520d0a5e5SRick Macklem * regular nfssvc() call to service NFS requests. 35620d0a5e5SRick Macklem * (This way the file remains open until the last nfsd is killed 35720d0a5e5SRick Macklem * off.) 35820d0a5e5SRick Macklem * Note that this file is not created by this daemon and can 35920d0a5e5SRick Macklem * only be relocated by recompiling the daemon, in order to 36020d0a5e5SRick Macklem * minimize accidentally starting up with the wrong file. 36120d0a5e5SRick Macklem * If should be created as an empty file Read and Write for 36220d0a5e5SRick Macklem * root before the first time you run NFS v4 and should never 36320d0a5e5SRick Macklem * be re-initialized if at all possible. It should live on a 36420d0a5e5SRick Macklem * local, non-volatile storage device that does not do hardware 36520d0a5e5SRick Macklem * level write-back caching. (See SCSI doc for more information 36620d0a5e5SRick Macklem * on how to prevent write-back caching on SCSI disks.) 36720d0a5e5SRick Macklem */ 36820d0a5e5SRick Macklem if (run_v4server > 0) { 36920d0a5e5SRick Macklem stablefd = open(NFSD_STABLERESTART, O_RDWR, 0); 37020d0a5e5SRick Macklem if (stablefd < 0) { 37120d0a5e5SRick Macklem syslog(LOG_ERR, "Can't open %s\n", NFSD_STABLERESTART); 37220d0a5e5SRick Macklem exit(1); 37320d0a5e5SRick Macklem } 37420d0a5e5SRick Macklem if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) { 37520d0a5e5SRick Macklem syslog(LOG_ERR, "Can't read stable storage file\n"); 37620d0a5e5SRick Macklem exit(1); 37720d0a5e5SRick Macklem } 37820d0a5e5SRick Macklem nfssvc_addsock = NFSSVC_NFSDADDSOCK; 37920d0a5e5SRick Macklem nfssvc_nfsd = NFSSVC_NFSDNFSD; 38020d0a5e5SRick Macklem new_syscall = TRUE; 38120d0a5e5SRick Macklem } else { 38220d0a5e5SRick Macklem nfssvc_addsock = NFSSVC_ADDSOCK; 38320d0a5e5SRick Macklem nfssvc_nfsd = NFSSVC_NFSD; 38420d0a5e5SRick Macklem /* 385a9148abdSDoug Rabson * Figure out if the kernel supports the new-style 386a9148abdSDoug Rabson * NFSSVC_NFSD. Old kernels will return ENXIO because they 387a9148abdSDoug Rabson * don't recognise the flag value, new ones will return EINVAL 388a9148abdSDoug Rabson * because argp is NULL. 389a9148abdSDoug Rabson */ 390a9148abdSDoug Rabson new_syscall = FALSE; 391a9148abdSDoug Rabson if (nfssvc(NFSSVC_NFSD, NULL) < 0 && errno == EINVAL) 392a9148abdSDoug Rabson new_syscall = TRUE; 39320d0a5e5SRick Macklem } 394a9148abdSDoug Rabson 395a9148abdSDoug Rabson if (!new_syscall) { 396fef7dd5aSIan Dowse /* If we use UDP only, we start the last server below. */ 397fef7dd5aSIan Dowse srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1; 398fef7dd5aSIan Dowse for (i = 0; i < srvcnt; i++) { 3998360efbdSAlfred Perlstein switch ((pid = fork())) { 4008fae3551SRodney W. Grimes case -1: 4018fae3551SRodney W. Grimes syslog(LOG_ERR, "fork: %m"); 402fef7dd5aSIan Dowse nfsd_exit(1); 4038fae3551SRodney W. Grimes case 0: 4048fae3551SRodney W. Grimes break; 4058fae3551SRodney W. Grimes default: 4068360efbdSAlfred Perlstein children[i] = pid; 4078fae3551SRodney W. Grimes continue; 4088fae3551SRodney W. Grimes } 409fef7dd5aSIan Dowse (void)signal(SIGUSR1, child_cleanup); 410a62dc406SDoug Rabson setproctitle("server"); 411fef7dd5aSIan Dowse 412fef7dd5aSIan Dowse start_server(0); 4138fae3551SRodney W. Grimes } 414a9148abdSDoug Rabson } else if (tcpflag) { 415a9148abdSDoug Rabson /* 416a9148abdSDoug Rabson * For TCP mode, we fork once to start the first 417a9148abdSDoug Rabson * kernel nfsd thread. The kernel will add more 418a9148abdSDoug Rabson * threads as needed. 419a9148abdSDoug Rabson */ 420a9148abdSDoug Rabson pid = fork(); 421a9148abdSDoug Rabson if (pid == -1) { 422a9148abdSDoug Rabson syslog(LOG_ERR, "fork: %m"); 423a9148abdSDoug Rabson nfsd_exit(1); 424a9148abdSDoug Rabson } 425a9148abdSDoug Rabson if (pid) { 426a9148abdSDoug Rabson children[0] = pid; 427a9148abdSDoug Rabson } else { 428a9148abdSDoug Rabson (void)signal(SIGUSR1, child_cleanup); 429a9148abdSDoug Rabson setproctitle("server"); 430a9148abdSDoug Rabson start_server(0); 431a9148abdSDoug Rabson } 432a9148abdSDoug Rabson } 4338fae3551SRodney W. Grimes 434fef7dd5aSIan Dowse (void)signal(SIGUSR1, cleanup); 4358360efbdSAlfred Perlstein FD_ZERO(&v4bits); 4368360efbdSAlfred Perlstein FD_ZERO(&v6bits); 4374cc03f63SAlexander Kabaev FD_ZERO(&sockbits); 4388360efbdSAlfred Perlstein 4398360efbdSAlfred Perlstein rpcbregcnt = 0; 4408360efbdSAlfred Perlstein /* Set up the socket for udp and rpcb register it. */ 4418360efbdSAlfred Perlstein if (udpflag) { 4428360efbdSAlfred Perlstein rpcbreg = 0; 4438360efbdSAlfred Perlstein for (i = 0; i < bindhostc; i++) { 4448360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 4458360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 4468360efbdSAlfred Perlstein hints.ai_family = AF_INET; 4478360efbdSAlfred Perlstein hints.ai_socktype = SOCK_DGRAM; 4488360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 4498360efbdSAlfred Perlstein if (setbindhost(&ai_udp, bindhost[i], hints) == 0) { 4508360efbdSAlfred Perlstein rpcbreg = 1; 4518360efbdSAlfred Perlstein rpcbregcnt++; 4528360efbdSAlfred Perlstein if ((sock = socket(ai_udp->ai_family, 4538360efbdSAlfred Perlstein ai_udp->ai_socktype, 4548360efbdSAlfred Perlstein ai_udp->ai_protocol)) < 0) { 4558360efbdSAlfred Perlstein syslog(LOG_ERR, 4568360efbdSAlfred Perlstein "can't create udp socket"); 457fef7dd5aSIan Dowse nfsd_exit(1); 4588fae3551SRodney W. Grimes } 4598360efbdSAlfred Perlstein if (bind(sock, ai_udp->ai_addr, 4608360efbdSAlfred Perlstein ai_udp->ai_addrlen) < 0) { 4618360efbdSAlfred Perlstein syslog(LOG_ERR, 4628360efbdSAlfred Perlstein "can't bind udp addr %s: %m", 4638360efbdSAlfred Perlstein bindhost[i]); 464fef7dd5aSIan Dowse nfsd_exit(1); 4658fae3551SRodney W. Grimes } 4668360efbdSAlfred Perlstein freeaddrinfo(ai_udp); 467a9148abdSDoug Rabson addsockargs.sock = sock; 468a9148abdSDoug Rabson addsockargs.name = NULL; 469a9148abdSDoug Rabson addsockargs.namelen = 0; 47020d0a5e5SRick Macklem if (nfssvc(nfssvc_addsock, &addsockargs) < 0) { 4718fae3551SRodney W. Grimes syslog(LOG_ERR, "can't Add UDP socket"); 472fef7dd5aSIan Dowse nfsd_exit(1); 4738fae3551SRodney W. Grimes } 4748fae3551SRodney W. Grimes (void)close(sock); 4758fae3551SRodney W. Grimes } 4768360efbdSAlfred Perlstein } 4778360efbdSAlfred Perlstein if (rpcbreg == 1) { 4788360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 4798360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 4808360efbdSAlfred Perlstein hints.ai_family = AF_INET; 4818360efbdSAlfred Perlstein hints.ai_socktype = SOCK_DGRAM; 4828360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 4838360efbdSAlfred Perlstein ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); 4848360efbdSAlfred Perlstein if (ecode != 0) { 4858360efbdSAlfred Perlstein syslog(LOG_ERR, "getaddrinfo udp: %s", 4868360efbdSAlfred Perlstein gai_strerror(ecode)); 487fef7dd5aSIan Dowse nfsd_exit(1); 4888360efbdSAlfred Perlstein } 4898360efbdSAlfred Perlstein nconf_udp = getnetconfigent("udp"); 4908360efbdSAlfred Perlstein if (nconf_udp == NULL) 4918360efbdSAlfred Perlstein err(1, "getnetconfigent udp failed"); 4928360efbdSAlfred Perlstein nb_udp.buf = ai_udp->ai_addr; 4938360efbdSAlfred Perlstein nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; 4940775314bSDoug Rabson if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) || 4950775314bSDoug Rabson (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp))) 4968360efbdSAlfred Perlstein err(1, "rpcb_set udp failed"); 4978360efbdSAlfred Perlstein freeaddrinfo(ai_udp); 4988360efbdSAlfred Perlstein } 4998360efbdSAlfred Perlstein } 5008fae3551SRodney W. Grimes 5018360efbdSAlfred Perlstein /* Set up the socket for udp6 and rpcb register it. */ 5028360efbdSAlfred Perlstein if (udpflag && ip6flag) { 5038360efbdSAlfred Perlstein rpcbreg = 0; 5048360efbdSAlfred Perlstein for (i = 0; i < bindhostc; i++) { 5058360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 5068360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 5078360efbdSAlfred Perlstein hints.ai_family = AF_INET6; 5088360efbdSAlfred Perlstein hints.ai_socktype = SOCK_DGRAM; 5098360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 5108360efbdSAlfred Perlstein if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) { 5118360efbdSAlfred Perlstein rpcbreg = 1; 5128360efbdSAlfred Perlstein rpcbregcnt++; 5138360efbdSAlfred Perlstein if ((sock = socket(ai_udp6->ai_family, 5148360efbdSAlfred Perlstein ai_udp6->ai_socktype, 5158360efbdSAlfred Perlstein ai_udp6->ai_protocol)) < 0) { 5168360efbdSAlfred Perlstein syslog(LOG_ERR, 5178360efbdSAlfred Perlstein "can't create udp6 socket"); 518fef7dd5aSIan Dowse nfsd_exit(1); 5198fae3551SRodney W. Grimes } 520fc99a00cSHajimu UMEMOTO if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, 5218360efbdSAlfred Perlstein &on, sizeof on) < 0) { 5228360efbdSAlfred Perlstein syslog(LOG_ERR, 5238360efbdSAlfred Perlstein "can't set v6-only binding for " 5248360efbdSAlfred Perlstein "udp6 socket: %m"); 525fef7dd5aSIan Dowse nfsd_exit(1); 5268fae3551SRodney W. Grimes } 5278360efbdSAlfred Perlstein if (bind(sock, ai_udp6->ai_addr, 5288360efbdSAlfred Perlstein ai_udp6->ai_addrlen) < 0) { 5298360efbdSAlfred Perlstein syslog(LOG_ERR, 5308360efbdSAlfred Perlstein "can't bind udp6 addr %s: %m", 5318360efbdSAlfred Perlstein bindhost[i]); 532fef7dd5aSIan Dowse nfsd_exit(1); 5338fae3551SRodney W. Grimes } 5348360efbdSAlfred Perlstein freeaddrinfo(ai_udp6); 535a9148abdSDoug Rabson addsockargs.sock = sock; 536a9148abdSDoug Rabson addsockargs.name = NULL; 537a9148abdSDoug Rabson addsockargs.namelen = 0; 53820d0a5e5SRick Macklem if (nfssvc(nfssvc_addsock, &addsockargs) < 0) { 5398360efbdSAlfred Perlstein syslog(LOG_ERR, 5408360efbdSAlfred Perlstein "can't add UDP6 socket"); 541fef7dd5aSIan Dowse nfsd_exit(1); 5428fae3551SRodney W. Grimes } 5438360efbdSAlfred Perlstein (void)close(sock); 5448fae3551SRodney W. Grimes } 5458360efbdSAlfred Perlstein } 5468360efbdSAlfred Perlstein if (rpcbreg == 1) { 5478360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 5488360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 5498360efbdSAlfred Perlstein hints.ai_family = AF_INET6; 5508360efbdSAlfred Perlstein hints.ai_socktype = SOCK_DGRAM; 5518360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 5528360efbdSAlfred Perlstein ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); 5538360efbdSAlfred Perlstein if (ecode != 0) { 5548360efbdSAlfred Perlstein syslog(LOG_ERR, "getaddrinfo udp6: %s", 5558360efbdSAlfred Perlstein gai_strerror(ecode)); 556fef7dd5aSIan Dowse nfsd_exit(1); 5578360efbdSAlfred Perlstein } 5588360efbdSAlfred Perlstein nconf_udp6 = getnetconfigent("udp6"); 5598360efbdSAlfred Perlstein if (nconf_udp6 == NULL) 5608360efbdSAlfred Perlstein err(1, "getnetconfigent udp6 failed"); 5618360efbdSAlfred Perlstein nb_udp6.buf = ai_udp6->ai_addr; 5628360efbdSAlfred Perlstein nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; 5630775314bSDoug Rabson if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) || 5640775314bSDoug Rabson (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6))) 5658360efbdSAlfred Perlstein err(1, "rpcb_set udp6 failed"); 5668360efbdSAlfred Perlstein freeaddrinfo(ai_udp6); 5678360efbdSAlfred Perlstein } 5688360efbdSAlfred Perlstein } 5698fae3551SRodney W. Grimes 5708360efbdSAlfred Perlstein /* Set up the socket for tcp and rpcb register it. */ 5718360efbdSAlfred Perlstein if (tcpflag) { 5728360efbdSAlfred Perlstein rpcbreg = 0; 5738360efbdSAlfred Perlstein for (i = 0; i < bindhostc; i++) { 5748360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 5758360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 5768360efbdSAlfred Perlstein hints.ai_family = AF_INET; 5778360efbdSAlfred Perlstein hints.ai_socktype = SOCK_STREAM; 5788360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_TCP; 5798360efbdSAlfred Perlstein if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) { 5808360efbdSAlfred Perlstein rpcbreg = 1; 5818360efbdSAlfred Perlstein rpcbregcnt++; 5828360efbdSAlfred Perlstein if ((tcpsock = socket(AF_INET, SOCK_STREAM, 5838360efbdSAlfred Perlstein 0)) < 0) { 5848360efbdSAlfred Perlstein syslog(LOG_ERR, 5858360efbdSAlfred Perlstein "can't create tpc socket"); 586fef7dd5aSIan Dowse nfsd_exit(1); 5878fae3551SRodney W. Grimes } 5888360efbdSAlfred Perlstein if (setsockopt(tcpsock, SOL_SOCKET, 5898360efbdSAlfred Perlstein SO_REUSEADDR, 5908360efbdSAlfred Perlstein (char *)&on, sizeof(on)) < 0) 5918360efbdSAlfred Perlstein syslog(LOG_ERR, 5928360efbdSAlfred Perlstein "setsockopt SO_REUSEADDR: %m"); 5938360efbdSAlfred Perlstein if (bind(tcpsock, ai_tcp->ai_addr, 5948360efbdSAlfred Perlstein ai_tcp->ai_addrlen) < 0) { 5958360efbdSAlfred Perlstein syslog(LOG_ERR, 5968360efbdSAlfred Perlstein "can't bind tcp addr %s: %m", 5978360efbdSAlfred Perlstein bindhost[i]); 598fef7dd5aSIan Dowse nfsd_exit(1); 5998fae3551SRodney W. Grimes } 6008fae3551SRodney W. Grimes if (listen(tcpsock, 5) < 0) { 6018fae3551SRodney W. Grimes syslog(LOG_ERR, "listen failed"); 602fef7dd5aSIan Dowse nfsd_exit(1); 6038fae3551SRodney W. Grimes } 6048360efbdSAlfred Perlstein freeaddrinfo(ai_tcp); 6058fae3551SRodney W. Grimes FD_SET(tcpsock, &sockbits); 6068360efbdSAlfred Perlstein FD_SET(tcpsock, &v4bits); 6078fae3551SRodney W. Grimes maxsock = tcpsock; 6088fae3551SRodney W. Grimes connect_type_cnt++; 6098fae3551SRodney W. Grimes } 6108360efbdSAlfred Perlstein } 6118360efbdSAlfred Perlstein if (rpcbreg == 1) { 6128360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 6138360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 6148360efbdSAlfred Perlstein hints.ai_family = AF_INET; 6158360efbdSAlfred Perlstein hints.ai_socktype = SOCK_STREAM; 6168360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_TCP; 6178360efbdSAlfred Perlstein ecode = getaddrinfo(NULL, "nfs", &hints, 6188360efbdSAlfred Perlstein &ai_tcp); 6198360efbdSAlfred Perlstein if (ecode != 0) { 6208360efbdSAlfred Perlstein syslog(LOG_ERR, "getaddrinfo tcp: %s", 6218360efbdSAlfred Perlstein gai_strerror(ecode)); 622fef7dd5aSIan Dowse nfsd_exit(1); 6238360efbdSAlfred Perlstein } 6248360efbdSAlfred Perlstein nconf_tcp = getnetconfigent("tcp"); 6258360efbdSAlfred Perlstein if (nconf_tcp == NULL) 6268360efbdSAlfred Perlstein err(1, "getnetconfigent tcp failed"); 6278360efbdSAlfred Perlstein nb_tcp.buf = ai_tcp->ai_addr; 6288360efbdSAlfred Perlstein nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; 6290775314bSDoug Rabson if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp, 6300775314bSDoug Rabson &nb_tcp)) || (!rpcb_set(NFS_PROGRAM, 3, 6318360efbdSAlfred Perlstein nconf_tcp, &nb_tcp))) 6328360efbdSAlfred Perlstein err(1, "rpcb_set tcp failed"); 6338360efbdSAlfred Perlstein freeaddrinfo(ai_tcp); 6348360efbdSAlfred Perlstein } 6358360efbdSAlfred Perlstein } 6368fae3551SRodney W. Grimes 6378360efbdSAlfred Perlstein /* Set up the socket for tcp6 and rpcb register it. */ 6388360efbdSAlfred Perlstein if (tcpflag && ip6flag) { 6398360efbdSAlfred Perlstein rpcbreg = 0; 6408360efbdSAlfred Perlstein for (i = 0; i < bindhostc; i++) { 6418360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 6428360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 6438360efbdSAlfred Perlstein hints.ai_family = AF_INET6; 6448360efbdSAlfred Perlstein hints.ai_socktype = SOCK_STREAM; 6458360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_TCP; 6468360efbdSAlfred Perlstein if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) { 6478360efbdSAlfred Perlstein rpcbreg = 1; 6488360efbdSAlfred Perlstein rpcbregcnt++; 6498360efbdSAlfred Perlstein if ((tcp6sock = socket(ai_tcp6->ai_family, 6508360efbdSAlfred Perlstein ai_tcp6->ai_socktype, 6518360efbdSAlfred Perlstein ai_tcp6->ai_protocol)) < 0) { 6528360efbdSAlfred Perlstein syslog(LOG_ERR, 6538360efbdSAlfred Perlstein "can't create tcp6 socket"); 654fef7dd5aSIan Dowse nfsd_exit(1); 6558fae3551SRodney W. Grimes } 6568360efbdSAlfred Perlstein if (setsockopt(tcp6sock, SOL_SOCKET, 6578360efbdSAlfred Perlstein SO_REUSEADDR, 6588360efbdSAlfred Perlstein (char *)&on, sizeof(on)) < 0) 6598360efbdSAlfred Perlstein syslog(LOG_ERR, 6608360efbdSAlfred Perlstein "setsockopt SO_REUSEADDR: %m"); 6618360efbdSAlfred Perlstein if (setsockopt(tcp6sock, IPPROTO_IPV6, 662fc99a00cSHajimu UMEMOTO IPV6_V6ONLY, &on, sizeof on) < 0) { 6638360efbdSAlfred Perlstein syslog(LOG_ERR, 6648360efbdSAlfred Perlstein "can't set v6-only binding for tcp6 " 6658360efbdSAlfred Perlstein "socket: %m"); 666fef7dd5aSIan Dowse nfsd_exit(1); 6678fae3551SRodney W. Grimes } 6688360efbdSAlfred Perlstein if (bind(tcp6sock, ai_tcp6->ai_addr, 6698360efbdSAlfred Perlstein ai_tcp6->ai_addrlen) < 0) { 6708360efbdSAlfred Perlstein syslog(LOG_ERR, 6718360efbdSAlfred Perlstein "can't bind tcp6 addr %s: %m", 6728360efbdSAlfred Perlstein bindhost[i]); 673fef7dd5aSIan Dowse nfsd_exit(1); 6748360efbdSAlfred Perlstein } 6758360efbdSAlfred Perlstein if (listen(tcp6sock, 5) < 0) { 6768fae3551SRodney W. Grimes syslog(LOG_ERR, "listen failed"); 677fef7dd5aSIan Dowse nfsd_exit(1); 6788fae3551SRodney W. Grimes } 6798360efbdSAlfred Perlstein freeaddrinfo(ai_tcp6); 6808360efbdSAlfred Perlstein FD_SET(tcp6sock, &sockbits); 6818360efbdSAlfred Perlstein FD_SET(tcp6sock, &v6bits); 6828360efbdSAlfred Perlstein if (maxsock < tcp6sock) 6838360efbdSAlfred Perlstein maxsock = tcp6sock; 6848fae3551SRodney W. Grimes connect_type_cnt++; 6858fae3551SRodney W. Grimes } 6868360efbdSAlfred Perlstein } 6878360efbdSAlfred Perlstein if (rpcbreg == 1) { 6888360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 6898360efbdSAlfred Perlstein hints.ai_flags = AI_PASSIVE; 6908360efbdSAlfred Perlstein hints.ai_family = AF_INET6; 6918360efbdSAlfred Perlstein hints.ai_socktype = SOCK_STREAM; 6928360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_TCP; 6938360efbdSAlfred Perlstein ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); 6948360efbdSAlfred Perlstein if (ecode != 0) { 6958360efbdSAlfred Perlstein syslog(LOG_ERR, "getaddrinfo tcp6: %s", 6968360efbdSAlfred Perlstein gai_strerror(ecode)); 697fef7dd5aSIan Dowse nfsd_exit(1); 6988360efbdSAlfred Perlstein } 6998360efbdSAlfred Perlstein nconf_tcp6 = getnetconfigent("tcp6"); 7008360efbdSAlfred Perlstein if (nconf_tcp6 == NULL) 7018360efbdSAlfred Perlstein err(1, "getnetconfigent tcp6 failed"); 7028360efbdSAlfred Perlstein nb_tcp6.buf = ai_tcp6->ai_addr; 7038360efbdSAlfred Perlstein nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; 7040775314bSDoug Rabson if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) || 7050775314bSDoug Rabson (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6))) 7068360efbdSAlfred Perlstein err(1, "rpcb_set tcp6 failed"); 7078360efbdSAlfred Perlstein freeaddrinfo(ai_tcp6); 7088360efbdSAlfred Perlstein } 7098360efbdSAlfred Perlstein } 7108fae3551SRodney W. Grimes 7118360efbdSAlfred Perlstein if (rpcbregcnt == 0) { 7128360efbdSAlfred Perlstein syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m"); 713fef7dd5aSIan Dowse nfsd_exit(1); 7148fae3551SRodney W. Grimes } 7158fae3551SRodney W. Grimes 716fef7dd5aSIan Dowse if (tcpflag && connect_type_cnt == 0) { 7178360efbdSAlfred Perlstein syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m"); 718fef7dd5aSIan Dowse nfsd_exit(1); 7198360efbdSAlfred Perlstein } 7208fae3551SRodney W. Grimes 721a62dc406SDoug Rabson setproctitle("master"); 722fef7dd5aSIan Dowse /* 723fef7dd5aSIan Dowse * We always want a master to have a clean way to to shut nfsd down 724fef7dd5aSIan Dowse * (with unregistration): if the master is killed, it unregisters and 725fef7dd5aSIan Dowse * kills all children. If we run for UDP only (and so do not have to 726fef7dd5aSIan Dowse * loop waiting waiting for accept), we instead make the parent 727fef7dd5aSIan Dowse * a "server" too. start_server will not return. 728fef7dd5aSIan Dowse */ 729fef7dd5aSIan Dowse if (!tcpflag) 730fef7dd5aSIan Dowse start_server(1); 7318fae3551SRodney W. Grimes 7328fae3551SRodney W. Grimes /* 7338fae3551SRodney W. Grimes * Loop forever accepting connections and passing the sockets 7348fae3551SRodney W. Grimes * into the kernel for the mounts. 7358fae3551SRodney W. Grimes */ 7368fae3551SRodney W. Grimes for (;;) { 7378fae3551SRodney W. Grimes ready = sockbits; 7388fae3551SRodney W. Grimes if (connect_type_cnt > 1) { 7398fae3551SRodney W. Grimes if (select(maxsock + 1, 7408fae3551SRodney W. Grimes &ready, NULL, NULL, NULL) < 1) { 741*873ec24aSJohn Baldwin error = errno; 7428fae3551SRodney W. Grimes syslog(LOG_ERR, "select failed: %m"); 743*873ec24aSJohn Baldwin if (error == EINTR) 7440be1e825SRobert Watson continue; 745fef7dd5aSIan Dowse nfsd_exit(1); 7468fae3551SRodney W. Grimes } 7478fae3551SRodney W. Grimes } 7488360efbdSAlfred Perlstein for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) { 7498360efbdSAlfred Perlstein if (FD_ISSET(tcpsock, &ready)) { 7508360efbdSAlfred Perlstein if (FD_ISSET(tcpsock, &v4bits)) { 7518fae3551SRodney W. Grimes len = sizeof(inetpeer); 7528fae3551SRodney W. Grimes if ((msgsock = accept(tcpsock, 7538fae3551SRodney W. Grimes (struct sockaddr *)&inetpeer, &len)) < 0) { 754*873ec24aSJohn Baldwin error = errno; 7558fae3551SRodney W. Grimes syslog(LOG_ERR, "accept failed: %m"); 756*873ec24aSJohn Baldwin if (error == ECONNABORTED || 757*873ec24aSJohn Baldwin error == EINTR) 7580be1e825SRobert Watson continue; 759fef7dd5aSIan Dowse nfsd_exit(1); 7608fae3551SRodney W. Grimes } 7618360efbdSAlfred Perlstein memset(inetpeer.sin_zero, 0, 7628360efbdSAlfred Perlstein sizeof(inetpeer.sin_zero)); 7638fae3551SRodney W. Grimes if (setsockopt(msgsock, SOL_SOCKET, 7648fae3551SRodney W. Grimes SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) 7658fae3551SRodney W. Grimes syslog(LOG_ERR, 7668fae3551SRodney W. Grimes "setsockopt SO_KEEPALIVE: %m"); 767a9148abdSDoug Rabson addsockargs.sock = msgsock; 768a9148abdSDoug Rabson addsockargs.name = (caddr_t)&inetpeer; 769a9148abdSDoug Rabson addsockargs.namelen = len; 77020d0a5e5SRick Macklem nfssvc(nfssvc_addsock, &addsockargs); 7718fae3551SRodney W. Grimes (void)close(msgsock); 7728360efbdSAlfred Perlstein } else if (FD_ISSET(tcpsock, &v6bits)) { 7738360efbdSAlfred Perlstein len = sizeof(inet6peer); 7748360efbdSAlfred Perlstein if ((msgsock = accept(tcpsock, 7758360efbdSAlfred Perlstein (struct sockaddr *)&inet6peer, 7768360efbdSAlfred Perlstein &len)) < 0) { 777*873ec24aSJohn Baldwin error = errno; 7788fae3551SRodney W. Grimes syslog(LOG_ERR, 7798360efbdSAlfred Perlstein "accept failed: %m"); 780*873ec24aSJohn Baldwin if (error == ECONNABORTED || 781*873ec24aSJohn Baldwin error == EINTR) 7820be1e825SRobert Watson continue; 783fef7dd5aSIan Dowse nfsd_exit(1); 7848fae3551SRodney W. Grimes } 7858fae3551SRodney W. Grimes if (setsockopt(msgsock, SOL_SOCKET, 7868360efbdSAlfred Perlstein SO_KEEPALIVE, (char *)&on, 7878360efbdSAlfred Perlstein sizeof(on)) < 0) 7888360efbdSAlfred Perlstein syslog(LOG_ERR, "setsockopt " 7898360efbdSAlfred Perlstein "SO_KEEPALIVE: %m"); 790a9148abdSDoug Rabson addsockargs.sock = msgsock; 791a9148abdSDoug Rabson addsockargs.name = (caddr_t)&inet6peer; 792a9148abdSDoug Rabson addsockargs.namelen = len; 79320d0a5e5SRick Macklem nfssvc(nfssvc_addsock, &addsockargs); 7948fae3551SRodney W. Grimes (void)close(msgsock); 7958fae3551SRodney W. Grimes } 7968360efbdSAlfred Perlstein } 7978360efbdSAlfred Perlstein } 7988fae3551SRodney W. Grimes } 7998fae3551SRodney W. Grimes } 8008fae3551SRodney W. Grimes 8018360efbdSAlfred Perlstein int 8028360efbdSAlfred Perlstein setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints) 80392fc2acfSMatthew Dillon { 8048360efbdSAlfred Perlstein int ecode; 8058360efbdSAlfred Perlstein u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 8068360efbdSAlfred Perlstein const char *hostptr; 80792fc2acfSMatthew Dillon 8088360efbdSAlfred Perlstein if (bindhost == NULL || strcmp("*", bindhost) == 0) 8098360efbdSAlfred Perlstein hostptr = NULL; 8108360efbdSAlfred Perlstein else 8118360efbdSAlfred Perlstein hostptr = bindhost; 8128360efbdSAlfred Perlstein 8138360efbdSAlfred Perlstein if (hostptr != NULL) { 8148360efbdSAlfred Perlstein switch (hints.ai_family) { 8158360efbdSAlfred Perlstein case AF_INET: 8168360efbdSAlfred Perlstein if (inet_pton(AF_INET, hostptr, host_addr) == 1) { 8178360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST; 8188360efbdSAlfred Perlstein } else { 8198360efbdSAlfred Perlstein if (inet_pton(AF_INET6, hostptr, 8208360efbdSAlfred Perlstein host_addr) == 1) 8218360efbdSAlfred Perlstein return (1); 82292fc2acfSMatthew Dillon } 8238360efbdSAlfred Perlstein break; 8248360efbdSAlfred Perlstein case AF_INET6: 8258360efbdSAlfred Perlstein if (inet_pton(AF_INET6, hostptr, host_addr) == 1) { 8268360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST; 8278360efbdSAlfred Perlstein } else { 8288360efbdSAlfred Perlstein if (inet_pton(AF_INET, hostptr, 8298360efbdSAlfred Perlstein host_addr) == 1) 8308360efbdSAlfred Perlstein return (1); 8318360efbdSAlfred Perlstein } 8328360efbdSAlfred Perlstein break; 8338360efbdSAlfred Perlstein default: 83437436e40SPeter Wemm break; 83592fc2acfSMatthew Dillon } 83692fc2acfSMatthew Dillon } 8378360efbdSAlfred Perlstein 8388360efbdSAlfred Perlstein ecode = getaddrinfo(hostptr, "nfs", &hints, ai); 8398360efbdSAlfred Perlstein if (ecode != 0) { 8408360efbdSAlfred Perlstein syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost, 8418360efbdSAlfred Perlstein gai_strerror(ecode)); 8428360efbdSAlfred Perlstein return (1); 8438360efbdSAlfred Perlstein } 8448360efbdSAlfred Perlstein return (0); 84592fc2acfSMatthew Dillon } 84692fc2acfSMatthew Dillon 84792fc2acfSMatthew Dillon void 84810bc3a7fSEd Schouten usage(void) 8498fae3551SRodney W. Grimes { 850a62dc406SDoug Rabson (void)fprintf(stderr, "usage: nfsd %s\n", USAGE); 8518fae3551SRodney W. Grimes exit(1); 8528fae3551SRodney W. Grimes } 8538fae3551SRodney W. Grimes 8548fae3551SRodney W. Grimes void 8556f52836bSXin LI nonfs(__unused int signo) 8568fae3551SRodney W. Grimes { 8579b4d716bSPhilippe Charnier syslog(LOG_ERR, "missing system call: NFS not available"); 8588fae3551SRodney W. Grimes } 8598fae3551SRodney W. Grimes 8608fae3551SRodney W. Grimes void 8616f52836bSXin LI reapchild(__unused int signo) 8628fae3551SRodney W. Grimes { 863fef7dd5aSIan Dowse pid_t pid; 864fef7dd5aSIan Dowse int i; 8658fae3551SRodney W. Grimes 866fef7dd5aSIan Dowse while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) { 867fef7dd5aSIan Dowse for (i = 0; i < nfsdcnt; i++) 868fef7dd5aSIan Dowse if (pid == children[i]) 869fef7dd5aSIan Dowse children[i] = -1; 870fef7dd5aSIan Dowse } 8718fae3551SRodney W. Grimes } 8728fae3551SRodney W. Grimes 8738360efbdSAlfred Perlstein void 87410bc3a7fSEd Schouten unregistration(void) 8758360efbdSAlfred Perlstein { 8760775314bSDoug Rabson if ((!rpcb_unset(NFS_PROGRAM, 2, NULL)) || 8770775314bSDoug Rabson (!rpcb_unset(NFS_PROGRAM, 3, NULL))) 8788360efbdSAlfred Perlstein syslog(LOG_ERR, "rpcb_unset failed"); 8798360efbdSAlfred Perlstein } 8808360efbdSAlfred Perlstein 8818360efbdSAlfred Perlstein void 88210bc3a7fSEd Schouten killchildren(void) 8838360efbdSAlfred Perlstein { 8848360efbdSAlfred Perlstein int i; 8858360efbdSAlfred Perlstein 8868360efbdSAlfred Perlstein for (i = 0; i < nfsdcnt; i++) { 8878360efbdSAlfred Perlstein if (children[i] > 0) 8888360efbdSAlfred Perlstein kill(children[i], SIGKILL); 8898360efbdSAlfred Perlstein } 8908360efbdSAlfred Perlstein } 8918360efbdSAlfred Perlstein 892fef7dd5aSIan Dowse /* 893fef7dd5aSIan Dowse * Cleanup master after SIGUSR1. 894fef7dd5aSIan Dowse */ 8958360efbdSAlfred Perlstein void 8966f52836bSXin LI cleanup(__unused int signo) 8978360efbdSAlfred Perlstein { 898fef7dd5aSIan Dowse nfsd_exit(0); 899fef7dd5aSIan Dowse } 900fef7dd5aSIan Dowse 901fef7dd5aSIan Dowse /* 902fef7dd5aSIan Dowse * Cleanup child after SIGUSR1. 903fef7dd5aSIan Dowse */ 904fef7dd5aSIan Dowse void 9056f52836bSXin LI child_cleanup(__unused int signo) 906fef7dd5aSIan Dowse { 9078360efbdSAlfred Perlstein exit(0); 9088360efbdSAlfred Perlstein } 909fef7dd5aSIan Dowse 910fef7dd5aSIan Dowse void 911fef7dd5aSIan Dowse nfsd_exit(int status) 912fef7dd5aSIan Dowse { 913fef7dd5aSIan Dowse killchildren(); 914fef7dd5aSIan Dowse unregistration(); 915fef7dd5aSIan Dowse exit(status); 916fef7dd5aSIan Dowse } 917fef7dd5aSIan Dowse 918fef7dd5aSIan Dowse void 919fef7dd5aSIan Dowse start_server(int master) 920fef7dd5aSIan Dowse { 92120d0a5e5SRick Macklem char principal[MAXHOSTNAMELEN + 5]; 922a9148abdSDoug Rabson struct nfsd_nfsd_args nfsdargs; 92320d0a5e5SRick Macklem int status, error; 92420d0a5e5SRick Macklem char hostname[MAXHOSTNAMELEN + 1], *cp; 92520d0a5e5SRick Macklem struct addrinfo *aip, hints; 926fef7dd5aSIan Dowse 927fef7dd5aSIan Dowse status = 0; 928a9148abdSDoug Rabson if (new_syscall) { 929a9148abdSDoug Rabson gethostname(hostname, sizeof (hostname)); 930a9148abdSDoug Rabson snprintf(principal, sizeof (principal), "nfs@%s", hostname); 93120d0a5e5SRick Macklem if ((cp = strchr(hostname, '.')) == NULL || 93220d0a5e5SRick Macklem *(cp + 1) == '\0') { 93320d0a5e5SRick Macklem /* If not fully qualified, try getaddrinfo() */ 93420d0a5e5SRick Macklem memset((void *)&hints, 0, sizeof (hints)); 93520d0a5e5SRick Macklem hints.ai_flags = AI_CANONNAME; 93620d0a5e5SRick Macklem error = getaddrinfo(hostname, NULL, &hints, &aip); 93720d0a5e5SRick Macklem if (error == 0) { 93820d0a5e5SRick Macklem if (aip->ai_canonname != NULL && 93920d0a5e5SRick Macklem (cp = strchr(aip->ai_canonname, '.')) != 94020d0a5e5SRick Macklem NULL && *(cp + 1) != '\0') 94120d0a5e5SRick Macklem snprintf(principal, sizeof (principal), 94220d0a5e5SRick Macklem "nfs@%s", aip->ai_canonname); 94320d0a5e5SRick Macklem freeaddrinfo(aip); 94420d0a5e5SRick Macklem } 94520d0a5e5SRick Macklem } 946a9148abdSDoug Rabson nfsdargs.principal = principal; 947a9148abdSDoug Rabson nfsdargs.minthreads = nfsdcnt; 948a9148abdSDoug Rabson nfsdargs.maxthreads = nfsdcnt; 94920d0a5e5SRick Macklem error = nfssvc(nfssvc_nfsd, &nfsdargs); 95020d0a5e5SRick Macklem if (error < 0 && errno == EAUTH) { 95120d0a5e5SRick Macklem /* 95220d0a5e5SRick Macklem * This indicates that it could not register the 95320d0a5e5SRick Macklem * rpcsec_gss credentials, usually because the 95420d0a5e5SRick Macklem * gssd daemon isn't running. 95520d0a5e5SRick Macklem * (only the experimental server with nfsv4) 95620d0a5e5SRick Macklem */ 95720d0a5e5SRick Macklem syslog(LOG_ERR, "No gssd, using AUTH_SYS only"); 95820d0a5e5SRick Macklem principal[0] = '\0'; 95920d0a5e5SRick Macklem error = nfssvc(nfssvc_nfsd, &nfsdargs); 96020d0a5e5SRick Macklem } 96120d0a5e5SRick Macklem if (error < 0) { 962fef7dd5aSIan Dowse syslog(LOG_ERR, "nfssvc: %m"); 963fef7dd5aSIan Dowse status = 1; 964fef7dd5aSIan Dowse } 965a9148abdSDoug Rabson } else { 966a9148abdSDoug Rabson if (nfssvc(NFSSVC_OLDNFSD, NULL) < 0) { 967a9148abdSDoug Rabson syslog(LOG_ERR, "nfssvc: %m"); 968a9148abdSDoug Rabson status = 1; 969a9148abdSDoug Rabson } 970a9148abdSDoug Rabson } 971fef7dd5aSIan Dowse if (master) 972fef7dd5aSIan Dowse nfsd_exit(status); 973fef7dd5aSIan Dowse else 974fef7dd5aSIan Dowse exit(status); 975fef7dd5aSIan Dowse } 976