12343Scsgr/*-
22343Scsgr * Copyright (c) 1993, John Brezak
32343Scsgr * All rights reserved.
42343Scsgr *
52343Scsgr * Redistribution and use in source and binary forms, with or without
62343Scsgr * modification, are permitted provided that the following conditions
72343Scsgr * are met:
82343Scsgr * 1. Redistributions of source code must retain the above copyright
92343Scsgr *    notice, this list of conditions and the following disclaimer.
102343Scsgr * 2. Redistributions in binary form must reproduce the above copyright
112343Scsgr *    notice, this list of conditions and the following disclaimer in the
122343Scsgr *    documentation and/or other materials provided with the distribution.
132343Scsgr * 3. All advertising materials mentioning features or use of this software
142343Scsgr *    must display the following acknowledgement:
152343Scsgr *	This product includes software developed by the University of
162343Scsgr *	California, Berkeley and its contributors.
172343Scsgr * 4. Neither the name of the University nor the names of its contributors
182343Scsgr *    may be used to endorse or promote products derived from this software
192343Scsgr *    without specific prior written permission.
202343Scsgr *
212343Scsgr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
222343Scsgr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232343Scsgr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242343Scsgr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
252343Scsgr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
262343Scsgr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
272343Scsgr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
282343Scsgr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
292343Scsgr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
302343Scsgr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
312343Scsgr * SUCH DAMAGE.
322343Scsgr */
332343Scsgr
3495616Smarkm#include <sys/cdefs.h>
352343Scsgr
3695616Smarkm__FBSDID("$FreeBSD$");
3795616Smarkm
382343Scsgr#include <sys/param.h>
392343Scsgr#include <sys/socket.h>
4095616Smarkm
412343Scsgr#include <rpc/rpc.h>
4227955Scharnier#include <rpc/pmap_clnt.h>
4395616Smarkm
442343Scsgr#undef FSHIFT			/* Use protocol's shift and scale values */
452343Scsgr#undef FSCALE
4695616Smarkm
472343Scsgr#include <rpcsvc/rstat.h>
482343Scsgr
4995616Smarkm#include <arpa/inet.h>
5095616Smarkm
5195616Smarkm#include <err.h>
5295616Smarkm#include <netdb.h>
5395616Smarkm#include <stdio.h>
5495616Smarkm#include <string.h>
5595616Smarkm#include <stdlib.h>
5695616Smarkm#include <time.h>
5795616Smarkm#include <unistd.h>
5895616Smarkm
592343Scsgr#define HOST_WIDTH 15
602343Scsgr
612343Scsgrstruct host_list {
622343Scsgr	struct host_list *next;
632343Scsgr	struct in_addr addr;
642343Scsgr} *hosts;
652343Scsgr
6695616Smarkmstatic int
6795616Smarkmsearch_host(struct in_addr addr)
682343Scsgr{
692343Scsgr	struct host_list *hp;
708874Srgrimes
712343Scsgr	if (!hosts)
722343Scsgr		return(0);
732343Scsgr
742343Scsgr	for (hp = hosts; hp != NULL; hp = hp->next) {
752343Scsgr		if (hp->addr.s_addr == addr.s_addr)
762343Scsgr			return(1);
772343Scsgr	}
782343Scsgr	return(0);
792343Scsgr}
802343Scsgr
8195616Smarkmstatic void
8295616Smarkmremember_host(struct in_addr addr)
832343Scsgr{
842343Scsgr	struct host_list *hp;
852343Scsgr
8627955Scharnier	if (!(hp = (struct host_list *)malloc(sizeof(struct host_list))))
8727955Scharnier		errx(1, "no memory");
882343Scsgr	hp->addr.s_addr = addr.s_addr;
892343Scsgr	hp->next = hosts;
902343Scsgr	hosts = hp;
912343Scsgr}
922343Scsgr
93121545Speterstatic bool_t
9474462Salfredrstat_reply(caddr_t replyp, struct sockaddr_in *raddrp)
952343Scsgr{
962343Scsgr	struct tm *tmp_time;
972343Scsgr	struct tm host_time;
982343Scsgr	struct tm host_uptime;
992343Scsgr	char days_buf[16];
1002343Scsgr	char hours_buf[16];
1012343Scsgr	struct hostent *hp;
1022343Scsgr	char *host;
1032343Scsgr	statstime *host_stat = (statstime *)replyp;
104153090Sphilip	time_t tmp_time_t;
1052343Scsgr
1062343Scsgr	if (search_host(raddrp->sin_addr))
1072343Scsgr		return(0);
1088874Srgrimes
1092343Scsgr	hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
1102343Scsgr			   sizeof(struct in_addr), AF_INET);
1112343Scsgr	if (hp)
1122343Scsgr		host = hp->h_name;
1132343Scsgr	else
1142343Scsgr		host = inet_ntoa(raddrp->sin_addr);
1152343Scsgr
1162343Scsgr	/* truncate hostname to fit nicely into field */
1172343Scsgr	if (strlen(host) > HOST_WIDTH)
1182343Scsgr		host[HOST_WIDTH] = '\0';
1192343Scsgr
1202343Scsgr	printf("%-*s\t", HOST_WIDTH, host);
1212343Scsgr
122153090Sphilip	if (sizeof(time_t) == sizeof(host_stat->curtime.tv_sec)) {
123153090Sphilip		tmp_time = localtime((time_t *)&host_stat->curtime.tv_sec);
124153090Sphilip		host_time = *tmp_time;
1252343Scsgr
126153090Sphilip		host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec;
1272343Scsgr
128153090Sphilip		tmp_time = gmtime((time_t *)&host_stat->curtime.tv_sec);
129153090Sphilip		host_uptime = *tmp_time;
130153090Sphilip	}
131153090Sphilip	else {			/* non-32-bit time_t */
132153090Sphilip		tmp_time_t = host_stat->curtime.tv_sec;
133153090Sphilip		tmp_time = localtime(&tmp_time_t);
134153090Sphilip		host_time = *tmp_time;
1352343Scsgr
136153090Sphilip		host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec;
137153090Sphilip
138153090Sphilip		tmp_time_t = host_stat->curtime.tv_sec;
139153090Sphilip		tmp_time = gmtime(&tmp_time_t);
140153090Sphilip		host_uptime = *tmp_time;
141153090Sphilip	}
142153090Sphilip
14312445Swpaul	#define updays (host_stat->curtime.tv_sec  / 86400)
1442343Scsgr	if (host_uptime.tm_yday != 0)
14512445Swpaul		sprintf(days_buf, "%3d day%s, ", updays,
14612445Swpaul			(updays > 1) ? "s" : "");
1472343Scsgr	else
1482343Scsgr		days_buf[0] = '\0';
1492343Scsgr
1502343Scsgr	if (host_uptime.tm_hour != 0)
1512343Scsgr		sprintf(hours_buf, "%2d:%02d, ",
1522343Scsgr			host_uptime.tm_hour, host_uptime.tm_min);
1532343Scsgr	else
1542343Scsgr		if (host_uptime.tm_min != 0)
1552343Scsgr			sprintf(hours_buf, "%2d mins, ", host_uptime.tm_min);
15685039Sfenner		else if (host_stat->curtime.tv_sec < 60)
15785039Sfenner			sprintf(hours_buf, "%2d secs, ", host_uptime.tm_sec);
1582343Scsgr		else
1592343Scsgr			hours_buf[0] = '\0';
1602343Scsgr
1612343Scsgr	printf(" %2d:%02d%cm  up %9.9s%9.9s load average: %.2f %.2f %.2f\n",
16234993Sdanny		(host_time.tm_hour % 12) ? host_time.tm_hour % 12 : 12,
1632343Scsgr		host_time.tm_min,
1642343Scsgr		(host_time.tm_hour >= 12) ? 'p' : 'a',
1652343Scsgr		days_buf,
1662343Scsgr		hours_buf,
1672343Scsgr		(double)host_stat->avenrun[0]/FSCALE,
1682343Scsgr		(double)host_stat->avenrun[1]/FSCALE,
1692343Scsgr		(double)host_stat->avenrun[2]/FSCALE);
1702343Scsgr
1712343Scsgr	remember_host(raddrp->sin_addr);
1722343Scsgr	return(0);
1732343Scsgr}
1742343Scsgr
17595616Smarkmstatic int
1762343Scsgronehost(char *host)
1772343Scsgr{
1782343Scsgr	CLIENT *rstat_clnt;
1792343Scsgr	statstime host_stat;
1802343Scsgr	struct sockaddr_in addr;
1812343Scsgr	struct hostent *hp;
18221093Speter	struct timeval tv;
1838874Srgrimes
1842343Scsgr	hp = gethostbyname(host);
1852343Scsgr	if (hp == NULL) {
18627955Scharnier		warnx("unknown host \"%s\"", host);
1872343Scsgr		return(-1);
1882343Scsgr	}
1892343Scsgr
1902343Scsgr	rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp");
1912343Scsgr	if (rstat_clnt == NULL) {
19227955Scharnier		warnx("%s %s", host, clnt_spcreateerror(""));
1932343Scsgr		return(-1);
1942343Scsgr	}
1952343Scsgr
1962343Scsgr	bzero((char *)&host_stat, sizeof(host_stat));
19721093Speter	tv.tv_sec = 15;	/* XXX ??? */
19821093Speter	tv.tv_usec = 0;
199121545Speter	if (clnt_call(rstat_clnt, RSTATPROC_STATS,
200121545Speter	    (xdrproc_t)xdr_void, NULL,
201121545Speter	    (xdrproc_t)xdr_statstime, &host_stat, tv) != RPC_SUCCESS) {
20227955Scharnier		warnx("%s: %s", host, clnt_sperror(rstat_clnt, host));
20378456Smikeh		clnt_destroy(rstat_clnt);
2042343Scsgr		return(-1);
2052343Scsgr	}
2062343Scsgr
2072343Scsgr	addr.sin_addr.s_addr = *(int *)hp->h_addr;
20874462Salfred	rstat_reply((caddr_t)&host_stat, &addr);
20978456Smikeh	clnt_destroy(rstat_clnt);
21027955Scharnier	return (0);
2112343Scsgr}
2122343Scsgr
21395616Smarkmstatic void
21495616Smarkmallhosts(void)
2152343Scsgr{
2162343Scsgr	statstime host_stat;
2172343Scsgr	enum clnt_stat clnt_stat;
2182343Scsgr
2192343Scsgr	clnt_stat = clnt_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
220121545Speter				   (xdrproc_t)xdr_void, NULL,
221121545Speter				   (xdrproc_t)xdr_statstime, &host_stat,
222121545Speter				   (resultproc_t)rstat_reply);
22327955Scharnier	if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
22427955Scharnier		errx(1, "%s", clnt_sperrno(clnt_stat));
2252343Scsgr}
2262343Scsgr
22727955Scharnierstatic void
22895616Smarkmusage(void)
2292343Scsgr{
230146466Sru	fprintf(stderr, "usage: rup [host ...]\n");
2312343Scsgr	exit(1);
2322343Scsgr}
2332343Scsgr
23427955Scharnierint
2352343Scsgrmain(int argc, char *argv[])
2362343Scsgr{
2372343Scsgr	int ch;
2382343Scsgr
2392343Scsgr	while ((ch = getopt(argc, argv, "?")) != -1)
2402343Scsgr		switch (ch) {
2412343Scsgr		default:
2422343Scsgr			usage();
2432343Scsgr			/*NOTREACHED*/
2442343Scsgr		}
2458874Srgrimes
2462343Scsgr	setlinebuf(stdout);
2472343Scsgr	if (argc == optind)
2482343Scsgr		allhosts();
2492343Scsgr	else {
2502343Scsgr		for (; optind < argc; optind++)
2512343Scsgr			(void) onehost(argv[optind]);
2522343Scsgr	}
2532343Scsgr	exit(0);
2542343Scsgr}
255