Home | History | Annotate | Line # | Download | only in rup
rup.c revision 1.26.12.1
      1  1.26.12.1      matt /*	$NetBSD: rup.c,v 1.26.12.1 2008/01/09 02:00:53 matt 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.26.12.1      matt __RCSID("$NetBSD: rup.c,v 1.26.12.1 2008/01/09 02:00:53 matt 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.26.12.1      matt static void usage(void) __dead;
    159       1.22      fvdl int main(int, char *[]);
    160       1.14  drochner 
    161       1.14  drochner int
    162       1.21      fvdl compare(struct rup_data *d1, struct rup_data *d2)
    163        1.9       jtc {
    164        1.9       jtc 	switch(sort_type) {
    165        1.9       jtc 	case SORT_HOST:
    166        1.9       jtc 		return strcmp(d1->host, d2->host);
    167        1.9       jtc 	case SORT_LDAV:
    168        1.9       jtc 		return d1->statstime.avenrun[0]
    169       1.26  christos 		    - d2->statstime.avenrun[0];
    170        1.9       jtc 	case SORT_UPTIME:
    171        1.9       jtc 		return d1->statstime.boottime.tv_sec
    172       1.26  christos 		    - d2->statstime.boottime.tv_sec;
    173        1.9       jtc 	default:
    174        1.9       jtc 		/* something's really wrong here */
    175        1.9       jtc 		abort();
    176       1.26  christos 		/*NOTREACHED*/
    177        1.9       jtc 	}
    178        1.9       jtc }
    179        1.9       jtc 
    180       1.26  christos static void
    181       1.21      fvdl remember_rup_data(const char *host, struct statstime *st)
    182        1.9       jtc {
    183       1.24    itojun 	struct rup_data *n;
    184       1.24    itojun 
    185        1.9       jtc         if (rup_data_idx >= rup_data_max) {
    186       1.24    itojun                 n = realloc(rup_data,
    187       1.24    itojun                     (rup_data_max + 16) * sizeof(struct rup_data));
    188       1.24    itojun                 if (n == NULL) {
    189       1.14  drochner                         err (1, "realloc");
    190        1.9       jtc 			/* NOTREACHED */
    191        1.9       jtc                 }
    192       1.24    itojun 		rup_data = n;
    193       1.24    itojun                 rup_data_max += 16;
    194        1.9       jtc         }
    195        1.9       jtc 
    196        1.9       jtc 	rup_data[rup_data_idx].host = strdup(host);
    197        1.9       jtc 	rup_data[rup_data_idx].statstime = *st;
    198        1.9       jtc 	rup_data_idx++;
    199        1.9       jtc }
    200        1.9       jtc 
    201        1.9       jtc 
    202       1.26  christos static int
    203       1.26  christos /*ARGSUSED*/
    204       1.21      fvdl rstat_reply(char *replyp, struct netbuf *raddrp, struct netconfig *nconf)
    205        1.1    brezak {
    206       1.21      fvdl 	char host[NI_MAXHOST];
    207       1.26  christos 	statstime *host_stat = (statstime *)(void *)replyp;
    208       1.21      fvdl 	struct sockaddr *sa = raddrp->buf;
    209        1.9       jtc 
    210       1.21      fvdl 	if (!search_host(sa)) {
    211       1.26  christos 		if (getnameinfo(sa, (socklen_t)sa->sa_len, host, sizeof host,
    212       1.26  christos 		    NULL, 0, 0))
    213       1.21      fvdl 			return 0;
    214        1.9       jtc 
    215       1.21      fvdl 		remember_host(sa);
    216        1.9       jtc 
    217        1.9       jtc 		if (sort_type != SORT_NONE) {
    218        1.9       jtc 			remember_rup_data(host, host_stat);
    219        1.9       jtc 		} else {
    220        1.9       jtc 			print_rup_data(host, host_stat);
    221        1.9       jtc 		}
    222        1.9       jtc 	}
    223        1.9       jtc 
    224       1.26  christos 	return 0;
    225        1.9       jtc }
    226        1.9       jtc 
    227        1.9       jtc 
    228       1.26  christos static void
    229       1.21      fvdl print_rup_data(const char *host, statstime *host_stat)
    230        1.9       jtc {
    231        1.1    brezak 	struct tm *tmp_time;
    232        1.1    brezak 	struct tm host_time;
    233       1.26  christos 	unsigned ups = 0, upm = 0, uph = 0, upd = 0;
    234       1.26  christos 	time_t now;
    235       1.13     perry 
    236        1.1    brezak 	char days_buf[16];
    237        1.1    brezak 	char hours_buf[16];
    238        1.1    brezak 
    239       1.18   hubertf 	if (printtime)
    240       1.26  christos 		(void)printf("%-*.*s", HOST_WIDTH-4, HOST_WIDTH-4, host);
    241       1.18   hubertf 	else
    242       1.26  christos 		(void)printf("%-*.*s", HOST_WIDTH, HOST_WIDTH, host);
    243        1.1    brezak 
    244       1.26  christos 	now = host_stat->curtime.tv_sec;
    245       1.26  christos 	tmp_time = localtime(&now);
    246        1.1    brezak 	host_time = *tmp_time;
    247        1.1    brezak 
    248        1.1    brezak 	host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec;
    249        1.1    brezak 
    250       1.13     perry 	ups=host_stat->curtime.tv_sec;
    251       1.26  christos 	upd=ups / (3600 * 24);
    252       1.26  christos 	ups-=upd * 3600 * 24;
    253       1.26  christos 	uph=ups / 3600;
    254       1.26  christos 	ups-=uph * 3600;
    255       1.26  christos 	upm=ups / 60;
    256       1.13     perry 
    257       1.13     perry 	if (upd != 0)
    258       1.26  christos 		(void)snprintf(days_buf, sizeof(days_buf), "%3u day%s, ", upd,
    259       1.26  christos 		    (upd > 1) ? "s" : "");
    260        1.1    brezak 	else
    261        1.1    brezak 		days_buf[0] = '\0';
    262        1.1    brezak 
    263       1.13     perry 	if (uph != 0)
    264       1.26  christos 		(void)snprintf(hours_buf, sizeof(hours_buf), "%2u:%02u, ",
    265       1.26  christos 		    uph, upm);
    266        1.1    brezak 	else
    267       1.13     perry 		if (upm != 0)
    268       1.26  christos 			(void)snprintf(hours_buf, sizeof(hours_buf),
    269       1.26  christos 			    "%2u min%s ", upm, (upm == 1) ? ", " : "s,");
    270       1.26  christos 		else if (ups < 60)
    271       1.26  christos 			(void)snprintf(hours_buf, sizeof(hours_buf),
    272       1.26  christos 			    "%2u secs ", ups);
    273        1.1    brezak 		else
    274        1.1    brezak 			hours_buf[0] = '\0';
    275        1.7   deraadt 	if (printtime)
    276       1.26  christos 		(void)printf(" %2d:%02d%cm",
    277       1.11   thorpej 		    (host_time.tm_hour % 12) ? (host_time.tm_hour % 12) : 12,
    278       1.11   thorpej 		    host_time.tm_min, (host_time.tm_hour >= 12) ? 'p' : 'a');
    279        1.7   deraadt 
    280       1.26  christos 	(void)printf(" up %9.9s%9.9s load average: %.2f %.2f %.2f\n",
    281       1.26  christos 	    days_buf, hours_buf, (double)host_stat->avenrun[0]/FSCALE,
    282       1.26  christos 	    (double)host_stat->avenrun[1]/FSCALE,
    283       1.26  christos 	    (double)host_stat->avenrun[2]/FSCALE);
    284        1.1    brezak }
    285        1.1    brezak 
    286        1.9       jtc 
    287       1.26  christos static int
    288       1.21      fvdl onehost(char *host)
    289        1.1    brezak {
    290        1.1    brezak 	CLIENT *rstat_clnt;
    291        1.1    brezak 	statstime host_stat;
    292       1.10        pk 	static struct timeval timeout = {25, 0};
    293        1.1    brezak 
    294        1.1    brezak 	rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp");
    295        1.1    brezak 	if (rstat_clnt == NULL) {
    296        1.9       jtc 		warnx("%s", clnt_spcreateerror(host));
    297       1.26  christos 		return 1;
    298        1.1    brezak 	}
    299        1.1    brezak 
    300       1.26  christos 	(void)memset(&host_stat, 0, sizeof(host_stat));
    301       1.26  christos 	if (clnt_call(rstat_clnt, RSTATPROC_STATS, xdr_void, NULL,
    302       1.26  christos 	    xdr_statstime, &host_stat, timeout) != RPC_SUCCESS) {
    303        1.9       jtc 		warnx("%s",  clnt_sperror(rstat_clnt, host));
    304       1.26  christos 		clnt_destroy(rstat_clnt);
    305       1.26  christos 		return 1;
    306        1.1    brezak 	}
    307        1.1    brezak 
    308        1.9       jtc 	print_rup_data(host, &host_stat);
    309        1.9       jtc 	clnt_destroy(rstat_clnt);
    310       1.26  christos 	return 0;
    311        1.1    brezak }
    312        1.1    brezak 
    313       1.26  christos static void
    314       1.26  christos allhosts(void)
    315        1.1    brezak {
    316        1.1    brezak 	statstime host_stat;
    317        1.1    brezak 	enum clnt_stat clnt_stat;
    318        1.9       jtc 	size_t i;
    319        1.9       jtc 
    320        1.9       jtc 	if (sort_type != SORT_NONE) {
    321       1.26  christos 		(void)printf("collecting responses...");
    322       1.26  christos 		(void)fflush(stdout);
    323        1.9       jtc 	}
    324        1.1    brezak 
    325       1.21      fvdl 	clnt_stat = rpc_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
    326       1.26  christos 	    xdr_void, NULL, xdr_statstime, (caddr_t)(void *)&host_stat,
    327       1.26  christos 	    (resultproc_t)rstat_reply, "udp");
    328       1.26  christos 	if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT)
    329       1.26  christos 		errx(1, "%s", clnt_sperrno(clnt_stat));
    330        1.9       jtc 
    331        1.9       jtc 	if (sort_type != SORT_NONE) {
    332       1.26  christos 		(void)putchar('\n');
    333       1.14  drochner 		qsort(rup_data, rup_data_idx, sizeof(struct rup_data),
    334       1.14  drochner 		      (int (*)(const void*, const void*))compare);
    335        1.9       jtc 
    336        1.9       jtc 		for (i = 0; i < rup_data_idx; i++) {
    337        1.9       jtc 			print_rup_data(rup_data[i].host, &rup_data[i].statstime);
    338        1.9       jtc 		}
    339        1.9       jtc 	}
    340        1.1    brezak }
    341        1.1    brezak 
    342       1.14  drochner int
    343       1.21      fvdl main(int argc, char *argv[])
    344        1.1    brezak {
    345       1.26  christos 	int ch, retval;
    346        1.1    brezak 
    347       1.26  christos 	setprogname(*argv);
    348        1.9       jtc 	sort_type = SORT_NONE;
    349       1.26  christos 	retval = 0;
    350        1.9       jtc 	while ((ch = getopt(argc, argv, "dhlt")) != -1)
    351        1.1    brezak 		switch (ch) {
    352        1.9       jtc 		case 'd':
    353        1.9       jtc 			printtime = 1;
    354        1.9       jtc 			break;
    355        1.9       jtc 		case 'h':
    356        1.9       jtc 			sort_type = SORT_HOST;
    357        1.9       jtc 			break;
    358        1.9       jtc 		case 'l':
    359        1.9       jtc 			sort_type = SORT_LDAV;
    360        1.9       jtc 			break;
    361        1.7   deraadt 		case 't':
    362        1.9       jtc 			sort_type = SORT_UPTIME;
    363        1.7   deraadt 			break;
    364        1.1    brezak 		default:
    365        1.1    brezak 			usage();
    366        1.1    brezak 			/*NOTREACHED*/
    367        1.1    brezak 		}
    368        1.1    brezak 
    369       1.26  christos 	(void)setlinebuf(stdout);
    370        1.9       jtc 
    371        1.1    brezak 	if (argc == optind)
    372        1.1    brezak 		allhosts();
    373        1.1    brezak 	else {
    374        1.1    brezak 		for (; optind < argc; optind++)
    375       1.26  christos 			retval += onehost(argv[optind]);
    376        1.1    brezak 	}
    377        1.9       jtc 
    378       1.26  christos 	return retval ? EXIT_FAILURE : EXIT_SUCCESS;
    379        1.9       jtc }
    380        1.9       jtc 
    381       1.14  drochner void
    382       1.26  christos usage(void)
    383        1.9       jtc {
    384       1.26  christos 	(void)fprintf(stderr, "Usage: %s [-dhlt] [hosts ...]\n",
    385       1.26  christos 	    getprogname());
    386       1.26  christos 	exit(EXIT_SUCCESS);
    387        1.1    brezak }
    388