static ssize_t write_versions(struct file *file, char *buf, size_t size) { /* * Format: * [-/+]vers [-/+]vers ... */ char *mesg = buf; char *vers, sign; int len, num; ssize_t tlen = 0; char *sep; if (size>0) { if (nfsd_serv) return -EBUSY; if (buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; vers = mesg; len = qword_get(&mesg, vers, size); if (len <= 0) return -EINVAL; do { sign = *vers; if (sign == '+' || sign == '-') num = simple_strtol((vers+1), NULL, 0); else num = simple_strtol(vers, NULL, 0); switch(num) { case 2: case 3: case 4: if (sign != '-') NFSCTL_VERSET(nfsd_versbits, num); else NFSCTL_VERUNSET(nfsd_versbits, num); break; default: return -EINVAL; } vers += len + 1; tlen += len; } while ((len = qword_get(&mesg, vers, size)) > 0); /* If all get turned off, turn them back on, as * having no versions is BAD */ if ((nfsd_versbits & NFSCTL_VERALL)==0) nfsd_versbits = NFSCTL_VERALL; } /* Now write current state into reply buffer */ len = 0; sep = ""; for (num=2 ; num <= 4 ; num++) if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) { len += sprintf(buf+len, "%s%c%d", sep, NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-', num); sep = " "; } len += sprintf(buf+len, "\n"); return len; }
int main(int argc, char **argv) { 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': /* * 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': /* only the last -p option has any effect */ portnum = atoi(optarg); if (portnum <= 0 || portnum > 65535) { fprintf(stderr, "%s: bad port number: %s\n", 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': switch((c = strtol(optarg, &p, 0))) { case 4: if (*p == '.') { minorvers4 = -atoi(p + 1); break; } case 3: case 2: NFSCTL_VERUNSET(versbits, c); break; default: fprintf(stderr, "%s: Unsupported version\n", optarg); exit(1); } break; case 's': xlog_syslog(1); xlog_stderr(0); break; case 'T': NFSCTL_TCPUNSET(protobits); break; case 'U': NFSCTL_UDPUNSET(protobits); break; default: fprintf(stderr, "Invalid argument: '%c'\n", c); case 'h': usage(progname); } } 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) { xlog(L_ERROR, "no version specified"); exit(1); } if (NFSCTL_VERISSET(versbits, 4) && !NFSCTL_TCPISSET(proto4) && !NFSCTL_TCPISSET(proto6)) { xlog(L_ERROR, "version 4 requires the TCP protocol"); exit(1); } if (chdir(NFS_STATEDIR)) { xlog(L_ERROR, "chdir(%s) failed: %m", NFS_STATEDIR); exit(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; } /* * 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) 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); 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); }