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); }
/* * 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); }
/* * 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++; } }
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 }
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); }
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; }
/* * 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++; } }
/* * 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); } } } } }
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); }
/* * 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); } }
/* * 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; }; }
/* * 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); } } }
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; }
/* * 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); } }
/* * 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"); } }
/* * 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*/ }
/* * 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); } } } } }
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); }
/* * 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*/ }
/* * 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); } } }
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); }
/* * 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); }
/* * 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"); }
/* * 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); } } }