nfsd.c revision 95861
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 * 3. All advertising materials mentioning features or use of this software 171558Srgrimes * must display the following acknowledgement: 181558Srgrimes * This product includes software developed by the University of 191558Srgrimes * California, Berkeley and its contributors. 201558Srgrimes * 4. Neither the name of the University nor the names of its contributors 211558Srgrimes * may be used to endorse or promote products derived from this software 221558Srgrimes * without specific prior written permission. 231558Srgrimes * 241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341558Srgrimes * SUCH DAMAGE. 351558Srgrimes */ 361558Srgrimes 371558Srgrimes#ifndef lint 3837666Scharnierstatic const char copyright[] = 391558Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\ 401558Srgrimes The Regents of the University of California. All rights reserved.\n"; 4195861Speter#endif /* not lint */ 421558Srgrimes 431558Srgrimes#ifndef lint 4437666Scharnier#if 0 4523684Speterstatic char sccsid[] = "@(#)nfsd.c 8.9 (Berkeley) 3/29/95"; 4637666Scharnier#endif 4737666Scharnierstatic const char rcsid[] = 4850476Speter "$FreeBSD: head/usr.sbin/nfsd/nfsd.c 95861 2002-05-01 06:49:43Z peter $"; 4995861Speter#endif /* not lint */ 501558Srgrimes 511558Srgrimes#include <sys/param.h> 521558Srgrimes#include <sys/syslog.h> 531558Srgrimes#include <sys/wait.h> 541558Srgrimes#include <sys/mount.h> 5585034Siedowse#include <sys/linker.h> 5685034Siedowse#include <sys/module.h> 571558Srgrimes 581558Srgrimes#include <rpc/rpc.h> 591558Srgrimes#include <rpc/pmap_clnt.h> 601558Srgrimes 6153096Sdillon#include <netdb.h> 6253096Sdillon#include <arpa/inet.h> 631558Srgrimes#include <nfs/rpcv2.h> 649336Sdfr#include <nfs/nfsproto.h> 6583653Speter#include <nfsserver/nfs.h> 661558Srgrimes 671558Srgrimes#include <err.h> 681558Srgrimes#include <errno.h> 6985034Siedowse#include <signal.h> 701558Srgrimes#include <stdio.h> 711558Srgrimes#include <stdlib.h> 7295861Speter#include <string.h> 731558Srgrimes#include <unistd.h> 7474462Salfred#include <netdb.h> 751558Srgrimes 761558Srgrimes/* Global defs */ 771558Srgrimes#ifdef DEBUG 7893233Spb#define syslog(e, s...) fprintf(stderr,s) 791558Srgrimesint debug = 1; 801558Srgrimes#else 811558Srgrimesint debug = 0; 821558Srgrimes#endif 831558Srgrimes 841558Srgrimesstruct nfsd_srvargs nsd; 851558Srgrimes 8674462Salfred#define MAXNFSDCNT 20 8774462Salfred#define DEFNFSDCNT 4 8874462Salfredpid_t children[MAXNFSDCNT]; /* PIDs of children */ 8974462Salfredint nfsdcnt; /* number of children */ 9074462Salfred 9174462Salfredvoid cleanup(int); 9285034Siedowsevoid child_cleanup(int); 9374462Salfredvoid killchildren(void); 9485034Siedowsevoid nfsd_exit(int); 9585034Siedowsevoid nonfs(int); 9685034Siedowsevoid reapchild(int); 9785034Siedowseint setbindhost(struct addrinfo **ia, const char *bindhost, 9885034Siedowse struct addrinfo hints); 9985034Siedowsevoid start_server(int); 10085034Siedowsevoid unregistration(void); 10185034Siedowsevoid usage(void); 1021558Srgrimes 1031558Srgrimes/* 1041558Srgrimes * Nfs server daemon mostly just a user context for nfssvc() 1051558Srgrimes * 1061558Srgrimes * 1 - do file descriptor and signal cleanup 1071558Srgrimes * 2 - fork the nfsd(s) 1081558Srgrimes * 3 - create server socket(s) 10974462Salfred * 4 - register socket with rpcbind 1101558Srgrimes * 1111558Srgrimes * For connectionless protocols, just pass the socket into the kernel via. 1121558Srgrimes * nfssvc(). 1131558Srgrimes * For connection based sockets, loop doing accepts. When you get a new 1141558Srgrimes * socket from accept, pass the msgsock into the kernel via. nfssvc(). 1151558Srgrimes * The arguments are: 11674462Salfred * -r - reregister with rpcbind 11774462Salfred * -d - unregister with rpcbind 1181558Srgrimes * -t - support tcp nfs clients 1191558Srgrimes * -u - support udp nfs clients 1201558Srgrimes * followed by "n" which is the number of nfsds' to fork off 1211558Srgrimes */ 1221558Srgrimesint 1231558Srgrimesmain(argc, argv, envp) 1241558Srgrimes int argc; 1251558Srgrimes char *argv[], *envp[]; 1261558Srgrimes{ 1271558Srgrimes struct nfsd_args nfsdargs; 12874462Salfred struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints; 12974462Salfred struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6; 13074462Salfred struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6; 13174462Salfred struct sockaddr_in inetpeer; 13274462Salfred struct sockaddr_in6 inet6peer; 1331558Srgrimes fd_set ready, sockbits; 13474462Salfred fd_set v4bits, v6bits; 13583653Speter int ch, connect_type_cnt, i, len, maxsock, msgsock; 13685034Siedowse int on = 1, unregister, reregister, sock; 13774462Salfred int tcp6sock, ip6flag, tcpflag, tcpsock; 13885034Siedowse int udpflag, ecode, s, srvcnt; 13985034Siedowse int bindhostc, bindanyflag, rpcbreg, rpcbregcnt; 14053096Sdillon char **bindhost = NULL; 14174462Salfred pid_t pid; 1421558Srgrimes 14383688Speter if (modfind("nfsserver") < 0) { 14483688Speter /* Not present in kernel, try loading it */ 14583688Speter if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 14683688Speter errx(1, "NFS serveris not available"); 1472999Swollman } 1482999Swollman 1491558Srgrimes nfsdcnt = DEFNFSDCNT; 15085034Siedowse unregister = reregister = tcpflag = maxsock = 0; 15185034Siedowse bindanyflag = udpflag = connect_type_cnt = bindhostc = 0; 15274462Salfred#define GETOPT "ah:n:rdtu" 15374462Salfred#define USAGE "[-ardtu] [-n num_servers] [-h bindip]" 15424359Simp while ((ch = getopt(argc, argv, GETOPT)) != -1) 1551558Srgrimes switch (ch) { 15653096Sdillon case 'a': 15753096Sdillon bindanyflag = 1; 15853096Sdillon break; 1591558Srgrimes case 'n': 1601558Srgrimes nfsdcnt = atoi(optarg); 1611558Srgrimes if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) { 16231206Sjdp warnx("nfsd count %d; reset to %d", nfsdcnt, 16331206Sjdp DEFNFSDCNT); 1641558Srgrimes nfsdcnt = DEFNFSDCNT; 1651558Srgrimes } 1661558Srgrimes break; 16753096Sdillon case 'h': 16853096Sdillon bindhostc++; 16953096Sdillon bindhost = realloc(bindhost,sizeof(char *)*bindhostc); 17053096Sdillon if (bindhost == NULL) 17153096Sdillon errx(1, "Out of memory"); 17253096Sdillon bindhost[bindhostc-1] = strdup(optarg); 17353096Sdillon if (bindhost[bindhostc-1] == NULL) 17453096Sdillon errx(1, "Out of memory"); 17553096Sdillon break; 1761558Srgrimes case 'r': 1771558Srgrimes reregister = 1; 1781558Srgrimes break; 17974462Salfred case 'd': 18074462Salfred unregister = 1; 18174462Salfred break; 1821558Srgrimes case 't': 1831558Srgrimes tcpflag = 1; 1841558Srgrimes break; 1851558Srgrimes case 'u': 1861558Srgrimes udpflag = 1; 1871558Srgrimes break; 1881558Srgrimes default: 1891558Srgrimes case '?': 1901558Srgrimes usage(); 1911558Srgrimes }; 19215496Sbde if (!tcpflag && !udpflag) 19315496Sbde udpflag = 1; 1941558Srgrimes argv += optind; 1951558Srgrimes argc -= optind; 1961558Srgrimes 1971558Srgrimes /* 1981558Srgrimes * XXX 1991558Srgrimes * Backward compatibility, trailing number is the count of daemons. 2001558Srgrimes */ 2011558Srgrimes if (argc > 1) 2021558Srgrimes usage(); 2031558Srgrimes if (argc == 1) { 2041558Srgrimes nfsdcnt = atoi(argv[0]); 2051558Srgrimes if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) { 20631206Sjdp warnx("nfsd count %d; reset to %d", nfsdcnt, 20731206Sjdp DEFNFSDCNT); 2081558Srgrimes nfsdcnt = DEFNFSDCNT; 2091558Srgrimes } 2101558Srgrimes } 21174800Salfred 21274462Salfred ip6flag = 1; 21374462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 21474800Salfred if (s == -1) { 21574800Salfred if (errno != EPROTONOSUPPORT) 21674800Salfred err(1, "socket"); 21774462Salfred ip6flag = 0; 21874800Salfred } else if (getnetconfigent("udp6") == NULL || 21974800Salfred getnetconfigent("tcp6") == NULL) { 22074800Salfred ip6flag = 0; 22174800Salfred } 22274800Salfred if (s != -1) 22374462Salfred close(s); 2241558Srgrimes 22553096Sdillon if (bindhostc == 0 || bindanyflag) { 22653096Sdillon bindhostc++; 22753096Sdillon bindhost = realloc(bindhost,sizeof(char *)*bindhostc); 22853096Sdillon if (bindhost == NULL) 22953096Sdillon errx(1, "Out of memory"); 23053096Sdillon bindhost[bindhostc-1] = strdup("*"); 23153096Sdillon if (bindhost[bindhostc-1] == NULL) 23253096Sdillon errx(1, "Out of memory"); 23353096Sdillon } 23453096Sdillon 23574462Salfred if (unregister) { 23674462Salfred unregistration(); 23774462Salfred exit (0); 23874462Salfred } 2391558Srgrimes if (reregister) { 24074462Salfred if (udpflag) { 24174462Salfred memset(&hints, 0, sizeof hints); 24274462Salfred hints.ai_flags = AI_PASSIVE; 24374462Salfred hints.ai_family = AF_INET; 24474462Salfred hints.ai_socktype = SOCK_DGRAM; 24574462Salfred hints.ai_protocol = IPPROTO_UDP; 24674462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); 24774800Salfred if (ecode != 0) 24874800Salfred err(1, "getaddrinfo udp: %s", gai_strerror(ecode)); 24974462Salfred nconf_udp = getnetconfigent("udp"); 25074462Salfred if (nconf_udp == NULL) 25174462Salfred err(1, "getnetconfigent udp failed"); 25274462Salfred nb_udp.buf = ai_udp->ai_addr; 25374462Salfred nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; 25474462Salfred if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) || 25574462Salfred (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp))) 25674462Salfred err(1, "rpcb_set udp failed"); 25774462Salfred freeaddrinfo(ai_udp); 25874462Salfred } 25974462Salfred if (udpflag && ip6flag) { 26074462Salfred memset(&hints, 0, sizeof hints); 26174462Salfred hints.ai_flags = AI_PASSIVE; 26274462Salfred hints.ai_family = AF_INET6; 26374462Salfred hints.ai_socktype = SOCK_DGRAM; 26474462Salfred hints.ai_protocol = IPPROTO_UDP; 26574462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); 26674800Salfred if (ecode != 0) 26774800Salfred err(1, "getaddrinfo udp6: %s", gai_strerror(ecode)); 26874462Salfred nconf_udp6 = getnetconfigent("udp6"); 26974462Salfred if (nconf_udp6 == NULL) 27074462Salfred err(1, "getnetconfigent udp6 failed"); 27174462Salfred nb_udp6.buf = ai_udp6->ai_addr; 27274462Salfred nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; 27374462Salfred if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) || 27474462Salfred (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6))) 27574462Salfred err(1, "rpcb_set udp6 failed"); 27674462Salfred freeaddrinfo(ai_udp6); 27774462Salfred } 27874462Salfred if (tcpflag) { 27974462Salfred memset(&hints, 0, sizeof hints); 28074462Salfred hints.ai_flags = AI_PASSIVE; 28174462Salfred hints.ai_family = AF_INET; 28274462Salfred hints.ai_socktype = SOCK_STREAM; 28374462Salfred hints.ai_protocol = IPPROTO_TCP; 28474462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp); 28574800Salfred if (ecode != 0) 28674800Salfred err(1, "getaddrinfo tcp: %s", gai_strerror(ecode)); 28774462Salfred nconf_tcp = getnetconfigent("tcp"); 28874462Salfred if (nconf_tcp == NULL) 28974462Salfred err(1, "getnetconfigent tcp failed"); 29074462Salfred nb_tcp.buf = ai_tcp->ai_addr; 29174462Salfred nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; 29274462Salfred if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) || 29374462Salfred (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp))) 29474462Salfred err(1, "rpcb_set tcp failed"); 29574462Salfred freeaddrinfo(ai_tcp); 29674462Salfred } 29774462Salfred if (tcpflag && ip6flag) { 29874462Salfred memset(&hints, 0, sizeof hints); 29974462Salfred hints.ai_flags = AI_PASSIVE; 30074462Salfred hints.ai_family = AF_INET6; 30174462Salfred hints.ai_socktype = SOCK_STREAM; 30274462Salfred hints.ai_protocol = IPPROTO_TCP; 30374462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); 30474800Salfred if (ecode != 0) 30574800Salfred err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode)); 30674462Salfred nconf_tcp6 = getnetconfigent("tcp6"); 30774462Salfred if (nconf_tcp6 == NULL) 30874462Salfred err(1, "getnetconfigent tcp6 failed"); 30974462Salfred nb_tcp6.buf = ai_tcp6->ai_addr; 31074462Salfred nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; 31174462Salfred if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) || 31274462Salfred (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6))) 31374462Salfred err(1, "rpcb_set tcp6 failed"); 31474462Salfred freeaddrinfo(ai_tcp6); 31574462Salfred } 31674462Salfred exit (0); 3171558Srgrimes } 31874800Salfred if (debug == 0) { 31974800Salfred daemon(0, 0); 32074800Salfred (void)signal(SIGHUP, SIG_IGN); 32174800Salfred (void)signal(SIGINT, SIG_IGN); 32274800Salfred /* 32374800Salfred * nfsd sits in the kernel most of the time. It needs 32474800Salfred * to ignore SIGTERM/SIGQUIT in order to stay alive as long 32574800Salfred * as possible during a shutdown, otherwise loopback 32674800Salfred * mounts will not be able to unmount. 32774800Salfred */ 32874800Salfred (void)signal(SIGTERM, SIG_IGN); 32974800Salfred (void)signal(SIGQUIT, SIG_IGN); 33074800Salfred } 33185034Siedowse (void)signal(SIGSYS, nonfs); 33274800Salfred (void)signal(SIGCHLD, reapchild); 33374462Salfred 33485034Siedowse openlog("nfsd", LOG_PID, LOG_DAEMON); 3351558Srgrimes 33685034Siedowse /* If we use UDP only, we start the last server below. */ 33785034Siedowse srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1; 33885034Siedowse for (i = 0; i < srvcnt; i++) { 33974462Salfred switch ((pid = fork())) { 3401558Srgrimes case -1: 3411558Srgrimes syslog(LOG_ERR, "fork: %m"); 34285034Siedowse nfsd_exit(1); 3431558Srgrimes case 0: 3441558Srgrimes break; 3451558Srgrimes default: 34674462Salfred children[i] = pid; 3471558Srgrimes continue; 3481558Srgrimes } 34985034Siedowse (void)signal(SIGUSR1, child_cleanup); 35085034Siedowse setproctitle("server"); 3511558Srgrimes 35285034Siedowse start_server(0); 3531558Srgrimes } 3541558Srgrimes 35585034Siedowse (void)signal(SIGUSR1, cleanup); 35674462Salfred FD_ZERO(&v4bits); 35774462Salfred FD_ZERO(&v6bits); 35874462Salfred 35974462Salfred rpcbregcnt = 0; 36074462Salfred /* Set up the socket for udp and rpcb register it. */ 36174462Salfred if (udpflag) { 36274462Salfred rpcbreg = 0; 36374462Salfred for (i = 0; i < bindhostc; i++) { 36474462Salfred memset(&hints, 0, sizeof hints); 36574462Salfred hints.ai_flags = AI_PASSIVE; 36674462Salfred hints.ai_family = AF_INET; 36774462Salfred hints.ai_socktype = SOCK_DGRAM; 36874462Salfred hints.ai_protocol = IPPROTO_UDP; 36974462Salfred if (setbindhost(&ai_udp, bindhost[i], hints) == 0) { 37074462Salfred rpcbreg = 1; 37174462Salfred rpcbregcnt++; 37274462Salfred if ((sock = socket(ai_udp->ai_family, 37374462Salfred ai_udp->ai_socktype, 37474462Salfred ai_udp->ai_protocol)) < 0) { 37574462Salfred syslog(LOG_ERR, 37674462Salfred "can't create udp socket"); 37785034Siedowse nfsd_exit(1); 37874462Salfred } 37974462Salfred if (bind(sock, ai_udp->ai_addr, 38074462Salfred ai_udp->ai_addrlen) < 0) { 38174462Salfred syslog(LOG_ERR, 38274462Salfred "can't bind udp addr %s: %m", 38374462Salfred bindhost[i]); 38485034Siedowse nfsd_exit(1); 38574462Salfred } 38674462Salfred freeaddrinfo(ai_udp); 38774462Salfred nfsdargs.sock = sock; 38874462Salfred nfsdargs.name = NULL; 38974462Salfred nfsdargs.namelen = 0; 39074462Salfred if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { 39174462Salfred syslog(LOG_ERR, "can't Add UDP socket"); 39285034Siedowse nfsd_exit(1); 39374462Salfred } 39474462Salfred (void)close(sock); 39574462Salfred } 3961558Srgrimes } 39774462Salfred if (rpcbreg == 1) { 39874462Salfred memset(&hints, 0, sizeof hints); 39974462Salfred hints.ai_flags = AI_PASSIVE; 40074462Salfred hints.ai_family = AF_INET; 40174462Salfred hints.ai_socktype = SOCK_DGRAM; 40274462Salfred hints.ai_protocol = IPPROTO_UDP; 40374462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); 40474462Salfred if (ecode != 0) { 40574462Salfred syslog(LOG_ERR, "getaddrinfo udp: %s", 40674462Salfred gai_strerror(ecode)); 40785034Siedowse nfsd_exit(1); 40874462Salfred } 40974462Salfred nconf_udp = getnetconfigent("udp"); 41074462Salfred if (nconf_udp == NULL) 41174462Salfred err(1, "getnetconfigent udp failed"); 41274462Salfred nb_udp.buf = ai_udp->ai_addr; 41374462Salfred nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; 41474462Salfred if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) || 41574462Salfred (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp))) 41674462Salfred err(1, "rpcb_set udp failed"); 41774462Salfred freeaddrinfo(ai_udp); 4181558Srgrimes } 4191558Srgrimes } 4201558Srgrimes 42174462Salfred /* Set up the socket for udp6 and rpcb register it. */ 42274462Salfred if (udpflag && ip6flag) { 42374462Salfred rpcbreg = 0; 42474462Salfred for (i = 0; i < bindhostc; i++) { 42574462Salfred memset(&hints, 0, sizeof hints); 42674462Salfred hints.ai_flags = AI_PASSIVE; 42774462Salfred hints.ai_family = AF_INET6; 42874462Salfred hints.ai_socktype = SOCK_DGRAM; 42974462Salfred hints.ai_protocol = IPPROTO_UDP; 43074462Salfred if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) { 43174462Salfred rpcbreg = 1; 43274462Salfred rpcbregcnt++; 43374462Salfred if ((sock = socket(ai_udp6->ai_family, 43474462Salfred ai_udp6->ai_socktype, 43574462Salfred ai_udp6->ai_protocol)) < 0) { 43674462Salfred syslog(LOG_ERR, 43774462Salfred "can't create udp6 socket"); 43885034Siedowse nfsd_exit(1); 43974462Salfred } 44074462Salfred if (setsockopt(sock, IPPROTO_IPV6, 44174462Salfred IPV6_BINDV6ONLY, 44274462Salfred &on, sizeof on) < 0) { 44374462Salfred syslog(LOG_ERR, 44474462Salfred "can't set v6-only binding for " 44574462Salfred "udp6 socket: %m"); 44685034Siedowse nfsd_exit(1); 44774462Salfred } 44874462Salfred if (bind(sock, ai_udp6->ai_addr, 44974462Salfred ai_udp6->ai_addrlen) < 0) { 45074462Salfred syslog(LOG_ERR, 45174462Salfred "can't bind udp6 addr %s: %m", 45274462Salfred bindhost[i]); 45385034Siedowse nfsd_exit(1); 45474462Salfred } 45574462Salfred freeaddrinfo(ai_udp6); 45674462Salfred nfsdargs.sock = sock; 45774462Salfred nfsdargs.name = NULL; 45874462Salfred nfsdargs.namelen = 0; 45974462Salfred if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { 46074462Salfred syslog(LOG_ERR, 46174462Salfred "can't add UDP6 socket"); 46285034Siedowse nfsd_exit(1); 46374462Salfred } 46474462Salfred (void)close(sock); 46574462Salfred } 4661558Srgrimes } 46774462Salfred if (rpcbreg == 1) { 46874462Salfred memset(&hints, 0, sizeof hints); 46974462Salfred hints.ai_flags = AI_PASSIVE; 47074462Salfred hints.ai_family = AF_INET6; 47174462Salfred hints.ai_socktype = SOCK_DGRAM; 47274462Salfred hints.ai_protocol = IPPROTO_UDP; 47374462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); 47474462Salfred if (ecode != 0) { 47574462Salfred syslog(LOG_ERR, "getaddrinfo udp6: %s", 47674462Salfred gai_strerror(ecode)); 47785034Siedowse nfsd_exit(1); 47874462Salfred } 47974462Salfred nconf_udp6 = getnetconfigent("udp6"); 48074462Salfred if (nconf_udp6 == NULL) 48174462Salfred err(1, "getnetconfigent udp6 failed"); 48274462Salfred nb_udp6.buf = ai_udp6->ai_addr; 48374462Salfred nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; 48474462Salfred if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) || 48574462Salfred (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6))) 48674462Salfred err(1, "rpcb_set udp6 failed"); 48774462Salfred freeaddrinfo(ai_udp6); 4881558Srgrimes } 4891558Srgrimes } 4901558Srgrimes 49174462Salfred /* Set up the socket for tcp and rpcb register it. */ 49274462Salfred if (tcpflag) { 49374462Salfred rpcbreg = 0; 49474462Salfred for (i = 0; i < bindhostc; i++) { 49574462Salfred memset(&hints, 0, sizeof hints); 49674462Salfred hints.ai_flags = AI_PASSIVE; 49774462Salfred hints.ai_family = AF_INET; 49874462Salfred hints.ai_socktype = SOCK_STREAM; 49974462Salfred hints.ai_protocol = IPPROTO_TCP; 50074462Salfred if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) { 50174462Salfred rpcbreg = 1; 50274462Salfred rpcbregcnt++; 50374462Salfred if ((tcpsock = socket(AF_INET, SOCK_STREAM, 50474462Salfred 0)) < 0) { 50574462Salfred syslog(LOG_ERR, 50674462Salfred "can't create tpc socket"); 50785034Siedowse nfsd_exit(1); 50874462Salfred } 50974462Salfred if (setsockopt(tcpsock, SOL_SOCKET, 51074462Salfred SO_REUSEADDR, 51174462Salfred (char *)&on, sizeof(on)) < 0) 51274462Salfred syslog(LOG_ERR, 51374462Salfred "setsockopt SO_REUSEADDR: %m"); 51474462Salfred if (bind(tcpsock, ai_tcp->ai_addr, 51574462Salfred ai_tcp->ai_addrlen) < 0) { 51674462Salfred syslog(LOG_ERR, 51774462Salfred "can't bind tcp addr %s: %m", 51874462Salfred bindhost[i]); 51985034Siedowse nfsd_exit(1); 52074462Salfred } 52174462Salfred if (listen(tcpsock, 5) < 0) { 52274462Salfred syslog(LOG_ERR, "listen failed"); 52385034Siedowse nfsd_exit(1); 52474462Salfred } 52574462Salfred freeaddrinfo(ai_tcp); 52674462Salfred FD_SET(tcpsock, &sockbits); 52774462Salfred FD_SET(tcpsock, &v4bits); 52874462Salfred maxsock = tcpsock; 52974462Salfred connect_type_cnt++; 53074462Salfred } 5311558Srgrimes } 53274462Salfred if (rpcbreg == 1) { 53374462Salfred memset(&hints, 0, sizeof hints); 53474462Salfred hints.ai_flags = AI_PASSIVE; 53574462Salfred hints.ai_family = AF_INET; 53674462Salfred hints.ai_socktype = SOCK_STREAM; 53774462Salfred hints.ai_protocol = IPPROTO_TCP; 53874462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, 53974462Salfred &ai_tcp); 54074462Salfred if (ecode != 0) { 54174462Salfred syslog(LOG_ERR, "getaddrinfo tcp: %s", 54274462Salfred gai_strerror(ecode)); 54385034Siedowse nfsd_exit(1); 54474462Salfred } 54574462Salfred nconf_tcp = getnetconfigent("tcp"); 54674462Salfred if (nconf_tcp == NULL) 54774462Salfred err(1, "getnetconfigent tcp failed"); 54874462Salfred nb_tcp.buf = ai_tcp->ai_addr; 54974462Salfred nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; 55074462Salfred if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, 55174462Salfred &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3, 55274462Salfred nconf_tcp, &nb_tcp))) 55374462Salfred err(1, "rpcb_set tcp failed"); 55474462Salfred freeaddrinfo(ai_tcp); 5551558Srgrimes } 5561558Srgrimes } 5571558Srgrimes 55874462Salfred /* Set up the socket for tcp6 and rpcb register it. */ 55974462Salfred if (tcpflag && ip6flag) { 56074462Salfred rpcbreg = 0; 56174462Salfred for (i = 0; i < bindhostc; i++) { 56274462Salfred memset(&hints, 0, sizeof hints); 56374462Salfred hints.ai_flags = AI_PASSIVE; 56474462Salfred hints.ai_family = AF_INET6; 56574462Salfred hints.ai_socktype = SOCK_STREAM; 56674462Salfred hints.ai_protocol = IPPROTO_TCP; 56774462Salfred if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) { 56874462Salfred rpcbreg = 1; 56974462Salfred rpcbregcnt++; 57074462Salfred if ((tcp6sock = socket(ai_tcp6->ai_family, 57174462Salfred ai_tcp6->ai_socktype, 57274462Salfred ai_tcp6->ai_protocol)) < 0) { 57374462Salfred syslog(LOG_ERR, 57474462Salfred "can't create tcp6 socket"); 57585034Siedowse nfsd_exit(1); 57674462Salfred } 57774462Salfred if (setsockopt(tcp6sock, SOL_SOCKET, 57874462Salfred SO_REUSEADDR, 57974462Salfred (char *)&on, sizeof(on)) < 0) 58074462Salfred syslog(LOG_ERR, 58174462Salfred "setsockopt SO_REUSEADDR: %m"); 58274462Salfred if (setsockopt(tcp6sock, IPPROTO_IPV6, 58374462Salfred IPV6_BINDV6ONLY, &on, sizeof on) < 0) { 58474462Salfred syslog(LOG_ERR, 58574462Salfred "can't set v6-only binding for tcp6 " 58674462Salfred "socket: %m"); 58785034Siedowse nfsd_exit(1); 58874462Salfred } 58974462Salfred if (bind(tcp6sock, ai_tcp6->ai_addr, 59074462Salfred ai_tcp6->ai_addrlen) < 0) { 59174462Salfred syslog(LOG_ERR, 59274462Salfred "can't bind tcp6 addr %s: %m", 59374462Salfred bindhost[i]); 59485034Siedowse nfsd_exit(1); 59574462Salfred } 59674462Salfred if (listen(tcp6sock, 5) < 0) { 59774462Salfred syslog(LOG_ERR, "listen failed"); 59885034Siedowse nfsd_exit(1); 59974462Salfred } 60074462Salfred freeaddrinfo(ai_tcp6); 60174462Salfred FD_SET(tcp6sock, &sockbits); 60274462Salfred FD_SET(tcp6sock, &v6bits); 60374462Salfred if (maxsock < tcp6sock) 60474462Salfred maxsock = tcp6sock; 60574462Salfred connect_type_cnt++; 60674462Salfred } 6071558Srgrimes } 60874462Salfred if (rpcbreg == 1) { 60974462Salfred memset(&hints, 0, sizeof hints); 61074462Salfred hints.ai_flags = AI_PASSIVE; 61174462Salfred hints.ai_family = AF_INET6; 61274462Salfred hints.ai_socktype = SOCK_STREAM; 61374462Salfred hints.ai_protocol = IPPROTO_TCP; 61474462Salfred ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); 61574462Salfred if (ecode != 0) { 61674462Salfred syslog(LOG_ERR, "getaddrinfo tcp6: %s", 61774462Salfred gai_strerror(ecode)); 61885034Siedowse nfsd_exit(1); 61974462Salfred } 62074462Salfred nconf_tcp6 = getnetconfigent("tcp6"); 62174462Salfred if (nconf_tcp6 == NULL) 62274462Salfred err(1, "getnetconfigent tcp6 failed"); 62374462Salfred nb_tcp6.buf = ai_tcp6->ai_addr; 62474462Salfred nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; 62574462Salfred if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) || 62674462Salfred (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6))) 62774462Salfred err(1, "rpcb_set tcp6 failed"); 62874462Salfred freeaddrinfo(ai_tcp6); 6291558Srgrimes } 6301558Srgrimes } 6311558Srgrimes 63274462Salfred if (rpcbregcnt == 0) { 63374462Salfred syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m"); 63485034Siedowse nfsd_exit(1); 6351558Srgrimes } 6361558Srgrimes 63785034Siedowse if (tcpflag && connect_type_cnt == 0) { 63874462Salfred syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m"); 63985034Siedowse nfsd_exit(1); 64074462Salfred } 6411558Srgrimes 6429336Sdfr setproctitle("master"); 64385034Siedowse /* 64485034Siedowse * We always want a master to have a clean way to to shut nfsd down 64585034Siedowse * (with unregistration): if the master is killed, it unregisters and 64685034Siedowse * kills all children. If we run for UDP only (and so do not have to 64785034Siedowse * loop waiting waiting for accept), we instead make the parent 64885034Siedowse * a "server" too. start_server will not return. 64985034Siedowse */ 65085034Siedowse if (!tcpflag) 65185034Siedowse start_server(1); 6521558Srgrimes 6531558Srgrimes /* 6541558Srgrimes * Loop forever accepting connections and passing the sockets 6551558Srgrimes * into the kernel for the mounts. 6561558Srgrimes */ 6571558Srgrimes for (;;) { 6581558Srgrimes ready = sockbits; 6591558Srgrimes if (connect_type_cnt > 1) { 6601558Srgrimes if (select(maxsock + 1, 6611558Srgrimes &ready, NULL, NULL, NULL) < 1) { 6621558Srgrimes syslog(LOG_ERR, "select failed: %m"); 66385034Siedowse nfsd_exit(1); 6641558Srgrimes } 6651558Srgrimes } 66674462Salfred for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) { 66774462Salfred if (FD_ISSET(tcpsock, &ready)) { 66874462Salfred if (FD_ISSET(tcpsock, &v4bits)) { 66974462Salfred len = sizeof(inetpeer); 67074462Salfred if ((msgsock = accept(tcpsock, 67174462Salfred (struct sockaddr *)&inetpeer, &len)) < 0) { 67274462Salfred syslog(LOG_ERR, "accept failed: %m"); 67385034Siedowse nfsd_exit(1); 67474462Salfred } 67574462Salfred memset(inetpeer.sin_zero, 0, 67674462Salfred sizeof(inetpeer.sin_zero)); 67774462Salfred if (setsockopt(msgsock, SOL_SOCKET, 67874462Salfred SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) 67974462Salfred syslog(LOG_ERR, 68074462Salfred "setsockopt SO_KEEPALIVE: %m"); 68174462Salfred nfsdargs.sock = msgsock; 68274462Salfred nfsdargs.name = (caddr_t)&inetpeer; 68385034Siedowse nfsdargs.namelen = len; 68474462Salfred nfssvc(NFSSVC_ADDSOCK, &nfsdargs); 68574462Salfred (void)close(msgsock); 68674462Salfred } else if (FD_ISSET(tcpsock, &v6bits)) { 68774462Salfred len = sizeof(inet6peer); 68874462Salfred if ((msgsock = accept(tcpsock, 68974462Salfred (struct sockaddr *)&inet6peer, 69074462Salfred &len)) < 0) { 69174462Salfred syslog(LOG_ERR, 69274462Salfred "accept failed: %m"); 69385034Siedowse nfsd_exit(1); 69474462Salfred } 69574462Salfred if (setsockopt(msgsock, SOL_SOCKET, 69674462Salfred SO_KEEPALIVE, (char *)&on, 69774462Salfred sizeof(on)) < 0) 69874462Salfred syslog(LOG_ERR, "setsockopt " 69974462Salfred "SO_KEEPALIVE: %m"); 70074462Salfred nfsdargs.sock = msgsock; 70174462Salfred nfsdargs.name = (caddr_t)&inet6peer; 70285034Siedowse nfsdargs.namelen = len; 70374462Salfred nfssvc(NFSSVC_ADDSOCK, &nfsdargs); 70474462Salfred (void)close(msgsock); 70574462Salfred } 7061558Srgrimes } 7071558Srgrimes } 7081558Srgrimes } 7091558Srgrimes} 7101558Srgrimes 71174462Salfredint 71274462Salfredsetbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints) 71353096Sdillon{ 71474462Salfred int ecode; 71574462Salfred u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 71674462Salfred const char *hostptr; 71753096Sdillon 71874462Salfred if (bindhost == NULL || strcmp("*", bindhost) == 0) 71974462Salfred hostptr = NULL; 72074462Salfred else 72174462Salfred hostptr = bindhost; 72274462Salfred 72374462Salfred if (hostptr != NULL) { 72474462Salfred switch (hints.ai_family) { 72574462Salfred case AF_INET: 72674462Salfred if (inet_pton(AF_INET, hostptr, host_addr) == 1) { 72774462Salfred hints.ai_flags = AI_NUMERICHOST; 72874462Salfred } else { 72974462Salfred if (inet_pton(AF_INET6, hostptr, 73074462Salfred host_addr) == 1) 73174462Salfred return (1); 73253096Sdillon } 73374462Salfred break; 73474462Salfred case AF_INET6: 73574462Salfred if (inet_pton(AF_INET6, hostptr, host_addr) == 1) { 73674462Salfred hints.ai_flags = AI_NUMERICHOST; 73774462Salfred } else { 73874462Salfred if (inet_pton(AF_INET, hostptr, 73974462Salfred host_addr) == 1) 74074462Salfred return (1); 74174462Salfred } 74274462Salfred break; 74374462Salfred default: 74495861Speter break; 74553096Sdillon } 74653096Sdillon } 74774462Salfred 74874462Salfred ecode = getaddrinfo(hostptr, "nfs", &hints, ai); 74974462Salfred if (ecode != 0) { 75074462Salfred syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost, 75174462Salfred gai_strerror(ecode)); 75274462Salfred return (1); 75374462Salfred } 75474462Salfred return (0); 75553096Sdillon} 75653096Sdillon 75753096Sdillonvoid 7581558Srgrimesusage() 7591558Srgrimes{ 7609336Sdfr (void)fprintf(stderr, "usage: nfsd %s\n", USAGE); 7611558Srgrimes exit(1); 7621558Srgrimes} 7631558Srgrimes 7641558Srgrimesvoid 7651558Srgrimesnonfs(signo) 7661558Srgrimes int signo; 7671558Srgrimes{ 76837666Scharnier syslog(LOG_ERR, "missing system call: NFS not available"); 7691558Srgrimes} 7701558Srgrimes 7711558Srgrimesvoid 7721558Srgrimesreapchild(signo) 7731558Srgrimes int signo; 7741558Srgrimes{ 77585034Siedowse pid_t pid; 77685034Siedowse int i; 7771558Srgrimes 77885034Siedowse while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) { 77985034Siedowse for (i = 0; i < nfsdcnt; i++) 78085034Siedowse if (pid == children[i]) 78185034Siedowse children[i] = -1; 78285034Siedowse } 7831558Srgrimes} 7841558Srgrimes 78574462Salfredvoid 78674462Salfredunregistration() 78774462Salfred{ 78874462Salfred if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) || 78974462Salfred (!rpcb_unset(RPCPROG_NFS, 3, NULL))) 79074462Salfred syslog(LOG_ERR, "rpcb_unset failed"); 79174462Salfred} 79274462Salfred 79374462Salfredvoid 79474462Salfredkillchildren() 79574462Salfred{ 79674462Salfred int i; 79774462Salfred 79874462Salfred for (i = 0; i < nfsdcnt; i++) { 79974462Salfred if (children[i] > 0) 80074462Salfred kill(children[i], SIGKILL); 80174462Salfred } 80274462Salfred} 80374462Salfred 80485034Siedowse/* 80585034Siedowse * Cleanup master after SIGUSR1. 80685034Siedowse */ 80774462Salfredvoid 80874462Salfredcleanup(signo) 80974462Salfred{ 81085034Siedowse nfsd_exit(0); 81185034Siedowse} 81285034Siedowse 81385034Siedowse/* 81485034Siedowse * Cleanup child after SIGUSR1. 81585034Siedowse */ 81685034Siedowsevoid 81785034Siedowsechild_cleanup(signo) 81885034Siedowse{ 81985034Siedowse exit(0); 82085034Siedowse} 82185034Siedowse 82285034Siedowsevoid 82385034Siedowsenfsd_exit(int status) 82485034Siedowse{ 82574462Salfred killchildren(); 82685034Siedowse unregistration(); 82785034Siedowse exit(status); 82874462Salfred} 82985034Siedowse 83085034Siedowsevoid 83185034Siedowsestart_server(int master) 83285034Siedowse{ 83385034Siedowse int status; 83485034Siedowse 83585034Siedowse status = 0; 83685034Siedowse nsd.nsd_nfsd = NULL; 83785034Siedowse if (nfssvc(NFSSVC_NFSD, &nsd) < 0) { 83885034Siedowse syslog(LOG_ERR, "nfssvc: %m"); 83985034Siedowse status = 1; 84085034Siedowse } 84185034Siedowse if (master) 84285034Siedowse nfsd_exit(status); 84385034Siedowse else 84485034Siedowse exit(status); 84585034Siedowse} 846