1 /* $NetBSD: rup.c,v 1.26 2005/08/07 16:01:45 christos Exp $ */
4 * Copyright (c) 1993, John Brezak
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
36 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: rup.c,v 1.26 2005/08/07 16:01:45 christos Exp $");
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
55 #undef FSHIFT /* Use protocol's shift and scale values */
57 #include <rpcsvc/rstat.h>
61 static int printtime
; /* print the remote host(s)'s time */
63 static struct host_list
{
64 struct host_list
*next
;
67 struct in6_addr _addr6
;
68 struct in_addr _addr4
;
72 #define addr6 addr._addr6
73 #define addr4 addr._addr4
75 static int search_host(struct sockaddr
*);
76 static void remember_host(struct sockaddr
*);
79 search_host(struct sockaddr
*sa
)
86 for (hp
= hosts
; hp
!= NULL
; hp
= hp
->next
) {
89 if (!memcmp(&hp
->addr6
,
90 &((struct sockaddr_in6
*)(void *)sa
)->sin6_addr
,
91 sizeof (struct in6_addr
)))
95 if (!memcmp(&hp
->addr4
,
96 &((struct sockaddr_in
*)(void *)sa
)->sin_addr
,
97 sizeof (struct in_addr
)))
108 remember_host(struct sockaddr
*sa
)
110 struct host_list
*hp
;
112 if ((hp
= malloc(sizeof(struct host_list
))) == NULL
) {
116 hp
->family
= sa
->sa_family
;
118 switch (sa
->sa_family
) {
120 (void)memcpy(&hp
->addr6
,
121 &((struct sockaddr_in6
*)(void *)sa
)->sin6_addr
,
122 sizeof (struct in6_addr
));
125 (void)memcpy(&hp
->addr4
,
126 &((struct sockaddr_in
*)(void *)sa
)->sin_addr
,
127 sizeof (struct in_addr
));
130 errx(1, "unknown address family");
138 struct statstime statstime
;
140 static struct rup_data
*rup_data
;
141 static size_t rup_data_idx
= 0;
142 static size_t rup_data_max
= 0;
150 static enum sort_type sort_type
;
152 static int compare(struct rup_data
*, struct rup_data
*);
153 static void remember_rup_data(const char *, struct statstime
*);
154 static int rstat_reply(char *, struct netbuf
*, struct netconfig
*);
155 static void print_rup_data(const char *, statstime
*);
156 static int onehost(char *);
157 static void allhosts(void);
158 static void usage(void) __dead
;
159 int main(int, char *[]);
162 compare(struct rup_data
*d1
, struct rup_data
*d2
)
166 return strcmp(d1
->host
, d2
->host
);
168 return d1
->statstime
.avenrun
[0]
169 - d2
->statstime
.avenrun
[0];
171 return d1
->statstime
.boottime
.tv_sec
172 - d2
->statstime
.boottime
.tv_sec
;
174 /* something's really wrong here */
181 remember_rup_data(const char *host
, struct statstime
*st
)
185 if (rup_data_idx
>= rup_data_max
) {
186 n
= realloc(rup_data
,
187 (rup_data_max
+ 16) * sizeof(struct rup_data
));
196 rup_data
[rup_data_idx
].host
= strdup(host
);
197 rup_data
[rup_data_idx
].statstime
= *st
;
204 rstat_reply(char *replyp
, struct netbuf
*raddrp
, struct netconfig
*nconf
)
206 char host
[NI_MAXHOST
];
207 statstime
*host_stat
= (statstime
*)(void *)replyp
;
208 struct sockaddr
*sa
= raddrp
->buf
;
210 if (!search_host(sa
)) {
211 if (getnameinfo(sa
, (socklen_t
)sa
->sa_len
, host
, sizeof host
,
217 if (sort_type
!= SORT_NONE
) {
218 remember_rup_data(host
, host_stat
);
220 print_rup_data(host
, host_stat
);
229 print_rup_data(const char *host
, statstime
*host_stat
)
233 unsigned ups
= 0, upm
= 0, uph
= 0, upd
= 0;
240 (void)printf("%-*.*s", HOST_WIDTH
-4, HOST_WIDTH
-4, host
);
242 (void)printf("%-*.*s", HOST_WIDTH
, HOST_WIDTH
, host
);
244 now
= host_stat
->curtime
.tv_sec
;
245 tmp_time
= localtime(&now
);
246 host_time
= *tmp_time
;
248 host_stat
->curtime
.tv_sec
-= host_stat
->boottime
.tv_sec
;
250 ups
=host_stat
->curtime
.tv_sec
;
251 upd
=ups
/ (3600 * 24);
252 ups
-=upd
* 3600 * 24;
258 (void)snprintf(days_buf
, sizeof(days_buf
), "%3u day%s, ", upd
,
259 (upd
> 1) ? "s" : "");
264 (void)snprintf(hours_buf
, sizeof(hours_buf
), "%2u:%02u, ",
268 (void)snprintf(hours_buf
, sizeof(hours_buf
),
269 "%2u min%s ", upm
, (upm
== 1) ? ", " : "s,");
271 (void)snprintf(hours_buf
, sizeof(hours_buf
),
276 (void)printf(" %2d:%02d%cm",
277 (host_time
.tm_hour
% 12) ? (host_time
.tm_hour
% 12) : 12,
278 host_time
.tm_min
, (host_time
.tm_hour
>= 12) ? 'p' : 'a');
280 (void)printf(" up %9.9s%9.9s load average: %.2f %.2f %.2f\n",
281 days_buf
, hours_buf
, (double)host_stat
->avenrun
[0]/FSCALE
,
282 (double)host_stat
->avenrun
[1]/FSCALE
,
283 (double)host_stat
->avenrun
[2]/FSCALE
);
292 static struct timeval timeout
= {25, 0};
294 rstat_clnt
= clnt_create(host
, RSTATPROG
, RSTATVERS_TIME
, "udp");
295 if (rstat_clnt
== NULL
) {
296 warnx("%s", clnt_spcreateerror(host
));
300 (void)memset(&host_stat
, 0, sizeof(host_stat
));
301 if (clnt_call(rstat_clnt
, RSTATPROC_STATS
, xdr_void
, NULL
,
302 xdr_statstime
, &host_stat
, timeout
) != RPC_SUCCESS
) {
303 warnx("%s", clnt_sperror(rstat_clnt
, host
));
304 clnt_destroy(rstat_clnt
);
308 print_rup_data(host
, &host_stat
);
309 clnt_destroy(rstat_clnt
);
317 enum clnt_stat clnt_stat
;
320 if (sort_type
!= SORT_NONE
) {
321 (void)printf("collecting responses...");
322 (void)fflush(stdout
);
325 clnt_stat
= rpc_broadcast(RSTATPROG
, RSTATVERS_TIME
, RSTATPROC_STATS
,
326 xdr_void
, NULL
, xdr_statstime
, (caddr_t
)(void *)&host_stat
,
327 (resultproc_t
)rstat_reply
, "udp");
328 if (clnt_stat
!= RPC_SUCCESS
&& clnt_stat
!= RPC_TIMEDOUT
)
329 errx(1, "%s", clnt_sperrno(clnt_stat
));
331 if (sort_type
!= SORT_NONE
) {
333 qsort(rup_data
, rup_data_idx
, sizeof(struct rup_data
),
334 (int (*)(const void*, const void*))compare
);
336 for (i
= 0; i
< rup_data_idx
; i
++) {
337 print_rup_data(rup_data
[i
].host
, &rup_data
[i
].statstime
);
343 main(int argc
, char *argv
[])
348 sort_type
= SORT_NONE
;
350 while ((ch
= getopt(argc
, argv
, "dhlt")) != -1)
356 sort_type
= SORT_HOST
;
359 sort_type
= SORT_LDAV
;
362 sort_type
= SORT_UPTIME
;
369 (void)setlinebuf(stdout
);
374 for (; optind
< argc
; optind
++)
375 retval
+= onehost(argv
[optind
]);
378 return retval
? EXIT_FAILURE
: EXIT_SUCCESS
;
384 (void)fprintf(stderr
, "Usage: %s [-dhlt] [hosts ...]\n",