Пример #1
0
static void
start_server(int master)
{
	char principal[MAXHOSTNAMELEN + 5];
	struct nfsd_nfsd_args nfsdargs;
	int status, error;
	char hostname[MAXHOSTNAMELEN + 1], *cp;
	struct addrinfo *aip, hints;

	status = 0;
	gethostname(hostname, sizeof (hostname));
	snprintf(principal, sizeof (principal), "nfs@%s", hostname);
	if ((cp = strchr(hostname, '.')) == NULL ||
	    *(cp + 1) == '\0') {
		/* If not fully qualified, try getaddrinfo() */
		memset((void *)&hints, 0, sizeof (hints));
		hints.ai_flags = AI_CANONNAME;
		error = getaddrinfo(hostname, NULL, &hints, &aip);
		if (error == 0) {
			if (aip->ai_canonname != NULL &&
			    (cp = strchr(aip->ai_canonname, '.')) !=
			    NULL && *(cp + 1) != '\0')
				snprintf(principal, sizeof (principal),
				    "nfs@%s", aip->ai_canonname);
			freeaddrinfo(aip);
		}
	}
	nfsdargs.principal = principal;

	if (nfsdcnt_set)
		nfsdargs.minthreads = nfsdargs.maxthreads = nfsdcnt;
	else {
		nfsdargs.minthreads = minthreads_set ? minthreads : get_tuned_nfsdcount();
		nfsdargs.maxthreads = maxthreads_set ? maxthreads : nfsdargs.minthreads;
		if (nfsdargs.maxthreads < nfsdargs.minthreads)
			nfsdargs.maxthreads = nfsdargs.minthreads;
	}
	error = nfssvc(nfssvc_nfsd, &nfsdargs);
	if (error < 0 && errno == EAUTH) {
		/*
		 * This indicates that it could not register the
		 * rpcsec_gss credentials, usually because the
		 * gssd daemon isn't running.
		 * (only the experimental server with nfsv4)
		 */
		syslog(LOG_ERR, "No gssd, using AUTH_SYS only");
		principal[0] = '\0';
		error = nfssvc(nfssvc_nfsd, &nfsdargs);
	}
	if (error < 0) {
		syslog(LOG_ERR, "nfssvc: %m");
		status = 1;
	}
	if (master)
		nfsd_exit(status);
	else
		exit(status);
}
Пример #2
0
/*
 * cleanup_term() called via SIGUSR1.
 */
static void
cleanup_term(int signo __unused)
{
	int i, cnt;

	if (im_a_slave)
		exit(0);

	/*
	 * Ok, so I'm the master.
	 * As the Governor of California might say, "Terminate them".
	 */
	cnt = 0;
	for (i = 0; i < nfsuserdcnt; i++) {
		if (slaves[i] != (pid_t)-1) {
			cnt++;
			kill(slaves[i], SIGUSR1);
		}
	}

	/*
	 * and wait for them to die
	 */
	for (i = 0; i < cnt; i++)
		wait3(NULL, 0, NULL);

	/*
	 * Finally, get rid of the socket
	 */
	if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
		syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
		exit(1);
	}
	exit(0);
}
Пример #3
0
/*
 * Dump the lock state for a file.
 */
static void
dump_lockstate(char *fname)
{
	struct nfsd_dumplocklist dumplocklist;
	int cnt, i;

	dumplocklist.ndllck_size = DUMPSIZE;
	dumplocklist.ndllck_list = (void *)lp;
	dumplocklist.ndllck_fname = fname;
	if (nfssvc(NFSSVC_DUMPLOCKS, &dumplocklist) < 0)
		errx(1, "Can't dump locks for %s\n", fname);

	printf("%-11s %-36s %-15s %s\n",
	    "Open/Lock",
	    "          Stateid or Lock Range",
	    "Clientaddr",
	    "Owner and ClientID");
	/*
	 * Loop through results, printing them out.
	 */
	cnt = 0;
	while (lp[cnt].ndlck_clid.nclid_idlen > 0 && cnt < DUMPSIZE) {
		if (lp[cnt].ndlck_flags & NFSLCK_OPEN)
			printf("%-11s %9d %08x %08x %08x ",
			    open_flags(lp[cnt].ndlck_flags),
			    lp[cnt].ndlck_stateid.seqid,
			    lp[cnt].ndlck_stateid.other[0],
			    lp[cnt].ndlck_stateid.other[1],
			    lp[cnt].ndlck_stateid.other[2]);
		else if (lp[cnt].ndlck_flags & (NFSLCK_DELEGREAD |
		    NFSLCK_DELEGWRITE))
			printf("%-11s %9d %08x %08x %08x ",
			    deleg_flags(lp[cnt].ndlck_flags),
			    lp[cnt].ndlck_stateid.seqid,
			    lp[cnt].ndlck_stateid.other[0],
			    lp[cnt].ndlck_stateid.other[1],
			    lp[cnt].ndlck_stateid.other[2]);
		else
			printf("%-11s  %17jd %17jd ",
			    lock_flags(lp[cnt].ndlck_flags),
			    lp[cnt].ndlck_first,
			    lp[cnt].ndlck_end);
		if (lp[cnt].ndlck_addrfam == AF_INET)
			printf("%-15s ",
			    inet_ntoa(lp[cnt].ndlck_cbaddr.sin_addr));
		else
			printf("%-15s ", "  ");
		for (i = 0; i < lp[cnt].ndlck_owner.nclid_idlen; i++)
			printf("%02x", lp[cnt].ndlck_owner.nclid_id[i]);
		printf(" ");
		for (i = 0; i < lp[cnt].ndlck_clid.nclid_idlen; i++)
			printf("%02x", lp[cnt].ndlck_clid.nclid_id[i]);
		printf("\n");
		cnt++;
	}
}
Пример #4
0
int
main(int argc, char **argv)
{
	char *cp;
	u_char val;
	int cnt, even;
	struct nfsd_clid revoke_handle;

	if (modfind("nfsd") < 0)
		errx(1, "nfsd not loaded - self terminating");
	if (argc != 2)
		usage();
	cnt = 0;
	cp = argv[1];
	if (strlen(cp) % 2)
		even = 0;
	else
		even = 1;
	val = 0;
	while (*cp) {
		if (*cp >= '0' && *cp <= '9')
			val += (u_char)(*cp - '0');
		else if (*cp >= 'A' && *cp <= 'F')
			val += ((u_char)(*cp - 'A')) + 0xa;
		else if (*cp >= 'a' && *cp <= 'f')
			val += ((u_char)(*cp - 'a')) + 0xa;
		else
			errx(1, "Non hexadecimal digit in %s", argv[1]);
		if (even) {
			val <<= 4;
			even = 0;
		} else {
			revoke_handle.nclid_id[cnt++] = val;
			if (cnt > NFSV4_OPAQUELIMIT)
				errx(1, "Clientid %s, loo long", argv[1]);
			val = 0;
			even = 1;
		}
		cp++;
	}

	/*
	 * Do the revocation system call.
	 */
	revoke_handle.nclid_idlen = cnt;
#ifdef DEBUG
	printf("Idlen=%d\n", revoke_handle.nclid_idlen);
	for (cnt = 0; cnt < revoke_handle.nclid_idlen; cnt++)
		printf("%02x", revoke_handle.nclid_id[cnt]);
	printf("\n");
#else
	if (nfssvc(NFSSVC_ADMINREVOKE, &revoke_handle) < 0)
		err(1, "Admin revoke failed");
#endif
}
Пример #5
0
void
start_server(int master)
{
	int status;

	status = 0;
	nsd.nsd_nfsd = NULL;
	if (nfssvc(NFSSVC_NFSD, &nsd) < 0) {
		syslog(LOG_ERR, "nfssvc: %m");
		status = 1;
	}
	if (master)
		nfsd_exit(status);
	else
		exit(status);
}
Пример #6
0
static void *
worker(void *dummy)
{
	struct	nfsd_srvargs nsd;
	int nfssvc_flag;

	pthread_setname_np(pthread_self(), "slave", NULL);
	nfssvc_flag = NFSSVC_NFSD;
	memset(&nsd, 0, sizeof(nsd));
	while (nfssvc(nfssvc_flag, &nsd) < 0) {
		if (errno != ENEEDAUTH) {
			logit(LOG_ERR, "nfssvc: %s", strerror(errno));
			exit(1);
		}
		nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
	}

	return NULL;
}
Пример #7
0
/*
 * Dump all open/lock state.
 */
static void
dump_openstate(void)
{
	struct nfsd_dumplist dumplist;
	int cnt, i;

	dumplist.ndl_size = DUMPSIZE;
	dumplist.ndl_list = (void *)dp;
	if (nfssvc(NFSSVC_DUMPCLIENTS, &dumplist) < 0)
		errx(1, "Can't perform dump clients syscall");

	printf("%-13s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %-15s %s\n",
	    "Flags", "OpenOwner", "Open", "LockOwner",
	    "Lock", "Deleg", "OldDeleg", "Clientaddr", "ClientID");
	/*
	 * Loop through results, printing them out.
	 */
	cnt = 0;
	while (dp[cnt].ndcl_clid.nclid_idlen > 0 && cnt < DUMPSIZE) {
		printf("%-13s ", client_flags(dp[cnt].ndcl_flags));
		printf("%9d %9d %9d %9d %9d %9d ",
		    dp[cnt].ndcl_nopenowners,
		    dp[cnt].ndcl_nopens,
		    dp[cnt].ndcl_nlockowners,
		    dp[cnt].ndcl_nlocks,
		    dp[cnt].ndcl_ndelegs,
		    dp[cnt].ndcl_nolddelegs);
		if (dp[cnt].ndcl_addrfam == AF_INET)
			printf("%-15s ",
			    inet_ntoa(dp[cnt].ndcl_cbaddr.sin_addr));
		for (i = 0; i < dp[cnt].ndcl_clid.nclid_idlen; i++)
			printf("%02x", dp[cnt].ndcl_clid.nclid_id[i]);
		printf("\n");
		cnt++;
	}
}
Пример #8
0
/*
 * Nfs server daemon mostly just a user context for nfssvc()
 *
 * 1 - do file descriptor and signal cleanup
 * 2 - fork the nfsd(s)
 * 3 - create server socket(s)
 * 4 - register socket with rpcbind
 *
 * For connectionless protocols, just pass the socket into the kernel via.
 * nfssvc().
 * For connection based sockets, loop doing accepts. When you get a new
 * socket from accept, pass the msgsock into the kernel via. nfssvc().
 * The arguments are:
 *	-r - reregister with rpcbind
 *	-d - unregister with rpcbind
 *	-t - support tcp nfs clients
 *	-u - support udp nfs clients
 *	-e - forces it to run a server that supports nfsv4
 * followed by "n" which is the number of nfsds' to fork off
 */
int
main(int argc, char **argv)
{
	struct nfsd_addsock_args addsockargs;
	struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
	struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
	struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
	struct sockaddr_in inetpeer;
	struct sockaddr_in6 inet6peer;
	fd_set ready, sockbits;
	fd_set v4bits, v6bits;
	int ch, connect_type_cnt, i, maxsock, msgsock;
	socklen_t len;
	int on = 1, unregister, reregister, sock;
	int tcp6sock, ip6flag, tcpflag, tcpsock;
	int udpflag, ecode, error, s;
	int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
	int nfssvc_addsock;
	int longindex = 0;
	const char *lopt;
	char **bindhost = NULL;
	pid_t pid;

	nfsdcnt = DEFNFSDCNT;
	unregister = reregister = tcpflag = maxsock = 0;
	bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
	getopt_shortopts = "ah:n:rdtue";
	getopt_usage =
	    "usage:\n"
	    "  nfsd [-ardtue] [-h bindip]\n"
	    "       [-n numservers] [--minthreads #] [--maxthreads #]\n";
	while ((ch = getopt_long(argc, argv, getopt_shortopts, longopts,
		    &longindex)) != -1)
		switch (ch) {
		case 'a':
			bindanyflag = 1;
			break;
		case 'n':
			set_nfsdcnt(atoi(optarg));
			break;
		case 'h':
			bindhostc++;
			bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
			if (bindhost == NULL) 
				errx(1, "Out of memory");
			bindhost[bindhostc-1] = strdup(optarg);
			if (bindhost[bindhostc-1] == NULL)
				errx(1, "Out of memory");
			break;
		case 'r':
			reregister = 1;
			break;
		case 'd':
			unregister = 1;
			break;
		case 't':
			tcpflag = 1;
			break;
		case 'u':
			udpflag = 1;
			break;
		case 'e':
			/* now a no-op, since this is the default */
			break;
		case 0:
			lopt = longopts[longindex].name;
			if (!strcmp(lopt, "minthreads")) {
				minthreads = atoi(optarg);
			} else if (!strcmp(lopt, "maxthreads")) {
				maxthreads = atoi(optarg);
			}
			break;
		default:
		case '?':
			usage();
		}
	if (!tcpflag && !udpflag)
		udpflag = 1;
	argv += optind;
	argc -= optind;
	if (minthreads_set && maxthreads_set && minthreads > maxthreads)
		errx(EX_USAGE,
		    "error: minthreads(%d) can't be greater than "
		    "maxthreads(%d)", minthreads, maxthreads);

	/*
	 * XXX
	 * Backward compatibility, trailing number is the count of daemons.
	 */
	if (argc > 1)
		usage();
	if (argc == 1)
		set_nfsdcnt(atoi(argv[0]));

	/*
	 * Unless the "-o" option was specified, try and run "nfsd".
	 * If "-o" was specified, try and run "nfsserver".
	 */
	if (modfind("nfsd") < 0) {
		/* Not present in kernel, try loading it */
		if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
			errx(1, "NFS server is not available");
	}

	ip6flag = 1;
	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
	if (s == -1) {
		if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
			err(1, "socket");
		ip6flag = 0;
	} else if (getnetconfigent("udp6") == NULL ||
		getnetconfigent("tcp6") == NULL) {
		ip6flag = 0;
	}
	if (s != -1)
		close(s);

	if (bindhostc == 0 || bindanyflag) {
		bindhostc++;
		bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
		if (bindhost == NULL) 
			errx(1, "Out of memory");
		bindhost[bindhostc-1] = strdup("*");
		if (bindhost[bindhostc-1] == NULL) 
			errx(1, "Out of memory");
	}

	if (unregister) {
		unregistration();
		exit (0);
	}
	if (reregister) {
		if (udpflag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
			if (ecode != 0)
				err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
			nconf_udp = getnetconfigent("udp");
			if (nconf_udp == NULL)
				err(1, "getnetconfigent udp failed");
			nb_udp.buf = ai_udp->ai_addr;
			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp)))
				err(1, "rpcb_set udp failed");
			freeaddrinfo(ai_udp);
		}
		if (udpflag && ip6flag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
			if (ecode != 0)
				err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
			nconf_udp6 = getnetconfigent("udp6");
			if (nconf_udp6 == NULL)
				err(1, "getnetconfigent udp6 failed");
			nb_udp6.buf = ai_udp6->ai_addr;
			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6)))
				err(1, "rpcb_set udp6 failed");
			freeaddrinfo(ai_udp6);
		}
		if (tcpflag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
			if (ecode != 0)
				err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
			nconf_tcp = getnetconfigent("tcp");
			if (nconf_tcp == NULL)
				err(1, "getnetconfigent tcp failed");
			nb_tcp.buf = ai_tcp->ai_addr;
			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp, &nb_tcp)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp, &nb_tcp)))
				err(1, "rpcb_set tcp failed");
			freeaddrinfo(ai_tcp);
		}
		if (tcpflag && ip6flag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
			if (ecode != 0)
				err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
			nconf_tcp6 = getnetconfigent("tcp6");
			if (nconf_tcp6 == NULL)
				err(1, "getnetconfigent tcp6 failed");
			nb_tcp6.buf = ai_tcp6->ai_addr;
			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6)))
				err(1, "rpcb_set tcp6 failed");
			freeaddrinfo(ai_tcp6);
		}
		exit (0);
	}
	if (debug == 0) {
		daemon(0, 0);
		(void)signal(SIGHUP, SIG_IGN);
		(void)signal(SIGINT, SIG_IGN);
		/*
		 * nfsd sits in the kernel most of the time.  It needs
		 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
		 * as possible during a shutdown, otherwise loopback
		 * mounts will not be able to unmount. 
		 */
		(void)signal(SIGTERM, SIG_IGN);
		(void)signal(SIGQUIT, SIG_IGN);
	}
	(void)signal(SIGSYS, nonfs);
	(void)signal(SIGCHLD, reapchild);
	(void)signal(SIGUSR2, backup_stable);

	openlog("nfsd", LOG_PID | (debug ? LOG_PERROR : 0), LOG_DAEMON);

	/*
	 * For V4, we open the stablerestart file and call nfssvc()
	 * to get it loaded. This is done before the daemons do the
	 * regular nfssvc() call to service NFS requests.
	 * (This way the file remains open until the last nfsd is killed
	 *  off.)
	 * It and the backup copy will be created as empty files
	 * the first time this nfsd is started and should never be
	 * deleted/replaced if at all possible. It should live on a
	 * local, non-volatile storage device that does not do hardware
	 * level write-back caching. (See SCSI doc for more information
	 * on how to prevent write-back caching on SCSI disks.)
	 */
	open_stable(&stablefd, &backupfd);
	if (stablefd < 0) {
		syslog(LOG_ERR, "Can't open %s: %m\n", NFSD_STABLERESTART);
		exit(1);
	}
	/* This system call will fail for old kernels, but that's ok. */
	nfssvc(NFSSVC_BACKUPSTABLE, NULL);
	if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) {
		syslog(LOG_ERR, "Can't read stable storage file: %m\n");
		exit(1);
	}
	nfssvc_addsock = NFSSVC_NFSDADDSOCK;
	nfssvc_nfsd = NFSSVC_NFSDNFSD;

	if (tcpflag) {
		/*
		 * For TCP mode, we fork once to start the first
		 * kernel nfsd thread. The kernel will add more
		 * threads as needed.
		 */
		pid = fork();
		if (pid == -1) {
			syslog(LOG_ERR, "fork: %m");
			nfsd_exit(1);
		}
		if (pid) {
			children[0] = pid;
		} else {
			(void)signal(SIGUSR1, child_cleanup);
			setproctitle("server");
			start_server(0);
		}
	}

	(void)signal(SIGUSR1, cleanup);
	FD_ZERO(&v4bits);
	FD_ZERO(&v6bits);
	FD_ZERO(&sockbits);
 
	rpcbregcnt = 0;
	/* Set up the socket for udp and rpcb register it. */
	if (udpflag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((sock = socket(ai_udp->ai_family,
				    ai_udp->ai_socktype,
				    ai_udp->ai_protocol)) < 0) {
					syslog(LOG_ERR,
					    "can't create udp socket");
					nfsd_exit(1);
				}
				if (bind(sock, ai_udp->ai_addr,
				    ai_udp->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind udp addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				freeaddrinfo(ai_udp);
				addsockargs.sock = sock;
				addsockargs.name = NULL;
				addsockargs.namelen = 0;
				if (nfssvc(nfssvc_addsock, &addsockargs) < 0) {
					syslog(LOG_ERR, "can't Add UDP socket");
					nfsd_exit(1);
				}
				(void)close(sock);
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo udp: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_udp = getnetconfigent("udp");
			if (nconf_udp == NULL)
				err(1, "getnetconfigent udp failed");
			nb_udp.buf = ai_udp->ai_addr;
			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp)))
				err(1, "rpcb_set udp failed");
			freeaddrinfo(ai_udp);
		}
	}

	/* Set up the socket for udp6 and rpcb register it. */
	if (udpflag && ip6flag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((sock = socket(ai_udp6->ai_family,
				    ai_udp6->ai_socktype,
				    ai_udp6->ai_protocol)) < 0) {
					syslog(LOG_ERR,
						"can't create udp6 socket");
					nfsd_exit(1);
				}
				if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
				    &on, sizeof on) < 0) {
					syslog(LOG_ERR,
					    "can't set v6-only binding for "
					    "udp6 socket: %m");
					nfsd_exit(1);
				}
				if (bind(sock, ai_udp6->ai_addr,
				    ai_udp6->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind udp6 addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				freeaddrinfo(ai_udp6);
				addsockargs.sock = sock;
				addsockargs.name = NULL;
				addsockargs.namelen = 0;
				if (nfssvc(nfssvc_addsock, &addsockargs) < 0) {
					syslog(LOG_ERR,
					    "can't add UDP6 socket");
					nfsd_exit(1);
				}
				(void)close(sock);    
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo udp6: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_udp6 = getnetconfigent("udp6");
			if (nconf_udp6 == NULL)
				err(1, "getnetconfigent udp6 failed");
			nb_udp6.buf = ai_udp6->ai_addr;
			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6)))
				err(1, "rpcb_set udp6 failed");
			freeaddrinfo(ai_udp6);
		}
	}

	/* Set up the socket for tcp and rpcb register it. */
	if (tcpflag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((tcpsock = socket(AF_INET, SOCK_STREAM,
				    0)) < 0) {
					syslog(LOG_ERR,
					    "can't create tcp socket");
					nfsd_exit(1);
				}
				if (setsockopt(tcpsock, SOL_SOCKET,
				    SO_REUSEADDR,
				    (char *)&on, sizeof(on)) < 0)
					syslog(LOG_ERR,
					     "setsockopt SO_REUSEADDR: %m");
				if (bind(tcpsock, ai_tcp->ai_addr,
				    ai_tcp->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind tcp addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				if (listen(tcpsock, -1) < 0) {
					syslog(LOG_ERR, "listen failed");
					nfsd_exit(1);
				}
				freeaddrinfo(ai_tcp);
				FD_SET(tcpsock, &sockbits);
				FD_SET(tcpsock, &v4bits); 
				maxsock = tcpsock;
				connect_type_cnt++;
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints,
			     &ai_tcp);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo tcp: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_tcp = getnetconfigent("tcp");
			if (nconf_tcp == NULL)
				err(1, "getnetconfigent tcp failed");
			nb_tcp.buf = ai_tcp->ai_addr;
			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp,
			    &nb_tcp)) || (!rpcb_set(NFS_PROGRAM, 3,
			    nconf_tcp, &nb_tcp)))
				err(1, "rpcb_set tcp failed");
			freeaddrinfo(ai_tcp);
		}
	}

	/* Set up the socket for tcp6 and rpcb register it. */
	if (tcpflag && ip6flag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((tcp6sock = socket(ai_tcp6->ai_family,
				    ai_tcp6->ai_socktype,
				    ai_tcp6->ai_protocol)) < 0) {
					syslog(LOG_ERR,
					    "can't create tcp6 socket");
					nfsd_exit(1);
				}
				if (setsockopt(tcp6sock, SOL_SOCKET,
				    SO_REUSEADDR,
				    (char *)&on, sizeof(on)) < 0)
					syslog(LOG_ERR,
					    "setsockopt SO_REUSEADDR: %m");
				if (setsockopt(tcp6sock, IPPROTO_IPV6,
				    IPV6_V6ONLY, &on, sizeof on) < 0) {
					syslog(LOG_ERR,
					"can't set v6-only binding for tcp6 "
					    "socket: %m");
					nfsd_exit(1);
				}
				if (bind(tcp6sock, ai_tcp6->ai_addr,
				    ai_tcp6->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind tcp6 addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				if (listen(tcp6sock, -1) < 0) {
					syslog(LOG_ERR, "listen failed");
					nfsd_exit(1);
				}
				freeaddrinfo(ai_tcp6);
				FD_SET(tcp6sock, &sockbits);
				FD_SET(tcp6sock, &v6bits);
				if (maxsock < tcp6sock)
					maxsock = tcp6sock;
				connect_type_cnt++;
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo tcp6: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_tcp6 = getnetconfigent("tcp6");
			if (nconf_tcp6 == NULL)
				err(1, "getnetconfigent tcp6 failed");
			nb_tcp6.buf = ai_tcp6->ai_addr;
			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
			if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) ||
			    (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6)))
				err(1, "rpcb_set tcp6 failed");
			freeaddrinfo(ai_tcp6);
		}
	}

	if (rpcbregcnt == 0) {
		syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
		nfsd_exit(1);
	}

	if (tcpflag && connect_type_cnt == 0) {
		syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
		nfsd_exit(1);
	}

	setproctitle("master");
	/*
	 * We always want a master to have a clean way to to shut nfsd down
	 * (with unregistration): if the master is killed, it unregisters and
	 * kills all children. If we run for UDP only (and so do not have to
	 * loop waiting waiting for accept), we instead make the parent
	 * a "server" too. start_server will not return.
	 */
	if (!tcpflag)
		start_server(1);

	/*
	 * Loop forever accepting connections and passing the sockets
	 * into the kernel for the mounts.
	 */
	for (;;) {
		ready = sockbits;
		if (connect_type_cnt > 1) {
			if (select(maxsock + 1,
			    &ready, NULL, NULL, NULL) < 1) {
				error = errno;
				if (error == EINTR)
					continue;
				syslog(LOG_ERR, "select failed: %m");
				nfsd_exit(1);
			}
		}
		for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
			if (FD_ISSET(tcpsock, &ready)) {
				if (FD_ISSET(tcpsock, &v4bits)) {
					len = sizeof(inetpeer);
					if ((msgsock = accept(tcpsock,
					    (struct sockaddr *)&inetpeer, &len)) < 0) {
						error = errno;
						syslog(LOG_ERR, "accept failed: %m");
						if (error == ECONNABORTED ||
						    error == EINTR)
							continue;
						nfsd_exit(1);
					}
					memset(inetpeer.sin_zero, 0,
						sizeof(inetpeer.sin_zero));
					if (setsockopt(msgsock, SOL_SOCKET,
					    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
						syslog(LOG_ERR,
						    "setsockopt SO_KEEPALIVE: %m");
					addsockargs.sock = msgsock;
					addsockargs.name = (caddr_t)&inetpeer;
					addsockargs.namelen = len;
					nfssvc(nfssvc_addsock, &addsockargs);
					(void)close(msgsock);
				} else if (FD_ISSET(tcpsock, &v6bits)) {
					len = sizeof(inet6peer);
					if ((msgsock = accept(tcpsock,
					    (struct sockaddr *)&inet6peer,
					    &len)) < 0) {
						error = errno;
						syslog(LOG_ERR,
						     "accept failed: %m");
						if (error == ECONNABORTED ||
						    error == EINTR)
							continue;
						nfsd_exit(1);
					}
					if (setsockopt(msgsock, SOL_SOCKET,
					    SO_KEEPALIVE, (char *)&on,
					    sizeof(on)) < 0)
						syslog(LOG_ERR, "setsockopt "
						    "SO_KEEPALIVE: %m");
					addsockargs.sock = msgsock;
					addsockargs.name = (caddr_t)&inet6peer;
					addsockargs.namelen = len;
					nfssvc(nfssvc_addsock, &addsockargs);
					(void)close(msgsock);
				}
			}
		}
	}
}
Пример #9
0
int
main(int argc, char *argv[])
{
	int i, j;
	int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
	struct nfsd_idargs nid;
	struct passwd *pwd;
	struct group *grp;
	int sock, one = 1;
	SVCXPRT *udptransp;
	u_short portnum;
	sigset_t signew;
	char hostname[MAXHOSTNAMELEN + 1], *cp;
	struct addrinfo *aip, hints;
	static uid_t check_dups[MAXUSERMAX];

	if (modfind("nfscommon") < 0) {
		/* Not present in kernel, try loading it */
		if (kldload("nfscommon") < 0 ||
		    modfind("nfscommon") < 0)
			errx(1, "Experimental nfs subsystem is not available");
	}

	/*
	 * First, figure out what our domain name and Kerberos Realm
	 * seem to be. Command line args may override these later.
	 */
	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
		if ((cp = strchr(hostname, '.')) != NULL &&
		    *(cp + 1) != '\0') {
			dnsname = cp + 1;
		} else {
			memset((void *)&hints, 0, sizeof (hints));
			hints.ai_flags = AI_CANONNAME;
			error = getaddrinfo(hostname, NULL, &hints, &aip);
			if (error == 0) {
			    if (aip->ai_canonname != NULL &&
				(cp = strchr(aip->ai_canonname, '.')) != NULL
				&& *(cp + 1) != '\0') {
					dnsname = cp + 1;
					mustfreeai = 1;
				} else {
					freeaddrinfo(aip);
				}
			}
		}
	}
	nid.nid_usermax = DEFUSERMAX;
	nid.nid_usertimeout = defusertimeout;

	argc--;
	argv++;
	while (argc >= 1) {
		if (!strcmp(*argv, "-domain")) {
			if (argc == 1)
				usage();
			argc--;
			argv++;
			strncpy(hostname, *argv, MAXHOSTNAMELEN);
			hostname[MAXHOSTNAMELEN] = '\0';
			dnsname = hostname;
		} else if (!strcmp(*argv, "-verbose")) {
			verbose = 1;
		} else if (!strcmp(*argv, "-force")) {
			forcestart = 1;
		} else if (!strcmp(*argv, "-usermax")) {
			if (argc == 1)
				usage();
			argc--;
			argv++;
			i = atoi(*argv);
			if (i < MINUSERMAX || i > MAXUSERMAX) {
				fprintf(stderr,
				    "usermax %d out of range %d<->%d\n", i,
				    MINUSERMAX, MAXUSERMAX);
				usage();
			}
			nid.nid_usermax = i;
		} else if (!strcmp(*argv, "-usertimeout")) {
			if (argc == 1)
				usage();
			argc--;
			argv++;
			i = atoi(*argv);
			if (i < 0 || i > 100000) {
				fprintf(stderr,
				    "usertimeout %d out of range 0<->100000\n",
				    i);
				usage();
			}
			nid.nid_usertimeout = defusertimeout = i * 60;
		} else if (nfsuserdcnt == -1) {
			nfsuserdcnt = atoi(*argv);
			if (nfsuserdcnt < 1)
				usage();
			if (nfsuserdcnt > MAXNFSUSERD) {
				warnx("nfsuserd count %d; reset to %d",
				    nfsuserdcnt, DEFNFSUSERD);
				nfsuserdcnt = DEFNFSUSERD;
			}
		} else {
			usage();
		}
		argc--;
		argv++;
	}
	if (nfsuserdcnt < 1)
		nfsuserdcnt = DEFNFSUSERD;

	/*
	 * Strip off leading and trailing '.'s in domain name and map
	 * alphabetics to lower case.
	 */
	while (*dnsname == '.')
		dnsname++;
	if (*dnsname == '\0')
		errx(1, "Domain name all '.'");
	len = strlen(dnsname);
	cp = dnsname + len - 1;
	while (*cp == '.') {
		*cp = '\0';
		len--;
		cp--;
	}
	for (i = 0; i < len; i++) {
		if (!isascii(dnsname[i]))
			errx(1, "Domain name has non-ascii char");
		if (isupper(dnsname[i]))
			dnsname[i] = tolower(dnsname[i]);
	}

	/*
	 * If the nfsuserd died off ungracefully, this is necessary to
	 * get them to start again.
	 */
	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
		errx(1, "Can't do nfssvc() to delete the port");

	if (verbose)
		fprintf(stderr,
		    "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
		    dnsname, nid.nid_usermax, nid.nid_usertimeout);

	for (i = 0; i < nfsuserdcnt; i++)
		slaves[i] = (pid_t)-1;

	/*
	 * Set up the service port to accept requests via UDP from
	 * localhost (127.0.0.1).
	 */
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
		err(1, "cannot create udp socket");

	/*
	 * Not sure what this does, so I'll leave it here for now.
	 */
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
	
	if ((udptransp = svcudp_create(sock)) == NULL)
		err(1, "Can't set up socket");

	/*
	 * By not specifying a protocol, it is linked into the
	 * dispatch queue, but not registered with portmapper,
	 * which is just what I want.
	 */
	if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
	    nfsuserdsrv, 0))
		err(1, "Can't register nfsuserd");

	/*
	 * Tell the kernel what my port# is.
	 */
	portnum = htons(udptransp->xp_port);
#ifdef DEBUG
	printf("portnum=0x%x\n", portnum);
#else
	if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
		if (errno == EPERM) {
			fprintf(stderr,
			    "Can't start nfsuserd when already running");
			fprintf(stderr,
			    " If not running, use the -force option.\n");
		} else {
			fprintf(stderr, "Can't do nfssvc() to add port\n");
		}
		exit(1);
	}
#endif

	pwd = getpwnam(defaultuser);
	if (pwd)
		nid.nid_uid = pwd->pw_uid;
	else
		nid.nid_uid = defaultuid;
	grp = getgrnam(defaultgroup);
	if (grp)
		nid.nid_gid = grp->gr_gid;
	else
		nid.nid_gid = defaultgid;
	nid.nid_name = dnsname;
	nid.nid_namelen = strlen(nid.nid_name);
	nid.nid_flag = NFSID_INITIALIZE;
#ifdef DEBUG
	printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid, 
	    nid.nid_name);
#else
	error = nfssvc(NFSSVC_IDNAME, &nid);
	if (error)
		errx(1, "Can't initialize nfs user/groups");
#endif

	i = 0;
	/*
	 * Loop around adding all groups.
	 */
	setgrent();
	while (i < nid.nid_usermax && (grp = getgrent())) {
		nid.nid_gid = grp->gr_gid;
		nid.nid_name = grp->gr_name;
		nid.nid_namelen = strlen(grp->gr_name);
		nid.nid_flag = NFSID_ADDGID;
#ifdef DEBUG
		printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
#else
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error)
			errx(1, "Can't add group %s", grp->gr_name);
#endif
		i++;
	}

	/*
	 * Loop around adding all users.
	 */
	start_uidpos = i;
	setpwent();
	while (i < nid.nid_usermax && (pwd = getpwent())) {
		fnd_dup = 0;
		/*
		 * Yes, this is inefficient, but it is only done once when
		 * the daemon is started and will run in a fraction of a second
		 * for nid_usermax at 10000. If nid_usermax is cranked up to
		 * 100000, it will take several seconds, depending on the CPU.
		 */
		for (j = 0; j < (i - start_uidpos); j++)
			if (check_dups[j] == pwd->pw_uid) {
				/* Found another entry for uid, so skip it */
				fnd_dup = 1;
				break;
			}
		if (fnd_dup != 0)
			continue;
		check_dups[i - start_uidpos] = pwd->pw_uid;
		nid.nid_uid = pwd->pw_uid;
		nid.nid_name = pwd->pw_name;
		nid.nid_namelen = strlen(pwd->pw_name);
		nid.nid_flag = NFSID_ADDUID;
#ifdef DEBUG
		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
#else
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error)
			errx(1, "Can't add user %s", pwd->pw_name);
#endif
		i++;
	}

	/*
	 * I should feel guilty for not calling this for all the above exit()
	 * upon error cases, but I don't.
	 */
	if (mustfreeai)
		freeaddrinfo(aip);

#ifdef DEBUG
	exit(0);
#endif
	/*
	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
	 * end up bogus.
	 */
	sigemptyset(&signew);
	sigaddset(&signew, SIGUSR1);
	sigaddset(&signew, SIGCHLD);
	sigprocmask(SIG_BLOCK, &signew, NULL);

	daemon(0, 0);
	(void)signal(SIGHUP, SIG_IGN);
	(void)signal(SIGINT, SIG_IGN);
	(void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGTERM, SIG_IGN);
	(void)signal(SIGUSR1, cleanup_term);
	(void)signal(SIGCHLD, cleanup_term);

	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);

	/*
	 * Fork off the slave daemons that do the work. All the master
	 * does is kill them off and cleanup.
	 */
	for (i = 0; i < nfsuserdcnt; i++) {
		slaves[i] = fork();
		if (slaves[i] == 0) {
			im_a_slave = 1;
			setproctitle("slave");
			sigemptyset(&signew);
			sigaddset(&signew, SIGUSR1);
			sigprocmask(SIG_UNBLOCK, &signew, NULL);

			/*
			 * and away we go.
			 */
			svc_run();
			syslog(LOG_ERR, "nfsuserd died: %m");
			exit(1);
		} else if (slaves[i] < 0) {
			syslog(LOG_ERR, "fork: %m");
		}
	}

	/*
	 * Just wait for SIGUSR1 or a child to die and then...
	 * As the Governor of California would say, "Terminate them".
	 */
	setproctitle("master");
	sigemptyset(&signew);
	while (1)
		sigsuspend(&signew);
}
Пример #10
0
/*
 * Print a description of the nfs stats.
 */
void
intpr(int clientOnly, int serverOnly)
{
	struct nfsstats nfsstats, *nfsstatsp;
	struct nfsrvstats nfsrvstats, *nfsrvstatsp;
	int nfssvc_flag;

	if (run_v4 == 0) {
		/*
		 * Only read the stats we are going to display to avoid zeroing
		 * stats the user didn't request.
		 */
		if (clientOnly)
			nfsstatsp = &nfsstats;
		else
			nfsstatsp = NULL;
		if (serverOnly)
			nfsrvstatsp = &nfsrvstats;
		else
			nfsrvstatsp = NULL;
	
		readstats(&nfsstatsp, &nfsrvstatsp, zflag);
	
		if (clientOnly && !nfsstatsp) {
			printf("Client not present!\n");
			clientOnly = 0;
		}
	} else {
		nfssvc_flag = NFSSVC_GETSTATS;
		if (zflag != 0) {
			if (clientOnly != 0)
				nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
			if (serverOnly != 0)
				nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
		}
		if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
			err(1, "Can't get stats");
	}
	if (clientOnly) {
		printf("Client Info:\n");
		printf("Rpc Counts:\n");
		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
			"Getattr", "Setattr", "Lookup", "Readlink", "Read",
			"Write", "Create", "Remove");
		if (run_v4 == 0)
			printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
				nfsstats.rpccnt[NFSPROC_GETATTR],
				nfsstats.rpccnt[NFSPROC_SETATTR],
				nfsstats.rpccnt[NFSPROC_LOOKUP],
				nfsstats.rpccnt[NFSPROC_READLINK],
				nfsstats.rpccnt[NFSPROC_READ],
				nfsstats.rpccnt[NFSPROC_WRITE],
				nfsstats.rpccnt[NFSPROC_CREATE],
				nfsstats.rpccnt[NFSPROC_REMOVE]);
		else
			printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
				ext_nfsstats.rpccnt[NFSPROC_GETATTR],
				ext_nfsstats.rpccnt[NFSPROC_SETATTR],
				ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
				ext_nfsstats.rpccnt[NFSPROC_READLINK],
				ext_nfsstats.rpccnt[NFSPROC_READ],
				ext_nfsstats.rpccnt[NFSPROC_WRITE],
				ext_nfsstats.rpccnt[NFSPROC_CREATE],
				ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
			"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
			"Readdir", "RdirPlus", "Access");
		if (run_v4 == 0)
			printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
				nfsstats.rpccnt[NFSPROC_RENAME],
				nfsstats.rpccnt[NFSPROC_LINK],
				nfsstats.rpccnt[NFSPROC_SYMLINK],
				nfsstats.rpccnt[NFSPROC_MKDIR],
				nfsstats.rpccnt[NFSPROC_RMDIR],
				nfsstats.rpccnt[NFSPROC_READDIR],
				nfsstats.rpccnt[NFSPROC_READDIRPLUS],
				nfsstats.rpccnt[NFSPROC_ACCESS]);
		else
			printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
				ext_nfsstats.rpccnt[NFSPROC_RENAME],
				ext_nfsstats.rpccnt[NFSPROC_LINK],
				ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
				ext_nfsstats.rpccnt[NFSPROC_MKDIR],
				ext_nfsstats.rpccnt[NFSPROC_RMDIR],
				ext_nfsstats.rpccnt[NFSPROC_READDIR],
				ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
				ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
			"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
		if (run_v4 == 0)
			printf("%9d %9d %9d %9d %9d\n",
				nfsstats.rpccnt[NFSPROC_MKNOD],
				nfsstats.rpccnt[NFSPROC_FSSTAT],
				nfsstats.rpccnt[NFSPROC_FSINFO],
				nfsstats.rpccnt[NFSPROC_PATHCONF],
				nfsstats.rpccnt[NFSPROC_COMMIT]);
		else
			printf("%9d %9d %9d %9d %9d\n",
				ext_nfsstats.rpccnt[NFSPROC_MKNOD],
				ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
				ext_nfsstats.rpccnt[NFSPROC_FSINFO],
				ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
				ext_nfsstats.rpccnt[NFSPROC_COMMIT]);
		printf("Rpc Info:\n");
		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
			"TimedOut", "Invalid", "X Replies", "Retries", 
			"Requests");
		if (run_v4 == 0)
			printf("%9d %9d %9d %9d %9d\n",
				nfsstats.rpctimeouts,
				nfsstats.rpcinvalid,
				nfsstats.rpcunexpected,
				nfsstats.rpcretries,
				nfsstats.rpcrequests);
		else
			printf("%9d %9d %9d %9d %9d\n",
				ext_nfsstats.rpctimeouts,
				ext_nfsstats.rpcinvalid,
				ext_nfsstats.rpcunexpected,
				ext_nfsstats.rpcretries,
				ext_nfsstats.rpcrequests);
		printf("Cache Info:\n");
		printf("%9.9s %9.9s %9.9s %9.9s",
			"Attr Hits", "Misses", "Lkup Hits", "Misses");
		printf(" %9.9s %9.9s %9.9s %9.9s\n",
			"BioR Hits", "Misses", "BioW Hits", "Misses");
		if (run_v4 == 0) {
			printf("%9d %9d %9d %9d",
				nfsstats.attrcache_hits,
				nfsstats.attrcache_misses,
				nfsstats.lookupcache_hits,
				nfsstats.lookupcache_misses);
			printf(" %9d %9d %9d %9d\n",
				nfsstats.biocache_reads-nfsstats.read_bios,
				nfsstats.read_bios,
				nfsstats.biocache_writes-nfsstats.write_bios,
				nfsstats.write_bios);
		} else {
			printf("%9d %9d %9d %9d",
				ext_nfsstats.attrcache_hits,
				ext_nfsstats.attrcache_misses,
				ext_nfsstats.lookupcache_hits,
				ext_nfsstats.lookupcache_misses);
			printf(" %9d %9d %9d %9d\n",
				ext_nfsstats.biocache_reads -
				ext_nfsstats.read_bios,
				ext_nfsstats.read_bios,
				ext_nfsstats.biocache_writes -
				ext_nfsstats.write_bios,
				ext_nfsstats.write_bios);
		}
		printf("%9.9s %9.9s %9.9s %9.9s",
			"BioRLHits", "Misses", "BioD Hits", "Misses");
		printf(" %9.9s %9.9s %9.9s %9.9s\n", "DirE Hits", "Misses", "Accs Hits", "Misses");
		if (run_v4 == 0) {
			printf("%9d %9d %9d %9d",
				nfsstats.biocache_readlinks -
				nfsstats.readlink_bios,
				nfsstats.readlink_bios,
				nfsstats.biocache_readdirs -
				nfsstats.readdir_bios,
				nfsstats.readdir_bios);
			printf(" %9d %9d %9d %9d\n",
				nfsstats.direofcache_hits,
				nfsstats.direofcache_misses,
				nfsstats.accesscache_hits,
				nfsstats.accesscache_misses);
		} else {
			printf("%9d %9d %9d %9d",
				ext_nfsstats.biocache_readlinks -
				ext_nfsstats.readlink_bios,
				ext_nfsstats.readlink_bios,
				ext_nfsstats.biocache_readdirs -
				ext_nfsstats.readdir_bios,
				ext_nfsstats.readdir_bios);
			printf(" %9d %9d %9d %9d\n",
				ext_nfsstats.direofcache_hits,
				ext_nfsstats.direofcache_misses,
				ext_nfsstats.accesscache_hits,
				ext_nfsstats.accesscache_misses);
		}
	}
	if (run_v4 == 0 && serverOnly && !nfsrvstatsp) {
		printf("Server not present!\n");
		serverOnly = 0;
	}
	if (serverOnly) {
		printf("\nServer Info:\n");
		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
			"Getattr", "Setattr", "Lookup", "Readlink", "Read",
			"Write", "Create", "Remove");
		if (run_v4 == 0)
			printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
				nfsrvstats.srvrpccnt[NFSPROC_GETATTR],
				nfsrvstats.srvrpccnt[NFSPROC_SETATTR],
				nfsrvstats.srvrpccnt[NFSPROC_LOOKUP],
				nfsrvstats.srvrpccnt[NFSPROC_READLINK],
				nfsrvstats.srvrpccnt[NFSPROC_READ],
				nfsrvstats.srvrpccnt[NFSPROC_WRITE],
				nfsrvstats.srvrpccnt[NFSPROC_CREATE],
				nfsrvstats.srvrpccnt[NFSPROC_REMOVE]);
		else
			printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
				ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
				ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
				ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
				ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
				ext_nfsstats.srvrpccnt[NFSV4OP_READ],
				ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
				ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
				ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
			"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
			"Readdir", "RdirPlus", "Access");
		if (run_v4 == 0)
			printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
				nfsrvstats.srvrpccnt[NFSPROC_RENAME],
				nfsrvstats.srvrpccnt[NFSPROC_LINK],
				nfsrvstats.srvrpccnt[NFSPROC_SYMLINK],
				nfsrvstats.srvrpccnt[NFSPROC_MKDIR],
				nfsrvstats.srvrpccnt[NFSPROC_RMDIR],
				nfsrvstats.srvrpccnt[NFSPROC_READDIR],
				nfsrvstats.srvrpccnt[NFSPROC_READDIRPLUS],
				nfsrvstats.srvrpccnt[NFSPROC_ACCESS]);
		else
			printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
				ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
				ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
				ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
				ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
				ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
				ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
				ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
				ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
			"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
		if (run_v4 == 0)
			printf("%9d %9d %9d %9d %9d\n",
				nfsrvstats.srvrpccnt[NFSPROC_MKNOD],
				nfsrvstats.srvrpccnt[NFSPROC_FSSTAT],
				nfsrvstats.srvrpccnt[NFSPROC_FSINFO],
				nfsrvstats.srvrpccnt[NFSPROC_PATHCONF],
				nfsrvstats.srvrpccnt[NFSPROC_COMMIT]);
		else
			printf("%9d %9d %9d %9d %9d\n",
				ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
				ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
				ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
				ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
				ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT]);
		printf("Server Ret-Failed\n");
		if (run_v4 == 0)
			printf("%17d\n", nfsrvstats.srvrpc_errs);
		else
			printf("%17d\n", ext_nfsstats.srvrpc_errs);
		printf("Server Faults\n");
		if (run_v4 == 0)
			printf("%13d\n", nfsrvstats.srv_errs);
		else
			printf("%13d\n", ext_nfsstats.srv_errs);
		printf("Server Cache Stats:\n");
		printf("%9.9s %9.9s %9.9s %9.9s\n",
			"Inprog", "Idem", "Non-idem", "Misses");
		if (run_v4 == 0)
			printf("%9d %9d %9d %9d\n",
				nfsrvstats.srvcache_inproghits,
				nfsrvstats.srvcache_idemdonehits,
				nfsrvstats.srvcache_nonidemdonehits,
				nfsrvstats.srvcache_misses);
		else
			printf("%9d %9d %9d %9d\n",
				ext_nfsstats.srvcache_inproghits,
				ext_nfsstats.srvcache_idemdonehits,
				ext_nfsstats.srvcache_nonidemdonehits,
				ext_nfsstats.srvcache_misses);
		printf("Server Write Gathering:\n");
		printf("%9.9s %9.9s %9.9s\n",
			"WriteOps", "WriteRPC", "Opsaved");
		if (run_v4 == 0)
			printf("%9d %9d %9d\n",
				nfsrvstats.srvvop_writes,
				nfsrvstats.srvrpccnt[NFSPROC_WRITE],
				nfsrvstats.srvrpccnt[NFSPROC_WRITE] - 
				    nfsrvstats.srvvop_writes);
		else
			/*
			 * The new client doesn't do write gathering. It was
			 * only useful for NFSv2.
			 */
			printf("%9d %9d %9d\n",
				ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
				ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 0);
	}
}
Пример #11
0
/*
 * The nfsuserd rpc service
 */
static void
nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
{
	struct passwd *pwd;
	struct group *grp;
	int error;
	u_short sport;
	struct info info;
	struct nfsd_idargs nid;
	u_int32_t saddr;

	/*
	 * Only handle requests from 127.0.0.1 on a reserved port number.
	 * (Since a reserved port # at localhost implies a client with
	 *  local root, there won't be a security breach. This is about
	 *  the only case I can think of where a reserved port # means
	 *  something.)
	 */
	sport = ntohs(transp->xp_raddr.sin_port);
	saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
	if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
	    saddr != 0x7f000001) {
		syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport);
		svcerr_weakauth(transp);
		return;
	}
	switch (rqstp->rq_proc) {
	case NULLPROC:
		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
			syslog(LOG_ERR, "Can't send reply");
		return;
	case RPCNFSUSERD_GETUID:
		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
		    (caddr_t)&info)) {
			svcerr_decode(transp);
			return;
		}
		pwd = getpwuid((uid_t)info.id);
		info.retval = 0;
		if (pwd != NULL) {
			nid.nid_usertimeout = defusertimeout;
			nid.nid_uid = pwd->pw_uid;
			nid.nid_name = pwd->pw_name;
		} else {
			nid.nid_usertimeout = 5;
			nid.nid_uid = (uid_t)info.id;
			nid.nid_name = defaultuser;
		}
		nid.nid_namelen = strlen(nid.nid_name);
		nid.nid_flag = NFSID_ADDUID;
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error) {
			info.retval = error;
			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
		} else if (verbose) {
			syslog(LOG_ERR,"Added uid=%d name=%s\n",
			    nid.nid_uid, nid.nid_name);
		}
		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
		    (caddr_t)&info))
			syslog(LOG_ERR, "Can't send reply");
		return;
	case RPCNFSUSERD_GETGID:
		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
		    (caddr_t)&info)) {
			svcerr_decode(transp);
			return;
		}
		grp = getgrgid((gid_t)info.id);
		info.retval = 0;
		if (grp != NULL) {
			nid.nid_usertimeout = defusertimeout;
			nid.nid_gid = grp->gr_gid;
			nid.nid_name = grp->gr_name;
		} else {
			nid.nid_usertimeout = 5;
			nid.nid_gid = (gid_t)info.id;
			nid.nid_name = defaultgroup;
		}
		nid.nid_namelen = strlen(nid.nid_name);
		nid.nid_flag = NFSID_ADDGID;
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error) {
			info.retval = error;
			syslog(LOG_ERR, "Can't add group %s\n",
			    grp->gr_name);
		} else if (verbose) {
			syslog(LOG_ERR,"Added gid=%d name=%s\n",
			    nid.nid_gid, nid.nid_name);
		}
		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
		    (caddr_t)&info))
			syslog(LOG_ERR, "Can't send reply");
		return;
	case RPCNFSUSERD_GETUSER:
		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
		    (caddr_t)&info)) {
			svcerr_decode(transp);
			return;
		}
		pwd = getpwnam(info.name);
		info.retval = 0;
		if (pwd != NULL) {
			nid.nid_usertimeout = defusertimeout;
			nid.nid_uid = pwd->pw_uid;
			nid.nid_name = pwd->pw_name;
		} else {
			nid.nid_usertimeout = 5;
			nid.nid_uid = defaultuid;
			nid.nid_name = info.name;
		}
		nid.nid_namelen = strlen(nid.nid_name);
		nid.nid_flag = NFSID_ADDUSERNAME;
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error) {
			info.retval = error;
			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
		} else if (verbose) {
			syslog(LOG_ERR,"Added uid=%d name=%s\n",
			    nid.nid_uid, nid.nid_name);
		}
		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
		    (caddr_t)&info))
			syslog(LOG_ERR, "Can't send reply");
		return;
	case RPCNFSUSERD_GETGROUP:
		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
		    (caddr_t)&info)) {
			svcerr_decode(transp);
			return;
		}
		grp = getgrnam(info.name);
		info.retval = 0;
		if (grp != NULL) {
			nid.nid_usertimeout = defusertimeout;
			nid.nid_gid = grp->gr_gid;
			nid.nid_name = grp->gr_name;
		} else {
			nid.nid_usertimeout = 5;
			nid.nid_gid = defaultgid;
			nid.nid_name = info.name;
		}
		nid.nid_namelen = strlen(nid.nid_name);
		nid.nid_flag = NFSID_ADDGROUPNAME;
		error = nfssvc(NFSSVC_IDNAME, &nid);
		if (error) {
			info.retval = error;
			syslog(LOG_ERR, "Can't add group %s\n",
			    grp->gr_name);
		} else if (verbose) {
			syslog(LOG_ERR,"Added gid=%d name=%s\n",
			    nid.nid_gid, nid.nid_name);
		}
		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
		    (caddr_t)&info))
			syslog(LOG_ERR, "Can't send reply");
		return;
	default:
		svcerr_noproc(transp);
		return;
	};
}
Пример #12
0
/*
 * Nfs server daemon mostly just a user context for nfssvc()
 *
 * 1 - do file descriptor and signal cleanup
 * 2 - create the nfsd thread(s)
 * 3 - create server socket(s)
 * 4 - register socket with portmap
 *
 * For connectionless protocols, just pass the socket into the kernel via
 * nfssvc().
 * For connection based sockets, loop doing accepts. When you get a new
 * socket from accept, pass the msgsock into the kernel via nfssvc().
 * The arguments are:
 *	-r - reregister with portmapper
 *	-t - support only tcp nfs clients
 *	-u - support only udp nfs clients
 *	-n num how many threads to create.
 *	-4 - use only ipv4
 *	-6 - use only ipv6
 */
int
main(int argc, char *argv[])
{
	struct conf cfg[4];
	struct pollfd set[__arraycount(cfg)];
	int ch, connect_type_cnt;
	size_t i, nfsdcnt;
	int reregister;
	int tcpflag, udpflag;
	int ip6flag, ip4flag;
	int s, compat;
	int parent_fd = -1;
	pthread_t *workers;

#define	DEFNFSDCNT	 4
	nfsdcnt = DEFNFSDCNT;
	compat = reregister = 0;
	tcpflag = udpflag = 1;
	ip6flag = ip4flag = 1;
#define	GETOPT	"46dn:rtu"
#define	USAGE	"[-46drtu] [-n num_servers]"
	while ((ch = getopt(argc, argv, GETOPT)) != -1) {
		switch (ch) {
		case '6':
			ip6flag = 1;
			ip4flag = 0;
			s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
			if (s < 0 && (errno == EPROTONOSUPPORT ||
			    errno == EPFNOSUPPORT || errno == EAFNOSUPPORT))
				ip6flag = 0;
			else
				close(s);
			break;
		case '4':
			ip6flag = 0;
			ip4flag = 1;
			s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
			if (s < 0 && (errno == EPROTONOSUPPORT ||
			    errno == EPFNOSUPPORT || errno == EAFNOSUPPORT))
				ip4flag = 0;
			else
				close(s);
			break;
		case 'd':
			debug++;
			break;
		case 'n':
			nfsdcnt = atoi(optarg);
			if (nfsdcnt < 1) {
				warnx("nfsd count %zu; reset to %d", nfsdcnt,
				    DEFNFSDCNT);
				nfsdcnt = DEFNFSDCNT;
			}
			break;
		case 'r':
			reregister = 1;
			break;
		case 't':
			compat |= 2;
			tcpflag = 1;
			udpflag = 0;
			break;
		case 'u':
			compat |= 1;
			tcpflag = 0;
			udpflag = 1;
			break;
		default:
		case '?':
			usage();
		}
	}
	argv += optind;
	argc -= optind;

	if (compat == 3) {
		warnx("Old -tu options detected; enabling both udp and tcp.");
		warnx("This is the default behavior now and you can remove");
		warnx("all options.");
		tcpflag = udpflag = 1;
		if (ip6flag == 1 && ip4flag == 0)
			ip4flag = 1;
	}

	if (debug == 0) {
		parent_fd = daemon2_fork();
		if (parent_fd == -1)
			logit(LOG_ERR, "daemon2_fork failed");
		openlog("nfsd", LOG_PID, LOG_DAEMON);
	}


	memset(cfg, 0, sizeof(cfg));
	for (i = 0; i < __arraycount(cfg); i++) {
		if (ip4flag == 0 && cfg_family[i] == PF_INET)
			continue;
		if (ip6flag == 0 && cfg_family[i] == PF_INET6)
			continue;
		if (tcpflag == 0 && cfg_protocol[i] == IPPROTO_TCP)
			continue;
		if (udpflag == 0 && cfg_protocol[i] == IPPROTO_UDP)
			continue;
		tryconf(&cfg[i], i, reregister);
	}

	workers = calloc(nfsdcnt, sizeof(*workers));
	if (workers == NULL) {
		logit(LOG_ERR, "thread alloc %s", strerror(errno));
		exit(1);
	}

	for (i = 0; i < nfsdcnt; i++) {
		int error;

		error = pthread_create(&workers[i], NULL, worker, NULL);
		if (error) {
			errno = error;
			logit(LOG_ERR, "pthread_create: %s", strerror(errno));
			exit(1);
		}
	}

	connect_type_cnt = 0;
	for (i = 0; i < __arraycount(cfg); i++) {
		set[i].fd = -1;
		set[i].events = POLLIN;
		set[i].revents = 0;

		if (cfg[i].nc == NULL)
			continue;

		setupsock(&cfg[i], &set[i], i);
		if (set[i].fd != -1)
			connect_type_cnt++;

	}

	pthread_setname_np(pthread_self(), "master", NULL);

	if (debug == 0) {
		daemon2_detach(parent_fd, 0, 0);
		(void)signal(SIGHUP, SIG_IGN);
		(void)signal(SIGINT, SIG_IGN);
		(void)signal(SIGQUIT, SIG_IGN);
		(void)signal(SIGSYS, nonfs);
	}

	if (connect_type_cnt == 0) {
		for (i = 0; i < nfsdcnt; i++)
			    pthread_join(workers[i], NULL);
		exit(0);
	}

	/*
	 * Loop forever accepting connections and passing the sockets
	 * into the kernel for the mounts.
	 */
	for (;;) {
		if (poll(set, __arraycount(set), INFTIM) == -1) {
			logit(LOG_ERR, "poll failed: %s", strerror(errno));
			exit(1);
		}

		for (i = 0; i < __arraycount(set); i++) {
			struct nfsd_args nfsdargs;
			struct sockaddr_storage ss;
			socklen_t len;
			int msgsock;
			int on = 1;

			if ((set[i].revents & POLLIN) == 0)
				continue;
			len = sizeof(ss);
			if ((msgsock = accept(set[i].fd,
			    (struct sockaddr *)&ss, &len)) == -1) {
				int serrno = errno;
				logit(LOG_ERR, "accept failed: %s",
				    strerror(errno));
				if (serrno == EINTR || serrno == ECONNABORTED)
					continue;
				exit(1);
			}
			if (setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE, &on,
			    sizeof(on)) == -1)
				logit(LOG_ERR, "setsockopt SO_KEEPALIVE: %s",
				    strerror(errno));
			nfsdargs.sock = msgsock;
			nfsdargs.name = (void *)&ss;
			nfsdargs.namelen = len;
			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
			(void)close(msgsock);
		}
	}
}
Пример #13
0
static int
setupsock(struct conf *cfg, struct pollfd *set, int p)
{
	int sock;
	struct nfsd_args nfsdargs;
	struct addrinfo *ai = cfg->ai;
	int on = 1;

	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);

	if (sock == -1) {
		logit(LOG_ERR, "can't create %s socket: %s", cfg_netconf[p],
		    strerror(errno));
		return -1;
	}
	if (cfg_family[p] == PF_INET6) {
		if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on,
		    sizeof(on)) == -1) {
			logit(LOG_ERR, "can't set v6-only binding for %s "
			    "socket: %s", cfg_netconf[p], strerror(errno));
			goto out;
		}
	}

	if (cfg_protocol[p] == IPPROTO_TCP) {
		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on,
		    sizeof(on)) == -1) {
			logit(LOG_ERR, "setsockopt SO_REUSEADDR for %s: %s",
			    cfg_netconf[p], strerror(errno));
			goto out;
		}
	}

	if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
		logit(LOG_ERR, "can't bind %s addr: %s", cfg_netconf[p],
		    strerror(errno));
		goto out;
	}

	if (cfg_protocol[p] == IPPROTO_TCP) {
		if (listen(sock, 5) == -1) {
			logit(LOG_ERR, "listen failed");
			goto out;
		}
	}

	if (!rpcb_set(RPCPROG_NFS, 2, cfg->nc, &cfg->nb) ||
	    !rpcb_set(RPCPROG_NFS, 3, cfg->nc, &cfg->nb)) {
		logit(LOG_ERR, "can't register with %s portmap",
		    cfg_netconf[p]);
		goto out;
	}


	if (cfg_protocol[p] == IPPROTO_TCP)
		set->fd = sock;
	else {
		nfsdargs.sock = sock;
		nfsdargs.name = NULL;
		nfsdargs.namelen = 0;
		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
			logit(LOG_ERR, "can't add %s socket: %s",
			    cfg_netconf[p], strerror(errno));
			goto out;
		}
		(void)close(sock);
	}
	return 0;
out:
	(void)close(sock);
	return -1;
}
Пример #14
0
/*
 * Print a description of the nfs stats for the experimental client/server.
 */
void
exp_intpr(int clientOnly, int serverOnly)
{
	int nfssvc_flag;

	nfssvc_flag = NFSSVC_GETSTATS;
	if (zflag != 0) {
		if (clientOnly != 0)
			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
		if (serverOnly != 0)
			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
	}
	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
		err(1, "Can't get stats");
	if (clientOnly != 0) {
		if (printtitle) {
			printf("Client Info:\n");
			printf("Rpc Counts:\n");
			printf(
			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
			    , "Getattr", "Setattr", "Lookup", "Readlink",
			    "Read", "Write", "Create", "Remove");
		}
		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.rpccnt[NFSPROC_GETATTR],
		    ext_nfsstats.rpccnt[NFSPROC_SETATTR],
		    ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
		    ext_nfsstats.rpccnt[NFSPROC_READLINK],
		    ext_nfsstats.rpccnt[NFSPROC_READ],
		    ext_nfsstats.rpccnt[NFSPROC_WRITE],
		    ext_nfsstats.rpccnt[NFSPROC_CREATE],
		    ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
		if (printtitle)
			printf(
			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
			    , "Rename", "Link", "Symlink", "Mkdir", "Rmdir",
			    "Readdir", "RdirPlus", "Access");
		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.rpccnt[NFSPROC_RENAME],
		    ext_nfsstats.rpccnt[NFSPROC_LINK],
		    ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
		    ext_nfsstats.rpccnt[NFSPROC_MKDIR],
		    ext_nfsstats.rpccnt[NFSPROC_RMDIR],
		    ext_nfsstats.rpccnt[NFSPROC_READDIR],
		    ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
		    ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
		if (printtitle)
			printf(
			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
			    , "Mknod", "Fsstat", "Fsinfo", "PathConf",
			    "Commit", "SetClId", "SetClIdCf", "Lock");
		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.rpccnt[NFSPROC_MKNOD],
		    ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
		    ext_nfsstats.rpccnt[NFSPROC_FSINFO],
		    ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
		    ext_nfsstats.rpccnt[NFSPROC_COMMIT],
		    ext_nfsstats.rpccnt[NFSPROC_SETCLIENTID],
		    ext_nfsstats.rpccnt[NFSPROC_SETCLIENTIDCFRM],
		    ext_nfsstats.rpccnt[NFSPROC_LOCK]);
		if (printtitle)
			printf("%9.9s %9.9s %9.9s %9.9s\n",
			    "LockT", "LockU", "Open", "OpenCfr");
		printf("%9d %9d %9d %9d\n",
		    ext_nfsstats.rpccnt[NFSPROC_LOCKT],
		    ext_nfsstats.rpccnt[NFSPROC_LOCKU],
		    ext_nfsstats.rpccnt[NFSPROC_OPEN],
		    ext_nfsstats.rpccnt[NFSPROC_OPENCONFIRM]);
		if (printtitle)
			printf(
			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
			    , "OpenOwner", "Opens", "LockOwner",
			    "Locks", "Delegs", "LocalOwn",
			    "LocalOpen", "LocalLOwn");
		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.clopenowners,
		    ext_nfsstats.clopens,
		    ext_nfsstats.cllockowners,
		    ext_nfsstats.cllocks,
		    ext_nfsstats.cldelegates,
		    ext_nfsstats.cllocalopenowners,
		    ext_nfsstats.cllocalopens,
		    ext_nfsstats.cllocallockowners);
		if (printtitle)
			printf("%9.9s\n", "LocalLock");
		printf("%9d\n", ext_nfsstats.cllocallocks);
		if (printtitle) {
			printf("Rpc Info:\n");
			printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
			    "TimedOut", "Invalid", "X Replies", "Retries",
			    "Requests");
		}
		printf("%9d %9d %9d %9d %9d\n",
		    ext_nfsstats.rpctimeouts,
		    ext_nfsstats.rpcinvalid,
		    ext_nfsstats.rpcunexpected,
		    ext_nfsstats.rpcretries,
		    ext_nfsstats.rpcrequests);
		if (printtitle) {
			printf("Cache Info:\n");
			printf("%9.9s %9.9s %9.9s %9.9s",
			    "Attr Hits", "Misses", "Lkup Hits", "Misses");
			printf(" %9.9s %9.9s %9.9s %9.9s\n",
			    "BioR Hits", "Misses", "BioW Hits", "Misses");
		}
		printf("%9d %9d %9d %9d",
		    ext_nfsstats.attrcache_hits,
		    ext_nfsstats.attrcache_misses,
		    ext_nfsstats.lookupcache_hits,
		    ext_nfsstats.lookupcache_misses);
		printf(" %9d %9d %9d %9d\n",
		    ext_nfsstats.biocache_reads - ext_nfsstats.read_bios,
		    ext_nfsstats.read_bios,
		    ext_nfsstats.biocache_writes - ext_nfsstats.write_bios,
		    ext_nfsstats.write_bios);
		if (printtitle) {
			printf("%9.9s %9.9s %9.9s %9.9s",
			    "BioRLHits", "Misses", "BioD Hits", "Misses");
			printf(" %9.9s %9.9s\n", "DirE Hits", "Misses");
		}
		printf("%9d %9d %9d %9d",
		    ext_nfsstats.biocache_readlinks -
		    ext_nfsstats.readlink_bios,
		    ext_nfsstats.readlink_bios,
		    ext_nfsstats.biocache_readdirs -
		    ext_nfsstats.readdir_bios,
		    ext_nfsstats.readdir_bios);
		printf(" %9d %9d\n",
		    ext_nfsstats.direofcache_hits,
		    ext_nfsstats.direofcache_misses);
	}
	if (serverOnly != 0) {
		if (printtitle) {
			printf("\nServer Info:\n");
			printf(
			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
			    , "Getattr", "Setattr", "Lookup", "Readlink",
			    "Read", "Write", "Create", "Remove");
		}
		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
		    ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
		    ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
		    ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
		    ext_nfsstats.srvrpccnt[NFSV4OP_READ],
		    ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
		    ext_nfsstats.srvrpccnt[NFSV4OP_V3CREATE],
		    ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
		if (printtitle)
			printf(
			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
			    , "Rename", "Link", "Symlink", "Mkdir", "Rmdir",
			    "Readdir", "RdirPlus", "Access");
		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
		    ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
		    ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
		    ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
		    ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
		    ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
		    ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
		    ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
		if (printtitle)
			printf(
			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
			    , "Mknod", "Fsstat", "Fsinfo", "PathConf",
			    "Commit", "LookupP", "SetClId", "SetClIdCf");
		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
		    ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
		    ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
		    ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
		    ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT],
		    ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUPP],
		    ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTID],
		    ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTIDCFRM]);
		if (printtitle)
			printf(
			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
			    , "Open", "OpenAttr", "OpenDwnGr", "OpenCfrm",
			    "DelePurge", "DeleRet", "GetFH", "Lock");
		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.srvrpccnt[NFSV4OP_OPEN],
		    ext_nfsstats.srvrpccnt[NFSV4OP_OPENATTR],
		    ext_nfsstats.srvrpccnt[NFSV4OP_OPENDOWNGRADE],
		    ext_nfsstats.srvrpccnt[NFSV4OP_OPENCONFIRM],
		    ext_nfsstats.srvrpccnt[NFSV4OP_DELEGPURGE],
		    ext_nfsstats.srvrpccnt[NFSV4OP_DELEGRETURN],
		    ext_nfsstats.srvrpccnt[NFSV4OP_GETFH],
		    ext_nfsstats.srvrpccnt[NFSV4OP_LOCK]);
		if (printtitle)
			printf(
			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
			    , "LockT", "LockU", "Close", "Verify", "NVerify",
			    "PutFH", "PutPubFH", "PutRootFH");
		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.srvrpccnt[NFSV4OP_LOCKT],
		    ext_nfsstats.srvrpccnt[NFSV4OP_LOCKU],
		    ext_nfsstats.srvrpccnt[NFSV4OP_CLOSE],
		    ext_nfsstats.srvrpccnt[NFSV4OP_VERIFY],
		    ext_nfsstats.srvrpccnt[NFSV4OP_NVERIFY],
		    ext_nfsstats.srvrpccnt[NFSV4OP_PUTFH],
		    ext_nfsstats.srvrpccnt[NFSV4OP_PUTPUBFH],
		    ext_nfsstats.srvrpccnt[NFSV4OP_PUTROOTFH]);
		if (printtitle)
			printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
			    "Renew", "RestoreFH", "SaveFH", "Secinfo",
			    "RelLckOwn", "V4Create");
		printf("%9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.srvrpccnt[NFSV4OP_RENEW],
		    ext_nfsstats.srvrpccnt[NFSV4OP_RESTOREFH],
		    ext_nfsstats.srvrpccnt[NFSV4OP_SAVEFH],
		    ext_nfsstats.srvrpccnt[NFSV4OP_SECINFO],
		    ext_nfsstats.srvrpccnt[NFSV4OP_RELEASELCKOWN],
		    ext_nfsstats.srvrpccnt[NFSV4OP_CREATE]);
		if (printtitle) {
			printf("Server:\n");
			printf("%9.9s %9.9s %9.9s\n",
			    "Retfailed", "Faults", "Clients");
		}
		printf("%9d %9d %9d\n",
		    ext_nfsstats.srv_errs, ext_nfsstats.srvrpc_errs,
		    ext_nfsstats.srvclients);
		if (printtitle)
			printf("%9.9s %9.9s %9.9s %9.9s %9.9s \n",
			    "OpenOwner", "Opens", "LockOwner",
			    "Locks", "Delegs");
		printf("%9d %9d %9d %9d %9d \n",
		    ext_nfsstats.srvopenowners,
		    ext_nfsstats.srvopens,
		    ext_nfsstats.srvlockowners,
		    ext_nfsstats.srvlocks,
		    ext_nfsstats.srvdelegates);
		if (printtitle) {
			printf("Server Cache Stats:\n");
			printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
			    "Inprog", "Idem", "Non-idem", "Misses", 
			    "CacheSize", "TCPPeak");
		}
		printf("%9d %9d %9d %9d %9d %9d\n",
		    ext_nfsstats.srvcache_inproghits,
		    ext_nfsstats.srvcache_idemdonehits,
		    ext_nfsstats.srvcache_nonidemdonehits,
		    ext_nfsstats.srvcache_misses,
		    ext_nfsstats.srvcache_size,
		    ext_nfsstats.srvcache_tcppeak);
	}
}
Пример #15
0
/*
 * Print a description of the nfs stats.
 */
static void
intpr(int clientOnly, int serverOnly)
{
	int nfssvc_flag;

	nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
	if (zflag != 0) {
		if (clientOnly != 0)
			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
		if (serverOnly != 0)
			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
	}
	ext_nfsstats.vers = NFSSTATS_V1;
	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
		xo_err(1, "Can't get stats");
	if (clientOnly) {
		xo_open_container("clientstats");

		if (printtitle)
			xo_emit("{T:Client Info:\n");

		xo_open_container("operations");
		xo_emit("{T:Rpc Counts:}\n");

		xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}"
		    "{T:Lookup/%13.13s}{T:Readlink/%13.13s}"
		    "{T:Read/%13.13s}{T:Write/%13.13s}"
		  "{T:Create/%13.13s}{T:Remove/%13.13s}\n");
		xo_emit("{:getattr/%13ju}{:setattr/%13ju}"
		    "{:lookup/%13ju}{:readlink/%13ju}"
		    "{:read/%13ju}{:write/%13ju}"
		    "{:create/%13ju}{:remove/%13ju}\n",
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE]);

		xo_emit("{T:Rename/%13.13s}{T:Link/%13.13s}"
		    "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}"
		    "{T:Rmdir/%13.13s}{T:Readdir/%13.13s}"
		  "{T:RdirPlus/%13.13s}{T:Access/%13.13s}\n");
		xo_emit("{:rename/%13ju}{:link/%13ju}"
		    "{:symlink/%13ju}{:mkdir/%13ju}"
		    "{:rmdir/%13ju}{:readdir/%13ju}"
		    "{:rdirplus/%13ju}{:access/%13ju}\n",
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS]);

		xo_emit("{T:Mknod/%13.13s}{T:Fsstat/%13.13s}"
		    "{T:Fsinfo/%13.13s}{T:PathConf/%13.13s}"
		    "{T:Commit/%13.13s}\n");
		xo_emit("{:mknod/%13ju}{:fsstat/%13ju}"
		    "{:fsinfo/%13ju}{:pathconf/%13ju}"
		    "{:commit/%13ju}\n",
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
			(uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT]);

		xo_close_container("operations");

		xo_open_container("rpcs");
		xo_emit("{T:Rpc Info:}\n");

		xo_emit("{T:TimedOut/%13.13s}{T:Invalid/%13.13s}"
		    "{T:X Replies/%13.13s}{T:Retries/%13.13s}"
		    "{T:Requests/%13.13s}\n");
		xo_emit("{:timedout/%13ju}{:invalid/%13ju}"
		    "{:xreplies/%13ju}{:retries/%13ju}"
		    "{:requests/%13ju}\n",
			(uintmax_t)ext_nfsstats.rpctimeouts,
			(uintmax_t)ext_nfsstats.rpcinvalid,
			(uintmax_t)ext_nfsstats.rpcunexpected,
			(uintmax_t)ext_nfsstats.rpcretries,
			(uintmax_t)ext_nfsstats.rpcrequests);
		xo_close_container("rpcs");

		xo_open_container("cache");
		xo_emit("{T:Cache Info:}\n");

		xo_emit("{T:Attr Hits/%13.13s}{T:Attr Misses/%13.13s}"
		    "{T:Lkup Hits/%13.13s}{T:Lkup Misses/%13.13s}"
		    "{T:BioR Hits/%13.13s}{T:BioR Misses/%13.13s}"
		    "{T:BioW Hits/%13.13s}{T:BioW Misses/%13.13s}\n");
		xo_emit("{:attrhits/%13ju}{:attrmisses/%13ju}"
		    "{:lkuphits/%13ju}{:lkupmisses/%13ju}"
		    "{:biorhits/%13ju}{:biormisses/%13ju}"
		    "{:biowhits/%13ju}{:biowmisses/%13ju}\n",
		    (uintmax_t)ext_nfsstats.attrcache_hits,
		    (uintmax_t)ext_nfsstats.attrcache_misses,
		    (uintmax_t)ext_nfsstats.lookupcache_hits,
		    (uintmax_t)ext_nfsstats.lookupcache_misses,
		    (uintmax_t)(ext_nfsstats.biocache_reads -
		    ext_nfsstats.read_bios),
		    (uintmax_t)ext_nfsstats.read_bios,
		    (uintmax_t)(ext_nfsstats.biocache_writes -
		    ext_nfsstats.write_bios),
		    (uintmax_t)ext_nfsstats.write_bios);

		xo_emit("{T:BioRL Hits/%13.13s}{T:BioRL Misses/%13.13s}"
		    "{T:BioD Hits/%13.13s}{T:BioD Misses/%13.13s}"
		    "{T:DirE Hits/%13.13s}{T:DirE Misses/%13.13s}"
		    "{T:Accs Hits/%13.13s}{T:Accs Misses/%13.13s}\n");
		xo_emit("{:biosrlhits/%13ju}{:biorlmisses/%13ju}"
		    "{:biodhits/%13ju}{:biodmisses/%13ju}"
		    "{:direhits/%13ju}{:diremisses/%13ju}"
		    "{:accshits/%13ju}{:accsmisses/%13ju}\n",
		    (uintmax_t)(ext_nfsstats.biocache_readlinks -
		    ext_nfsstats.readlink_bios),
		    (uintmax_t)ext_nfsstats.readlink_bios,
		    (uintmax_t)(ext_nfsstats.biocache_readdirs -
		    ext_nfsstats.readdir_bios),
		    (uintmax_t)ext_nfsstats.readdir_bios,
		    (uintmax_t)ext_nfsstats.direofcache_hits,
		    (uintmax_t)ext_nfsstats.direofcache_misses,
		    (uintmax_t)ext_nfsstats.accesscache_hits,
		    (uintmax_t)ext_nfsstats.accesscache_misses);

		xo_close_container("cache");

		xo_close_container("clientstats");
	}
	if (serverOnly) {
		xo_open_container("serverstats");

		xo_emit("{T:Server Info:}\n");
		xo_open_container("operations");

		xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}"
		    "{T:Lookup/%13.13s}{T:Readlink/%13.13s}"
		    "{T:Read/%13.13s}{T:Write/%13.13s}"
		    "{T:Create/%13.13s}{T:Remove/%13.13s}\n");
		xo_emit("{:getattr/%13ju}{:setattr/%13ju}"
		    "{:lookup/%13ju}{:readlink/%13ju}"
		    "{:read/%13ju}{:write/%13ju}"
		    "{:create/%13ju}{:remove/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);

		xo_emit("{T:Rename/%13.13s}{T:Link/%13.13s}"
		    "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}"
		    "{T:Rmdir/%13.13s}{T:Readdir/%13.13s}"
		    "{T:RdirPlus/%13.13s}{T:Access/%13.13s}\n");
		xo_emit("{:rename/%13ju}{:link/%13ju}"
		    "{:symlink/%13ju}{:mkdir/%13ju}"
		    "{:rmdir/%13ju}{:readdir/%13ju}"
		    "{:rdirplus/%13ju}{:access/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);

		xo_emit("{T:Mknod/%13.13s}{T:Fsstat/%13.13s}"
		    "{T:Fsinfo/%13.13s}{T:PathConf/%13.13s}"
		    "{T:Commit/%13.13s}\n");
		xo_emit("{:mknod/%13ju}{:fsstat/%13ju}"
		    "{:fsinfo/%13ju}{:pathconf/%13ju}"
		    "{:commit/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT]);

		xo_close_container("operations");

		xo_open_container("server");
		xo_emit("{T:Server Re-Failed:}\n");
		xo_emit("{T:retfailed/%17ju}\n", (uintmax_t)ext_nfsstats.srvrpc_errs);

		xo_emit("{T:Server Faults:}\n");
		xo_emit("{T:faults/%13ju}\n", (uintmax_t)ext_nfsstats.srv_errs);

		xo_emit("{T:Server Write Gathering:/%13.13s}\n");

		xo_emit("{T:WriteOps/%13.13s}{T:WriteRPC/%13.13s}"
		    "{T:Opsaved/%13.13s}\n");
		xo_emit("{:writeops/%13ju}{:writerpc/%13ju}"
		    "{:opsaved/%13ju}\n",
		/*
		 * The new client doesn't do write gathering. It was
		 * only useful for NFSv2.
		 */
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 0);

		xo_close_container("server");

		xo_open_container("cache");
		xo_emit("{T:Server Cache Stats:/%13.13s}\n");
		xo_emit("{T:Inprog/%13.13s}{T:Idem/%13.13s}"
		    "{T:Non-Idem/%13.13s}{T:Misses/%13.13s}\n");
		xo_emit("{:inprog/%13ju}{:idem/%13ju}"
		    "{:nonidem/%13ju}{:misses/%13ju}\n",
			(uintmax_t)ext_nfsstats.srvcache_inproghits,
			(uintmax_t)ext_nfsstats.srvcache_idemdonehits,
			(uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
			(uintmax_t)ext_nfsstats.srvcache_misses);
		xo_close_container("cache");

		xo_close_container("serverstats");
	}
}
Пример #16
0
/*
 * Print a running summary of nfs statistics for the experimental client and/or
 * server.
 * Repeat display every interval seconds, showing statistics
 * collected over that interval.  Assumes that interval is non-zero.
 * First line printed at top of screen is always cumulative.
 */
static void
exp_sidewaysintpr(u_int interval, int clientOnly, int serverOnly,
    int newStats)
{
	struct nfsstatsv1 nfsstats, lastst, *ext_nfsstatsp;
	struct nfsstatsv1 curtotal, lasttotal;
	struct timespec ts, lastts;
	int hdrcnt = 1;

	ext_nfsstatsp = &lastst;
	ext_nfsstatsp->vers = NFSSTATS_V1;
	if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp) < 0)
		err(1, "Can't get stats");
	clock_gettime(CLOCK_MONOTONIC, &lastts);
	compute_totals(&lasttotal, ext_nfsstatsp);
	sleep(interval);

	for (;;) {
		ext_nfsstatsp = &nfsstats;
		ext_nfsstatsp->vers = NFSSTATS_V1;
		if (nfssvc(NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT, ext_nfsstatsp)
		    < 0)
			err(1, "Can't get stats");
		clock_gettime(CLOCK_MONOTONIC, &ts);

		if (--hdrcnt == 0) {
			printhdr(clientOnly, serverOnly, newStats);
			if (newStats)
				hdrcnt = 20;
			else if (clientOnly && serverOnly)
				hdrcnt = 10;
			else
				hdrcnt = 20;
		}
		if (clientOnly && newStats == 0) {
		    printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju",
			((clientOnly && serverOnly) ? "Client:" : ""),
			(uintmax_t)DELTA(rpccnt[NFSPROC_GETATTR]),
			(uintmax_t)DELTA(rpccnt[NFSPROC_LOOKUP]),
			(uintmax_t)DELTA(rpccnt[NFSPROC_READLINK]),
			(uintmax_t)DELTA(rpccnt[NFSPROC_READ]),
			(uintmax_t)DELTA(rpccnt[NFSPROC_WRITE]),
			(uintmax_t)DELTA(rpccnt[NFSPROC_RENAME]),
			(uintmax_t)DELTA(rpccnt[NFSPROC_ACCESS]),
			(uintmax_t)(DELTA(rpccnt[NFSPROC_READDIR]) +
			DELTA(rpccnt[NFSPROC_READDIRPLUS]))
		    );
		    if (widemode) {
			    printf(" %s %s %s %s %s %s",
				sperc1(DELTA(attrcache_hits),
				    DELTA(attrcache_misses)),
				sperc1(DELTA(lookupcache_hits), 
				    DELTA(lookupcache_misses)),
				sperc2(DELTA(biocache_reads),
				    DELTA(read_bios)),
				sperc2(DELTA(biocache_writes),
				    DELTA(write_bios)),
				sperc1(DELTA(accesscache_hits),
				    DELTA(accesscache_misses)),
				sperc2(DELTA(biocache_readdirs),
				    DELTA(readdir_bios))
			    );
		    }
		    printf("\n");
		}

		if (serverOnly && newStats) {
			long double cur_secs, last_secs, etime;
			long double mbsec;
			long double kb_per_transfer;
			long double transfers_per_second;
			long double ms_per_transfer;
			uint64_t queue_len;
			long double busy_pct;
			int i;

			cur_secs = ts.tv_sec +
			    ((long double)ts.tv_nsec / 1000000000);
			last_secs = lastts.tv_sec +
			    ((long double)lastts.tv_nsec / 1000000000);
			etime = cur_secs - last_secs;

			compute_totals(&curtotal, &nfsstats);

			for (i = 0; i < NUM_STAT_TYPES; i++) {
				compute_new_stats(&nfsstats, &lastst,
				    STAT_TYPE_TO_NFS(i), etime, &mbsec,
				    &kb_per_transfer,
				    &transfers_per_second,
				    &ms_per_transfer, &queue_len,
				    &busy_pct);

				if (i == STAT_TYPE_COMMIT) {
					if (widemode == 0)
						continue;

					printf("%2.0Lf %7.2Lf ",
					    transfers_per_second,
					    ms_per_transfer);
				} else {
					printf("%5.2Lf %5.0Lf %7.2Lf ",
					    kb_per_transfer,
					    transfers_per_second, mbsec);
					if (widemode)
						printf("%5.2Lf ",
						    ms_per_transfer);
				}
			}

			compute_new_stats(&curtotal, &lasttotal, 0, etime,
			    &mbsec, &kb_per_transfer, &transfers_per_second,
			    &ms_per_transfer, &queue_len, &busy_pct);

			printf("%5.2Lf %5.0Lf %7.2Lf %5.2Lf %3ju %3.0Lf\n",
			    kb_per_transfer, transfers_per_second, mbsec,
			    ms_per_transfer, queue_len, busy_pct);
		} else if (serverOnly) {
		    printf("%s %6ju %6ju %6ju %6ju %6ju %6ju %6ju %6ju",
			((clientOnly && serverOnly) ? "Server:" : ""),
			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_GETATTR]),
			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_LOOKUP]),
			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_READLINK]),
			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_READ]),
			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_WRITE]),
			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_RENAME]),
			(uintmax_t)DELTA(srvrpccnt[NFSV4OP_ACCESS]),
			(uintmax_t)(DELTA(srvrpccnt[NFSV4OP_READDIR]) +
			DELTA(srvrpccnt[NFSV4OP_READDIRPLUS])));
		    printf("\n");
		}
		bcopy(&nfsstats, &lastst, sizeof(lastst));
		bcopy(&curtotal, &lasttotal, sizeof(lasttotal));
		lastts = ts;
		fflush(stdout);
		sleep(interval);
	}
	/*NOTREACHED*/
}
Пример #17
0
/*
 * Nfs server daemon mostly just a user context for nfssvc()
 *
 * 1 - do file descriptor and signal cleanup
 * 2 - fork the nfsd(s)
 * 3 - create server socket(s)
 * 4 - register socket with rpcbind
 *
 * For connectionless protocols, just pass the socket into the kernel via.
 * nfssvc().
 * For connection based sockets, loop doing accepts. When you get a new
 * socket from accept, pass the msgsock into the kernel via. nfssvc().
 * The arguments are:
 *	-r - reregister with rpcbind
 *	-d - unregister with rpcbind
 *	-t - support tcp nfs clients
 *	-u - support udp nfs clients
 * followed by "n" which is the number of nfsds' to fork off
 */
int
main(int argc, char **argv)
{
	struct nfsd_args nfsdargs;
	struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
	struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
	struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
	struct sockaddr_in inetpeer;
	struct sockaddr_in6 inet6peer;
	fd_set ready, sockbits;
	fd_set v4bits, v6bits;
	int ch, connect_type_cnt, i, maxsock, msgsock;
	socklen_t len;
	int on = 1, unregister, reregister, sock;
	int tcp6sock, ip6flag, tcpflag, tcpsock;
	int udpflag, ecode, s, srvcnt;
	int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
	char **bindhost = NULL;
	pid_t pid;
	struct vfsconf vfc;
	int error;

	error = getvfsbyname("nfs", &vfc);
	if (error && vfsisloadable("nfs")) {
		if (vfsload("nfs"))
			err(1, "vfsload(nfs)");
		endvfsent();	/* flush cache */
		error = getvfsbyname("nfs", &vfc);
	}
	if (error)
		errx(1, "NFS is not available in the running kernel");

	nfsdcnt = DEFNFSDCNT;
	unregister = reregister = tcpflag = maxsock = 0;
	bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
#define	GETOPT	"ah:n:rdtu"
#define	USAGE	"[-ardtu] [-n num_servers] [-h bindip]"
	while ((ch = getopt(argc, argv, GETOPT)) != -1)
		switch (ch) {
		case 'a':
			bindanyflag = 1;
			break;
		case 'n':
			nfsdcnt = atoi(optarg);
			if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
				warnx("nfsd count %d; reset to %d", nfsdcnt,
				    DEFNFSDCNT);
				nfsdcnt = DEFNFSDCNT;
			}
			break;
		case 'h':
			bindhostc++;
			bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
			if (bindhost == NULL)
				errx(1, "Out of memory");
			bindhost[bindhostc-1] = strdup(optarg);
			if (bindhost[bindhostc-1] == NULL)
				errx(1, "Out of memory");
			break;
		case 'r':
			reregister = 1;
			break;
		case 'd':
			unregister = 1;
			break;
		case 't':
			tcpflag = 1;
			break;
		case 'u':
			udpflag = 1;
			break;
		default:
		case '?':
			usage();
		};
	if (!tcpflag && !udpflag)
		udpflag = 1;
	argv += optind;
	argc -= optind;

	/*
	 * XXX
	 * Backward compatibility, trailing number is the count of daemons.
	 */
	if (argc > 1)
		usage();
	if (argc == 1) {
		nfsdcnt = atoi(argv[0]);
		if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
			warnx("nfsd count %d; reset to %d", nfsdcnt,
			    DEFNFSDCNT);
			nfsdcnt = DEFNFSDCNT;
		}
	}

	ip6flag = 1;
	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
	if (s == -1) {
		if (errno != EPROTONOSUPPORT)
			err(1, "socket");
		ip6flag = 0;
	} else if (getnetconfigent("udp6") == NULL ||
		getnetconfigent("tcp6") == NULL) {
		ip6flag = 0;
	}
	if (s != -1)
		close(s);

	if (bindhostc == 0 || bindanyflag) {
		bindhostc++;
		bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
		if (bindhost == NULL)
			errx(1, "Out of memory");
		bindhost[bindhostc-1] = strdup("*");
		if (bindhost[bindhostc-1] == NULL)
			errx(1, "Out of memory");
	}

	if (unregister) {
		unregistration();
		exit (0);
	}
	if (reregister) {
		if (udpflag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
			if (ecode != 0)
				err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
			nconf_udp = getnetconfigent("udp");
			if (nconf_udp == NULL)
				err(1, "getnetconfigent udp failed");
			nb_udp.buf = ai_udp->ai_addr;
			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
			    (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
				err(1, "rpcb_set udp failed");
			freeaddrinfo(ai_udp);
		}
		if (udpflag && ip6flag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
			if (ecode != 0)
				err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
			nconf_udp6 = getnetconfigent("udp6");
			if (nconf_udp6 == NULL)
				err(1, "getnetconfigent udp6 failed");
			nb_udp6.buf = ai_udp6->ai_addr;
			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
			    (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
				err(1, "rpcb_set udp6 failed");
			freeaddrinfo(ai_udp6);
		}
		if (tcpflag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
			if (ecode != 0)
				err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
			nconf_tcp = getnetconfigent("tcp");
			if (nconf_tcp == NULL)
				err(1, "getnetconfigent tcp failed");
			nb_tcp.buf = ai_tcp->ai_addr;
			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) ||
			    (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)))
				err(1, "rpcb_set tcp failed");
			freeaddrinfo(ai_tcp);
		}
		if (tcpflag && ip6flag) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
			if (ecode != 0)
				err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
			nconf_tcp6 = getnetconfigent("tcp6");
			if (nconf_tcp6 == NULL)
				err(1, "getnetconfigent tcp6 failed");
			nb_tcp6.buf = ai_tcp6->ai_addr;
			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
			    (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
				err(1, "rpcb_set tcp6 failed");
			freeaddrinfo(ai_tcp6);
		}
		exit (0);
	}
	if (debug == 0) {
		daemon(0, 0);
		signal(SIGHUP, SIG_IGN);
		signal(SIGINT, SIG_IGN);
		/*
		 * nfsd sits in the kernel most of the time.  It needs
		 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
		 * as possible during a shutdown, otherwise loopback
		 * mounts will not be able to unmount.
		 */
		signal(SIGTERM, SIG_IGN);
		signal(SIGQUIT, SIG_IGN);
	}
	signal(SIGSYS, nonfs);
	signal(SIGCHLD, reapchild);

	openlog("nfsd", LOG_PID, LOG_DAEMON);

	/* If we use UDP only, we start the last server below. */
	srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1;
	for (i = 0; i < srvcnt; i++) {
		switch ((pid = fork())) {
		case -1:
			syslog(LOG_ERR, "fork: %m");
			nfsd_exit(1);
		case 0:
			break;
		default:
			children[i] = pid;
			continue;
		}
		signal(SIGUSR1, child_cleanup);
		setproctitle("server");

		start_server(0);
	}

	signal(SIGUSR1, cleanup);
	FD_ZERO(&v4bits);
	FD_ZERO(&v6bits);
	FD_ZERO(&sockbits);

	rpcbregcnt = 0;
	/* Set up the socket for udp and rpcb register it. */
	if (udpflag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((sock = socket(ai_udp->ai_family,
				    ai_udp->ai_socktype,
				    ai_udp->ai_protocol)) < 0) {
					syslog(LOG_ERR,
					    "can't create udp socket");
					nfsd_exit(1);
				}
				if (bind(sock, ai_udp->ai_addr,
				    ai_udp->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind udp addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				freeaddrinfo(ai_udp);
				nfsdargs.sock = sock;
				nfsdargs.name = NULL;
				nfsdargs.namelen = 0;
				if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
					syslog(LOG_ERR, "can't Add UDP socket");
					nfsd_exit(1);
				}
				close(sock);
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo udp: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_udp = getnetconfigent("udp");
			if (nconf_udp == NULL)
				err(1, "getnetconfigent udp failed");
			nb_udp.buf = ai_udp->ai_addr;
			nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
			    (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
				err(1, "rpcb_set udp failed");
			freeaddrinfo(ai_udp);
		}
	}

	/* Set up the socket for udp6 and rpcb register it. */
	if (udpflag && ip6flag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((sock = socket(ai_udp6->ai_family,
				    ai_udp6->ai_socktype,
				    ai_udp6->ai_protocol)) < 0) {
					syslog(LOG_ERR,
						"can't create udp6 socket");
					nfsd_exit(1);
				}
				if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
				    &on, sizeof on) < 0) {
					syslog(LOG_ERR,
					    "can't set v6-only binding for "
					    "udp6 socket: %m");
					nfsd_exit(1);
				}
				if (bind(sock, ai_udp6->ai_addr,
				    ai_udp6->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind udp6 addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				freeaddrinfo(ai_udp6);
				nfsdargs.sock = sock;
				nfsdargs.name = NULL;
				nfsdargs.namelen = 0;
				if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
					syslog(LOG_ERR,
					    "can't add UDP6 socket");
					nfsd_exit(1);
				}
				close(sock);
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_DGRAM;
			hints.ai_protocol = IPPROTO_UDP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo udp6: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_udp6 = getnetconfigent("udp6");
			if (nconf_udp6 == NULL)
				err(1, "getnetconfigent udp6 failed");
			nb_udp6.buf = ai_udp6->ai_addr;
			nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
			    (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
				err(1, "rpcb_set udp6 failed");
			freeaddrinfo(ai_udp6);
		}
	}

	/* Set up the socket for tcp and rpcb register it. */
	if (tcpflag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((tcpsock = socket(AF_INET, SOCK_STREAM,
				    0)) < 0) {
					syslog(LOG_ERR,
					    "can't create tpc socket");
					nfsd_exit(1);
				}
				if (setsockopt(tcpsock, SOL_SOCKET,
				    SO_REUSEADDR,
				    (char *)&on, sizeof(on)) < 0)
					syslog(LOG_ERR,
					     "setsockopt SO_REUSEADDR: %m");
				if (bind(tcpsock, ai_tcp->ai_addr,
				    ai_tcp->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind tcp addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				if (listen(tcpsock, 64) < 0) {
					syslog(LOG_ERR, "listen failed");
					nfsd_exit(1);
				}
				freeaddrinfo(ai_tcp);
				FD_SET(tcpsock, &sockbits);
				FD_SET(tcpsock, &v4bits);
				maxsock = tcpsock;
				connect_type_cnt++;
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints,
			     &ai_tcp);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo tcp: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_tcp = getnetconfigent("tcp");
			if (nconf_tcp == NULL)
				err(1, "getnetconfigent tcp failed");
			nb_tcp.buf = ai_tcp->ai_addr;
			nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp,
			    &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3,
			    nconf_tcp, &nb_tcp)))
				err(1, "rpcb_set tcp failed");
			freeaddrinfo(ai_tcp);
		}
	}

	/* Set up the socket for tcp6 and rpcb register it. */
	if (tcpflag && ip6flag) {
		rpcbreg = 0;
		for (i = 0; i < bindhostc; i++) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
				rpcbreg = 1;
				rpcbregcnt++;
				if ((tcp6sock = socket(ai_tcp6->ai_family,
				    ai_tcp6->ai_socktype,
				    ai_tcp6->ai_protocol)) < 0) {
					syslog(LOG_ERR,
					    "can't create tcp6 socket");
					nfsd_exit(1);
				}
				if (setsockopt(tcp6sock, SOL_SOCKET,
				    SO_REUSEADDR,
				    (char *)&on, sizeof(on)) < 0)
					syslog(LOG_ERR,
					    "setsockopt SO_REUSEADDR: %m");
				if (setsockopt(tcp6sock, IPPROTO_IPV6,
				    IPV6_V6ONLY, &on, sizeof on) < 0) {
					syslog(LOG_ERR,
					"can't set v6-only binding for tcp6 "
					    "socket: %m");
					nfsd_exit(1);
				}
				if (bind(tcp6sock, ai_tcp6->ai_addr,
				    ai_tcp6->ai_addrlen) < 0) {
					syslog(LOG_ERR,
					    "can't bind tcp6 addr %s: %m",
					    bindhost[i]);
					nfsd_exit(1);
				}
				if (listen(tcp6sock, 64) < 0) {
					syslog(LOG_ERR, "listen failed");
					nfsd_exit(1);
				}
				freeaddrinfo(ai_tcp6);
				FD_SET(tcp6sock, &sockbits);
				FD_SET(tcp6sock, &v6bits);
				if (maxsock < tcp6sock)
					maxsock = tcp6sock;
				connect_type_cnt++;
			}
		}
		if (rpcbreg == 1) {
			memset(&hints, 0, sizeof hints);
			hints.ai_flags = AI_PASSIVE;
			hints.ai_family = AF_INET6;
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_protocol = IPPROTO_TCP;
			ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
			if (ecode != 0) {
				syslog(LOG_ERR, "getaddrinfo tcp6: %s",
				   gai_strerror(ecode));
				nfsd_exit(1);
			}
			nconf_tcp6 = getnetconfigent("tcp6");
			if (nconf_tcp6 == NULL)
				err(1, "getnetconfigent tcp6 failed");
			nb_tcp6.buf = ai_tcp6->ai_addr;
			nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
			if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
			    (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
				err(1, "rpcb_set tcp6 failed");
			freeaddrinfo(ai_tcp6);
		}
	}

	if (rpcbregcnt == 0) {
		syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
		nfsd_exit(1);
	}

	if (tcpflag && connect_type_cnt == 0) {
		syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
		nfsd_exit(1);
	}

	setproctitle("master");
	/*
	 * We always want a master to have a clean way to to shut nfsd down
	 * (with unregistration): if the master is killed, it unregisters and
	 * kills all children. If we run for UDP only (and so do not have to
	 * loop waiting waiting for accept), we instead make the parent
	 * a "server" too. start_server will not return.
	 */
	if (!tcpflag)
		start_server(1);

	/*
	 * Loop forever accepting connections and passing the sockets
	 * into the kernel for the mounts.
	 */
	for (;;) {
		ready = sockbits;
		if (connect_type_cnt > 1) {
			if (select(maxsock + 1,
			    &ready, NULL, NULL, NULL) < 1) {
				syslog(LOG_ERR, "select failed: %m");
				if (errno == EINTR)
					continue;
				nfsd_exit(1);
			}
		}
		for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
			if (FD_ISSET(tcpsock, &ready)) {
				if (FD_ISSET(tcpsock, &v4bits)) {
					len = sizeof(inetpeer);
					if ((msgsock = accept(tcpsock,
					    (struct sockaddr *)&inetpeer, &len)) < 0) {
						syslog(LOG_ERR, "accept failed: %m");
						if (errno == ECONNABORTED ||
						    errno == EINTR)
							continue;
						nfsd_exit(1);
					}
					memset(inetpeer.sin_zero, 0,
						sizeof(inetpeer.sin_zero));
					if (setsockopt(msgsock, SOL_SOCKET,
					    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
						syslog(LOG_ERR,
						    "setsockopt SO_KEEPALIVE: %m");
					nfsdargs.sock = msgsock;
					nfsdargs.name = (caddr_t)&inetpeer;
					nfsdargs.namelen = len;
					nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
					close(msgsock);
				} else if (FD_ISSET(tcpsock, &v6bits)) {
					len = sizeof(inet6peer);
					if ((msgsock = accept(tcpsock,
					    (struct sockaddr *)&inet6peer,
					    &len)) < 0) {
						syslog(LOG_ERR,
						     "accept failed: %m");
						if (errno == ECONNABORTED ||
						    errno == EINTR)
							continue;
						nfsd_exit(1);
					}
					if (setsockopt(msgsock, SOL_SOCKET,
					    SO_KEEPALIVE, (char *)&on,
					    sizeof(on)) < 0)
						syslog(LOG_ERR, "setsockopt "
						    "SO_KEEPALIVE: %m");
					nfsdargs.sock = msgsock;
					nfsdargs.name = (caddr_t)&inet6peer;
					nfsdargs.namelen = len;
					nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
					close(msgsock);
				}
			}
		}
	}
}
Пример #18
0
int
main(int argc, char *argv[])
{
	int all, errs, ch, mntsize, error, nfsforce, ret;
	char **typelist = NULL;
	struct statfs *mntbuf, *sfs;
	struct addrinfo hints;

	nfsforce = all = errs = 0;
	while ((ch = getopt(argc, argv, "AaF:fh:Nnt:v")) != -1)
		switch (ch) {
		case 'A':
			all = 2;
			break;
		case 'a':
			all = 1;
			break;
		case 'F':
			setfstab(optarg);
			break;
		case 'f':
			fflag |= MNT_FORCE;
			break;
		case 'h':	/* -h implies -A. */
			all = 2;
			nfshost = optarg;
			break;
		case 'N':
			nfsforce = 1;
			break;
		case 'n':
			fflag |= MNT_NONBUSY;
			break;
		case 't':
			if (typelist != NULL)
				err(1, "only one -t option may be specified");
			typelist = makevfslist(optarg);
			break;
		case 'v':
			vflag = 1;
			break;
		default:
			usage();
			/* NOTREACHED */
		}
	argc -= optind;
	argv += optind;

	if ((fflag & MNT_FORCE) != 0 && (fflag & MNT_NONBUSY) != 0)
		err(1, "-f and -n are mutually exclusive");

	/* Start disks transferring immediately. */
	if ((fflag & (MNT_FORCE | MNT_NONBUSY)) == 0 && nfsforce == 0)
		sync();

	if ((argc == 0 && !all) || (argc != 0 && all))
		usage();

	if (nfsforce != 0 && (argc == 0 || nfshost != NULL || typelist != NULL))
		usage();

	/* -h implies "-t nfs" if no -t flag. */
	if ((nfshost != NULL) && (typelist == NULL))
		typelist = makevfslist("nfs");

	if (nfshost != NULL) {
		memset(&hints, 0, sizeof hints);
		error = getaddrinfo(nfshost, NULL, &hints, &nfshost_ai);
		if (error)
			errx(1, "%s: %s", nfshost, gai_strerror(error));
	}

	switch (all) {
	case 2:
		if ((mntsize = mntinfo(&mntbuf)) <= 0)
			break;
		/*
		 * We unmount the nfs-mounts in the reverse order
		 * that they were mounted.
		 */
		for (errs = 0, mntsize--; mntsize > 0; mntsize--) {
			sfs = &mntbuf[mntsize];
			if (checkvfsname(sfs->f_fstypename, typelist))
				continue;
			if (strcmp(sfs->f_mntonname, "/dev") == 0)
				continue;
			if (umountfs(sfs) != 0)
				errs = 1;
		}
		free(mntbuf);
		break;
	case 1:
		if (setfsent() == 0)
			err(1, "%s", getfstab());
		errs = umountall(typelist);
		break;
	case 0:
		for (errs = 0; *argv != NULL; ++argv)
			if (nfsforce != 0) {
				/*
				 * First do the nfssvc() syscall to shut down
				 * the mount point and then do the forced
				 * dismount.
				 */
				ret = nfssvc(NFSSVC_FORCEDISM, *argv);
				if (ret >= 0)
					ret = unmount(*argv, MNT_FORCE);
				if (ret < 0) {
					warn("%s", *argv);
					errs = 1;
				}
			} else if (checkname(*argv, typelist) != 0)
				errs = 1;
		break;
	}
	exit(errs);
}
Пример #19
0
/*
 * Print a running summary of nfs statistics for the experimental client and/or
 * server.
 * Repeat display every interval seconds, showing statistics
 * collected over that interval.  Assumes that interval is non-zero.
 * First line printed at top of screen is always cumulative.
 */
void
exp_sidewaysintpr(u_int interval, int clientOnly, int serverOnly)
{
	struct ext_nfsstats nfsstats, lastst, *ext_nfsstatsp;
	int hdrcnt = 1;

	ext_nfsstatsp = &lastst;
	if (nfssvc(NFSSVC_GETSTATS, ext_nfsstatsp) < 0)
		err(1, "Can't get stats");
	sleep(interval);

	for (;;) {
		ext_nfsstatsp = &nfsstats;
		if (nfssvc(NFSSVC_GETSTATS, ext_nfsstatsp) < 0)
			err(1, "Can't get stats");

		if (--hdrcnt == 0) {
			printhdr(clientOnly, serverOnly);
			if (clientOnly && serverOnly)
				hdrcnt = 10;
			else
				hdrcnt = 20;
		}
		if (clientOnly) {
		    printf("%s %6d %6d %6d %6d %6d %6d %6d %6d",
			((clientOnly && serverOnly) ? "Client:" : ""),
			DELTA(attrcache_hits) + DELTA(attrcache_misses),
			DELTA(lookupcache_hits) + DELTA(lookupcache_misses),
			DELTA(biocache_readlinks),
			DELTA(biocache_reads),
			DELTA(biocache_writes),
			nfsstats.rpccnt[NFSPROC_RENAME] -
			lastst.rpccnt[NFSPROC_RENAME],
			DELTA(accesscache_hits) + DELTA(accesscache_misses),
			DELTA(biocache_readdirs)
		    );
		    if (widemode) {
			    printf(" %s %s %s %s %s %s",
				sperc1(DELTA(attrcache_hits),
				    DELTA(attrcache_misses)),
				sperc1(DELTA(lookupcache_hits), 
				    DELTA(lookupcache_misses)),
				sperc2(DELTA(biocache_reads),
				    DELTA(read_bios)),
				sperc2(DELTA(biocache_writes),
				    DELTA(write_bios)),
				sperc1(DELTA(accesscache_hits),
				    DELTA(accesscache_misses)),
				sperc2(DELTA(biocache_readdirs),
				    DELTA(readdir_bios))
			    );
		    }
		    printf("\n");
		    lastst = nfsstats;
		}
		if (serverOnly) {
		    printf("%s %6d %6d %6d %6d %6d %6d %6d %6d",
			((clientOnly && serverOnly) ? "Server:" : ""),
			nfsstats.srvrpccnt[NFSV4OP_GETATTR] -
			lastst.srvrpccnt[NFSV4OP_GETATTR],
			nfsstats.srvrpccnt[NFSV4OP_LOOKUP] -
			lastst.srvrpccnt[NFSV4OP_LOOKUP],
			nfsstats.srvrpccnt[NFSV4OP_READLINK] -
			lastst.srvrpccnt[NFSV4OP_READLINK],
			nfsstats.srvrpccnt[NFSV4OP_READ] -
			lastst.srvrpccnt[NFSV4OP_READ],
			nfsstats.srvrpccnt[NFSV4OP_WRITE] -
			lastst.srvrpccnt[NFSV4OP_WRITE],
			nfsstats.srvrpccnt[NFSV4OP_RENAME] -
			lastst.srvrpccnt[NFSV4OP_RENAME],
			nfsstats.srvrpccnt[NFSV4OP_ACCESS] -
			lastst.srvrpccnt[NFSV4OP_ACCESS],
			(nfsstats.srvrpccnt[NFSV4OP_READDIR] -
			 lastst.srvrpccnt[NFSV4OP_READDIR]) +
			(nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS] -
			 lastst.srvrpccnt[NFSV4OP_READDIRPLUS]));
		    printf("\n");
		    lastst = nfsstats;
		}
		fflush(stdout);
		sleep(interval);
	}
	/*NOTREACHED*/
}
Пример #20
0
/*
 * Nfs server daemon mostly just a user context for nfssvc()
 *
 * 1 - do file descriptor and signal cleanup
 * 2 - fork the nfsd(s)
 * 3 - create server socket(s)
 * 4 - register socket with portmap
 *
 * For connectionless protocols, just pass the socket into the kernel via.
 * nfssvc().
 * For connection based sockets, loop doing accepts. When you get a new
 * socket from accept, pass the msgsock into the kernel via. nfssvc().
 * The arguments are:
 *	-r - reregister with portmapper
 *	-t - support tcp nfs clients
 *	-u - support udp nfs clients
 * followed by "n" which is the number of nfsds' to fork off
 */
int
main(int argc, char *argv[])
{
	struct nfsd_args nfsdargs;
	struct sockaddr_in inetaddr, inetpeer;
	fd_set *ready, *sockbits;
	size_t fd_size;
	int ch, connect_type_cnt, i, maxsock = 0, msgsock;
	int nfsdcnt = DEFNFSDCNT, on, reregister = 0, sock;
	int udpflag = 0, tcpflag = 0, tcpsock;
	const char *errstr = NULL;
	socklen_t len;

	/* Start by writing to both console and log. */
	openlog("nfsd", LOG_PID | LOG_PERROR, LOG_DAEMON);

	if (argc == 1)
		udpflag = 1;
	while ((ch = getopt(argc, argv, "n:rtu")) != -1)
		switch (ch) {
		case 'n':
			nfsdcnt = strtonum(optarg, 1, MAXNFSDCNT, &errstr);
			if (errstr) {
				syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg);
				return(1);
			}
			break;
		case 'r':
			reregister = 1;
			break;
		case 't':
			tcpflag = 1;
			break;
		case 'u':
			udpflag = 1;
			break;
		default:
			usage();
		};
	argv += optind;
	argc -= optind;

	/*
	 * XXX
	 * Backward compatibility, trailing number is the count of daemons.
	 */
	if (argc > 1)
		usage();
	if (argc == 1) {
		nfsdcnt = strtonum(argv[0], 1, MAXNFSDCNT, &errstr);
		if (errstr) {
			syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg);
			return(1);
		}
	}

	if (debug == 0) {
		daemon(0, 0);
		(void)signal(SIGHUP, SIG_IGN);
		(void)signal(SIGINT, SIG_IGN);
		(void)signal(SIGQUIT, SIG_IGN);
		(void)signal(SIGSYS, nonfs);
	}
	(void)signal(SIGCHLD, reapchild);

	if (reregister) {
		if (udpflag &&
		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT))) {
			syslog(LOG_ERR, "can't register with portmap for UDP (%m).");
			return (1);
		}
		if (tcpflag &&
		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT))) {
			syslog(LOG_ERR, "can't register with portmap for TCP (%m).");
			return (1);
		}
		return (0);
	}

	/* Cut back to writing to log only. */
	closelog();
	openlog("nfsd", LOG_PID, LOG_DAEMON);

	for (i = 0; i < nfsdcnt; i++) {
		switch (fork()) {
		case -1:
			syslog(LOG_ERR, "fork: %m");
			return (1);
		case 0:
			break;
		default:
			continue;
		}

		setproctitle("server");
		nsd.nsd_nfsd = NULL;
		if (nfssvc(NFSSVC_NFSD, &nsd) < 0) {
			syslog(LOG_ERR, "nfssvc: %m");
			return (1);
		}
		return (0);
	}

	/* If we are serving udp, set up the socket. */
	if (udpflag) {
		if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
			syslog(LOG_ERR, "can't create udp socket");
			return (1);
		}
		memset(&inetaddr, 0, sizeof inetaddr);
		inetaddr.sin_family = AF_INET;
		inetaddr.sin_addr.s_addr = INADDR_ANY;
		inetaddr.sin_port = htons(NFS_PORT);
		inetaddr.sin_len = sizeof(inetaddr);
		if (bind(sock, (struct sockaddr *)&inetaddr,
		    sizeof(inetaddr)) < 0) {
			syslog(LOG_ERR, "can't bind udp addr");
			return (1);
		}
		if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
		    !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) {
			syslog(LOG_ERR, "can't register with udp portmap");
			return (1);
		}
		nfsdargs.sock = sock;
		nfsdargs.name = NULL;
		nfsdargs.namelen = 0;
		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
			syslog(LOG_ERR, "can't Add UDP socket");
			return (1);
		}
		(void)close(sock);
	}

	/* Now set up the master server socket waiting for tcp connections. */
	on = 1;
	connect_type_cnt = 0;
	if (tcpflag) {
		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
			syslog(LOG_ERR, "can't create tcp socket");
			return (1);
		}
		if (setsockopt(tcpsock,
		    SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
		memset(&inetaddr, 0, sizeof inetaddr);
		inetaddr.sin_family = AF_INET;
		inetaddr.sin_addr.s_addr = INADDR_ANY;
		inetaddr.sin_port = htons(NFS_PORT);
		inetaddr.sin_len = sizeof(inetaddr);
		if (bind(tcpsock, (struct sockaddr *)&inetaddr,
		    sizeof (inetaddr)) < 0) {
			syslog(LOG_ERR, "can't bind tcp addr");
			return (1);
		}
		if (listen(tcpsock, 5) < 0) {
			syslog(LOG_ERR, "listen failed");
			return (1);
		}
		if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
		    !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) {
			syslog(LOG_ERR, "can't register tcp with portmap");
			return (1);
		}
		maxsock = tcpsock;
		connect_type_cnt++;
	}

	if (connect_type_cnt == 0)
		return (0);

	setproctitle("master");

	/*
	 * Allocate space for the fd_set pointers and fill in sockbits
	 */
	fd_size = howmany(maxsock + 1, NFDBITS) * sizeof(fd_mask);
	sockbits = malloc(fd_size);
	ready = malloc(fd_size);
	if (sockbits == NULL || ready == NULL) {
		syslog(LOG_ERR, "cannot allocate memory");
		return (1);
	}
	memset(sockbits, 0, fd_size);
	if (tcpflag)
		FD_SET(tcpsock, sockbits);

	/*
	 * Loop forever accepting connections and passing the sockets
	 * into the kernel for the mounts.
	 */
	for (;;) {
		memcpy(ready, sockbits, fd_size);
		if (connect_type_cnt > 1) {
			if (select(maxsock + 1,
			    ready, NULL, NULL, NULL) < 1) {
				syslog(LOG_ERR, "select failed: %m");
				return (1);
			}
		}
		if (tcpflag && FD_ISSET(tcpsock, ready)) {
			len = sizeof(inetpeer);
			if ((msgsock = accept(tcpsock,
			    (struct sockaddr *)&inetpeer, &len)) < 0) {
				if (errno == EWOULDBLOCK || errno == EINTR ||
				    errno == ECONNABORTED)
					continue;
				syslog(LOG_ERR, "accept failed: %m");
				return (1);
			}
			memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
			if (setsockopt(msgsock, SOL_SOCKET,
			    SO_KEEPALIVE, &on, sizeof(on)) < 0)
				syslog(LOG_ERR,
				    "setsockopt SO_KEEPALIVE: %m");
			nfsdargs.sock = msgsock;
			nfsdargs.name = (caddr_t)&inetpeer;
			nfsdargs.namelen = sizeof(inetpeer);
			if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
				syslog(LOG_ERR, "can't Add TCP socket");
				return (1);
			}
			(void)close(msgsock);
		}
	}
}
Пример #21
0
int
main(int argc, char **argv)
{
	u_int interval;
	int clientOnly = -1;
	int serverOnly = -1;
	int newStats = 0;
	int ch;
	char *memf, *nlistf;
	int mntlen, i;
	char buf[1024];
	struct statfs *mntbuf;
	struct nfscl_dumpmntopts dumpmntopts;

	interval = 0;
	memf = nlistf = NULL;

	argc = xo_parse_args(argc, argv);
	if (argc < 0)
		exit(1);

	xo_set_version(NFSSTAT_XO_VERSION);

	while ((ch = getopt(argc, argv, "cdEesWM:mN:w:zq")) != -1)
		switch(ch) {
		case 'M':
			memf = optarg;
			break;
		case 'm':
			/* Display mount options for NFS mount points. */
			mntlen = getmntinfo(&mntbuf, MNT_NOWAIT);
			for (i = 0; i < mntlen; i++) {
				if (strcmp(mntbuf->f_fstypename, "nfs") == 0) {
					dumpmntopts.ndmnt_fname =
					    mntbuf->f_mntonname;
					dumpmntopts.ndmnt_buf = buf;
					dumpmntopts.ndmnt_blen = sizeof(buf);
					if (nfssvc(NFSSVC_DUMPMNTOPTS,
					    &dumpmntopts) >= 0)
						printf("%s on %s\n%s\n",
						    mntbuf->f_mntfromname,
						    mntbuf->f_mntonname, buf);
					else if (errno == EPERM)
						errx(1, "Only priviledged users"
						    " can use the -m option");
				}
				mntbuf++;
			}
			exit(0);
		case 'N':
			nlistf = optarg;
			break;
		case 'W':
			widemode = 1;
			break;
		case 'w':
			interval = atoi(optarg);
			break;
		case 'c':
			clientOnly = 1;
			if (serverOnly < 0)
				serverOnly = 0;
			break;
		case 'd':
			newStats = 1;
			if (interval == 0)
				interval = 1;
			break;
		case 's':
			serverOnly = 1;
			if (clientOnly < 0)
				clientOnly = 0;
			break;
		case 'z':
			zflag = 1;
			break;
		case 'E':
			if (extra_output != 0)
				xo_err(1, "-e and -E are mutually exclusive");
			extra_output = 2;
			break;
		case 'e':
			if (extra_output != 0)
				xo_err(1, "-e and -E are mutually exclusive");
			extra_output = 1;
			break;
		case 'q':
			printtitle = 0;
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

#define	BACKWARD_COMPATIBILITY
#ifdef	BACKWARD_COMPATIBILITY
	if (*argv) {
		interval = atoi(*argv);
		if (*++argv) {
			nlistf = *argv;
			if (*++argv)
				memf = *argv;
		}
	}
#endif
	if (modfind("nfscommon") < 0)
		xo_err(1, "NFS client/server not loaded");

	if (interval) {
		exp_sidewaysintpr(interval, clientOnly, serverOnly,
		    newStats);
	} else {
		xo_open_container("nfsstat");
		if (extra_output != 0)
			exp_intpr(clientOnly, serverOnly, extra_output - 1);
		else
			intpr(clientOnly, serverOnly);
		xo_close_container("nfsstat");
	}

	xo_finish();
	exit(0);
}
Пример #22
0
/*
 * NFS stuff and unmount(2) call
 */
int
umountfs(struct statfs *sfs)
{
	char fsidbuf[64];
	enum clnt_stat clnt_stat;
	struct timeval try;
	struct addrinfo *ai, hints;
	int do_rpc;
	CLIENT *clp;
	char *nfsdirname, *orignfsdirname;
	char *hostp, *delimp;
	char buf[1024];
	struct nfscl_dumpmntopts dumpmntopts;
	const char *proto_ptr = NULL;

	ai = NULL;
	do_rpc = 0;
	hostp = NULL;
	nfsdirname = delimp = orignfsdirname = NULL;
	memset(&hints, 0, sizeof hints);

	if (strcmp(sfs->f_fstypename, "nfs") == 0) {
		if ((nfsdirname = strdup(sfs->f_mntfromname)) == NULL)
			err(1, "strdup");
		orignfsdirname = nfsdirname;
		if (*nfsdirname == '[' &&
		    (delimp = strchr(nfsdirname + 1, ']')) != NULL &&
		    *(delimp + 1) == ':') {
			hostp = nfsdirname + 1;
			nfsdirname = delimp + 2;
		} else if ((delimp = strrchr(nfsdirname, ':')) != NULL) {
			hostp = nfsdirname;
			nfsdirname = delimp + 1;
		}
		if (hostp != NULL) {
			*delimp = '\0';
			getaddrinfo(hostp, NULL, &hints, &ai);
			if (ai == NULL) {
				warnx("can't get net id for host");
			}
		}

		/*
		 * Check if we have to start the rpc-call later.
		 * If there are still identical nfs-names mounted,
		 * we skip the rpc-call. Obviously this has to
		 * happen before unmount(2), but it should happen
		 * after the previous namecheck.
		 * A non-NULL return means that this is the last
		 * mount from mntfromname that is still mounted.
		 */
		if (getmntentry(sfs->f_mntfromname, NULL, NULL,
		    CHECKUNIQUE) != NULL) {
			do_rpc = 1;
			proto_ptr = "udp";
			/*
			 * Try and find out whether this NFS mount is NFSv4 and
			 * what protocol is being used. If this fails, the
			 * default is NFSv2,3 and use UDP for the Unmount RPC.
			 */
			dumpmntopts.ndmnt_fname = sfs->f_mntonname;
			dumpmntopts.ndmnt_buf = buf;
			dumpmntopts.ndmnt_blen = sizeof(buf);
			if (nfssvc(NFSSVC_DUMPMNTOPTS, &dumpmntopts) >= 0) {
				if (strstr(buf, "nfsv4,") != NULL)
					do_rpc = 0;
				else if (strstr(buf, ",tcp,") != NULL)
					proto_ptr = "tcp";
			}
		}
	}

	if (!namematch(ai)) {
		free(orignfsdirname);
		return (1);
	}
	/* First try to unmount using the file system ID. */
	snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", sfs->f_fsid.val[0],
	    sfs->f_fsid.val[1]);
	if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) {
		/* XXX, non-root users get a zero fsid, so don't warn. */
		if (errno != ENOENT || sfs->f_fsid.val[0] != 0 ||
		    sfs->f_fsid.val[1] != 0)
			warn("unmount of %s failed", sfs->f_mntonname);
		if (errno != ENOENT) {
			free(orignfsdirname);
			return (1);
		}
		/* Compatibility for old kernels. */
		if (sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0)
			warnx("retrying using path instead of file system ID");
		if (unmount(sfs->f_mntonname, fflag) != 0) {
			warn("unmount of %s failed", sfs->f_mntonname);
			free(orignfsdirname);
			return (1);
		}
	}
	/* Mark this this file system as unmounted. */
	getmntentry(NULL, NULL, &sfs->f_fsid, REMOVE);
	if (vflag)
		(void)printf("%s: unmount from %s\n", sfs->f_mntfromname,
		    sfs->f_mntonname);
	/*
	 * Report to mountd-server which nfsname
	 * has been unmounted.
	 */
	if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) {
		clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS3, proto_ptr);
		if (clp  == NULL) {
			warnx("%s: %s", hostp,
			    clnt_spcreateerror("MOUNTPROG"));
			free(orignfsdirname);
			return (1);
		}
		clp->cl_auth = authsys_create_default();
		try.tv_sec = 20;
		try.tv_usec = 0;
		clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir,
		    nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try);
		if (clnt_stat != RPC_SUCCESS) {
			warnx("%s: %s", hostp,
			    clnt_sperror(clp, "RPCMNT_UMOUNT"));
			free(orignfsdirname);
			return (1);
		}
		/*
		 * Remove the unmounted entry from /var/db/mounttab.
		 */
		if (read_mtab()) {
			clean_mtab(hostp, nfsdirname, vflag);
			if(!write_mtab(vflag))
				warnx("cannot remove mounttab entry %s:%s",
				    hostp, nfsdirname);
			free_mtab();
		}
		auth_destroy(clp->cl_auth);
		clnt_destroy(clp);
	}
Пример #23
0
/*
 * Print a description of the nfs stats for the client/server,
 * including NFSv4.1.
 */
static void
exp_intpr(int clientOnly, int serverOnly, int nfs41)
{
	int nfssvc_flag;

	xo_open_container("nfsv4");

	nfssvc_flag = NFSSVC_GETSTATS | NFSSVC_NEWSTRUCT;
	if (zflag != 0) {
		if (clientOnly != 0)
			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
		if (serverOnly != 0)
			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
	}
	ext_nfsstats.vers = NFSSTATS_V1;
	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
		xo_err(1, "Can't get stats");
	if (clientOnly != 0) {
		xo_open_container("clientstats");

		xo_open_container("operations");
		if (printtitle) {
			xo_emit("{T:Client Info:}\n");
			xo_emit("{T:RPC Counts:}\n");
		}
		xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}"
		    "{T:Lookup/%13.13s}{T:Readlink/%13.13s}"
		    "{T:Read/%13.13s}{T:Write/%13.13s}\n");
		xo_emit("{:getattr/%13ju}{:setattr/%13ju}{:lookup/%13ju}"
		    "{:readlink/%13ju}{:read/%13ju}{:write/%13ju}\n",
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETATTR],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETATTR],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READLINK],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READ],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITE]);
		xo_emit("{T:Create/%13.13s}{T:Remove/%13.13s}"
		    "{T:Rename/%13.13s}{T:Link/%13.13s}"
		    "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}\n");
		xo_emit("{:create/%13ju}{:remove/%13ju}{:rename/%13ju}"
		  "{:link/%13ju}{:symlink/%13ju}{:mkdir/%13ju}\n",
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATE],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_REMOVE],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RENAME],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LINK],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKDIR]);
		xo_emit("{T:Rmdir/%13.13s}{T:Readdir/%13.13s}"
		    "{T:RdirPlus/%13.13s}{T:Access/%13.13s}"
		    "{T:Mknod/%13.13s}{T:Fsstat/%13.13s}\n");
		xo_emit("{:rmdir/%13ju}{:readdir/%13ju}{:rdirplus/%13ju}"
		    "{:access/%13ju}{:mknod/%13ju}{:fsstat/%13ju}\n",
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RMDIR],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIR],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_ACCESS],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_MKNOD],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSSTAT]);
		xo_emit("{T:FSinfo/%13.13s}{T:pathConf/%13.13s}"
		    "{T:Commit/%13.13s}{T:SetClId/%13.13s}"
		    "{T:SetClIdCf/%13.13s}{T:Lock/%13.13s}\n");
		xo_emit("{:fsinfo/%13ju}{:pathconf/%13ju}{:commit/%13ju}"
		    "{:setclientid/%13ju}{:setclientidcf/%13ju}{:lock/%13ju}\n",
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FSINFO],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMIT],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTID],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETCLIENTIDCFRM],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCK]);
		xo_emit("{T:LockT/%13.13s}{T:LockU/%13.13s}"
		    "{T:Open/%13.13s}{T:OpenCfr/%13.13s}\n");
		xo_emit("{:lockt/%13ju}{:locku/%13ju}"
		    "{:open/%13ju}{:opencfr/%13ju}\n",
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKT],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LOCKU],
		    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPEN],
		  (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENCONFIRM]);

		if (nfs41) {
			xo_open_container("nfsv41");

			xo_emit("{T:OpenDownGr/%13.13s}{T:Close/%13.13s}\n");
			xo_emit("{:opendowngr/%13ju}{:close/%13ju}\n",
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENDOWNGRADE],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CLOSE]);

			xo_emit("{T:RelLckOwn/%13.13s}{T:FreeStateID/%13.13s}"
			    "{T:PutRootFH/%13.13s}{T:DelegRet/%13.13s}"
			    "{T:GetAcl/%13.13s}{T:SetAcl/%13.13s}\n");
			xo_emit("{:rellckown/%13ju}{:freestateid/%13ju}"
			    "{:getacl/%13ju}{:delegret/%13ju}"
			    "{:getacl/%13ju}{:setacl/%13ju}\n",
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RELEASELCKOWN],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_FREESTATEID],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_PUTROOTFH],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DELEGRETURN],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETACL],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_SETACL]);

			xo_emit("{T:ExchangeId/%13.13s}{T:CreateSess/%13.13s}"
			    "{T:DestroySess/%13.13s}{T:DestroyClId/%13.13s}"
			    "{T:LayoutGet/%13.13s}{T:GetDevInfo/%13.13s}\n");
			xo_emit("{:exchangeid/%13ju}{:createsess/%13ju}"
			    "{:destroysess/%13ju}{:destroyclid/%13ju}"
			    "{:layoutget/%13ju}{:getdevinfo/%13ju}\n",
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_EXCHANGEID],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATESESSION],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYSESSION],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_DESTROYCLIENT],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTGET],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_GETDEVICEINFO]);

			xo_emit("{T:LayoutCommit/%13.13s}{T:LayoutReturn/%13.13s}"
			    "{T:ReclaimCompl/%13.13s}{T:ReadDataS/%13.13s}"
			    "{T:WriteDataS/%13.13s}{T:CommitDataS/%13.13s}\n");
			xo_emit("{:layoutcomit/%13ju}{:layoutreturn/%13ju}"
			    "{:reclaimcompl/%13ju}{:readdatas/%13ju}"
			    "{:writedatas/%13ju}{:commitdatas/%13ju}\n",
			  (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTCOMMIT],
			  (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_LAYOUTRETURN],
			  (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_RECLAIMCOMPL],
			  (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_READDS],
			  (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_WRITEDS],
			  (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_COMMITDS]);

			xo_emit("{T:OpenLayout/%13.13s}{T:CreateLayout/%13.13s}\n");
			xo_emit("{:openlayout/%13ju}{:createlayout/%13ju}\n",
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_OPENLAYGET],
			    (uintmax_t)ext_nfsstats.rpccnt[NFSPROC_CREATELAYGET]);

			xo_close_container("nfsv41");
		}
		xo_close_container("operations");

		xo_open_container("client");
		xo_emit("{T:OpenOwner/%13.13s}{T:Opens/%13.13s}"
		    "{T:LockOwner/%13.13s}{T:Locks/%13.13s}"
		    "{T:Delegs/%13.13s}{T:LocalOwn/%13.13s}\n");
		xo_emit("{:openowner/%13ju}{:opens/%13ju}"
		    "{:lockowner/%13ju}{:locks/%13ju}"
		    "{:delegs/%13ju}{:localown/%13ju}\n",
		    (uintmax_t)ext_nfsstats.clopenowners,
		    (uintmax_t)ext_nfsstats.clopens,
		    (uintmax_t)ext_nfsstats.cllockowners,
		    (uintmax_t)ext_nfsstats.cllocks,
		    (uintmax_t)ext_nfsstats.cldelegates,
		    (uintmax_t)ext_nfsstats.cllocalopenowners);

		xo_emit("{T:LocalOpen/%13.13s}{T:LocalLown/%13.13s}"
		    "{T:LocalLock/%13.13s}\n");
		xo_emit("{:localopen/%13ju}{:locallown/%13ju}"
		    "{:locallock/%13ju}\n",
		    (uintmax_t)ext_nfsstats.cllocalopens,
		    (uintmax_t)ext_nfsstats.cllocallockowners,
		    (uintmax_t)ext_nfsstats.cllocallocks);
		xo_close_container("client");

		xo_open_container("rpc");
		if (printtitle)
			xo_emit("{T:Rpc Info:}\n");
		xo_emit("{T:TimedOut/%13.13s}{T:Invalid/%13.13s}"
		    "{T:X Replies/%13.13s}{T:Retries/%13.13s}"
		    "{T:Requests/%13.13s}\n");
		xo_emit("{:timedout/%13ju}{:invalid/%13ju}"
		    "{:xreplies/%13ju}{:retries/%13ju}"
		    "{:requests/%13ju}\n",
		    (uintmax_t)ext_nfsstats.rpctimeouts,
		    (uintmax_t)ext_nfsstats.rpcinvalid,
		    (uintmax_t)ext_nfsstats.rpcunexpected,
		    (uintmax_t)ext_nfsstats.rpcretries,
		    (uintmax_t)ext_nfsstats.rpcrequests);
		xo_close_container("rpc");

		xo_open_container("cache");
		if (printtitle)
			xo_emit("{T:Cache Info:}\n");
		xo_emit("{T:Attr Hits/%13.13s}{T:Attr Misses/%13.13s}"
		    "{T:Lkup Hits/%13.13s}{T:Lkup Misses/%13.13s}\n");
		xo_emit("{:attrhits/%13ju}{:attrmisses/%13ju}"
		    "{:lkuphits/%13ju}{:lkupmisses/%13ju}\n",
		    (uintmax_t)ext_nfsstats.attrcache_hits,
		    (uintmax_t)ext_nfsstats.attrcache_misses,
		    (uintmax_t)ext_nfsstats.lookupcache_hits,
		    (uintmax_t)ext_nfsstats.lookupcache_misses);

		xo_emit("{T:BioR Hits/%13.13s}{T:BioR Misses/%13.13s}"
		    "{T:BioW Hits/%13.13s}{T:BioW Misses/%13.13s}\n");
		xo_emit("{:biorhits/%13ju}{:biormisses/%13ju}"
		    "{:biowhits/%13ju}{:biowmisses/%13ju}\n",
		    (uintmax_t)(ext_nfsstats.biocache_reads -
		    ext_nfsstats.read_bios),
		    (uintmax_t)ext_nfsstats.read_bios,
		    (uintmax_t)(ext_nfsstats.biocache_writes -
		    ext_nfsstats.write_bios),
		    (uintmax_t)ext_nfsstats.write_bios);

		xo_emit("{T:BioRL Hits/%13.13s}{T:BioRL Misses/%13.13s}"
		    "{T:BioD Hits/%13.13s}{T:BioD Misses/%13.13s}\n");
		xo_emit("{:biorlhits/%13ju}{:biorlmisses/%13ju}"
		    "{:biodhits/%13ju}{:biodmisses/%13ju}\n",
		    (uintmax_t)(ext_nfsstats.biocache_readlinks -
		    ext_nfsstats.readlink_bios),
		    (uintmax_t)ext_nfsstats.readlink_bios,
		    (uintmax_t)(ext_nfsstats.biocache_readdirs -
		    ext_nfsstats.readdir_bios),
		    (uintmax_t)ext_nfsstats.readdir_bios);

		xo_emit("{T:DirE Hits/%13.13s}{T:DirE Misses/%13.13s}\n");
		xo_emit("{:direhits/%13ju}{:diremisses/%13ju}\n",
		    (uintmax_t)ext_nfsstats.direofcache_hits,
		    (uintmax_t)ext_nfsstats.direofcache_misses);
		xo_open_container("cache");

		xo_close_container("clientstats");
	}
	if (serverOnly != 0) {
		xo_open_container("serverstats");

		xo_open_container("operations");
		if (printtitle)
			xo_emit("{T:Server Info:}\n");
		xo_emit("{T:Getattr/%13.13s}{T:Setattr/%13.13s}"
		    "{T:Lookup/%13.13s}{T:Readlink/%13.13s}"
		    "{T:Read/%13.13s}{T:Write/%13.13s}\n");
		xo_emit("{:getattr/%13ju}{:setattr/%13ju}{:lookup/%13ju}"
		    "{:readlink/%13ju}{:read/%13ju}{:write/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READ],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WRITE]);
		xo_emit("{T:Create/%13.13s}{T:Remove/%13.13s}"
		    "{T:Rename/%13.13s}{T:Link/%13.13s}"
		    "{T:Symlink/%13.13s}{T:Mkdir/%13.13s}\n");
		xo_emit("{:create/%13ju}{:remove/%13ju}{:rename/%13ju}"
		    "{:link/%13ju}{:symlink/%13ju}{:mkdir/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_V3CREATE],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR]);
		xo_emit("{T:Rmdir/%13.13s}{T:Readdir/%13.13s}"
		    "{T:RdirPlus/%13.13s}{T:Access/%13.13s}"
		    "{T:Mknod/%13.13s}{T:Fsstat/%13.13s}\n");
		xo_emit("{:rmdir/%13ju}{:readdir/%13ju}{:rdirplus/%13ju}"
		    "{:access/%13ju}{:mknod/%13ju}{:fsstat/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT]);
		xo_emit("{T:FSinfo/%13.13s}{T:pathConf/%13.13s}"
		    "{T:Commit/%13.13s}{T:LookupP/%13.13s}"
		    "{T:SetClId/%13.13s}{T:SetClIdCf/%13.13s}\n");
		xo_emit("{:fsinfo/%13ju}{:pathconf/%13ju}{:commit/%13ju}"
		    "{:lookupp/%13ju}{:setclientid/%13ju}{:setclientidcfrm/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUPP],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTID],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTIDCFRM]);
		xo_emit("{T:Open/%13.13s}{T:OpenAttr/%13.13s}"
		    "{T:OpenDwnGr/%13.13s}{T:OpenCfrm/%13.13s}"
		    "{T:DelePurge/%13.13s}{T:DelRet/%13.13s}\n");
		xo_emit("{:open/%13ju}{:openattr/%13ju}{:opendwgr/%13ju}"
		    "{:opencfrm/%13ju}{:delepurge/%13ju}{:delreg/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPEN],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENATTR],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENDOWNGRADE],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_OPENCONFIRM],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGPURGE],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DELEGRETURN]);
		xo_emit("{T:GetFH/%13.13s}{T:Lock/%13.13s}"
		    "{T:LockT/%13.13s}{T:LockU/%13.13s}"
		    "{T:Close/%13.13s}{T:Verify/%13.13s}\n");
		xo_emit("{:getfh/%13ju}{:lock/%13ju}{:lockt/%13ju}"
		    "{:locku/%13ju}{:close/%13ju}{:verify/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETFH],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCK],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKT],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LOCKU],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CLOSE],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_VERIFY]);
		xo_emit("{T:NVerify/%13.13s}{T:PutFH/%13.13s}"
		    "{T:PutPubFH/%13.13s}{T:PutRootFH/%13.13s}"
		    "{T:Renew/%13.13s}{T:RestoreFH/%13.13s}\n");
		xo_emit("{:nverify/%13ju}{:putfh/%13ju}{:putpubfh/%13ju}"
		    "{:putrootfh/%13ju}{:renew/%13ju}{:restore/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_NVERIFY],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTFH],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTPUBFH],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_PUTROOTFH],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RENEW],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RESTOREFH]);
		xo_emit("{T:SaveFH/%13.13s}{T:Secinfo/%13.13s}"
		    "{T:RelLockOwn/%13.13s}{T:V4Create/%13.13s}\n");
		xo_emit("{:savefh/%13ju}{:secinfo/%13ju}{:rellockown/%13ju}"
		    "{:v4create/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SAVEFH],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFO],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RELEASELCKOWN],
		    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATE]);
		if (nfs41) {
			xo_open_container("nfsv41");
			xo_emit("{T:BackChannelCtrl/%13.13s}{T:BindConnToSess/%13.13s}"
			    "{T:ExchangeID/%13.13s}{T:CreateSess/%13.13s}"
			    "{T:DestroySess/%13.13s}{T:FreeStateID/%13.13s}\n");
			xo_emit("{:backchannelctrl/%13ju}{:bindconntosess/%13ju}"
			    "{:exchangeid/%13ju}{:createsess/%13ju}"
			    "{:destroysess/%13ju}{:freestateid/%13ju}\n",
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BACKCHANNELCTL],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_BINDCONNTOSESS],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_EXCHANGEID],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_CREATESESSION],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYSESSION],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_FREESTATEID]),

			xo_emit("{T:GetDirDeleg/%13.13s}{T:GetDevInfo/%13.13s}"
			    "{T:GetDevList/%13.13s}{T:layoutCommit/%13.13s}"
			    "{T:LayoutGet/%13.13s}{T:LayoutReturn/%13.13s}\n");
			xo_emit("{:getdirdeleg/%13ju}{:getdevinfo/%13ju}"
			    "{:getdevlist/%13ju}{:layoutcommit/%13ju}"
			    "{:layoutget/%13ju}{:layoutreturn/%13ju}\n",
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDIRDELEG],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVINFO],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_GETDEVLIST],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTCOMMIT],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTGET],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_LAYOUTRETURN]);

			xo_emit("{T:SecInfNoName/%13.13s}{T:Sequence/%13.13s}"
			    "{T:SetSSV/%13.13s}{T:TestStateID/%13.13s}"
			    "{T:WantDeleg/%13.13s}{T:DestroyClId/%13.13s}\n");
			xo_emit("{:secinfnoname/%13ju}{:sequence/%13ju}"
			    "{:setssv/%13ju}{:teststateid/%13ju}{:wantdeleg/%13ju}"
			    "{:destroyclid/%13ju}\n",
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SECINFONONAME],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SEQUENCE],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_SETSSV],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_TESTSTATEID],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_WANTDELEG],
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_DESTROYCLIENTID]);

			xo_emit("{T:ReclaimCompl/%13.13s}\n");
			xo_emit("{:reclaimcompl/%13ju}\n",
			    (uintmax_t)ext_nfsstats.srvrpccnt[NFSV4OP_RECLAIMCOMPL]);

			xo_close_container("nfsv41");
		}

		xo_close_container("operations");

		if (printtitle)
			xo_emit("{T:Server:}\n");
		xo_open_container("server");
		xo_emit("{T:Retfailed/%13.13s}{T:Faults/%13.13s}"
		    "{T:Clients/%13.13s}\n");
		xo_emit("{:retfailed/%13ju}{:faults/%13ju}{:clients/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srv_errs,
		    (uintmax_t)ext_nfsstats.srvrpc_errs,
		    (uintmax_t)ext_nfsstats.srvclients);
		xo_emit("{T:OpenOwner/%13.13s}{T:Opens/%13.13s}"
		    "{T:LockOwner/%13.13s}{T:Locks/%13.13s}"
		    "{T:Delegs/%13.13s}\n");
		xo_emit("{:openowner/%13ju}{:opens/%13ju}{:lockowner/%13ju}"
		  "{:locks/%13ju}{:delegs/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvopenowners,
		    (uintmax_t)ext_nfsstats.srvopens,
		    (uintmax_t)ext_nfsstats.srvlockowners,
		    (uintmax_t)ext_nfsstats.srvlocks,
		    (uintmax_t)ext_nfsstats.srvdelegates);
		xo_close_container("server");

		if (printtitle)
			xo_emit("{T:Server Cache Stats:}\n");
		xo_open_container("cache");
		xo_emit("{T:Inprog/%13.13s}{T:Idem/%13.13s}"
		    "{T:Non-idem/%13.13s}{T:Misses/%13.13s}"
		    "{T:CacheSize/%13.13s}{T:TCPPeak/%13.13s}\n");
		xo_emit("{:inprog/%13ju}{:idem/%13ju}{:nonidem/%13ju}"
		    "{:misses/%13ju}{:cachesize/%13ju}{:tcppeak/%13ju}\n",
		    (uintmax_t)ext_nfsstats.srvcache_inproghits,
		    (uintmax_t)ext_nfsstats.srvcache_idemdonehits,
		    (uintmax_t)ext_nfsstats.srvcache_nonidemdonehits,
		    (uintmax_t)ext_nfsstats.srvcache_misses,
		    (uintmax_t)ext_nfsstats.srvcache_size,
		    (uintmax_t)ext_nfsstats.srvcache_tcppeak);
		xo_close_container("cache");

		xo_close_container("serverstats");
	}

	xo_close_container("nfsv4");
}
Пример #24
0
/*
 * Nfs callback server daemon.
 *
 * 1 - do file descriptor and signal cleanup
 * 2 - fork the nfscbd(s)
 * 4 - create callback server socket(s)
 * 5 - set up server socket for rpc
 *
 * For connectionless protocols, just pass the socket into the kernel via.
 * nfssvc().
 * For connection based sockets, loop doing accepts. When you get a new
 * socket from accept, pass the msgsock into the kernel via. nfssvc().
 */
int
main(int argc, char *argv[])
{
	struct nfscbd_args nfscbdargs;
	struct nfsd_nfscbd_args nfscbdargs2;
	struct sockaddr_in inetaddr, inetpeer;
	fd_set ready, sockbits;
	int ch, connect_type_cnt, len, maxsock, msgsock, error;
	int nfssvc_flag, on, sock, tcpsock, ret, mustfreeai = 0;
	char *cp, princname[128];
	char myname[MAXHOSTNAMELEN], *myfqdnname = NULL;
	struct addrinfo *aip, hints;
	pid_t pid;
	short myport = NFSV4_CBPORT;

	if (modfind("nfscl") < 0) {
		/* Not present in kernel, try loading it */
		if (kldload("nfscl") < 0 ||
		    modfind("nfscl") < 0)
			errx(1, "nfscl is not available");
	}
	/*
	 * First, get our fully qualified host name, if possible.
	 */
	if (gethostname(myname, MAXHOSTNAMELEN) >= 0) {
		cp = strchr(myname, '.');
		if (cp != NULL && *(cp + 1) != '\0') {
			cp = myname;
		} else {
			/*
			 * No domain on myname, so try looking it up.
			 */
			cp = NULL;
			memset((void *)&hints, 0, sizeof (hints));
			hints.ai_flags = AI_CANONNAME;
			error = getaddrinfo(myname, NULL, &hints, &aip);
			if (error == 0) {
			    if (aip->ai_canonname != NULL &&
				(cp = strchr(aip->ai_canonname, '.')) != NULL
				&& *(cp + 1) != '\0') {
				    cp = aip->ai_canonname;
				    mustfreeai = 1;
			    } else {
				    freeaddrinfo(aip);
			    }
			}
		}
		if (cp == NULL)
			warnx("Can't get fully qualified host name");
		myfqdnname = cp;
	}

	princname[0] = '\0';
#define	GETOPT	"p:P:"
#define	USAGE	"[ -p port_num ] [ -P client_principal ]"
	while ((ch = getopt(argc, argv, GETOPT)) != -1)
		switch (ch) {
		case 'p':
			myport = atoi(optarg);
			if (myport < 1) {
				warnx("port# non-positive, reset to %d",
				    NFSV4_CBPORT);
				myport = NFSV4_CBPORT;
			}
			break;
		case 'P':
			cp = optarg;
			if (cp != NULL && strlen(cp) > 0 &&
			    strlen(cp) < sizeof (princname)) {
				if (strchr(cp, '@') == NULL &&
				    myfqdnname != NULL)
					snprintf(princname, sizeof (princname),
					    "%s@%s", cp, myfqdnname);
				else
					strlcpy(princname, cp,
					    sizeof (princname));
			} else {
				warnx("client princ invalid. ignored\n");
			}
			break;
		default:
		case '?':
			usage();
		};
	argv += optind;
	argc -= optind;

	if (argc > 0)
		usage();

	if (mustfreeai)
		freeaddrinfo(aip);
	nfscbdargs2.principal = (const char *)princname;
	if (debug == 0) {
		daemon(0, 0);
		(void)signal(SIGTERM, SIG_IGN);
		(void)signal(SIGHUP, SIG_IGN);
		(void)signal(SIGINT, SIG_IGN);
		(void)signal(SIGQUIT, SIG_IGN);
	}
	(void)signal(SIGSYS, nonfs);
	(void)signal(SIGCHLD, reapchild);

	openlog("nfscbd:", LOG_PID, LOG_DAEMON);

	pid = fork();
	if (pid < 0) {
		syslog(LOG_ERR, "fork: %m");
		nfscbd_exit(1);
	} else if (pid > 0) {
		children = pid;
	} else {
		(void)signal(SIGUSR1, child_cleanup);
		setproctitle("server");
		nfssvc_flag = NFSSVC_NFSCBD;
		if (nfssvc(nfssvc_flag, &nfscbdargs2) < 0) {
			syslog(LOG_ERR, "nfssvc: %m");
			nfscbd_exit(1);
		}
		exit(0);
	}
	(void)signal(SIGUSR1, cleanup);

	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		syslog(LOG_ERR, "can't create udp socket");
		nfscbd_exit(1);
	}
	memset(&inetaddr, 0, sizeof inetaddr);
	inetaddr.sin_family = AF_INET;
	inetaddr.sin_addr.s_addr = INADDR_ANY;
	inetaddr.sin_port = htons(myport);
	inetaddr.sin_len = sizeof(inetaddr);
	ret = bind(sock, (struct sockaddr *)&inetaddr, sizeof(inetaddr));
	/* If bind() fails, this is a restart, so just skip UDP. */
	if (ret == 0) {
		len = sizeof(inetaddr);
		if (getsockname(sock, (struct sockaddr *)&inetaddr, &len) < 0){
			syslog(LOG_ERR, "can't get bound addr");
			nfscbd_exit(1);
		}
		nfscbdargs.port = ntohs(inetaddr.sin_port);
		if (nfscbdargs.port != myport) {
			syslog(LOG_ERR, "BAD PORT#");
			nfscbd_exit(1);
		}
		nfscbdargs.sock = sock;
		nfscbdargs.name = NULL;
		nfscbdargs.namelen = 0;
		if (nfssvc(NFSSVC_CBADDSOCK, &nfscbdargs) < 0) {
			syslog(LOG_ERR, "can't Add UDP socket");
			nfscbd_exit(1);
		}
	}
	(void)close(sock);

	/* Now set up the master server socket waiting for tcp connections. */
	on = 1;
	FD_ZERO(&sockbits);
	connect_type_cnt = 0;
	if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		syslog(LOG_ERR, "can't create tcp socket");
		nfscbd_exit(1);
	}
	if (setsockopt(tcpsock,
	    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
		syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
	/* sin_port is already set */
	inetaddr.sin_family = AF_INET;
	inetaddr.sin_addr.s_addr = INADDR_ANY;
	inetaddr.sin_port = htons(myport);
	inetaddr.sin_len = sizeof(inetaddr);
	if (bind(tcpsock,
	    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
		syslog(LOG_ERR, "can't bind tcp addr");
		nfscbd_exit(1);
	}
	if (listen(tcpsock, 5) < 0) {
		syslog(LOG_ERR, "listen failed");
		nfscbd_exit(1);
	}
	FD_SET(tcpsock, &sockbits);
	maxsock = tcpsock;
	connect_type_cnt++;

	setproctitle("master");

	/*
	 * Loop forever accepting connections and passing the sockets
	 * into the kernel for the mounts.
	 */
	for (;;) {
		ready = sockbits;
		if (connect_type_cnt > 1) {
			if (select(maxsock + 1,
			    &ready, NULL, NULL, NULL) < 1) {
				syslog(LOG_ERR, "select failed: %m");
				nfscbd_exit(1);
			}
		}
		if (FD_ISSET(tcpsock, &ready)) {
			len = sizeof(inetpeer);
			if ((msgsock = accept(tcpsock,
			    (struct sockaddr *)&inetpeer, &len)) < 0) {
				syslog(LOG_ERR, "accept failed: %m");
				nfscbd_exit(1);
			}
			memset(inetpeer.sin_zero, 0,
			    sizeof (inetpeer.sin_zero));
			if (setsockopt(msgsock, SOL_SOCKET,
			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
				syslog(LOG_ERR,
				    "setsockopt SO_KEEPALIVE: %m");
			nfscbdargs.sock = msgsock;
			nfscbdargs.name = (caddr_t)&inetpeer;
			nfscbdargs.namelen = sizeof(inetpeer);
			nfssvc(NFSSVC_CBADDSOCK, &nfscbdargs);
			(void)close(msgsock);
		}
	}
}