Home | History | Annotate | Line # | Download | only in rup
rup.c revision 1.11
      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.11 1996/09/27 01:44:58 thorpej 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 {
     97 	char *host;
     98 	struct statstime statstime;
     99 };
    100 struct rup_data *rup_data;
    101 int rup_data_idx = 0;
    102 int rup_data_max = 0;
    103 
    104 enum sort_type {
    105 	SORT_NONE,
    106 	SORT_HOST,
    107 	SORT_LDAV,
    108 	SORT_UPTIME
    109 };
    110 enum sort_type sort_type;
    111 
    112 compare(d1, d2)
    113 	struct rup_data *d1;
    114 	struct rup_data *d2;
    115 {
    116 	switch(sort_type) {
    117 	case SORT_HOST:
    118 		return strcmp(d1->host, d2->host);
    119 	case SORT_LDAV:
    120 		return d1->statstime.avenrun[0]
    121 			- d2->statstime.avenrun[0];
    122 	case SORT_UPTIME:
    123 		return d1->statstime.boottime.tv_sec
    124 			- d2->statstime.boottime.tv_sec;
    125 	default:
    126 		/* something's really wrong here */
    127 		abort();
    128 	}
    129 }
    130 
    131 void
    132 remember_rup_data(host, st)
    133 	char *host;
    134 	struct statstime *st;
    135 {
    136         if (rup_data_idx >= rup_data_max) {
    137                 rup_data_max += 16;
    138                 rup_data = realloc (rup_data,
    139 				rup_data_max * sizeof(struct rup_data));
    140                 if (rup_data == NULL) {
    141                         err (1, NULL);
    142 			/* NOTREACHED */
    143                 }
    144         }
    145 
    146 	rup_data[rup_data_idx].host = strdup(host);
    147 	rup_data[rup_data_idx].statstime = *st;
    148 	rup_data_idx++;
    149 }
    150 
    151 
    152 int
    153 rstat_reply(replyp, raddrp)
    154 	char *replyp;
    155 	struct sockaddr_in *raddrp;
    156 {
    157 	struct hostent *hp;
    158 	char *host;
    159 	statstime *host_stat = (statstime *)replyp;
    160 
    161 	if (!search_host(raddrp->sin_addr)) {
    162 		hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
    163 			sizeof(struct in_addr), AF_INET);
    164 
    165 		if (hp)
    166 			host = hp->h_name;
    167 		else
    168 			host = inet_ntoa(raddrp->sin_addr);
    169 
    170 		remember_host(raddrp->sin_addr);
    171 
    172 		if (sort_type != SORT_NONE) {
    173 			remember_rup_data(host, host_stat);
    174 		} else {
    175 			print_rup_data(host, host_stat);
    176 		}
    177 	}
    178 
    179 	return (0);
    180 }
    181 
    182 
    183 int
    184 print_rup_data(host, host_stat)
    185 	char *host;
    186 	statstime *host_stat;
    187 {
    188 	struct tm *tmp_time;
    189 	struct tm host_time;
    190 	struct tm host_uptime;
    191 	char days_buf[16];
    192 	char hours_buf[16];
    193 
    194 	printf("%-*.*s", HOST_WIDTH, HOST_WIDTH, host);
    195 
    196 	tmp_time = localtime((time_t *)&host_stat->curtime.tv_sec);
    197 	host_time = *tmp_time;
    198 
    199 	host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec;
    200 
    201 	tmp_time = gmtime((time_t *)&host_stat->curtime.tv_sec);
    202 	host_uptime = *tmp_time;
    203 
    204 	if (host_uptime.tm_yday != 0)
    205 		sprintf(days_buf, "%3d day%s, ", host_uptime.tm_yday,
    206 			(host_uptime.tm_yday > 1) ? "s" : "");
    207 	else
    208 		days_buf[0] = '\0';
    209 
    210 	if (host_uptime.tm_hour != 0)
    211 		sprintf(hours_buf, "%2d:%02d, ",
    212 			host_uptime.tm_hour, host_uptime.tm_min);
    213 	else
    214 		if (host_uptime.tm_min != 0)
    215 			sprintf(hours_buf, "%2d mins, ", host_uptime.tm_min);
    216 		else
    217 			hours_buf[0] = '\0';
    218 
    219 	if (printtime)
    220 		printf(" %2d:%02d%cm",
    221 		    (host_time.tm_hour % 12) ? (host_time.tm_hour % 12) : 12,
    222 		    host_time.tm_min, (host_time.tm_hour >= 12) ? 'p' : 'a');
    223 
    224 	printf(" up %9.9s%9.9s load average: %.2f %.2f %.2f\n",
    225 		days_buf, hours_buf,
    226 		(double)host_stat->avenrun[0]/FSCALE,
    227 		(double)host_stat->avenrun[1]/FSCALE,
    228 		(double)host_stat->avenrun[2]/FSCALE);
    229 
    230 	return(0);
    231 }
    232 
    233 
    234 void
    235 onehost(host)
    236 	char *host;
    237 {
    238 	CLIENT *rstat_clnt;
    239 	statstime host_stat;
    240 	static struct timeval timeout = {25, 0};
    241 
    242 	rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp");
    243 	if (rstat_clnt == NULL) {
    244 		warnx("%s", clnt_spcreateerror(host));
    245 		return;
    246 	}
    247 
    248 	bzero((char *)&host_stat, sizeof(host_stat));
    249 	if (clnt_call(rstat_clnt, RSTATPROC_STATS, xdr_void, NULL, xdr_statstime, &host_stat, timeout) != RPC_SUCCESS) {
    250 		warnx("%s",  clnt_sperror(rstat_clnt, host));
    251 		return;
    252 	}
    253 
    254 	print_rup_data(host, &host_stat);
    255 	clnt_destroy(rstat_clnt);
    256 }
    257 
    258 void
    259 allhosts()
    260 {
    261 	statstime host_stat;
    262 	enum clnt_stat clnt_stat;
    263 	size_t i;
    264 
    265 	if (sort_type != SORT_NONE) {
    266 		printf("collecting responses...");
    267 		fflush(stdout);
    268 	}
    269 
    270 	clnt_stat = clnt_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
    271 				   xdr_void, NULL,
    272 				   xdr_statstime, &host_stat, rstat_reply);
    273 	if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) {
    274 		warnx("%s", clnt_sperrno(clnt_stat));
    275 		exit(1);
    276 	}
    277 
    278 	if (sort_type != SORT_NONE) {
    279 		putchar('\n');
    280 		qsort(rup_data, rup_data_idx, sizeof(struct rup_data), compare);
    281 
    282 		for (i = 0; i < rup_data_idx; i++) {
    283 			print_rup_data(rup_data[i].host, &rup_data[i].statstime);
    284 		}
    285 	}
    286 }
    287 
    288 
    289 main(argc, argv)
    290 	int argc;
    291 	char *argv[];
    292 {
    293 	int ch;
    294 	extern int optind;
    295 
    296 	sort_type = SORT_NONE;
    297 	while ((ch = getopt(argc, argv, "dhlt")) != -1)
    298 		switch (ch) {
    299 		case 'd':
    300 			printtime = 1;
    301 			break;
    302 		case 'h':
    303 			sort_type = SORT_HOST;
    304 			break;
    305 		case 'l':
    306 			sort_type = SORT_LDAV;
    307 			break;
    308 		case 't':
    309 			sort_type = SORT_UPTIME;
    310 			break;
    311 		default:
    312 			usage();
    313 			/*NOTREACHED*/
    314 		}
    315 
    316 	setlinebuf(stdout);
    317 
    318 	if (argc == optind)
    319 		allhosts();
    320 	else {
    321 		for (; optind < argc; optind++)
    322 			onehost(argv[optind]);
    323 	}
    324 
    325 	exit(0);
    326 }
    327 
    328 
    329 usage()
    330 {
    331 	fprintf(stderr, "Usage: rup [-dhlt] [hosts ...]\n");
    332 	exit(1);
    333 }
    334