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