From cd87151ef60378ffcd4e74ec3662883ecf97a64a Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Aug 16 2009 20:03:23 +0000 Subject: - Added upstream 1.2.1-rc3 patch - Add IPv6 support to nfsd - Allow nfssvc_setfds to properly deal with AF_INET6 - Convert nfssvc_setfds to use getaddrinfo - Move check for active knfsd to helper function - Declare a static common buffer for nfssvc.c routine - Convert rpc.nfsd to use xlog() and add --debug and --syslog options --- diff --git a/nfs-utils-1.2.0-nfsd-41vers.patch b/nfs-utils-1.2.0-nfsd-41vers.patch deleted file mode 100644 index f90612b..0000000 --- a/nfs-utils-1.2.0-nfsd-41vers.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff -up nfs-utils-1.2.0/support/nfs/nfssvc.c.orig nfs-utils-1.2.0/support/nfs/nfssvc.c ---- nfs-utils-1.2.0/support/nfs/nfssvc.c.orig 2009-06-02 10:43:05.000000000 -0400 -+++ nfs-utils-1.2.0/support/nfs/nfssvc.c 2009-07-27 11:22:13.000000000 -0400 -@@ -127,17 +127,19 @@ nfssvc_versbits(unsigned int ctlbits, in - if (fd < 0) - return; - -+ n = minorvers4 >= 0 ? minorvers4 : -minorvers4; -+ if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4) -+ off += snprintf(ptr+off, BUFSIZ - off, "%c4.%d ", -+ minorvers4 > 0 ? '+' : '-', -+ n); -+ - for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { - if (NFSCTL_VERISSET(ctlbits, n)) - off += snprintf(ptr+off, BUFSIZ - off, "+%d ", n); - else - off += snprintf(ptr+off, BUFSIZ - off, "-%d ", n); - } -- n = minorvers4 >= 0 ? minorvers4 : -minorvers4; -- if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4) -- off += snprintf(ptr+off, BUFSIZ - off, "%c4.%d", -- minorvers4 > 0 ? '+' : '-', -- n); -+ - snprintf(ptr+off, BUFSIZ - off, "\n"); - if (write(fd, buf, strlen(buf)) != strlen(buf)) { - syslog(LOG_ERR, "nfssvc: Setting version failed: errno %d (%s)", diff --git a/nfs-utils-1.2.1-rc3.patch b/nfs-utils-1.2.1-rc3.patch new file mode 100644 index 0000000..3322887 --- /dev/null +++ b/nfs-utils-1.2.1-rc3.patch @@ -0,0 +1,1003 @@ +diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h +index 00b0028..a64eb0a 100644 +--- a/support/include/nfs/nfs.h ++++ b/support/include/nfs/nfs.h +@@ -42,14 +42,21 @@ struct nfs_fh_old { + #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ + #define NFSCTL_GETFS 8 /* get an fh by path with max size (used by mountd) */ + ++#define NFSCTL_UDPBIT (1 << (17 - 1)) ++#define NFSCTL_TCPBIT (1 << (18 - 1)) ++ + #define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1))) +-#define NFSCTL_UDPUNSET(_cltbits) ((_cltbits) &= ~(1 << (17 - 1))) +-#define NFSCTL_TCPUNSET(_cltbits) ((_cltbits) &= ~(1 << (18 - 1))) ++#define NFSCTL_UDPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_UDPBIT) ++#define NFSCTL_TCPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_TCPBIT) + + #define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1))) +-#define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & (1 << (17 - 1))) +-#define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & (1 << (18 - 1))) ++#define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & NFSCTL_UDPBIT) ++#define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT) ++ ++#define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT) ++#define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= NFSCTL_TCPBIT) + ++#define NFSCTL_ANYPROTO(_cltbits) ((_cltbits) & (NFSCTL_UDPBIT | NFSCTL_TCPBIT)) + #define NFSCTL_ALLBITS (~0) + + /* SVC */ +diff --git a/support/include/nfslib.h b/support/include/nfslib.h +index ae98650..537a31e 100644 +--- a/support/include/nfslib.h ++++ b/support/include/nfslib.h +@@ -130,7 +130,6 @@ int wildmat(char *text, char *pattern); + * nfsd library functions. + */ + int nfsctl(int, struct nfsctl_arg *, union nfsctl_res *); +-int nfssvc(int port, int nrservs, unsigned int versbits, int minorvers4, unsigned int portbits, char *haddr); + int nfsaddclient(struct nfsctl_client *clp); + int nfsdelclient(struct nfsctl_client *clp); + int nfsexport(struct nfsctl_export *exp); +diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am +index 86f52a1..096f56d 100644 +--- a/support/nfs/Makefile.am ++++ b/support/nfs/Makefile.am +@@ -2,7 +2,7 @@ + + noinst_LIBRARIES = libnfs.a + libnfs_a_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ +- xlog.c xcommon.c wildmat.c nfssvc.c nfsclient.c \ ++ xlog.c xcommon.c wildmat.c nfsclient.c \ + nfsexport.c getfh.c nfsctl.c rpc_socket.c getport.c \ + svc_socket.c cacheio.c closeall.c nfs_mntent.c + +diff --git a/support/nfs/nfssvc.c b/support/nfs/nfssvc.c +deleted file mode 100644 +index 33c15a7..0000000 +--- a/support/nfs/nfssvc.c ++++ /dev/null +@@ -1,187 +0,0 @@ +-/* +- * support/nfs/nfssvc.c +- * +- * Run an NFS daemon. +- * +- * Copyright (C) 1995, 1996 Olaf Kirch +- */ +- +-#ifdef HAVE_CONFIG_H +-#include +-#endif +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +- +-#include "nfslib.h" +- +-#define NFSD_PORTS_FILE "/proc/fs/nfsd/portlist" +-#define NFSD_VERS_FILE "/proc/fs/nfsd/versions" +-#define NFSD_THREAD_FILE "/proc/fs/nfsd/threads" +- +-static void +-nfssvc_setfds(int port, unsigned int ctlbits, char *haddr) +-{ +- int fd, n, on=1; +- char buf[BUFSIZ]; +- int udpfd = -1, tcpfd = -1; +- struct sockaddr_in sin; +- +- fd = open(NFSD_PORTS_FILE, O_RDONLY); +- if (fd < 0) +- return; +- n = read(fd, buf, BUFSIZ); +- close(fd); +- if (n != 0) +- return; +- /* there are no ports currently open, so it is safe to +- * try to open some and pass them through. +- * Note: If the user explicitly asked for 'udp', then +- * we should probably check if that is open, and should +- * open it if not. However we don't yet. All sockets +- * have to be opened when the first daemon is started. +- */ +- fd = open(NFSD_PORTS_FILE, O_WRONLY); +- if (fd < 0) +- return; +- sin.sin_family = AF_INET; +- sin.sin_port = htons(port); +- sin.sin_addr.s_addr = inet_addr(haddr); +- +- if (NFSCTL_UDPISSET(ctlbits)) { +- udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +- if (udpfd < 0) { +- syslog(LOG_ERR, "nfssvc: unable to create UPD socket: " +- "errno %d (%s)\n", errno, strerror(errno)); +- exit(1); +- } +- if (bind(udpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0){ +- syslog(LOG_ERR, "nfssvc: unable to bind UPD socket: " +- "errno %d (%s)\n", errno, strerror(errno)); +- exit(1); +- } +- } +- +- if (NFSCTL_TCPISSET(ctlbits)) { +- tcpfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +- if (tcpfd < 0) { +- syslog(LOG_ERR, "nfssvc: unable to createt tcp socket: " +- "errno %d (%s)\n", errno, strerror(errno)); +- exit(1); +- } +- if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { +- syslog(LOG_ERR, "nfssvc: unable to set SO_REUSEADDR: " +- "errno %d (%s)\n", errno, strerror(errno)); +- exit(1); +- } +- if (bind(tcpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0){ +- syslog(LOG_ERR, "nfssvc: unable to bind TCP socket: " +- "errno %d (%s)\n", errno, strerror(errno)); +- exit(1); +- } +- if (listen(tcpfd, 64) < 0){ +- syslog(LOG_ERR, "nfssvc: unable to create listening socket: " +- "errno %d (%s)\n", errno, strerror(errno)); +- exit(1); +- } +- } +- if (udpfd >= 0) { +- snprintf(buf, BUFSIZ,"%d\n", udpfd); +- if (write(fd, buf, strlen(buf)) != strlen(buf)) { +- syslog(LOG_ERR, +- "nfssvc: writing fds to kernel failed: errno %d (%s)", +- errno, strerror(errno)); +- } +- close(fd); +- fd = -1; +- } +- if (tcpfd >= 0) { +- if (fd < 0) +- fd = open(NFSD_PORTS_FILE, O_WRONLY); +- snprintf(buf, BUFSIZ,"%d\n", tcpfd); +- if (write(fd, buf, strlen(buf)) != strlen(buf)) { +- syslog(LOG_ERR, +- "nfssvc: writing fds to kernel failed: errno %d (%s)", +- errno, strerror(errno)); +- } +- } +- close(fd); +- +- return; +-} +-static void +-nfssvc_versbits(unsigned int ctlbits, int minorvers4) +-{ +- int fd, n, off; +- char buf[BUFSIZ], *ptr; +- +- ptr = buf; +- off = 0; +- fd = open(NFSD_VERS_FILE, O_WRONLY); +- if (fd < 0) +- return; +- +- for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { +- if (NFSCTL_VERISSET(ctlbits, n)) +- off += snprintf(ptr+off, BUFSIZ - off, "+%d ", n); +- else +- off += snprintf(ptr+off, BUFSIZ - off, "-%d ", n); +- } +- n = minorvers4 >= 0 ? minorvers4 : -minorvers4; +- if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4) +- off += snprintf(ptr+off, BUFSIZ - off, "%c4.%d", +- minorvers4 > 0 ? '+' : '-', +- n); +- snprintf(ptr+off, BUFSIZ - off, "\n"); +- if (write(fd, buf, strlen(buf)) != strlen(buf)) { +- syslog(LOG_ERR, "nfssvc: Setting version failed: errno %d (%s)", +- errno, strerror(errno)); +- } +- close(fd); +- +- return; +-} +-int +-nfssvc(int port, int nrservs, unsigned int versbits, int minorvers4, +- unsigned protobits, char *haddr) +-{ +- struct nfsctl_arg arg; +- int fd; +- +- /* Note: must set versions before fds so that +- * the ports get registered with portmap against correct +- * versions +- */ +- nfssvc_versbits(versbits, minorvers4); +- nfssvc_setfds(port, protobits, haddr); +- +- fd = open(NFSD_THREAD_FILE, O_WRONLY); +- if (fd < 0) +- fd = open("/proc/fs/nfs/threads", O_WRONLY); +- if (fd >= 0) { +- /* 2.5+ kernel with nfsd filesystem mounted. +- * Just write the number in. +- * Cannot handle port number yet, but does anyone care? +- */ +- char buf[20]; +- int n; +- snprintf(buf, 20,"%d\n", nrservs); +- n = write(fd, buf, strlen(buf)); +- close(fd); +- if (n != strlen(buf)) +- return -1; +- else +- return 0; +- } +- +- arg.ca_version = NFSCTL_VERSION; +- arg.ca_svc.svc_nthreads = nrservs; +- arg.ca_svc.svc_port = port; +- return nfsctl(NFSCTL_SVC, &arg, NULL); +-} +diff --git a/utils/nfsd/Makefile.am b/utils/nfsd/Makefile.am +index 445e3fd..c4c6fb0 100644 +--- a/utils/nfsd/Makefile.am ++++ b/utils/nfsd/Makefile.am +@@ -7,10 +7,8 @@ RPCPREFIX = rpc. + KPREFIX = @kprefix@ + sbin_PROGRAMS = nfsd + +-nfsd_SOURCES = nfsd.c +-nfsd_LDADD = ../../support/export/libexport.a \ +- ../../support/nfs/libnfs.a \ +- ../../support/misc/libmisc.a ++nfsd_SOURCES = nfsd.c nfssvc.c ++nfsd_LDADD = ../../support/nfs/libnfs.a + + MAINTAINERCLEANFILES = Makefile.in + +diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c +index e3c0094..650c593 100644 +--- a/utils/nfsd/nfsd.c ++++ b/utils/nfsd/nfsd.c +@@ -18,13 +18,14 @@ + #include + #include + #include +-#include + #include + #include + #include + #include + + #include "nfslib.h" ++#include "nfssvc.h" ++#include "xlog.h" + + static void usage(const char *); + +@@ -37,47 +38,116 @@ static struct option longopts[] = + { "no-udp", 0, 0, 'U' }, + { "port", 1, 0, 'P' }, + { "port", 1, 0, 'p' }, ++ { "debug", 0, 0, 'd' }, ++ { "syslog", 0, 0, 's' }, + { NULL, 0, 0, 0 } + }; +-unsigned int protobits = NFSCTL_ALLBITS; +-unsigned int versbits = NFSCTL_ALLBITS; +-int minorvers4 = NFSD_MAXMINORVERS4; /* nfsv4 minor version */ +-char *haddr = NULL; ++ ++/* given a family and ctlbits, disable any that aren't listed in netconfig */ ++#ifdef HAVE_LIBTIRPC ++static void ++nfsd_enable_protos(unsigned int *proto4, unsigned int *proto6) ++{ ++ struct netconfig *nconf; ++ unsigned int *famproto; ++ void *handle; ++ ++ xlog(D_GENERAL, "Checking netconfig for visible protocols."); ++ ++ handle = setnetconfig(); ++ while((nconf = getnetconfig(handle))) { ++ if (!(nconf->nc_flag & NC_VISIBLE)) ++ continue; ++ ++ if (!strcmp(nconf->nc_protofmly, NC_INET)) ++ famproto = proto4; ++ else if (!strcmp(nconf->nc_protofmly, NC_INET6)) ++ famproto = proto6; ++ else ++ continue; ++ ++ if (!strcmp(nconf->nc_proto, NC_TCP)) ++ NFSCTL_TCPSET(*famproto); ++ else if (!strcmp(nconf->nc_proto, NC_UDP)) ++ NFSCTL_UDPSET(*famproto); ++ ++ xlog(D_GENERAL, "Enabling %s %s.", nconf->nc_protofmly, ++ nconf->nc_proto); ++ } ++ endnetconfig(handle); ++ return; ++} ++#else /* HAVE_LIBTIRPC */ ++static void ++nfsd_enable_protos(unsigned int *proto4, unsigned int *proto6) ++{ ++ /* Enable all IPv4 protocols if no TIRPC support */ ++ *proto4 = NFSCTL_ALLBITS; ++ *proto6 = 0; ++} ++#endif /* HAVE_LIBTIRPC */ + + int + main(int argc, char **argv) + { +- int count = 1, c, error, port, fd, found_one; +- struct servent *ent; +- struct hostent *hp; +- char *p; +- +- ent = getservbyname ("nfs", "udp"); +- if (ent != NULL) +- port = ntohs (ent->s_port); +- else +- port = 2049; +- +- while ((c = getopt_long(argc, argv, "H:hN:p:P:TU", longopts, NULL)) != EOF) { ++ int count = 1, c, error = 0, portnum = 0, fd, found_one; ++ char *p, *progname, *port; ++ char *haddr = NULL; ++ int socket_up = 0; ++ int minorvers4 = NFSD_MAXMINORVERS4; /* nfsv4 minor version */ ++ unsigned int versbits = NFSCTL_ALLBITS; ++ unsigned int protobits = NFSCTL_ALLBITS; ++ unsigned int proto4 = 0; ++ unsigned int proto6 = 0; ++ ++ progname = strdup(basename(argv[0])); ++ if (!progname) { ++ fprintf(stderr, "%s: unable to allocate memory.\n", argv[0]); ++ exit(1); ++ } ++ ++ port = strdup("nfs"); ++ if (!port) { ++ fprintf(stderr, "%s: unable to allocate memory.\n", progname); ++ exit(1); ++ } ++ ++ xlog_syslog(0); ++ xlog_stderr(1); ++ ++ while ((c = getopt_long(argc, argv, "dH:hN:p:P:sTU", longopts, NULL)) != EOF) { + switch(c) { ++ case 'd': ++ xlog_config(D_ALL, 1); ++ break; + case 'H': +- if (inet_addr(optarg) != INADDR_NONE) { +- haddr = strdup(optarg); +- } else if ((hp = gethostbyname(optarg)) != NULL) { +- haddr = inet_ntoa((*(struct in_addr*)(hp->h_addr_list[0]))); +- } else { +- fprintf(stderr, "%s: Unknown hostname: %s\n", +- argv[0], optarg); +- usage(argv [0]); ++ /* ++ * for now, this only handles one -H option. Use the ++ * last one specified. ++ */ ++ free(haddr); ++ haddr = strdup(optarg); ++ if (!haddr) { ++ fprintf(stderr, "%s: unable to allocate " ++ "memory.\n", progname); ++ exit(1); + } + break; + case 'P': /* XXX for nfs-server compatibility */ + case 'p': +- port = atoi(optarg); +- if (port <= 0 || port > 65535) { ++ /* only the last -p option has any effect */ ++ portnum = atoi(optarg); ++ if (portnum <= 0 || portnum > 65535) { + fprintf(stderr, "%s: bad port number: %s\n", +- argv[0], optarg); +- usage(argv [0]); ++ progname, optarg); ++ usage(progname); ++ } ++ free(port); ++ port = strdup(optarg); ++ if (!port) { ++ fprintf(stderr, "%s: unable to allocate " ++ "memory.\n", progname); ++ exit(1); + } + break; + case 'N': +@@ -96,80 +166,133 @@ main(int argc, char **argv) + exit(1); + } + break; ++ case 's': ++ xlog_syslog(1); ++ xlog_stderr(0); ++ break; + case 'T': +- NFSCTL_TCPUNSET(protobits); +- break; ++ NFSCTL_TCPUNSET(protobits); ++ break; + case 'U': +- NFSCTL_UDPUNSET(protobits); +- break; ++ NFSCTL_UDPUNSET(protobits); ++ break; + default: + fprintf(stderr, "Invalid argument: '%c'\n", c); + case 'h': +- usage(argv[0]); ++ usage(progname); + } + } +- /* +- * Do some sanity checking, if the ctlbits are set +- */ +- if (!NFSCTL_UDPISSET(protobits) && !NFSCTL_TCPISSET(protobits)) { +- fprintf(stderr, "invalid protocol specified\n"); +- exit(1); ++ ++ if (optind < argc) { ++ if ((count = atoi(argv[optind])) < 0) { ++ /* insane # of servers */ ++ fprintf(stderr, ++ "%s: invalid server count (%d), using 1\n", ++ argv[0], count); ++ count = 1; ++ } else if (count == 0) { ++ /* ++ * don't bother setting anything else if the threads ++ * are coming down anyway. ++ */ ++ socket_up = 1; ++ goto set_threads; ++ } + } ++ ++ xlog_open(progname); ++ ++ nfsd_enable_protos(&proto4, &proto6); ++ ++ if (!NFSCTL_TCPISSET(protobits)) { ++ NFSCTL_TCPUNSET(proto4); ++ NFSCTL_TCPUNSET(proto6); ++ } ++ ++ if (!NFSCTL_UDPISSET(protobits)) { ++ NFSCTL_UDPUNSET(proto4); ++ NFSCTL_UDPUNSET(proto6); ++ } ++ ++ /* make sure that at least one version is enabled */ + found_one = 0; + for (c = NFSD_MINVERS; c <= NFSD_MAXVERS; c++) { + if (NFSCTL_VERISSET(versbits, c)) + found_one = 1; + } + if (!found_one) { +- fprintf(stderr, "no version specified\n"); ++ xlog(L_ERROR, "no version specified"); + exit(1); + } + +- if (NFSCTL_VERISSET(versbits, 4) && !NFSCTL_TCPISSET(protobits)) { +- fprintf(stderr, "version 4 requires the TCP protocol\n"); ++ if (NFSCTL_VERISSET(versbits, 4) && ++ !NFSCTL_TCPISSET(proto4) && ++ !NFSCTL_TCPISSET(proto6)) { ++ xlog(L_ERROR, "version 4 requires the TCP protocol"); + exit(1); + } +- if (haddr == NULL) { +- struct in_addr in = {INADDR_ANY}; +- haddr = strdup(inet_ntoa(in)); +- } + + if (chdir(NFS_STATEDIR)) { +- fprintf(stderr, "%s: chdir(%s) failed: %s\n", +- argv [0], NFS_STATEDIR, strerror(errno)); ++ xlog(L_ERROR, "chdir(%s) failed: %m", NFS_STATEDIR); + exit(1); + } + +- if (optind < argc) { +- if ((count = atoi(argv[optind])) < 0) { +- /* insane # of servers */ +- fprintf(stderr, +- "%s: invalid server count (%d), using 1\n", +- argv[0], count); +- count = 1; +- } ++ /* can only change number of threads if nfsd is already up */ ++ if (nfssvc_inuse()) { ++ socket_up = 1; ++ goto set_threads; + } +- /* KLUDGE ALERT: +- Some kernels let nfsd kernel threads inherit open files +- from the program that spawns them (i.e. us). So close +- everything before spawning kernel threads. --Chip */ ++ ++ /* ++ * must set versions before the fd's so that the right versions get ++ * registered with rpcbind. Note that on older kernels w/o the right ++ * interfaces, these are a no-op. ++ */ ++ nfssvc_setvers(versbits, minorvers4); ++ ++ error = nfssvc_set_sockets(AF_INET, proto4, haddr, port); ++ if (!error) ++ socket_up = 1; ++ ++#ifdef IPV6_SUPPORTED ++ error = nfssvc_set_sockets(AF_INET6, proto6, haddr, port); ++ if (!error) ++ socket_up = 1; ++#endif /* IPV6_SUPPORTED */ ++ ++set_threads: ++ /* don't start any threads if unable to hand off any sockets */ ++ if (!socket_up) { ++ xlog(L_ERROR, "unable to set any sockets for nfsd"); ++ goto out; ++ } ++ error = 0; ++ ++ /* ++ * KLUDGE ALERT: ++ * Some kernels let nfsd kernel threads inherit open files ++ * from the program that spawns them (i.e. us). So close ++ * everything before spawning kernel threads. --Chip ++ */ + fd = open("/dev/null", O_RDWR); + if (fd == -1) +- perror("/dev/null"); ++ xlog(L_ERROR, "Unable to open /dev/null: %m"); + else { ++ /* switch xlog output to syslog since stderr is being closed */ ++ xlog_syslog(1); ++ xlog_stderr(0); + (void) dup2(fd, 0); + (void) dup2(fd, 1); + (void) dup2(fd, 2); + } + closeall(3); + +- openlog("nfsd", LOG_PID, LOG_DAEMON); +- if ((error = nfssvc(port, count, versbits, minorvers4, protobits, haddr)) < 0) { +- int e = errno; +- syslog(LOG_ERR, "nfssvc: %s", strerror(e)); +- closelog(); +- } +- ++ if ((error = nfssvc_threads(portnum, count)) < 0) ++ xlog(L_ERROR, "error starting threads: errno %d (%m)", errno); ++out: ++ free(port); ++ free(haddr); ++ free(progname); + return (error != 0); + } + +@@ -177,7 +300,7 @@ static void + usage(const char *prog) + { + fprintf(stderr, "Usage:\n" +- "%s [-H hostname] [-p|-P|--port port] [-N|--no-nfs-version version ] [-T|--no-tcp] [-U|--no-udp] nrservs\n", ++ "%s [-d|--debug] [-H hostname] [-p|-P|--port port] [-N|--no-nfs-version version ] [-s|--syslog] [-T|--no-tcp] [-U|--no-udp] nrservs\n", + prog); + exit(2); + } +diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man +index 4eb3e21..d8988d2 100644 +--- a/utils/nfsd/nfsd.man ++++ b/utils/nfsd/nfsd.man +@@ -13,8 +13,9 @@ The + program implements the user level part of the NFS service. The + main functionality is handled by the + .B nfsd +-kernel module; the user space program merely starts the specified +-number of kernel threads. ++kernel module. The user space program merely specifies what sort of sockets ++the kernel service should listen on, what NFS versions it should support, and ++how many kernel threads it should use. + .P + The + .B rpc.mountd +@@ -22,6 +23,9 @@ server provides an ancillary service needed to satisfy mount requests + by NFS clients. + .SH OPTIONS + .TP ++.B \-d " or " \-\-debug ++enable logging of debugging messages ++.TP + .B \-H " or " \-\-host hostname + specify a particular hostname (or address) that NFS requests will + be accepted on. By default, +@@ -45,6 +49,14 @@ does not offer certain versions of NFS. The current version of + .B rpc.nfsd + can support both NFS version 2,3 and the newer version 4. + .TP ++.B \-s " or " \-\-syslog ++By default, ++.B rpc.nfsd ++logs error messages (and debug messages, if enabled) to stderr. This option makes ++.B rpc.nfsd ++log these messages to syslog instead. Note that errors encountered during ++option processing will still be logged to stderr regardless of this option. ++.TP + .B \-T " or " \-\-no-tcp + Disable + .B rpc.nfsd +@@ -75,12 +87,19 @@ In particular + .B rpc.nfsd 0 + will stop all threads and thus close any open connections. + ++.SH NOTES ++If the program is built with TI-RPC support, it will enable any protocol and ++address family combinations that are marked visible in the ++.B netconfig ++database. ++ + .SH SEE ALSO + .BR rpc.mountd (8), + .BR exports (5), + .BR exportfs (8), + .BR rpc.rquotad (8), +-.BR nfsstat (8). ++.BR nfsstat (8), ++.BR netconfig(5). + .SH AUTHOR + Olaf Kirch, Bill Hawes, H. J. Lu, G. Allan Morris III, + and a host of others. +diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c +new file mode 100644 +index 0000000..ee862b2 +--- /dev/null ++++ b/utils/nfsd/nfssvc.c +@@ -0,0 +1,289 @@ ++/* ++ * utils/nfsd/nfssvc.c ++ * ++ * Run an NFS daemon. ++ * ++ * Copyright (C) 1995, 1996 Olaf Kirch ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "nfslib.h" ++#include "xlog.h" ++ ++#define NFSD_PORTS_FILE "/proc/fs/nfsd/portlist" ++#define NFSD_VERS_FILE "/proc/fs/nfsd/versions" ++#define NFSD_THREAD_FILE "/proc/fs/nfsd/threads" ++ ++/* ++ * declaring a common static scratch buffer here keeps us from having to ++ * continually thrash the stack. The value of 128 bytes here is really just a ++ * SWAG and can be increased if necessary. It ought to be enough for the ++ * routines below however. ++ */ ++char buf[128]; ++ ++/* ++ * Are there already sockets configured? If not, then it is safe to try to ++ * open some and pass them through. ++ * ++ * Note: If the user explicitly asked for 'udp', then we should probably check ++ * if that is open, and should open it if not. However we don't yet. All ++ * sockets have to be opened when the first daemon is started. ++ */ ++int ++nfssvc_inuse(void) ++{ ++ int fd, n; ++ ++ fd = open(NFSD_PORTS_FILE, O_RDONLY); ++ ++ /* problem opening file, assume that nothing is configured */ ++ if (fd < 0) ++ return 0; ++ ++ n = read(fd, buf, sizeof(buf)); ++ close(fd); ++ ++ xlog(D_GENERAL, "knfsd is currently %s", (n > 0) ? "up" : "down"); ++ ++ return (n > 0); ++} ++ ++static int ++nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port) ++{ ++ int fd, on = 1, fac = L_ERROR; ++ int sockfd = -1, rc = 0; ++ struct addrinfo *addrhead = NULL, *addr; ++ char *proto, *family; ++ ++ /* ++ * if file can't be opened, then assume that it's not available and ++ * that the caller should just fall back to the old nfsctl interface ++ */ ++ fd = open(NFSD_PORTS_FILE, O_WRONLY); ++ if (fd < 0) ++ return 0; ++ ++ switch(hints->ai_family) { ++ case AF_INET: ++ family = "inet"; ++ break; ++#ifdef IPV6_SUPPORTED ++ case AF_INET6: ++ family = "inet6"; ++ break; ++#endif /* IPV6_SUPPORTED */ ++ default: ++ xlog(L_ERROR, "Unknown address family specified: %d\n", ++ hints->ai_family); ++ rc = EAFNOSUPPORT; ++ goto error; ++ } ++ ++ rc = getaddrinfo(node, port, hints, &addrhead); ++ if (rc == EAI_NONAME && !strcmp(port, "nfs")) { ++ snprintf(buf, sizeof(buf), "%d", NFS_PORT); ++ rc = getaddrinfo(node, buf, hints, &addrhead); ++ } ++ ++ if (rc != 0) { ++ xlog(L_ERROR, "unable to resolve %s:%s to %s address: " ++ "%s", node ? node : "ANYADDR", port, family, ++ rc == EAI_SYSTEM ? strerror(errno) : ++ gai_strerror(rc)); ++ goto error; ++ } ++ ++ addr = addrhead; ++ while(addr) { ++ /* skip non-TCP / non-UDP sockets */ ++ switch(addr->ai_protocol) { ++ case IPPROTO_UDP: ++ proto = "UDP"; ++ break; ++ case IPPROTO_TCP: ++ proto = "TCP"; ++ break; ++ default: ++ addr = addr->ai_next; ++ continue; ++ } ++ ++ xlog(D_GENERAL, "Creating %s %s socket.", family, proto); ++ ++ /* open socket and prepare to hand it off to kernel */ ++ sockfd = socket(addr->ai_family, addr->ai_socktype, ++ addr->ai_protocol); ++ if (sockfd < 0) { ++ xlog(L_ERROR, "unable to create %s %s socket: " ++ "errno %d (%m)", family, proto, errno); ++ rc = errno; ++ goto error; ++ } ++#ifdef IPV6_SUPPORTED ++ if (addr->ai_family == AF_INET6 && ++ setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) { ++ xlog(L_ERROR, "unable to set IPV6_V6ONLY: " ++ "errno %d (%m)\n", errno); ++ rc = errno; ++ goto error; ++ } ++#endif /* IPV6_SUPPORTED */ ++ if (addr->ai_protocol == IPPROTO_TCP && ++ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) { ++ xlog(L_ERROR, "unable to set SO_REUSEADDR on %s " ++ "socket: errno %d (%m)", family, errno); ++ rc = errno; ++ goto error; ++ } ++ if (bind(sockfd, addr->ai_addr, addr->ai_addrlen)) { ++ xlog(L_ERROR, "unable to bind %s %s socket: " ++ "errno %d (%m)", family, proto, errno); ++ rc = errno; ++ goto error; ++ } ++ if (addr->ai_protocol == IPPROTO_TCP && listen(sockfd, 64)) { ++ xlog(L_ERROR, "unable to create listening socket: " ++ "errno %d (%m)", errno); ++ rc = errno; ++ goto error; ++ } ++ ++ if (fd < 0) ++ fd = open(NFSD_PORTS_FILE, O_WRONLY); ++ ++ if (fd < 0) { ++ xlog(L_ERROR, "couldn't open ports file: errno " ++ "%d (%m)", errno); ++ goto error; ++ } ++ ++ snprintf(buf, sizeof(buf), "%d\n", sockfd); ++ if (write(fd, buf, strlen(buf)) != strlen(buf)) { ++ /* ++ * this error may be common on older kernels that don't ++ * support IPv6, so turn into a debug message. ++ */ ++ if (errno == EAFNOSUPPORT) ++ fac = D_ALL; ++ xlog(fac, "writing fd to kernel failed: errno %d (%m)", ++ errno); ++ rc = errno; ++ goto error; ++ } ++ close(fd); ++ close(sockfd); ++ sockfd = fd = -1; ++ addr = addr->ai_next; ++ } ++error: ++ if (fd >= 0) ++ close(fd); ++ if (sockfd >= 0) ++ close(sockfd); ++ if (addrhead) ++ freeaddrinfo(addrhead); ++ return rc; ++} ++ ++int ++nfssvc_set_sockets(const int family, const unsigned int protobits, ++ const char *host, const char *port) ++{ ++ struct addrinfo hints = { .ai_flags = AI_PASSIVE | AI_ADDRCONFIG }; ++ ++ hints.ai_family = family; ++ ++ if (!NFSCTL_ANYPROTO(protobits)) ++ return EPROTOTYPE; ++ else if (!NFSCTL_UDPISSET(protobits)) ++ hints.ai_protocol = IPPROTO_TCP; ++ else if (!NFSCTL_TCPISSET(protobits)) ++ hints.ai_protocol = IPPROTO_UDP; ++ ++ return nfssvc_setfds(&hints, host, port); ++} ++ ++void ++nfssvc_setvers(unsigned int ctlbits, int minorvers4) ++{ ++ int fd, n, off; ++ char *ptr; ++ ++ ptr = buf; ++ off = 0; ++ fd = open(NFSD_VERS_FILE, O_WRONLY); ++ if (fd < 0) ++ return; ++ ++ for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { ++ if (NFSCTL_VERISSET(ctlbits, n)) ++ off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n); ++ else ++ off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n); ++ } ++ n = minorvers4 >= 0 ? minorvers4 : -minorvers4; ++ if (n >= NFSD_MINMINORVERS4 && n <= NFSD_MAXMINORVERS4) ++ off += snprintf(ptr+off, sizeof(buf) - off, "%c4.%d", ++ minorvers4 > 0 ? '+' : '-', ++ n); ++ xlog(D_GENERAL, "Writing version string to kernel: %s", buf); ++ snprintf(ptr+off, sizeof(buf) - off, "\n"); ++ if (write(fd, buf, strlen(buf)) != strlen(buf)) ++ xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno); ++ ++ close(fd); ++ ++ return; ++} ++ ++int ++nfssvc_threads(unsigned short port, const int nrservs) ++{ ++ struct nfsctl_arg arg; ++ struct servent *ent; ++ ssize_t n; ++ int fd; ++ ++ fd = open(NFSD_THREAD_FILE, O_WRONLY); ++ if (fd < 0) ++ fd = open("/proc/fs/nfs/threads", O_WRONLY); ++ if (fd >= 0) { ++ /* 2.5+ kernel with nfsd filesystem mounted. ++ * Just write the number of threads. ++ */ ++ snprintf(buf, sizeof(buf), "%d\n", nrservs); ++ n = write(fd, buf, strlen(buf)); ++ close(fd); ++ if (n != strlen(buf)) ++ return -1; ++ else ++ return 0; ++ } ++ ++ if (!port) { ++ ent = getservbyname("nfs", "udp"); ++ if (ent != NULL) ++ port = ntohs(ent->s_port); ++ else ++ port = NFS_PORT; ++ } ++ ++ arg.ca_version = NFSCTL_VERSION; ++ arg.ca_svc.svc_nthreads = nrservs; ++ arg.ca_svc.svc_port = port; ++ return nfsctl(NFSCTL_SVC, &arg, NULL); ++} +diff --git a/utils/nfsd/nfssvc.h b/utils/nfsd/nfssvc.h +new file mode 100644 +index 0000000..0c69bd6 +--- /dev/null ++++ b/utils/nfsd/nfssvc.h +@@ -0,0 +1,27 @@ ++/* ++ * utils/nfsd/nfssvc.h -- nfs service control routines for rpc.nfsd ++ * ++ * Copyright (C) 2009 Red Hat, Inc . ++ * Copyright (C) 2009 Jeff Layton ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ * ++ */ ++ ++int nfssvc_inuse(void); ++int nfssvc_set_sockets(const int family, const unsigned int protobits, ++ const char *host, const char *port); ++void nfssvc_setvers(unsigned int ctlbits, int minorvers4); ++int nfssvc_threads(unsigned short port, int nrservs); diff --git a/nfs-utils.spec b/nfs-utils.spec index 781ba98..f571341 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 1.2.0 -Release: 8%{?dist} +Release: 9%{?dist} Epoch: 1 # group all 32bit related archs @@ -25,7 +25,7 @@ Patch02: nfs-utils-1.1.0-exp-subtree-warn-off.patch Patch100: nfs-utils-1.2.1-rc1.patch Patch101: nfs-utils-1.2.1-rc2.patch Patch102: nfs-utils-1.2.0-proots-rel5.patch -Patch103: nfs-utils-1.2.0-nfsd-41vers.patch +Patch103: nfs-utils-1.2.1-rc3.patch Group: System Environment/Daemons Provides: exportfs = %{epoch}:%{version}-%{release} @@ -249,35 +249,44 @@ fi %attr(4755,root,root) /sbin/umount.nfs4 %changelog -* Tue Jul 28 2009 1.2.0-8 +* Fri Aug 14 2009 Steve Dickson 1.2.0-9 +- Added upstream 1.2.1-rc3 patch + - Add IPv6 support to nfsd + - Allow nfssvc_setfds to properly deal with AF_INET6 + - Convert nfssvc_setfds to use getaddrinfo + - Move check for active knfsd to helper function + - Declare a static common buffer for nfssvc.c routine + - Convert rpc.nfsd to use xlog() and add --debug and --syslog options + +* Tue Jul 28 2009 Steve Dickson 1.2.0-8 - Fixed 4.1 versioning problem (bz 512377) -* Wed Jul 15 2009 1.2.0-7 +* Wed Jul 15 2009 Steve Dickson 1.2.0-7 - Added upstream 1.2.1-rc2 patch - A large number of mount command changes. -* Mon Jul 13 2009 1.2.0-6 +* Mon Jul 13 2009 Steve Dickson 1.2.0-6 - Added NFSD v4 dynamic pseudo root patch which allows NFS v3 exports to be mounted by v4 clients. -* Mon Jun 29 2009 1.2.0-5 +* Mon Jun 29 2009 Steve Dickson 1.2.0-5 - Stopped rpc.idmapd from spinning (bz 508221) -* Mon Jun 22 2009 1.2.0-4 +* Mon Jun 22 2009 Steve Dickson 1.2.0-4 - Added upstream 1.2.1-rc1 patch - Fix to check in closeall() - Make --enable-tirpc the default - Set all verbose types in gssd daemons - Retry exports if getfh() fails -* Wed Jun 10 2009 1.2.0-3 +* Wed Jun 10 2009 Steve Dickson 1.2.0-3 - Updated init scripts to add dependencies on other system facilities (bz 475133) -* Wed Jun 10 2009 1.2.0-2 +* Wed Jun 10 2009 Steve Dickson 1.2.0-2 - nfsnobody gid is wrong (bz 485379) -* Tue Jun 2 2009 1.2.0-1 +* Tue Jun 2 2009 Steve Dickson 1.2.0-1 - Updated to latest upstream release: 1.2.0 * Tue May 19 2009 Tom "spot" Callaway 1.1.6-4