1*39bbc68aSsevan /* $NetBSD: rup.c,v 1.29 2016/09/05 00:40:29 sevan Exp $ */
219f013a5Sthorpej
35f2b3676Sbrezak /*-
45f2b3676Sbrezak * Copyright (c) 1993, John Brezak
55f2b3676Sbrezak * All rights reserved.
65f2b3676Sbrezak *
75f2b3676Sbrezak * Redistribution and use in source and binary forms, with or without
85f2b3676Sbrezak * modification, are permitted provided that the following conditions
95f2b3676Sbrezak * are met:
105f2b3676Sbrezak * 1. Redistributions of source code must retain the above copyright
115f2b3676Sbrezak * notice, this list of conditions and the following disclaimer.
125f2b3676Sbrezak * 2. Redistributions in binary form must reproduce the above copyright
135f2b3676Sbrezak * notice, this list of conditions and the following disclaimer in the
145f2b3676Sbrezak * documentation and/or other materials provided with the distribution.
155f2b3676Sbrezak * 3. All advertising materials mentioning features or use of this software
165f2b3676Sbrezak * must display the following acknowledgement:
175f2b3676Sbrezak * This product includes software developed by the University of
185f2b3676Sbrezak * California, Berkeley and its contributors.
195f2b3676Sbrezak * 4. Neither the name of the University nor the names of its contributors
205f2b3676Sbrezak * may be used to endorse or promote products derived from this software
215f2b3676Sbrezak * without specific prior written permission.
225f2b3676Sbrezak *
235f2b3676Sbrezak * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
245f2b3676Sbrezak * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
255f2b3676Sbrezak * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
265f2b3676Sbrezak * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
275f2b3676Sbrezak * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
285f2b3676Sbrezak * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
295f2b3676Sbrezak * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
305f2b3676Sbrezak * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
315f2b3676Sbrezak * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
325f2b3676Sbrezak * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
335f2b3676Sbrezak * SUCH DAMAGE.
345f2b3676Sbrezak */
355f2b3676Sbrezak
363cb8fe8bSdrochner #include <sys/cdefs.h>
37aee4b07bSmycroft #ifndef lint
38*39bbc68aSsevan __RCSID("$NetBSD: rup.c,v 1.29 2016/09/05 00:40:29 sevan Exp $");
39aee4b07bSmycroft #endif /* not lint */
40aee4b07bSmycroft
4136af0320Sperry #include <sys/types.h>
4236af0320Sperry #include <sys/socket.h>
4336af0320Sperry #include <netinet/in.h>
4436af0320Sperry #include <arpa/inet.h>
4536af0320Sperry
4636af0320Sperry #include <err.h>
4736af0320Sperry #include <netdb.h>
4836af0320Sperry #include <rpc/rpc.h>
495f2b3676Sbrezak #include <stdio.h>
50ac5c852dSjtc #include <stdlib.h>
515f2b3676Sbrezak #include <string.h>
525f2b3676Sbrezak #include <time.h>
5336af0320Sperry #include <unistd.h>
54ac5c852dSjtc
55ac5c852dSjtc #undef FSHIFT /* Use protocol's shift and scale values */
56ac5c852dSjtc #undef FSCALE
575f2b3676Sbrezak #include <rpcsvc/rstat.h>
585f2b3676Sbrezak
59b52aae9dSderaadt #define HOST_WIDTH 24
605f2b3676Sbrezak
619eb4baf4Schristos static int printtime; /* print the remote host(s)'s time */
62b52aae9dSderaadt
639eb4baf4Schristos static struct host_list {
645f2b3676Sbrezak struct host_list *next;
655531feb1Sfvdl int family;
665531feb1Sfvdl union {
675531feb1Sfvdl struct in6_addr _addr6;
685531feb1Sfvdl struct in_addr _addr4;
695531feb1Sfvdl } addr;
705f2b3676Sbrezak } *hosts;
715f2b3676Sbrezak
725531feb1Sfvdl #define addr6 addr._addr6
735531feb1Sfvdl #define addr4 addr._addr4
745531feb1Sfvdl
759eb4baf4Schristos static int search_host(struct sockaddr *);
769eb4baf4Schristos static void remember_host(struct sockaddr *);
773cb8fe8bSdrochner
789eb4baf4Schristos static int
search_host(struct sockaddr * sa)795531feb1Sfvdl search_host(struct sockaddr *sa)
805f2b3676Sbrezak {
815f2b3676Sbrezak struct host_list *hp;
825f2b3676Sbrezak
835f2b3676Sbrezak if (!hosts)
849eb4baf4Schristos return 0;
855f2b3676Sbrezak
865f2b3676Sbrezak for (hp = hosts; hp != NULL; hp = hp->next) {
875531feb1Sfvdl switch (hp->family) {
885531feb1Sfvdl case AF_INET6:
895531feb1Sfvdl if (!memcmp(&hp->addr6,
909eb4baf4Schristos &((struct sockaddr_in6 *)(void *)sa)->sin6_addr,
915531feb1Sfvdl sizeof (struct in6_addr)))
925531feb1Sfvdl return 1;
935531feb1Sfvdl break;
945531feb1Sfvdl case AF_INET:
955531feb1Sfvdl if (!memcmp(&hp->addr4,
969eb4baf4Schristos &((struct sockaddr_in *)(void *)sa)->sin_addr,
975531feb1Sfvdl sizeof (struct in_addr)))
985531feb1Sfvdl return 1;
995531feb1Sfvdl break;
1005531feb1Sfvdl default:
101fdfcf196Scgd break;
1025531feb1Sfvdl }
1035f2b3676Sbrezak }
1049eb4baf4Schristos return 0;
1055f2b3676Sbrezak }
1065f2b3676Sbrezak
1079eb4baf4Schristos static void
remember_host(struct sockaddr * sa)1085531feb1Sfvdl remember_host(struct sockaddr *sa)
1095f2b3676Sbrezak {
1105f2b3676Sbrezak struct host_list *hp;
1115f2b3676Sbrezak
1129eb4baf4Schristos if ((hp = malloc(sizeof(struct host_list))) == NULL) {
1133cb8fe8bSdrochner err(1, "malloc");
114fe6e50dbSjtc /* NOTREACHED */
1155f2b3676Sbrezak }
1165531feb1Sfvdl hp->family = sa->sa_family;
1175f2b3676Sbrezak hp->next = hosts;
1185531feb1Sfvdl switch (sa->sa_family) {
1195531feb1Sfvdl case AF_INET6:
1209eb4baf4Schristos (void)memcpy(&hp->addr6,
1219eb4baf4Schristos &((struct sockaddr_in6 *)(void *)sa)->sin6_addr,
1225531feb1Sfvdl sizeof (struct in6_addr));
1235531feb1Sfvdl break;
1245531feb1Sfvdl case AF_INET:
1259eb4baf4Schristos (void)memcpy(&hp->addr4,
1269eb4baf4Schristos &((struct sockaddr_in *)(void *)sa)->sin_addr,
1275531feb1Sfvdl sizeof (struct in_addr));
1285531feb1Sfvdl break;
1295531feb1Sfvdl default:
1309eb4baf4Schristos errx(1, "unknown address family");
1315531feb1Sfvdl /* NOTREACHED */
1325531feb1Sfvdl }
1335f2b3676Sbrezak hosts = hp;
1345f2b3676Sbrezak }
1355f2b3676Sbrezak
136fe6e50dbSjtc struct rup_data {
1377bcd049dSjdolecek const char *host;
138fe6e50dbSjtc struct statstime statstime;
139fe6e50dbSjtc };
1409eb4baf4Schristos static struct rup_data *rup_data;
1419eb4baf4Schristos static size_t rup_data_idx = 0;
1429eb4baf4Schristos static size_t rup_data_max = 0;
143fe6e50dbSjtc
144fe6e50dbSjtc enum sort_type {
145fe6e50dbSjtc SORT_NONE,
146fe6e50dbSjtc SORT_HOST,
147fe6e50dbSjtc SORT_LDAV,
148fe6e50dbSjtc SORT_UPTIME
149fe6e50dbSjtc };
1509eb4baf4Schristos static enum sort_type sort_type;
151fe6e50dbSjtc
1529eb4baf4Schristos static int compare(struct rup_data *, struct rup_data *);
1539eb4baf4Schristos static void remember_rup_data(const char *, struct statstime *);
1549eb4baf4Schristos static int rstat_reply(char *, struct netbuf *, struct netconfig *);
1559eb4baf4Schristos static void print_rup_data(const char *, statstime *);
1569eb4baf4Schristos static int onehost(char *);
1579eb4baf4Schristos static void allhosts(void);
1588b0f9554Sperry static void usage(void) __dead;
1593cb8fe8bSdrochner
1603cb8fe8bSdrochner int
compare(struct rup_data * d1,struct rup_data * d2)1615531feb1Sfvdl compare(struct rup_data *d1, struct rup_data *d2)
162fe6e50dbSjtc {
163fe6e50dbSjtc switch(sort_type) {
164fe6e50dbSjtc case SORT_HOST:
165fe6e50dbSjtc return strcmp(d1->host, d2->host);
166fe6e50dbSjtc case SORT_LDAV:
167fe6e50dbSjtc return d1->statstime.avenrun[0]
168fe6e50dbSjtc - d2->statstime.avenrun[0];
169fe6e50dbSjtc case SORT_UPTIME:
170fe6e50dbSjtc return d1->statstime.boottime.tv_sec
171fe6e50dbSjtc - d2->statstime.boottime.tv_sec;
172fe6e50dbSjtc default:
173fe6e50dbSjtc /* something's really wrong here */
174fe6e50dbSjtc abort();
1759eb4baf4Schristos /*NOTREACHED*/
176fe6e50dbSjtc }
177fe6e50dbSjtc }
178fe6e50dbSjtc
1799eb4baf4Schristos static void
remember_rup_data(const char * host,struct statstime * st)1805531feb1Sfvdl remember_rup_data(const char *host, struct statstime *st)
181fe6e50dbSjtc {
18250847da5Sitojun struct rup_data *n;
18350847da5Sitojun
184fe6e50dbSjtc if (rup_data_idx >= rup_data_max) {
18550847da5Sitojun n = realloc(rup_data,
18650847da5Sitojun (rup_data_max + 16) * sizeof(struct rup_data));
18750847da5Sitojun if (n == NULL) {
1883cb8fe8bSdrochner err (1, "realloc");
189fe6e50dbSjtc /* NOTREACHED */
190fe6e50dbSjtc }
19150847da5Sitojun rup_data = n;
19250847da5Sitojun rup_data_max += 16;
193fe6e50dbSjtc }
194fe6e50dbSjtc
195fe6e50dbSjtc rup_data[rup_data_idx].host = strdup(host);
196fe6e50dbSjtc rup_data[rup_data_idx].statstime = *st;
197fe6e50dbSjtc rup_data_idx++;
198fe6e50dbSjtc }
199fe6e50dbSjtc
200fe6e50dbSjtc
2019eb4baf4Schristos static int
2029eb4baf4Schristos /*ARGSUSED*/
rstat_reply(char * replyp,struct netbuf * raddrp,struct netconfig * nconf)2035531feb1Sfvdl rstat_reply(char *replyp, struct netbuf *raddrp, struct netconfig *nconf)
2045f2b3676Sbrezak {
2055531feb1Sfvdl char host[NI_MAXHOST];
2069eb4baf4Schristos statstime *host_stat = (statstime *)(void *)replyp;
2075531feb1Sfvdl struct sockaddr *sa = raddrp->buf;
208fe6e50dbSjtc
2095531feb1Sfvdl if (!search_host(sa)) {
2109eb4baf4Schristos if (getnameinfo(sa, (socklen_t)sa->sa_len, host, sizeof host,
2119eb4baf4Schristos NULL, 0, 0))
2125531feb1Sfvdl return 0;
213fe6e50dbSjtc
2145531feb1Sfvdl remember_host(sa);
215fe6e50dbSjtc
216fe6e50dbSjtc if (sort_type != SORT_NONE) {
217fe6e50dbSjtc remember_rup_data(host, host_stat);
218fe6e50dbSjtc } else {
219fe6e50dbSjtc print_rup_data(host, host_stat);
220fe6e50dbSjtc }
221fe6e50dbSjtc }
222fe6e50dbSjtc
2239eb4baf4Schristos return 0;
224fe6e50dbSjtc }
225fe6e50dbSjtc
226fe6e50dbSjtc
2279eb4baf4Schristos static void
print_rup_data(const char * host,statstime * host_stat)2285531feb1Sfvdl print_rup_data(const char *host, statstime *host_stat)
229fe6e50dbSjtc {
2305f2b3676Sbrezak struct tm *tmp_time;
2315f2b3676Sbrezak struct tm host_time;
232bf059fabSperry unsigned ups = 0, upm = 0, uph = 0, upd = 0;
2339eb4baf4Schristos time_t now;
234bf059fabSperry
2355f2b3676Sbrezak char days_buf[16];
2365f2b3676Sbrezak char hours_buf[16];
2375f2b3676Sbrezak
2384b53c6d8Shubertf if (printtime)
2399eb4baf4Schristos (void)printf("%-*.*s", HOST_WIDTH-4, HOST_WIDTH-4, host);
2404b53c6d8Shubertf else
2419eb4baf4Schristos (void)printf("%-*.*s", HOST_WIDTH, HOST_WIDTH, host);
2425f2b3676Sbrezak
2439eb4baf4Schristos now = host_stat->curtime.tv_sec;
2449eb4baf4Schristos tmp_time = localtime(&now);
2455f2b3676Sbrezak host_time = *tmp_time;
2465f2b3676Sbrezak
2475f2b3676Sbrezak host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec;
2485f2b3676Sbrezak
249bf059fabSperry ups=host_stat->curtime.tv_sec;
250bf059fabSperry upd=ups / (3600 * 24);
251bf059fabSperry ups-=upd * 3600 * 24;
252bf059fabSperry uph=ups / 3600;
253bf059fabSperry ups-=uph * 3600;
254bf059fabSperry upm=ups / 60;
2555f2b3676Sbrezak
256bf059fabSperry if (upd != 0)
2579eb4baf4Schristos (void)snprintf(days_buf, sizeof(days_buf), "%3u day%s, ", upd,
258bf059fabSperry (upd > 1) ? "s" : "");
2595f2b3676Sbrezak else
2605f2b3676Sbrezak days_buf[0] = '\0';
2615f2b3676Sbrezak
262bf059fabSperry if (uph != 0)
2639eb4baf4Schristos (void)snprintf(hours_buf, sizeof(hours_buf), "%2u:%02u, ",
264bf059fabSperry uph, upm);
2655f2b3676Sbrezak else
266bf059fabSperry if (upm != 0)
2679eb4baf4Schristos (void)snprintf(hours_buf, sizeof(hours_buf),
2689eb4baf4Schristos "%2u min%s ", upm, (upm == 1) ? ", " : "s,");
2699eb4baf4Schristos else if (ups < 60)
2709eb4baf4Schristos (void)snprintf(hours_buf, sizeof(hours_buf),
2719eb4baf4Schristos "%2u secs ", ups);
2725f2b3676Sbrezak else
2735f2b3676Sbrezak hours_buf[0] = '\0';
274b52aae9dSderaadt if (printtime)
2759eb4baf4Schristos (void)printf(" %2d:%02d%cm",
27613a88ddbSthorpej (host_time.tm_hour % 12) ? (host_time.tm_hour % 12) : 12,
27713a88ddbSthorpej host_time.tm_min, (host_time.tm_hour >= 12) ? 'p' : 'a');
278b52aae9dSderaadt
2799eb4baf4Schristos (void)printf(" up %9.9s%9.9s load average: %.2f %.2f %.2f\n",
2809eb4baf4Schristos days_buf, hours_buf, (double)host_stat->avenrun[0]/FSCALE,
2815f2b3676Sbrezak (double)host_stat->avenrun[1]/FSCALE,
2825f2b3676Sbrezak (double)host_stat->avenrun[2]/FSCALE);
2835f2b3676Sbrezak }
2845f2b3676Sbrezak
285fe6e50dbSjtc
2869eb4baf4Schristos static int
onehost(char * host)2875531feb1Sfvdl onehost(char *host)
2885f2b3676Sbrezak {
2895f2b3676Sbrezak CLIENT *rstat_clnt;
2905f2b3676Sbrezak statstime host_stat;
2917080a02cSpk static struct timeval timeout = {25, 0};
2925f2b3676Sbrezak
2935f2b3676Sbrezak rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp");
2945f2b3676Sbrezak if (rstat_clnt == NULL) {
295fe6e50dbSjtc warnx("%s", clnt_spcreateerror(host));
2969eb4baf4Schristos return 1;
2975f2b3676Sbrezak }
2985f2b3676Sbrezak
2999eb4baf4Schristos (void)memset(&host_stat, 0, sizeof(host_stat));
3009eb4baf4Schristos if (clnt_call(rstat_clnt, RSTATPROC_STATS, xdr_void, NULL,
3019eb4baf4Schristos xdr_statstime, &host_stat, timeout) != RPC_SUCCESS) {
302fe6e50dbSjtc warnx("%s", clnt_sperror(rstat_clnt, host));
3039eb4baf4Schristos clnt_destroy(rstat_clnt);
3049eb4baf4Schristos return 1;
3055f2b3676Sbrezak }
3065f2b3676Sbrezak
307fe6e50dbSjtc print_rup_data(host, &host_stat);
308fe6e50dbSjtc clnt_destroy(rstat_clnt);
3099eb4baf4Schristos return 0;
3105f2b3676Sbrezak }
3115f2b3676Sbrezak
3129eb4baf4Schristos static void
allhosts(void)3139eb4baf4Schristos allhosts(void)
3145f2b3676Sbrezak {
3155f2b3676Sbrezak statstime host_stat;
3165f2b3676Sbrezak enum clnt_stat clnt_stat;
317fe6e50dbSjtc size_t i;
318fe6e50dbSjtc
319fe6e50dbSjtc if (sort_type != SORT_NONE) {
3209eb4baf4Schristos (void)printf("collecting responses...");
3219eb4baf4Schristos (void)fflush(stdout);
322fe6e50dbSjtc }
3235f2b3676Sbrezak
3245531feb1Sfvdl clnt_stat = rpc_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
32587d4f607Splunky (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_statstime, (caddr_t)(void *)&host_stat,
3265531feb1Sfvdl (resultproc_t)rstat_reply, "udp");
3279eb4baf4Schristos if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
3289eb4baf4Schristos errx(1, "%s", clnt_sperrno(clnt_stat));
329fe6e50dbSjtc
330fe6e50dbSjtc if (sort_type != SORT_NONE) {
3319eb4baf4Schristos (void)putchar('\n');
3323cb8fe8bSdrochner qsort(rup_data, rup_data_idx, sizeof(struct rup_data),
3333cb8fe8bSdrochner (int (*)(const void*, const void*))compare);
334fe6e50dbSjtc
335fe6e50dbSjtc for (i = 0; i < rup_data_idx; i++) {
336fe6e50dbSjtc print_rup_data(rup_data[i].host, &rup_data[i].statstime);
337fe6e50dbSjtc }
338fe6e50dbSjtc }
3395f2b3676Sbrezak }
3405f2b3676Sbrezak
3413cb8fe8bSdrochner int
main(int argc,char * argv[])3425531feb1Sfvdl main(int argc, char *argv[])
3435f2b3676Sbrezak {
3449eb4baf4Schristos int ch, retval;
3455f2b3676Sbrezak
3469eb4baf4Schristos setprogname(*argv);
347fe6e50dbSjtc sort_type = SORT_NONE;
3489eb4baf4Schristos retval = 0;
349fe6e50dbSjtc while ((ch = getopt(argc, argv, "dhlt")) != -1)
3505f2b3676Sbrezak switch (ch) {
351fe6e50dbSjtc case 'd':
352fe6e50dbSjtc printtime = 1;
353fe6e50dbSjtc break;
354fe6e50dbSjtc case 'h':
355fe6e50dbSjtc sort_type = SORT_HOST;
356fe6e50dbSjtc break;
357fe6e50dbSjtc case 'l':
358fe6e50dbSjtc sort_type = SORT_LDAV;
359fe6e50dbSjtc break;
360b52aae9dSderaadt case 't':
361fe6e50dbSjtc sort_type = SORT_UPTIME;
362b52aae9dSderaadt break;
3635f2b3676Sbrezak default:
3645f2b3676Sbrezak usage();
3655f2b3676Sbrezak /*NOTREACHED*/
3665f2b3676Sbrezak }
3675f2b3676Sbrezak
3689eb4baf4Schristos (void)setlinebuf(stdout);
369fe6e50dbSjtc
3705f2b3676Sbrezak if (argc == optind)
3715f2b3676Sbrezak allhosts();
3725f2b3676Sbrezak else {
3735f2b3676Sbrezak for (; optind < argc; optind++)
3749eb4baf4Schristos retval += onehost(argv[optind]);
3755f2b3676Sbrezak }
376fe6e50dbSjtc
3779eb4baf4Schristos return retval ? EXIT_FAILURE : EXIT_SUCCESS;
3785f2b3676Sbrezak }
379fe6e50dbSjtc
3803cb8fe8bSdrochner void
usage(void)3819eb4baf4Schristos usage(void)
382fe6e50dbSjtc {
3839eb4baf4Schristos (void)fprintf(stderr, "Usage: %s [-dhlt] [hosts ...]\n",
3849eb4baf4Schristos getprogname());
3859eb4baf4Schristos exit(EXIT_SUCCESS);
386fe6e50dbSjtc }
387