1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1993, John Brezak 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 40 #include <rpc/rpc.h> 41 #include <rpc/pmap_clnt.h> 42 #include <rpcsvc/rnusers.h> 43 44 #include <arpa/inet.h> 45 46 #include <err.h> 47 #include <netdb.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <timeconv.h> 52 #include <unistd.h> 53 54 #define MAX_INT 0x7fffffff 55 #define HOST_WIDTH 20 56 #define LINE_WIDTH 15 57 58 static int longopt; 59 static int allopt; 60 61 static struct host_list { 62 struct host_list *next; 63 struct in_addr addr; 64 } *hosts; 65 66 static int 67 search_host(struct in_addr addr) 68 { 69 struct host_list *hp; 70 71 if (hosts == NULL) 72 return (0); 73 74 for (hp = hosts; hp != NULL; hp = hp->next) { 75 if (hp->addr.s_addr == addr.s_addr) 76 return (1); 77 } 78 return (0); 79 } 80 81 static void 82 remember_host(struct in_addr addr) 83 { 84 struct host_list *hp; 85 86 if ((hp = (struct host_list *)malloc(sizeof(struct host_list))) == NULL) 87 errx(1, "no memory"); 88 hp->addr.s_addr = addr.s_addr; 89 hp->next = hosts; 90 hosts = hp; 91 } 92 93 static int 94 rusers_reply(void *replyp, struct sockaddr_in *raddrp) 95 { 96 unsigned int x; 97 int idle; 98 char date[32], idle_time[64], remote[64]; 99 struct hostent *hp; 100 utmpidlearr *up, u; 101 char *host; 102 int days, hours, minutes, seconds; 103 104 up = &u; 105 memcpy(up, replyp, sizeof(*up)); 106 if (search_host(raddrp->sin_addr)) 107 return (0); 108 109 if (!allopt && up->utmpidlearr_len == 0) 110 return (0); 111 112 hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, 113 sizeof(struct in_addr), AF_INET); 114 if (hp != NULL) 115 host = hp->h_name; 116 else 117 host = inet_ntoa(raddrp->sin_addr); 118 119 if (!longopt) 120 printf("%-*s ", HOST_WIDTH, host); 121 122 for (x = 0; x < up->utmpidlearr_len; x++) { 123 time_t t = _int_to_time(up->utmpidlearr_val[x].ui_utmp.ut_time); 124 strncpy(date, &(ctime(&t)[4]), sizeof(date) - 1); 125 126 idle = up->utmpidlearr_val[x].ui_idle; 127 sprintf(idle_time, " :%02d", idle); 128 if (idle == MAX_INT) 129 strcpy(idle_time, "??"); 130 else if (idle == 0) 131 strcpy(idle_time, ""); 132 else { 133 seconds = idle; 134 days = seconds / (60 * 60 * 24); 135 seconds %= (60 * 60 * 24); 136 hours = seconds / (60 * 60); 137 seconds %= (60 * 60); 138 minutes = seconds / 60; 139 seconds %= 60; 140 if (idle > 60) 141 sprintf(idle_time, "%d:%02d", minutes, seconds); 142 if (idle >= (60 * 60)) 143 sprintf(idle_time, "%d:%02d:%02d", 144 hours, minutes, seconds); 145 if (idle >= (24 * 60 * 60)) 146 sprintf(idle_time, "%d days, %d:%02d:%02d", 147 days, hours, minutes, seconds); 148 } 149 150 strncpy(remote, up->utmpidlearr_val[x].ui_utmp.ut_host, 151 sizeof(remote) - 1); 152 if (strlen(remote) != 0) 153 sprintf(remote, "(%.16s)", 154 up->utmpidlearr_val[x].ui_utmp.ut_host); 155 156 if (longopt) 157 printf("%-8.8s %*s:%-*.*s %-12.12s %6s %.18s\n", 158 up->utmpidlearr_val[x].ui_utmp.ut_name, 159 HOST_WIDTH, host, LINE_WIDTH, LINE_WIDTH, 160 up->utmpidlearr_val[x].ui_utmp.ut_line, date, 161 idle_time, remote ); 162 else 163 printf("%s ", 164 up->utmpidlearr_val[x].ui_utmp.ut_name); 165 } 166 if (!longopt) 167 putchar('\n'); 168 169 remember_host(raddrp->sin_addr); 170 return (0); 171 } 172 173 static void 174 onehost(char *host) 175 { 176 utmpidlearr up; 177 CLIENT *rusers_clnt; 178 struct sockaddr_in addr; 179 struct hostent *hp; 180 struct timeval tv; 181 182 hp = gethostbyname(host); 183 if (hp == NULL) 184 errx(1, "unknown host \"%s\"", host); 185 186 rusers_clnt = clnt_create(host, RUSERSPROG, RUSERSVERS_IDLE, "udp"); 187 if (rusers_clnt == NULL) 188 errx(1, "%s", clnt_spcreateerror("")); 189 190 memset(&up, 0, sizeof(up)); 191 tv.tv_sec = 15; /* XXX ?? */ 192 tv.tv_usec = 0; 193 if (clnt_call(rusers_clnt, RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, 194 (xdrproc_t)xdr_utmpidlearr, &up, tv) != RPC_SUCCESS) 195 errx(1, "%s", clnt_sperror(rusers_clnt, "")); 196 memcpy(&addr.sin_addr.s_addr, hp->h_addr, sizeof(addr.sin_addr.s_addr)); 197 rusers_reply(&up, &addr); 198 clnt_destroy(rusers_clnt); 199 } 200 201 static void 202 allhosts(void) 203 { 204 utmpidlearr up; 205 enum clnt_stat clnt_stat; 206 207 memset(&up, 0, sizeof(up)); 208 clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE, 209 RUSERSPROC_NAMES, (xdrproc_t)xdr_void, NULL, 210 (xdrproc_t)xdr_utmpidlearr, (char *)&up, 211 (resultproc_t)rusers_reply); 212 if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) 213 errx(1, "%s", clnt_sperrno(clnt_stat)); 214 } 215 216 static void 217 usage(void) 218 { 219 220 fprintf(stderr, "usage: rusers [-al] [host ...]\n"); 221 exit(1); 222 } 223 224 int 225 main(int argc, char *argv[]) 226 { 227 int ch; 228 229 while ((ch = getopt(argc, argv, "al")) != -1) 230 switch (ch) { 231 case 'a': 232 allopt++; 233 break; 234 case 'l': 235 longopt++; 236 break; 237 default: 238 usage(); 239 /* NOTREACHED */ 240 } 241 242 setlinebuf(stdout); 243 if (argc == optind) 244 allhosts(); 245 else { 246 for (; optind < argc; optind++) 247 (void)onehost(argv[optind]); 248 } 249 exit(0); 250 } 251