X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fnfsd%2Fnfsd.c;h=e7e1470d3c9ef2a9e20f8f915761d8eac4bf58ea;hp=e3c0094c1b81ea8e680932c990af268b1ecf8883;hb=706bfd7c94d48659a1411fdef2a3a61d4719f1aa;hpb=c88c4091db87c0fc23ed67e76d63439b59a82369 diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c index e3c0094..e7e1470 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,136 @@ 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; - } + /* make sure nfsdfs is mounted if it's available */ + nfssvc_mount_nfsdfs(progname); + + /* 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 +303,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); }