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