diff --git a/include/rpcsvc/rstat.x b/include/rpcsvc/rstat.x --- a/include/rpcsvc/rstat.x +++ b/include/rpcsvc/rstat.x @@ -57,6 +57,25 @@ unsigned int tv_usec; /* and microseconds */ }; +struct statsvar { /* RSTATVERS_VAR */ + int cp_time<>; /* variable number of CPU states */ + int dk_xfer<>; /* variable number of disks */ + unsigned v_pgpgin; /* these are cumulative sum */ + unsigned v_pgpgout; + unsigned v_pswpin; + unsigned v_pswpout; + unsigned v_intr; + int if_ipackets; + int if_ierrors; + int if_opackets; + int if_oerrors; + int if_collisions; + unsigned v_swtch; + int avenrun[3]; + rstat_timeval boottime; + rstat_timeval curtime; +}; + struct statstime { /* RSTATVERS_TIME */ int cp_time[RSTAT_CPUSTATES]; int dk_xfer[RSTAT_DK_NDRIVE]; @@ -111,6 +130,16 @@ program RSTATPROG { + /* + * Version 4 allows for variable number of disk and RSTAT_CPU states. + */ + version RSTATVERS_VAR { + statsvar + RSTATPROC_STATS (void) = 1; + + unsigned int + RSTATPROC_HAVEDISK (void) = 2; + } = 4; /* * Newest version includes current time and context switching info */ diff --git a/libexec/rpc.rstatd/rstat_proc.c b/libexec/rpc.rstatd/rstat_proc.c --- a/libexec/rpc.rstatd/rstat_proc.c +++ b/libexec/rpc.rstatd/rstat_proc.c @@ -77,6 +77,7 @@ struct statsswtch s2; struct statstime s3; } stats_all; +statsvar stats_all_s4; void updatestat(); static int stat_is_init = 0; @@ -100,6 +101,16 @@ alarm(1); } + +statsvar * +rstatproc_stats_4_svc(void *argp, struct svc_req *rqstp) +{ + if (! stat_is_init) + stat_init(); + sincelastreq = 0; + return(&stats_all_s4); +} + statstime * rstatproc_stats_3_svc(void *argp, struct svc_req *rqstp) { @@ -127,6 +138,12 @@ return(&stats_all.s1); } +u_int * +rstatproc_havedisk_4_svc(void *argp, struct svc_req *rqstp) +{ + return (rstatproc_havedisk_3_svc(argp, rqstp)); +} + u_int * rstatproc_havedisk_3_svc(void *argp, struct svc_req *rqstp) { @@ -194,14 +211,21 @@ syslog(LOG_ERR, "sysctl(kern.cp_time): %m"); exit(1); } - for(i = 0; i < RSTAT_CPUSTATES ; i++) + stats_all_s4.cp_time.cp_time_val = malloc(RSTAT_CPUSTATES * sizeof(int*)); + for(i = 0; i < RSTAT_CPUSTATES ; i++) { stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]]; + stats_all_s4.cp_time.cp_time_val[i] = bsd_cp_time[cp_time_xlat[i]]; + } (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); stats_all.s2.avenrun[0] = avrun[0] * FSCALE; stats_all.s2.avenrun[1] = avrun[1] * FSCALE; stats_all.s2.avenrun[2] = avrun[2] * FSCALE; + stats_all_s4.avenrun[0] = avrun[0] * FSCALE; + stats_all_s4.avenrun[1] = avrun[1] * FSCALE; + stats_all_s4.avenrun[2] = avrun[2] * FSCALE; + mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; @@ -213,6 +237,8 @@ stats_all.s2.boottime.tv_sec = btm.tv_sec; stats_all.s2.boottime.tv_usec = btm.tv_usec; + stats_all_s4.boottime.tv_sec = btm.tv_sec; + stats_all_s4.boottime.tv_usec = btm.tv_usec; #ifdef DEBUG @@ -235,12 +261,21 @@ FETCH_CNT(stats_all.s1.v_pswpout, vm.v_swappgsout); FETCH_CNT(stats_all.s1.v_intr, sys.v_intr); FETCH_CNT(stats_all.s2.v_swtch, sys.v_swtch); + FETCH_CNT(stats_all_s4.v_pgpgin, vm.v_vnodepgsin); + FETCH_CNT(stats_all_s4.v_pgpgout, vm.v_vnodepgsout); + FETCH_CNT(stats_all_s4.v_pswpin, vm.v_swappgsin); + FETCH_CNT(stats_all_s4.v_pswpout, vm.v_swappgsout); + FETCH_CNT(stats_all_s4.v_intr, sys.v_intr); + FETCH_CNT(stats_all_s4.v_swtch, sys.v_swtch); (void)gettimeofday(&tm, NULL); stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + hz*(tm.tv_usec - btm.tv_usec)/1000000; /* update disk transfers */ updatexfers(RSTAT_DK_NDRIVE, stats_all.s1.dk_xfer); + stats_all_s4.dk_xfer.dk_xfer_len = RSTAT_DK_NDRIVE; + stats_all_s4.dk_xfer.dk_xfer_val = malloc(RSTAT_DK_NDRIVE * sizeof(int*)); + updatexfers(RSTAT_DK_NDRIVE, stats_all_s4.dk_xfer.dk_xfer_val); // TODO mib[0] = CTL_NET; mib[1] = PF_LINK; @@ -252,12 +287,16 @@ syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m"); exit(1); } - stats_all.s1.if_ipackets = 0; stats_all.s1.if_opackets = 0; stats_all.s1.if_ierrors = 0; stats_all.s1.if_oerrors = 0; stats_all.s1.if_collisions = 0; + stats_all_s4.if_ipackets = 0; + stats_all_s4.if_opackets = 0; + stats_all_s4.if_ierrors = 0; + stats_all_s4.if_oerrors = 0; + stats_all_s4.if_collisions = 0; for (i = 1; i <= ifcount; i++) { len = sizeof ifmd; mib[3] = IFMIB_IFDATA; @@ -277,10 +316,17 @@ stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors; stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors; stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions; + stats_all_s4.if_ipackets += ifmd.ifmd_data.ifi_ipackets; + stats_all_s4.if_opackets += ifmd.ifmd_data.ifi_opackets; + stats_all_s4.if_ierrors += ifmd.ifmd_data.ifi_ierrors; + stats_all_s4.if_oerrors += ifmd.ifmd_data.ifi_oerrors; + stats_all_s4.if_collisions += ifmd.ifmd_data.ifi_collisions; } (void)gettimeofday(&tm, NULL); stats_all.s3.curtime.tv_sec = tm.tv_sec; stats_all.s3.curtime.tv_usec = tm.tv_usec; + stats_all_s4.curtime.tv_sec = tm.tv_sec; + stats_all_s4.curtime.tv_usec = tm.tv_usec; alarm(1); } @@ -420,6 +466,9 @@ case RSTATVERS_TIME: local = (svc_cb *)rstatproc_stats_3_svc; break; + case RSTATVERS_VAR: + local = (svc_cb *)rstatproc_stats_4_svc; + break; default: svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); goto leave; @@ -440,6 +489,9 @@ case RSTATVERS_TIME: local = (svc_cb *)rstatproc_havedisk_3_svc; break; + case RSTATVERS_VAR: + local = (svc_cb *)rstatproc_havedisk_4_svc; + break; default: svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); goto leave; diff --git a/libexec/rpc.rstatd/rstatd.c b/libexec/rpc.rstatd/rstatd.c --- a/libexec/rpc.rstatd/rstatd.c +++ b/libexec/rpc.rstatd/rstatd.c @@ -29,6 +29,7 @@ * SUCH DAMAGE. */ +#include #include #include #include @@ -43,6 +44,7 @@ void cleanup(int sig __unused) { + (void) rpcb_unset(RSTATPROG, RSTATVERS_VAR, NULL); (void) rpcb_unset(RSTATPROG, RSTATVERS_TIME, NULL); (void) rpcb_unset(RSTATPROG, RSTATVERS_SWTCH, NULL); (void) rpcb_unset(RSTATPROG, RSTATVERS_ORIG, NULL); @@ -56,6 +58,8 @@ int ok; struct sockaddr_storage from; socklen_t fromlen; + struct netconfig *nconf; + void *handle; if (argc == 2) closedown = atoi(argv[1]); @@ -73,6 +77,7 @@ if (!from_inetd) { daemon(0, 0); + (void)rpcb_unset(RSTATPROG, RSTATVERS_VAR, NULL); (void)rpcb_unset(RSTATPROG, RSTATVERS_TIME, NULL); (void)rpcb_unset(RSTATPROG, RSTATVERS_SWTCH, NULL); (void)rpcb_unset(RSTATPROG, RSTATVERS_ORIG, NULL); @@ -85,42 +90,45 @@ openlog("rpc.rstatd", LOG_CONS|LOG_PID, LOG_DAEMON); if (from_inetd) { - transp = svc_tli_create(0, NULL, NULL, 0, 0); - if (transp == NULL) { - syslog(LOG_ERR, "cannot create udp service."); + if ((handle = setnetconfig()) == NULL) { + syslog(LOG_ERR, "setnetconfig failed."); + exit(1); + } + while ((nconf = getnetconfig(handle)) != NULL) { + transp = svc_tli_create(0, nconf, NULL, 0, 0); + if (transp == NULL) { + syslog(LOG_ERR, "cannot create %s service.", nconf->nc_proto); + exit(1); + } + if (!svc_reg(transp, RSTATPROG, RSTATVERS_VAR, rstat_service, NULL)) { + syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_VAR, (inetd))"); + exit(1); + } + if (!svc_reg(transp, RSTATPROG, RSTATVERS_TIME, rstat_service, NULL)) { + syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_TIME, (inetd))"); + exit(1); + } + if (!svc_reg(transp, RSTATPROG, RSTATVERS_SWTCH, rstat_service, NULL)) { + syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_SWTCH, (inetd))"); + exit(1); + } + } + freenetconfigent(nconf); + } else { + if (!svc_create(rstat_service, RSTATPROG, RSTATVERS_VAR, "netpath")) { + syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_VAR, netpath"); + exit(1); + } + if (!svc_create(rstat_service, RSTATPROG, RSTATVERS_TIME, "netpath")) { + syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_TIME, netpath"); + exit(1); + } + if (!svc_create(rstat_service, RSTATPROG, RSTATVERS_SWTCH, "netpath")) { + syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_SWTCH, netpath"); exit(1); } - ok = svc_reg(transp, RSTATPROG, RSTATVERS_TIME, - rstat_service, NULL); - } else - ok = svc_create(rstat_service, - RSTATPROG, RSTATVERS_TIME, "udp"); - if (!ok) { - syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_TIME, %s)", (!from_inetd)?"udp":"(inetd)"); - exit(1); - } - if (from_inetd) - ok = svc_reg(transp, RSTATPROG, RSTATVERS_SWTCH, - rstat_service, NULL); - else - ok = svc_create(rstat_service, - RSTATPROG, RSTATVERS_SWTCH, "udp"); - if (!ok) { - syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_SWTCH, %s)", (!from_inetd)?"udp":"(inetd)"); - exit(1); - } - if (from_inetd) - ok = svc_reg(transp, RSTATPROG, RSTATVERS_ORIG, - rstat_service, NULL); - else - ok = svc_create(rstat_service, - RSTATPROG, RSTATVERS_ORIG, "udp"); - if (!ok) { - syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_ORIG, %s)", (!from_inetd)?"udp":"(inetd)"); - exit(1); } - - svc_run(); + svc_run(); syslog(LOG_ERR, "svc_run returned"); exit(1); } diff --git a/usr.bin/rup/rup.c b/usr.bin/rup/rup.c --- a/usr.bin/rup/rup.c +++ b/usr.bin/rup/rup.c @@ -57,13 +57,14 @@ #define HOST_WIDTH 15 +static int vers; /* which version we used now */ static struct host_list { struct host_list *next; - struct in_addr addr; + struct netbuf addr; } *hosts; static int -search_host(struct in_addr addr) +search_host(struct netbuf addr) { struct host_list *hp; @@ -71,45 +72,63 @@ return(0); for (hp = hosts; hp != NULL; hp = hp->next) { - if (hp->addr.s_addr == addr.s_addr) - return(1); + if (hp->addr.len == addr.len && + memcmp(hp->addr.buf, addr.buf, addr.len) == 0) + return (1); } return(0); } static void -remember_host(struct in_addr addr) +remember_host(struct netbuf addr) { struct host_list *hp; if (!(hp = (struct host_list *)malloc(sizeof(struct host_list)))) errx(1, "no memory"); - hp->addr.s_addr = addr.s_addr; + hp->addr.len = addr.len; + hp->addr.maxlen = addr.maxlen; + if ((hp->addr.buf = malloc(addr.maxlen)) == NULL) + errx(1, "no memory"); + memcpy(hp->addr.buf, addr.buf, addr.len); hp->next = hosts; hosts = hp; } static bool_t -rstat_reply(statstime *host_stat, struct sockaddr_in *raddrp) +rstat_reply(void *resultsp, struct netbuf *addr, struct netconfig *_unused) { + struct sockaddr *sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + struct statsvar *sv; + struct statstime *host_stat; struct tm *tmp_time; struct tm host_time; struct tm host_uptime; char days_buf[16]; char hours_buf[16]; - struct hostent *hp; - char *host; + char *host, host_buf[NI_MAXHOST]; time_t tmp_time_t; - if (search_host(raddrp->sin_addr)) + (void)_unused; + if (search_host(*addr)) return(0); - hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, - sizeof(struct in_addr), AF_INET); - if (hp) - host = hp->h_name; - else - host = inet_ntoa(raddrp->sin_addr); + sa = (struct sockaddr *)addr->buf; + if (getnameinfo(sa, addr->len, host_buf, sizeof(host_buf), + NULL, 0, NI_NAMEREQD) == 0) { + host = host_buf; + } + else if (sa->sa_family == AF_INET) { + memcpy(&sin, sa, sa->sa_len); + inet_ntop(AF_INET, &sin.sin_addr, host_buf, sizeof(host_buf)); + } + else { + memcpy(&sin6, sa, sa->sa_len); + inet_ntop(AF_INET6, &sin6.sin6_addr, host_buf, sizeof(host_buf)); + } + host = host_buf; /* truncate hostname to fit nicely into field */ if (strlen(host) > HOST_WIDTH) @@ -117,45 +136,93 @@ printf("%-*s\t", HOST_WIDTH, host); - tmp_time_t = host_stat->curtime.tv_sec; - tmp_time = localtime(&tmp_time_t); - host_time = *tmp_time; - - host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec; - - tmp_time_t = host_stat->curtime.tv_sec; - tmp_time = gmtime(&tmp_time_t); - host_uptime = *tmp_time; - - #define updays (host_stat->curtime.tv_sec / 86400) - if (host_uptime.tm_yday != 0) - sprintf(days_buf, "%3d day%s, ", updays, - (updays > 1) ? "s" : ""); - else - days_buf[0] = '\0'; - - if (host_uptime.tm_hour != 0) - sprintf(hours_buf, "%2d:%02d, ", - host_uptime.tm_hour, host_uptime.tm_min); - else - if (host_uptime.tm_min != 0) - sprintf(hours_buf, "%2d mins, ", host_uptime.tm_min); - else if (host_stat->curtime.tv_sec < 60) - sprintf(hours_buf, "%2d secs, ", host_uptime.tm_sec); + if (vers == RSTATVERS_VAR) { + sv = (statsvar *)resultsp; + + tmp_time_t = sv->curtime.tv_sec; + tmp_time = localtime(&tmp_time_t); + host_time = *tmp_time; + + sv->curtime.tv_sec -= sv->boottime.tv_sec; + + tmp_time_t = sv->curtime.tv_sec; + tmp_time = gmtime(&tmp_time_t); + host_uptime = *tmp_time; + + #define updays2 (sv->curtime.tv_sec / 86400) + if (host_uptime.tm_yday != 0) + sprintf(days_buf, "%3d day%s, ", updays2, + (updays2 > 1) ? "s" : ""); + else + days_buf[0] = '\0'; + + if (host_uptime.tm_hour != 0) + sprintf(hours_buf, "%2d:%02d, ", + host_uptime.tm_hour, host_uptime.tm_min); else - hours_buf[0] = '\0'; - - printf(" %2d:%02d%cm up %9.9s%9.9s load average: %.2f %.2f %.2f\n", - (host_time.tm_hour % 12) ? host_time.tm_hour % 12 : 12, - host_time.tm_min, - (host_time.tm_hour >= 12) ? 'p' : 'a', - days_buf, - hours_buf, - (double)host_stat->avenrun[0]/FSCALE, - (double)host_stat->avenrun[1]/FSCALE, - (double)host_stat->avenrun[2]/FSCALE); - - remember_host(raddrp->sin_addr); + if (host_uptime.tm_min != 0) + sprintf(hours_buf, "%2d mins, ", host_uptime.tm_min); + else if (sv->curtime.tv_sec < 60) + sprintf(hours_buf, "%2d secs, ", host_uptime.tm_sec); + else + hours_buf[0] = '\0'; + + printf(" %2d:%02d%cm up %9.9s%9.9s load average: %.2f %.2f %.2f\n", + (host_time.tm_hour % 12) ? host_time.tm_hour % 12 : 12, + host_time.tm_min, + (host_time.tm_hour >= 12) ? 'p' : 'a', + days_buf, + hours_buf, + (double)sv->avenrun[0]/FSCALE, + (double)sv->avenrun[1]/FSCALE, + (double)sv->avenrun[2]/FSCALE); + } + else if (vers == RSTATVERS_TIME) { + host_stat = (statstime *)resultsp; + + tmp_time_t = host_stat->curtime.tv_sec; + tmp_time = localtime(&tmp_time_t); + host_time = *tmp_time; + + host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec; + + tmp_time_t = host_stat->curtime.tv_sec; + tmp_time = gmtime(&tmp_time_t); + host_uptime = *tmp_time; + + #define updays (host_stat->curtime.tv_sec / 86400) + if (host_uptime.tm_yday != 0) + sprintf(days_buf, "%3d day%s, ", updays, + (updays > 1) ? "s" : ""); + else + days_buf[0] = '\0'; + + if (host_uptime.tm_hour != 0) + sprintf(hours_buf, "%2d:%02d, ", + host_uptime.tm_hour, host_uptime.tm_min); + else + if (host_uptime.tm_min != 0) + sprintf(hours_buf, "%2d mins, ", host_uptime.tm_min); + else if (host_stat->curtime.tv_sec < 60) + sprintf(hours_buf, "%2d secs, ", host_uptime.tm_sec); + else + hours_buf[0] = '\0'; + + printf(" %2d:%02d%cm up %9.9s%9.9s load average: %.2f %.2f %.2f\n", + (host_time.tm_hour % 12) ? host_time.tm_hour % 12 : 12, + host_time.tm_min, + (host_time.tm_hour >= 12) ? 'p' : 'a', + days_buf, + hours_buf, + (double)host_stat->avenrun[0]/FSCALE, + (double)host_stat->avenrun[1]/FSCALE, + (double)host_stat->avenrun[2]/FSCALE); + } + else { + return (0); + } + + remember_host(*addr); return(0); } @@ -163,50 +230,86 @@ onehost(char *host) { CLIENT *rstat_clnt; + statsvar sv; statstime host_stat; - struct sockaddr_in addr; - struct hostent *hp; + enum clnt_stat err; + struct netbuf addr; + struct addrinfo *res; struct timeval tv; - hp = gethostbyname(host); - if (hp == NULL) { + if (getaddrinfo(host, NULL, &(struct addrinfo) { + .ai_family = AF_UNSPEC + }, &res) != 0){ warnx("unknown host \"%s\"", host); return(-1); } - rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp"); + rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_VAR, "netpath"); if (rstat_clnt == NULL) { warnx("%s %s", host, clnt_spcreateerror("")); return(-1); } - bzero((char *)&host_stat, sizeof(host_stat)); + memset(&sv, 0, sizeof(sv)); tv.tv_sec = 15; /* XXX ??? */ tv.tv_usec = 0; - if (clnt_call(rstat_clnt, RSTATPROC_STATS, - (xdrproc_t)xdr_void, NULL, - (xdrproc_t)xdr_statstime, &host_stat, tv) != RPC_SUCCESS) { + err = clnt_call(rstat_clnt, RSTATPROC_STATS, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_statsvar, &sv, tv); + if (err == RPC_PROGVERSMISMATCH) { + clnt_destroy(rstat_clnt); + memset(&host_stat, 0, sizeof(host_stat)); + rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "netpath"); + if (rstat_clnt == NULL) { + warnx("%s %s", host, clnt_spcreateerror("")); + return(-1); + } + err = clnt_call(rstat_clnt, RSTATPROC_STATS, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_statstime, &host_stat, tv); + if (err != RPC_SUCCESS) { + warnx("%s: %s", host, clnt_sperror(rstat_clnt, host)); + clnt_destroy(rstat_clnt); + return(-1); + } + } + else if (err != RPC_SUCCESS) { warnx("%s: %s", host, clnt_sperror(rstat_clnt, host)); clnt_destroy(rstat_clnt); return(-1); } - memcpy(&addr.sin_addr.s_addr, hp->h_addr, sizeof(int)); - rstat_reply(&host_stat, &addr); + addr.len = addr.maxlen = res->ai_addrlen; + addr.buf = malloc(addr.len); + if (addr.buf == NULL) + errx(1, "malloc failed"); + memcpy(addr.buf, res->ai_addr, addr.len); + rstat_reply(&host_stat, &addr, NULL); + free(addr.buf); clnt_destroy(rstat_clnt); + freeaddrinfo(res); return (0); } static void allhosts(void) { + statsvar sv; statstime host_stat; enum clnt_stat clnt_stat; - clnt_stat = clnt_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS, + memset(&sv, 0, sizeof(sv)); + memset(&host_stat, 0, sizeof(host_stat)); + vers = RSTATVERS_VAR; + clnt_stat = rpc_broadcast(RSTATPROG, RSTATVERS_VAR, RSTATPROC_STATS, + (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_statsvar, (char *)&sv, + (resultproc_t)rstat_reply, "netpath"); + if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) + errx(1, "%s", clnt_sperrno(clnt_stat)); + vers = RSTATVERS_TIME; + clnt_stat = rpc_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS, (xdrproc_t)xdr_void, NULL, - (xdrproc_t)xdr_statstime, &host_stat, - (resultproc_t)rstat_reply); + (xdrproc_t)xdr_statstime, (char *)&host_stat, + (resultproc_t)rstat_reply, "netpath"); if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) errx(1, "%s", clnt_sperrno(clnt_stat)); }