1 /*- 2 * Copyright (c) 1993, John Brezak 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char rcsid[] = "$Id: rup.c,v 1.10 1994/02/05 14:58:14 pk Exp $"; 36 #endif /* not lint */ 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <time.h> 42 #include <sys/param.h> 43 #include <sys/socket.h> 44 #include <netdb.h> 45 #include <rpc/rpc.h> 46 #include <arpa/inet.h> 47 #include <err.h> 48 49 #undef FSHIFT /* Use protocol's shift and scale values */ 50 #undef FSCALE 51 #include <rpcsvc/rstat.h> 52 53 #define HOST_WIDTH 24 54 55 int printtime; /* print the remote host(s)'s time */ 56 57 struct host_list { 58 struct host_list *next; 59 struct in_addr addr; 60 } *hosts; 61 62 int 63 search_host(addr) 64 struct in_addr addr; 65 { 66 struct host_list *hp; 67 68 if (!hosts) 69 return(0); 70 71 for (hp = hosts; hp != NULL; hp = hp->next) { 72 if (hp->addr.s_addr == addr.s_addr) 73 return(1); 74 } 75 return(0); 76 } 77 78 void 79 remember_host(addr) 80 struct in_addr addr; 81 { 82 struct host_list *hp; 83 84 if (!(hp = (struct host_list *)malloc(sizeof(struct host_list)))) { 85 err(1, NULL); 86 /* NOTREACHED */ 87 } 88 hp->addr.s_addr = addr.s_addr; 89 hp->next = hosts; 90 hosts = hp; 91 } 92 93 94 95 struct rup_data { 96 char *host; 97 struct statstime statstime; 98 }; 99 struct rup_data *rup_data; 100 int rup_data_idx = 0; 101 int rup_data_max = 0; 102 103 enum sort_type { 104 SORT_NONE, 105 SORT_HOST, 106 SORT_LDAV, 107 SORT_UPTIME 108 }; 109 enum sort_type sort_type; 110 111 compare(d1, d2) 112 struct rup_data *d1; 113 struct rup_data *d2; 114 { 115 switch(sort_type) { 116 case SORT_HOST: 117 return strcmp(d1->host, d2->host); 118 case SORT_LDAV: 119 return d1->statstime.avenrun[0] 120 - d2->statstime.avenrun[0]; 121 case SORT_UPTIME: 122 return d1->statstime.boottime.tv_sec 123 - d2->statstime.boottime.tv_sec; 124 default: 125 /* something's really wrong here */ 126 abort(); 127 } 128 } 129 130 void 131 remember_rup_data(host, st) 132 char *host; 133 struct statstime *st; 134 { 135 if (rup_data_idx >= rup_data_max) { 136 rup_data_max += 16; 137 rup_data = realloc (rup_data, 138 rup_data_max * sizeof(struct rup_data)); 139 if (rup_data == NULL) { 140 err (1, NULL); 141 /* NOTREACHED */ 142 } 143 } 144 145 rup_data[rup_data_idx].host = strdup(host); 146 rup_data[rup_data_idx].statstime = *st; 147 rup_data_idx++; 148 } 149 150 151 int 152 rstat_reply(replyp, raddrp) 153 char *replyp; 154 struct sockaddr_in *raddrp; 155 { 156 struct hostent *hp; 157 char *host; 158 statstime *host_stat = (statstime *)replyp; 159 160 if (!search_host(raddrp->sin_addr)) { 161 hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr, 162 sizeof(struct in_addr), AF_INET); 163 164 if (hp) 165 host = hp->h_name; 166 else 167 host = inet_ntoa(raddrp->sin_addr); 168 169 remember_host(raddrp->sin_addr); 170 171 if (sort_type != SORT_NONE) { 172 remember_rup_data(host, host_stat); 173 } else { 174 print_rup_data(host, host_stat); 175 } 176 } 177 178 return (0); 179 } 180 181 182 int 183 print_rup_data(host, host_stat) 184 char *host; 185 statstime *host_stat; 186 { 187 struct tm *tmp_time; 188 struct tm host_time; 189 struct tm host_uptime; 190 char days_buf[16]; 191 char hours_buf[16]; 192 193 printf("%-*.*s", HOST_WIDTH, HOST_WIDTH, host); 194 195 tmp_time = localtime((time_t *)&host_stat->curtime.tv_sec); 196 host_time = *tmp_time; 197 198 host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec; 199 200 tmp_time = gmtime((time_t *)&host_stat->curtime.tv_sec); 201 host_uptime = *tmp_time; 202 203 if (host_uptime.tm_yday != 0) 204 sprintf(days_buf, "%3d day%s, ", host_uptime.tm_yday, 205 (host_uptime.tm_yday > 1) ? "s" : ""); 206 else 207 days_buf[0] = '\0'; 208 209 if (host_uptime.tm_hour != 0) 210 sprintf(hours_buf, "%2d:%02d, ", 211 host_uptime.tm_hour, host_uptime.tm_min); 212 else 213 if (host_uptime.tm_min != 0) 214 sprintf(hours_buf, "%2d mins, ", host_uptime.tm_min); 215 else 216 hours_buf[0] = '\0'; 217 218 if (printtime) 219 printf(" %2d:%02d%cm", host_time.tm_hour % 12, 220 host_time.tm_min, 221 (host_time.tm_hour >= 12) ? 'p' : 'a'); 222 223 printf(" up %9.9s%9.9s load average: %.2f %.2f %.2f\n", 224 days_buf, hours_buf, 225 (double)host_stat->avenrun[0]/FSCALE, 226 (double)host_stat->avenrun[1]/FSCALE, 227 (double)host_stat->avenrun[2]/FSCALE); 228 229 return(0); 230 } 231 232 233 void 234 onehost(host) 235 char *host; 236 { 237 CLIENT *rstat_clnt; 238 statstime host_stat; 239 static struct timeval timeout = {25, 0}; 240 241 rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp"); 242 if (rstat_clnt == NULL) { 243 warnx("%s", clnt_spcreateerror(host)); 244 return; 245 } 246 247 bzero((char *)&host_stat, sizeof(host_stat)); 248 if (clnt_call(rstat_clnt, RSTATPROC_STATS, xdr_void, NULL, xdr_statstime, &host_stat, timeout) != RPC_SUCCESS) { 249 warnx("%s", clnt_sperror(rstat_clnt, host)); 250 return; 251 } 252 253 print_rup_data(host, &host_stat); 254 clnt_destroy(rstat_clnt); 255 } 256 257 void 258 allhosts() 259 { 260 statstime host_stat; 261 enum clnt_stat clnt_stat; 262 size_t i; 263 264 if (sort_type != SORT_NONE) { 265 printf("collecting responses..."); 266 fflush(stdout); 267 } 268 269 clnt_stat = clnt_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS, 270 xdr_void, NULL, 271 xdr_statstime, &host_stat, rstat_reply); 272 if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) { 273 warnx("%s", clnt_sperrno(clnt_stat)); 274 exit(1); 275 } 276 277 if (sort_type != SORT_NONE) { 278 putchar('\n'); 279 qsort(rup_data, rup_data_idx, sizeof(struct rup_data), compare); 280 281 for (i = 0; i < rup_data_idx; i++) { 282 print_rup_data(rup_data[i].host, &rup_data[i].statstime); 283 } 284 } 285 } 286 287 288 main(argc, argv) 289 int argc; 290 char *argv[]; 291 { 292 int ch; 293 extern int optind; 294 295 sort_type = SORT_NONE; 296 while ((ch = getopt(argc, argv, "dhlt")) != -1) 297 switch (ch) { 298 case 'd': 299 printtime = 1; 300 break; 301 case 'h': 302 sort_type = SORT_HOST; 303 break; 304 case 'l': 305 sort_type = SORT_LDAV; 306 break; 307 case 't': 308 sort_type = SORT_UPTIME; 309 break; 310 default: 311 usage(); 312 /*NOTREACHED*/ 313 } 314 315 setlinebuf(stdout); 316 317 if (argc == optind) 318 allhosts(); 319 else { 320 for (; optind < argc; optind++) 321 onehost(argv[optind]); 322 } 323 324 exit(0); 325 } 326 327 328 usage() 329 { 330 fprintf(stderr, "Usage: rup [-dhlt] [hosts ...]\n"); 331 exit(1); 332 } 333