rup.c revision 1.12 1 /* $NetBSD: rup.c,v 1.12 1996/09/27 01:46:10 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1993, John Brezak
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 static char rcsid[] = "$NetBSD: rup.c,v 1.12 1996/09/27 01:46:10 thorpej Exp $";
38 #endif /* not lint */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <time.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <netdb.h>
47 #include <rpc/rpc.h>
48 #include <arpa/inet.h>
49 #include <err.h>
50
51 #undef FSHIFT /* Use protocol's shift and scale values */
52 #undef FSCALE
53 #include <rpcsvc/rstat.h>
54
55 #define HOST_WIDTH 24
56
57 int printtime; /* print the remote host(s)'s time */
58
59 struct host_list {
60 struct host_list *next;
61 struct in_addr addr;
62 } *hosts;
63
64 int
65 search_host(addr)
66 struct in_addr addr;
67 {
68 struct host_list *hp;
69
70 if (!hosts)
71 return(0);
72
73 for (hp = hosts; hp != NULL; hp = hp->next) {
74 if (hp->addr.s_addr == addr.s_addr)
75 return(1);
76 }
77 return(0);
78 }
79
80 void
81 remember_host(addr)
82 struct in_addr addr;
83 {
84 struct host_list *hp;
85
86 if (!(hp = (struct host_list *)malloc(sizeof(struct host_list)))) {
87 err(1, NULL);
88 /* NOTREACHED */
89 }
90 hp->addr.s_addr = addr.s_addr;
91 hp->next = hosts;
92 hosts = hp;
93 }
94
95
96
97 struct rup_data {
99 char *host;
100 struct statstime statstime;
101 };
102 struct rup_data *rup_data;
103 int rup_data_idx = 0;
104 int rup_data_max = 0;
105
106 enum sort_type {
107 SORT_NONE,
108 SORT_HOST,
109 SORT_LDAV,
110 SORT_UPTIME
111 };
112 enum sort_type sort_type;
113
114 compare(d1, d2)
115 struct rup_data *d1;
116 struct rup_data *d2;
117 {
118 switch(sort_type) {
119 case SORT_HOST:
120 return strcmp(d1->host, d2->host);
121 case SORT_LDAV:
122 return d1->statstime.avenrun[0]
123 - d2->statstime.avenrun[0];
124 case SORT_UPTIME:
125 return d1->statstime.boottime.tv_sec
126 - d2->statstime.boottime.tv_sec;
127 default:
128 /* something's really wrong here */
129 abort();
130 }
131 }
132
133 void
134 remember_rup_data(host, st)
135 char *host;
136 struct statstime *st;
137 {
138 if (rup_data_idx >= rup_data_max) {
139 rup_data_max += 16;
140 rup_data = realloc (rup_data,
141 rup_data_max * sizeof(struct rup_data));
142 if (rup_data == NULL) {
143 err (1, NULL);
144 /* NOTREACHED */
145 }
146 }
147
148 rup_data[rup_data_idx].host = strdup(host);
149 rup_data[rup_data_idx].statstime = *st;
150 rup_data_idx++;
151 }
152
153
154 int
155 rstat_reply(replyp, raddrp)
156 char *replyp;
157 struct sockaddr_in *raddrp;
158 {
159 struct hostent *hp;
160 char *host;
161 statstime *host_stat = (statstime *)replyp;
162
163 if (!search_host(raddrp->sin_addr)) {
164 hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
165 sizeof(struct in_addr), AF_INET);
166
167 if (hp)
168 host = hp->h_name;
169 else
170 host = inet_ntoa(raddrp->sin_addr);
171
172 remember_host(raddrp->sin_addr);
173
174 if (sort_type != SORT_NONE) {
175 remember_rup_data(host, host_stat);
176 } else {
177 print_rup_data(host, host_stat);
178 }
179 }
180
181 return (0);
182 }
183
184
185 int
186 print_rup_data(host, host_stat)
187 char *host;
188 statstime *host_stat;
189 {
190 struct tm *tmp_time;
191 struct tm host_time;
192 struct tm host_uptime;
193 char days_buf[16];
194 char hours_buf[16];
195
196 printf("%-*.*s", HOST_WIDTH, HOST_WIDTH, host);
197
198 tmp_time = localtime((time_t *)&host_stat->curtime.tv_sec);
199 host_time = *tmp_time;
200
201 host_stat->curtime.tv_sec -= host_stat->boottime.tv_sec;
202
203 tmp_time = gmtime((time_t *)&host_stat->curtime.tv_sec);
204 host_uptime = *tmp_time;
205
206 if (host_uptime.tm_yday != 0)
207 sprintf(days_buf, "%3d day%s, ", host_uptime.tm_yday,
208 (host_uptime.tm_yday > 1) ? "s" : "");
209 else
210 days_buf[0] = '\0';
211
212 if (host_uptime.tm_hour != 0)
213 sprintf(hours_buf, "%2d:%02d, ",
214 host_uptime.tm_hour, host_uptime.tm_min);
215 else
216 if (host_uptime.tm_min != 0)
217 sprintf(hours_buf, "%2d mins, ", host_uptime.tm_min);
218 else
219 hours_buf[0] = '\0';
220
221 if (printtime)
222 printf(" %2d:%02d%cm",
223 (host_time.tm_hour % 12) ? (host_time.tm_hour % 12) : 12,
224 host_time.tm_min, (host_time.tm_hour >= 12) ? 'p' : 'a');
225
226 printf(" up %9.9s%9.9s load average: %.2f %.2f %.2f\n",
227 days_buf, hours_buf,
228 (double)host_stat->avenrun[0]/FSCALE,
229 (double)host_stat->avenrun[1]/FSCALE,
230 (double)host_stat->avenrun[2]/FSCALE);
231
232 return(0);
233 }
234
235
236 void
237 onehost(host)
238 char *host;
239 {
240 CLIENT *rstat_clnt;
241 statstime host_stat;
242 static struct timeval timeout = {25, 0};
243
244 rstat_clnt = clnt_create(host, RSTATPROG, RSTATVERS_TIME, "udp");
245 if (rstat_clnt == NULL) {
246 warnx("%s", clnt_spcreateerror(host));
247 return;
248 }
249
250 bzero((char *)&host_stat, sizeof(host_stat));
251 if (clnt_call(rstat_clnt, RSTATPROC_STATS, xdr_void, NULL, xdr_statstime, &host_stat, timeout) != RPC_SUCCESS) {
252 warnx("%s", clnt_sperror(rstat_clnt, host));
253 return;
254 }
255
256 print_rup_data(host, &host_stat);
257 clnt_destroy(rstat_clnt);
258 }
259
260 void
261 allhosts()
262 {
263 statstime host_stat;
264 enum clnt_stat clnt_stat;
265 size_t i;
266
267 if (sort_type != SORT_NONE) {
268 printf("collecting responses...");
269 fflush(stdout);
270 }
271
272 clnt_stat = clnt_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
273 xdr_void, NULL,
274 xdr_statstime, &host_stat, rstat_reply);
275 if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_TIMEDOUT) {
276 warnx("%s", clnt_sperrno(clnt_stat));
277 exit(1);
278 }
279
280 if (sort_type != SORT_NONE) {
281 putchar('\n');
282 qsort(rup_data, rup_data_idx, sizeof(struct rup_data), compare);
283
284 for (i = 0; i < rup_data_idx; i++) {
285 print_rup_data(rup_data[i].host, &rup_data[i].statstime);
286 }
287 }
288 }
289
290
291 main(argc, argv)
292 int argc;
293 char *argv[];
294 {
295 int ch;
296 extern int optind;
297
298 sort_type = SORT_NONE;
299 while ((ch = getopt(argc, argv, "dhlt")) != -1)
300 switch (ch) {
301 case 'd':
302 printtime = 1;
303 break;
304 case 'h':
305 sort_type = SORT_HOST;
306 break;
307 case 'l':
308 sort_type = SORT_LDAV;
309 break;
310 case 't':
311 sort_type = SORT_UPTIME;
312 break;
313 default:
314 usage();
315 /*NOTREACHED*/
316 }
317
318 setlinebuf(stdout);
319
320 if (argc == optind)
321 allhosts();
322 else {
323 for (; optind < argc; optind++)
324 onehost(argv[optind]);
325 }
326
327 exit(0);
328 }
329
330
331 usage()
332 {
333 fprintf(stderr, "Usage: rup [-dhlt] [hosts ...]\n");
334 exit(1);
335 }
336