1 /* $NetBSD: rup.c,v 1.15 1997/10/19 14:25:03 lukem Exp $ */ 2 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 #include <sys/cdefs.h> 37 #ifndef lint 38 __RCSID("$NetBSD: rup.c,v 1.15 1997/10/19 14:25:03 lukem Exp $"); 39 #endif /* not lint */ 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <time.h> 45 #include <sys/param.h> 46 #include <sys/socket.h> 47 #include <netdb.h> 48 #include <rpc/rpc.h> 49 #include <arpa/inet.h> 50 #include <err.h> 51 52 #undef FSHIFT /* Use protocol's shift and scale values */ 53 #undef FSCALE 54 #include <rpcsvc/rstat.h> 55 56 #define HOST_WIDTH 24 57 58 int printtime; /* print the remote host(s)'s time */ 59 60 struct host_list { 61 struct host_list *next; 62 struct in_addr addr; 63 } *hosts; 64 65 int search_host __P((struct in_addr)); 66 void remember_host __P((struct in_addr)); 67 68 int 69 search_host(addr) 70 struct in_addr addr; 71 { 72 struct host_list *hp; 73 74 if (!hosts) 75 return(0); 76 77 for (hp = hosts; hp != NULL; hp = hp->next) { 78 if (hp->addr.s_addr == addr.s_addr) 79 return(1); 80 } 81 return(0); 82 } 83 84 void 85 remember_host(addr) 86 struct in_addr addr; 87 { 88 struct host_list *hp; 89 90 if (!(hp = (struct host_list *)malloc(sizeof(struct host_list)))) { 91 err(1, "malloc"); 92 /* NOTREACHED */ 93 } 94 hp->addr.s_addr = addr.s_addr; 95 hp->next = hosts; 96 hosts = hp; 97 } 98 99 100 101 struct rup_data { 102 char *host; 103 struct statstime statstime; 104 }; 105 struct rup_data *rup_data; 106 int rup_data_idx = 0; 107 int rup_data_max = 0; 108 109 enum sort_type { 110 SORT_NONE, 111 SORT_HOST, 112 SORT_LDAV, 113 SORT_UPTIME 114 }; 115 enum sort_type sort_type; 116 117 int compare __P((struct rup_data *, struct rup_data *)); 118 void remember_rup_data __P((char *, struct statstime *)); 119 int rstat_reply __P((char *, struct sockaddr_in *)); 120 int print_rup_data __P((char *, statstime *)); 121 void onehost __P((char *)); 122 void allhosts __P((void)); 123 int main __P((int, char *[])); 124 void usage __P((void)); 125 126 int 127 compare(d1, d2) 128 struct rup_data *d1; 129 struct rup_data *d2; 130 { 131 switch(sort_type) { 132 case SORT_HOST: 133 return strcmp(d1->host, d2->host); 134 case SORT_LDAV: 135 return d1->statstime.avenrun[0] 136 - d2->statstime.avenrun[0]; 137 case SORT_UPTIME: 138 return d1->statstime.boottime.tv_sec 139 - d2->statstime.boottime.tv_sec; 140 default: 141 /* something's really wrong here */ 142 abort(); 143 } 144 } 145 146 void 147 remember_rup_data(host, st) 148 char *host; 149 struct statstime *st; 150 { 151 if (rup_data_idx >= rup_data_max) { 152 rup_data_max += 16; 153 rup_data = realloc (rup_data, 154 rup_data_max * sizeof(struct rup_data)); 155 if (rup_data == NULL) { 156 err (1, "realloc"); 157 /* NOTREACHED */ 158 } 159 } 160 161 rup_data[rup_data_idx].host = strdup(host); 162 rup_data[rup_data_idx].statstime = *st; 163 rup_data_idx++; 164 } 165 166 167 int 168 rstat_reply(replyp, raddrp) 169 char *replyp; 170 struct sockaddr_in *raddrp; 171 { 172 struct hostent *hp; 173 char *host; 174 statstime *host_stat = (statstime *)replyp; 175 176 if (!search_host(raddrp->sin_addr)) { 177 hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, 178 sizeof(struct in_addr), AF_INET); 179 180 if (hp) 181 host = hp->h_name; 182 else 183 host = inet_ntoa(raddrp->sin_addr); 184 185 remember_host(raddrp->sin_addr); 186 187 if (sort_type != SORT_NONE) { 188 remember_rup_data(host, host_stat); 189 } else { 190 print_rup_data(host, host_stat); 191 } 192 } 193 194 return (0); 195 } 196 197 198 int 199 print_rup_data(host, host_stat) 200 char *host; 201 statstime *host_stat; 202 { 203 struct tm *tmp_time; 204 struct tm host_time; 205 unsigned ups=0,upm=0,uph=0,upd=0; 206 207 char days_buf[16]; 208 char hours_buf[16]; 209 210 printf("%-*.*s", HOST_WIDTH, HOST_WIDTH, host); 211 212 tmp_time = localtime((time_t *)&host_stat->curtime.tv_sec); 213 host_time = *tmp_time; 214 215 host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec; 216 217 ups=host_stat->curtime.tv_sec; 218 upd=ups/(3600*24); 219 ups-=upd*3600*24; 220 uph=ups/3600; 221 ups-=uph*3600; 222 upm=ups/60; 223 224 if (upd != 0) 225 sprintf(days_buf, "%3u day%s, ", upd, 226 (upd > 1) ? "s" : ""); 227 else 228 days_buf[0] = '\0'; 229 230 if (uph != 0) 231 sprintf(hours_buf, "%2u:%02u, ", 232 uph, upm); 233 else 234 if (upm != 0) 235 sprintf(hours_buf, "%2u mins, ", upm); 236 else 237 hours_buf[0] = '\0'; 238 if (printtime) 239 printf(" %2d:%02d%cm", 240 (host_time.tm_hour % 12) ? (host_time.tm_hour % 12) : 12, 241 host_time.tm_min, (host_time.tm_hour >= 12) ? 'p' : 'a'); 242 243 printf(" up %9.9s%9.9s load average: %.2f %.2f %.2f\n", 244 days_buf, hours_buf, 245 (double)host_stat->avenrun[0]/FSCALE, 246 (double)host_stat->avenrun[1]/FSCALE, 247 (double)host_stat->avenrun[2]/FSCALE); 248 249 return(0); 250 } 251 252 253 void 254 onehost(host) 255 char *host; 256 { 257 CLIENT *rstat_clnt; 258 statstime host_stat; 259 static struct timeval timeout = {25, 0}; 260 261 rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp"); 262 if (rstat_clnt == NULL) { 263 warnx("%s", clnt_spcreateerror(host)); 264 return; 265 } 266 267 memset((char *)&host_stat, 0, sizeof(host_stat)); 268 if (clnt_call(rstat_clnt, RSTATPROC_STATS, xdr_void, NULL, xdr_statstime, &host_stat, timeout) != RPC_SUCCESS) { 269 warnx("%s", clnt_sperror(rstat_clnt, host)); 270 return; 271 } 272 273 print_rup_data(host, &host_stat); 274 clnt_destroy(rstat_clnt); 275 } 276 277 void 278 allhosts() 279 { 280 statstime host_stat; 281 enum clnt_stat clnt_stat; 282 size_t i; 283 284 if (sort_type != SORT_NONE) { 285 printf("collecting responses..."); 286 fflush(stdout); 287 } 288 289 clnt_stat = clnt_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS, 290 xdr_void, NULL, 291 xdr_statstime, (char*)&host_stat, rstat_reply); 292 if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) { 293 warnx("%s", clnt_sperrno(clnt_stat)); 294 exit(1); 295 } 296 297 if (sort_type != SORT_NONE) { 298 putchar('\n'); 299 qsort(rup_data, rup_data_idx, sizeof(struct rup_data), 300 (int (*)(const void*, const void*))compare); 301 302 for (i = 0; i < rup_data_idx; i++) { 303 print_rup_data(rup_data[i].host, &rup_data[i].statstime); 304 } 305 } 306 } 307 308 int 309 main(argc, argv) 310 int argc; 311 char *argv[]; 312 { 313 int ch; 314 extern int optind; 315 316 sort_type = SORT_NONE; 317 while ((ch = getopt(argc, argv, "dhlt")) != -1) 318 switch (ch) { 319 case 'd': 320 printtime = 1; 321 break; 322 case 'h': 323 sort_type = SORT_HOST; 324 break; 325 case 'l': 326 sort_type = SORT_LDAV; 327 break; 328 case 't': 329 sort_type = SORT_UPTIME; 330 break; 331 default: 332 usage(); 333 /*NOTREACHED*/ 334 } 335 336 setlinebuf(stdout); 337 338 if (argc == optind) 339 allhosts(); 340 else { 341 for (; optind < argc; optind++) 342 onehost(argv[optind]); 343 } 344 345 exit(0); 346 } 347 348 void 349 usage() 350 { 351 fprintf(stderr, "Usage: rup [-dhlt] [hosts ...]\n"); 352 exit(1); 353 } 354