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