xref: /netbsd-src/usr.bin/rup/rup.c (revision 39bbc68a3b8731308f39852383f5430560168a91)
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