Example #1
0
void
nfssvc_setvers(unsigned int ctlbits, unsigned int minorvers, unsigned int minorversset)
{
	int fd, n, off;
	char *ptr;

	ptr = buf;
	off = 0;
	fd = open(NFSD_VERS_FILE, O_WRONLY);
	if (fd < 0)
		return;

	for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) {
		if (NFSCTL_VERISSET(minorversset, n)) {
			if (NFSCTL_VERISSET(minorvers, n))
				off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n);
			else
				off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n);
		}
	}
	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);
	}
	xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
	snprintf(ptr+off, sizeof(buf) - off, "\n");
	if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
		xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);

	close(fd);

	return;
}
Example #2
0
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;
}
Example #3
0
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);
}