=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/rusers/rusers.c,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- src/usr.bin/rusers/rusers.c 2001/10/11 03:06:32 1.13 +++ src/usr.bin/rusers/rusers.c 2001/11/01 23:37:42 1.14 @@ -1,9 +1,35 @@ -/* $OpenBSD: rusers.c,v 1.13 2001/10/11 03:06:32 millert Exp $ */ +/* $OpenBSD: rusers.c,v 1.14 2001/11/01 23:37:42 millert Exp $ */ +/* + * Copyright (c) 2001 Todd C. Miller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /*- * Copyright (c) 1993 John Brezak * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -14,7 +40,7 @@ * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -29,46 +55,105 @@ */ #ifndef lint -static const char rcsid[] = "$OpenBSD: rusers.c,v 1.13 2001/10/11 03:06:32 millert Exp $"; +static const char rcsid[] = "$OpenBSD: rusers.c,v 1.14 2001/11/01 23:37:42 millert Exp $"; #endif /* not lint */ -#include #include +#include #include -#include -#include -#include -#include #include -#include +#include +#include +#include +#include /* Old protocol version */ #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include -/* - * For now we only try version 2 of the protocol. The current - * version is 3 (rusers.h), but only Solaris and NetBSD seem - * to support it currently. - */ -#include /* Old version */ - -#define MAX_INT 0x7fffffff /* Preferred formatting */ -#define HOST_WIDTH 20 +#define HOST_WIDTH 17 #define LINE_WIDTH 8 #define NAME_WIDTH 8 -struct timeval timeout = { 25, 0 }; +int search_host(struct in_addr); +void remember_host(char **); +void fmt_idle(int, char *, size_t); +void print_longline(int, u_int, char *, char *, char *, char *, int); +void onehost(char *); +void allhosts(void); +void alarmclock(int); +bool_t rusers_reply(char *, struct sockaddr_in *); +bool_t rusers_reply_3(char *, struct sockaddr_in *); +enum clnt_stat get_reply(int, u_long, u_long, struct rpc_msg *, + struct rmtcallres *, bool_t (*)()); +__dead void usage(void); + int longopt; int allopt; +long termwidth; +struct itimerval timeout; +extern char *__progname; struct host_list { struct host_list *next; struct in_addr addr; } *hosts; -extern char *__progname; +#define MAX_BROADCAST_SIZE 1400 int +main(int argc, char **argv) +{ + struct winsize win; + char *cp, *ep; + int ch; + + while ((ch = getopt(argc, argv, "al")) != -1) + switch (ch) { + case 'a': + allopt++; + break; + case 'l': + longopt++; + break; + default: + usage(); + /*NOTREACHED*/ + } + + if (isatty(STDOUT_FILENO)) { + if ((cp = getenv("COLUMNS")) != NULL && *cp != '\0') { + termwidth = strtol(cp, &ep, 10); + if (*ep != '\0' || termwidth >= INT_MAX || + termwidth < 0) + termwidth = 0; + } + if (termwidth == 0 && + ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && + win.ws_col > 0) + termwidth = win.ws_col; + else + termwidth = 80; + } + setlinebuf(stdout); + if (argc == optind) + allhosts(); + else { + for (; optind < argc; optind++) + (void) onehost(argv[optind]); + } + exit(0); +} + +int search_host(struct in_addr addr) { struct host_list *hp; @@ -84,28 +169,90 @@ } void -remember_host(struct in_addr addr) +remember_host(char **ap) { struct host_list *hp; - if (!(hp = (struct host_list *)malloc(sizeof(struct host_list)))) - err(1, NULL); - hp->addr.s_addr = addr.s_addr; - hp->next = hosts; - hosts = hp; + for (; *ap; ap++) { + if (!(hp = malloc(sizeof(struct host_list)))) + err(1, NULL); + hp->addr.s_addr = *(in_addr_t *)*ap; + hp->next = hosts; + hosts = hp; + } } +void +fmt_idle(int idle, char *idle_time, size_t idle_time_len) +{ + int days, hours, minutes, seconds; + + switch (idle) { + case 0: + *idle_time = '\0'; + break; + case INT_MAX: + strlcpy(idle_time, "??", idle_time_len); + break; + default: + seconds = idle; + days = seconds / (60*60*24); + seconds %= (60*60*24); + hours = seconds / (60*60); + seconds %= (60*60); + minutes = seconds / 60; + seconds %= 60; + if (idle >= (24*60*60)) + snprintf(idle_time, idle_time_len, + "%d days, %d:%02d:%02d", + days, hours, minutes, seconds); + else if (idle >= (60*60)) + snprintf(idle_time, idle_time_len, "%2d:%02d:%02d", + hours, minutes, seconds); + else if (idle > 60) + snprintf(idle_time, idle_time_len, "%2d:%02d", + minutes, seconds); + else + snprintf(idle_time, idle_time_len, " :%02d", idle); + break; + } +} + +void +print_longline(int ut_time, u_int idle, char *host, char *user, char *line, + char *remhost, int remhostmax) +{ + char date[32], idle_time[64]; + char remote[RUSERS_MAXHOSTLEN + 1]; + int len; + + strftime(date, sizeof(date), "%h %d %R", localtime((time_t *)&ut_time)); + date[sizeof(date) - 1] = '\0'; + fmt_idle(idle, idle_time, sizeof(idle_time)); + len = termwidth - + (MAX(strlen(user), NAME_WIDTH) + 1 + HOST_WIDTH + 1 + LINE_WIDTH + + 1 + strlen(date) + 1 + MAX(8, strlen(idle_time)) + 1 + 2); + if (len > 0 && *remhost != '\0') + snprintf(remote, sizeof(remote), "(%.*s)", + MIN(len, remhostmax), remhost); + else + remote[0] = '\0'; + len = HOST_WIDTH - MIN(HOST_WIDTH, strlen(host)) + + LINE_WIDTH - MIN(LINE_WIDTH, strlen(line)); + printf("%-*s %.*s:%.*s%-*s %-12s %8s %s\n", + NAME_WIDTH, user, HOST_WIDTH, host, LINE_WIDTH, line, + len, "", date, idle_time, remote); +} + int rusers_reply(char *replyp, struct sockaddr_in *raddrp) { - int x, idle, i; - char date[32], idle_time[64], remote[RNUSERS_MAXHOSTLEN + 1]; - char local[HOST_WIDTH + LINE_WIDTH + 2]; + char user[RNUSERS_MAXUSERLEN + 1]; char utline[RNUSERS_MAXLINELEN + 1]; - struct hostent *hp; utmpidlearr *up = (utmpidlearr *)replyp; - char *host, *tmp; - int days, hours, minutes, seconds; + struct hostent *hp; + char *host, *taddrs[2]; + int i; if (search_host(raddrp->sin_addr)) return(0); @@ -114,82 +261,94 @@ return(0); hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, - sizeof(struct in_addr), AF_INET); - if (hp) + sizeof(struct in_addr), AF_INET); + if (hp) { host = hp->h_name; - else + remember_host(hp->h_addr_list); + } else { host = inet_ntoa(raddrp->sin_addr); + taddrs[0] = (char *)&raddrp->sin_addr; + taddrs[1] = NULL; + remember_host(taddrs); + } if (!longopt) printf("%-*.*s ", HOST_WIDTH, HOST_WIDTH, host); - for (x = 0; x < up->uia_cnt; x++) { - strlcpy(date, - &(ctime((time_t *)&(up->uia_arr[x]->ui_utmp.ut_time))[4]), - sizeof(date)); - /* ctime() adds a trailing \n. Trimming it is only - * mandatory if the output formatting changes. - */ - if ((tmp = strchr(date, '\n')) != NULL) - *tmp = '\0'; - - idle = up->uia_arr[x]->ui_idle; - sprintf(idle_time, " :%02d", idle); - if (idle == MAX_INT) - strcpy(idle_time, "??"); - else if (idle == 0) - strcpy(idle_time, ""); - else { - seconds = idle; - days = seconds/(60*60*24); - seconds %= (60*60*24); - hours = seconds/(60*60); - seconds %= (60*60); - minutes = seconds/60; - seconds %= 60; - if (idle > 60) - sprintf(idle_time, "%2d:%02d", - minutes, seconds); - if (idle >= (60*60)) - sprintf(idle_time, "%2d:%02d:%02d", - hours, minutes, seconds); - if (idle >= (24*60*60)) - sprintf(idle_time, "%d days, %d:%02d:%02d", - days, hours, minutes, seconds); + for (i = 0; i < up->uia_cnt; i++) { + /* NOTE: strncpy() used below for non-terminated strings. */ + strncpy(user, up->uia_arr[i]->ui_utmp.ut_name, + sizeof(user) - 1); + user[sizeof(user) - 1] = '\0'; + if (longopt) { + strncpy(utline, up->uia_arr[i]->ui_utmp.ut_line, + sizeof(utline) - 1); + utline[sizeof(utline) - 1] = '\0'; + print_longline(up->uia_arr[i]->ui_utmp.ut_time, + up->uia_arr[i]->ui_idle, host, user, utline, + up->uia_arr[i]->ui_utmp.ut_host, RNUSERS_MAXHOSTLEN); + } else { + fputs(user, stdout); + putchar(' '); } + } + if (!longopt) + putchar('\n'); + + return(0); +} - strncpy(remote, up->uia_arr[x]->ui_utmp.ut_host, - sizeof(remote)-1); - remote[sizeof(remote) - 1] = '\0'; - if (strlen(remote) != 0) - snprintf(remote, sizeof(remote), "(%.16s)", - up->uia_arr[x]->ui_utmp.ut_host); +int +rusers_reply_3(char *replyp, struct sockaddr_in *raddrp) +{ + char user[RUSERS_MAXUSERLEN + 1]; + char utline[RUSERS_MAXLINELEN + 1]; + utmp_array *up3 = (utmp_array *)replyp; + struct hostent *hp; + char *host, *taddrs[2]; + int i; + + if (search_host(raddrp->sin_addr)) + return(0); + if (!allopt && !up3->utmp_array_len) + return(0); + + hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, + sizeof(struct in_addr), AF_INET); + if (hp) { + host = hp->h_name; + remember_host(hp->h_addr_list); + } else { + host = inet_ntoa(raddrp->sin_addr); + taddrs[0] = (char *)&raddrp->sin_addr; + taddrs[1] = NULL; + remember_host(taddrs); + } + + if (!longopt) + printf("%-*.*s ", HOST_WIDTH, HOST_WIDTH, host); + + for (i = 0; i < up3->utmp_array_len; i++) { + /* NOTE: strncpy() used below for non-terminated strings. */ + strncpy(user, up3->utmp_array_val[i].ut_user, + sizeof(user) - 1); + user[sizeof(user) - 1] = '\0'; if (longopt) { - strncpy(local, host, sizeof(local)); - strncpy(utline, up->uia_arr[x]->ui_utmp.ut_line, + strncpy(utline, up3->utmp_array_val[i].ut_line, sizeof(utline) - 1); utline[sizeof(utline) - 1] = '\0'; - i = sizeof(local) - strlen(utline) - 2; - if (i < 0) - i = 0; - local[i] = '\0'; - strcat(local, ":"); - strlcat(local, utline, sizeof(local)); - - printf("%-*.*s %-*.*s %-12.12s %8s %.18s\n", - NAME_WIDTH, RNUSERS_MAXUSERLEN, - up->uia_arr[x]->ui_utmp.ut_name, - HOST_WIDTH+LINE_WIDTH+1, HOST_WIDTH+LINE_WIDTH+1, - local, date, idle_time, remote); - } else - printf("%.*s ", RNUSERS_MAXUSERLEN, - up->uia_arr[x]->ui_utmp.ut_name); + print_longline(up3->utmp_array_val[i].ut_time, + up3->utmp_array_val[i].ut_idle, host, user, utline, + up3->utmp_array_val[i].ut_host, RUSERS_MAXHOSTLEN); + } else { + fputs(user, stdout); + putchar(' '); + } } if (!longopt) putchar('\n'); - remember_host(raddrp->sin_addr); return(0); } @@ -197,23 +356,53 @@ onehost(char *host) { utmpidlearr up; + utmp_array up3; CLIENT *rusers_clnt; struct sockaddr_in addr; struct hostent *hp; + struct timeval tv = { 25, 0 }; + int error; hp = gethostbyname(host); if (hp == NULL) errx(1, "unknown host \"%s\"", host); + /* try version 3 first */ + rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_3, "udp"); + if (rusers_clnt == NULL) { + clnt_pcreateerror(__progname); + exit(1); + } + + memset(&up3, 0, sizeof(up3)); + error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, + xdr_utmp_array, &up3, tv); + switch (error) { + case RPC_SUCCESS: + addr.sin_addr.s_addr = *(int *)hp->h_addr; + rusers_reply_3((char *)&up3, &addr); + clnt_destroy(rusers_clnt); + return; + case RPC_PROGVERSMISMATCH: + clnt_destroy(rusers_clnt); + break; + default: + clnt_perror(rusers_clnt, __progname); + clnt_destroy(rusers_clnt); + exit(1); + } + + /* fall back to version 2 */ rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp"); if (rusers_clnt == NULL) { clnt_pcreateerror(__progname); exit(1); } - bzero((char *)&up, sizeof(up)); - if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, - xdr_utmpidlearr, &up, timeout) != RPC_SUCCESS) { + memset(&up, 0, sizeof(up)); + error = clnt_call(rusers_clnt, RUSERSPROC_NAMES, xdr_void, NULL, + xdr_utmpidlearr, &up, tv); + if (error != RPC_SUCCESS) { clnt_perror(rusers_clnt, __progname); clnt_destroy(rusers_clnt); exit(1); @@ -223,52 +412,250 @@ clnt_destroy(rusers_clnt); } +enum clnt_stat +get_reply(int sock, u_long port, u_long xid, struct rpc_msg *msgp, + struct rmtcallres *resp, bool_t (*callback)()) +{ + int inlen, fromlen; + struct sockaddr_in raddr; + char inbuf[UDPMSGSIZE]; + XDR xdr; + +retry: + msgp->acpted_rply.ar_verf = _null_auth; + msgp->acpted_rply.ar_results.where = (caddr_t)resp; + msgp->acpted_rply.ar_results.proc = xdr_rmtcallres; + + fromlen = sizeof(struct sockaddr); + inlen = recvfrom(sock, inbuf, sizeof(inbuf), 0, + (struct sockaddr *)&raddr, &fromlen); + if (inlen < 0) { + if (errno == EINTR) + goto retry; + return (RPC_CANTRECV); + } + if (inlen < sizeof(u_int32_t)) + goto retry; + + /* + * If the reply we got matches our request, decode the + * replay and pass it to the callback function. + */ + xdrmem_create(&xdr, inbuf, (u_int)inlen, XDR_DECODE); + if (xdr_replymsg(&xdr, msgp)) { + if ((msgp->rm_xid == xid) && + (msgp->rm_reply.rp_stat == MSG_ACCEPTED) && + (msgp->acpted_rply.ar_stat == SUCCESS)) { + raddr.sin_port = htons((u_short)port); + (void)(*callback)(resp->results_ptr, &raddr); + } + } + xdr.x_op = XDR_FREE; + msgp->acpted_rply.ar_results.proc = xdr_void; + (void)xdr_replymsg(&xdr, msgp); + (void)(*resp->xdr_results)(&xdr, resp->results_ptr); + xdr_destroy(&xdr); + + return(RPC_SUCCESS); +} + +enum clnt_stat +rpc_setup(int *fdp, XDR *xdrs, struct rpc_msg *msg, struct rmtcallargs *args, + AUTH *unix_auth, char *buf) +{ + int on = 1; + + if ((*fdp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + return(RPC_CANTSEND); + + if (setsockopt(*fdp, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) + return(RPC_CANTSEND); + + msg->rm_xid = arc4random(); + msg->rm_direction = CALL; + msg->rm_call.cb_rpcvers = RPC_MSG_VERSION; + msg->rm_call.cb_prog = PMAPPROG; + msg->rm_call.cb_vers = PMAPVERS; + msg->rm_call.cb_proc = PMAPPROC_CALLIT; + msg->rm_call.cb_cred = unix_auth->ah_cred; + msg->rm_call.cb_verf = unix_auth->ah_verf; + + xdrmem_create(xdrs, buf, MAX_BROADCAST_SIZE, XDR_ENCODE); + if (!xdr_callmsg(xdrs, msg) || !xdr_rmtcall_args(xdrs, args)) + return(RPC_CANTENCODEARGS); + + return(RPC_SUCCESS); +} + void allhosts(void) { + enum clnt_stat stat; + AUTH *unix_auth = authunix_create_default(); + int outlen, outlen3; + int sock = -1; + int sock3 = -1; + int i, maxfd, rval; + u_long xid, xid3; + u_long port, port3; + fd_set *fds = NULL; + struct sockaddr_in *sin, baddr; + struct rmtcallargs args; + struct rmtcallres res, res3; + struct rpc_msg msg, msg3; + struct ifaddrs *ifa, *ifap = NULL; + char buf[MAX_BROADCAST_SIZE], buf3[MAX_BROADCAST_SIZE]; utmpidlearr up; - enum clnt_stat clnt_stat; + utmp_array up3; + XDR xdr; - bzero((char *)&up, sizeof(up)); - clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE, - RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr, - (char *)&up, rusers_reply); - if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) - errx(1, "%s", clnt_sperrno(clnt_stat)); + if (getifaddrs(&ifap) != 0) { + perror("Cannot get list of interface addresses"); + stat = RPC_CANTSEND; + goto cleanup; + } + + args.prog = RUSERSPROG; + args.vers = RUSERSVERS_IDLE; + args.proc = RUSERSPROC_NAMES; + args.xdr_args = xdr_void; + args.args_ptr = NULL; + + stat = rpc_setup(&sock, &xdr, &msg, &args, unix_auth, buf); + if (stat != RPC_SUCCESS) + goto cleanup; + xid = msg.rm_xid; + outlen = (int)xdr_getpos(&xdr); + xdr_destroy(&xdr); + + args.vers = RUSERSVERS_3; + stat = rpc_setup(&sock3, &xdr, &msg3, &args, unix_auth, buf3); + if (stat != RPC_SUCCESS) + goto cleanup; + xid3 = msg3.rm_xid; + outlen3 = (int)xdr_getpos(&xdr); + xdr_destroy(&xdr); + + maxfd = sock3 + 1; + fds = (fd_set *)calloc(howmany(maxfd, NFDBITS), sizeof(fd_mask)); + if (fds == NULL) { + stat = RPC_CANTSEND; + goto cleanup; + } + + memset(&baddr, 0, sizeof(baddr)); + baddr.sin_len = sizeof(struct sockaddr_in); + baddr.sin_family = AF_INET; + baddr.sin_port = htons(PMAPPORT); + baddr.sin_addr.s_addr = htonl(INADDR_ANY); + + memset(&res, 0, sizeof(res)); + res.port_ptr = &port; + res.xdr_results = xdr_utmpidlearr; + res.results_ptr = (caddr_t)&up; + + memset(&res3, 0, sizeof(res3)); + res3.port_ptr = &port3; + res3.xdr_results = xdr_utmp_array; + res3.results_ptr = (caddr_t)&up3; + + (void)signal(SIGALRM, alarmclock); + + /* + * We do 6 runs through the loop. On even runs we send + * a version 3 broadcast. On odd ones we send a version 2 + * broadcast. This should give version 3 replies enough + * of an 'edge' over the old version 2 ones in most cases. + * We select() waiting for replies for 5 seconds in between + * each broadcast. + */ + for (i = 0; i < 6; i++) { + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != AF_INET || + !(ifa->ifa_flags & IFF_BROADCAST) || + !(ifa->ifa_flags & IFF_UP) || + ifa->ifa_broadaddr == NULL || + ifa->ifa_broadaddr->sa_family != AF_INET) + continue; + sin = (struct sockaddr_in *)ifa->ifa_broadaddr; + baddr.sin_addr = sin->sin_addr; + + /* use protocol 2 or 3 depending on i (odd or even) */ + if (i & 1) { + if (sendto(sock, buf, outlen, 0, + (struct sockaddr *)&baddr, + sizeof(struct sockaddr)) != outlen) { + warn("unable to send broadcast packet"); + stat = RPC_CANTSEND; + goto cleanup; + } + } else { + if (sendto(sock3, buf3, outlen3, 0, + (struct sockaddr *)&baddr, + sizeof(struct sockaddr)) != outlen3) { + warn("unable to send broadcast packet"); + stat = RPC_CANTSEND; + goto cleanup; + } + } + } + + /* + * We stay in the select loop for ~5 seconds + */ + timerclear(&timeout.it_value); + timeout.it_value.tv_sec = 5; + timeout.it_value.tv_usec = 0; + while (timerisset(&timeout.it_value)) { + FD_SET(sock, fds); + FD_SET(sock3, fds); + setitimer(ITIMER_REAL, &timeout, NULL); + rval = select(maxfd, fds, NULL, NULL, NULL); + setitimer(ITIMER_REAL, NULL, &timeout); + if (rval == -1) { + if (!timerisset(&timeout.it_value)) + break; + warn("select"); /* shouldn't happen */ + stat = RPC_CANTRECV; + goto cleanup; + } + if (FD_ISSET(sock3, fds)) { + stat = get_reply(sock3, port3, xid3, &msg3, + &res3, rusers_reply_3); + if (stat != RPC_SUCCESS) + goto cleanup; + } + if (FD_ISSET(sock, fds)) { + stat = get_reply(sock, port, xid, &msg, + &res, rusers_reply); + if (stat != RPC_SUCCESS) + goto cleanup; + } + } + } +cleanup: + if (ifap != NULL) + freeifaddrs(ifap); + if (fds != NULL) + free(fds); + if (sock >= 0) + (void)close(sock); + if (sock3 >= 0) + (void)close(sock3); + AUTH_DESTROY(unix_auth); } void -usage(void) +alarmclock(int signo) { - fprintf(stderr, "Usage: %s [-la] [hosts ...]\n", __progname); - exit(1); + + timerclear(&timeout.it_value); } -int -main(int argc, char *argv[]) +void +usage(void) { - int ch; - extern int optind; - - while ((ch = getopt(argc, argv, "al")) != -1) - switch (ch) { - case 'a': - allopt++; - break; - case 'l': - longopt++; - break; - default: - usage(); - /*NOTREACHED*/ - } - setlinebuf(stdout); - if (argc == optind) - allhosts(); - else { - for (; optind < argc; optind++) - (void) onehost(argv[optind]); - } - exit(0); + fprintf(stderr, "usage: %s [-la] [hosts ...]\n", __progname); + exit(1); }