4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
31 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
38 #include <rpcsvc/rstat.h>
39 #include <rpc/pmap_clnt.h>
42 #define MACHINELEN 15 /* length of machine name printed out */
43 #define MACHINELENMAX 128 /* maximum machine name length */
44 #define AVENSIZE (3 * sizeof (long))
50 static int collectnames();
51 int singlehost(); /* returns 1 if rup of given host fails */
52 void printsinglehosts();
54 static void putline();
55 int netbufeq(struct netbuf
*ap
, struct netbuf
*bp
);
59 struct netconfig
*nconf
;
62 struct timeval boottime
;
70 int vers
; /* which version did the broadcasting */
71 int lflag
; /* load: sort by load average */
72 int tflag
; /* time: sort by uptime average */
73 int hflag
; /* host: sort by machine name */
74 int dflag
; /* debug: list only first n machines */
78 main(int argc
, char *argv
[])
85 * set number of slots to be 256 to begin with,
86 * this is large enough for most subnets but not all
90 total_entries
= SLOTS
;
91 entry
= malloc(sizeof (struct entry
) * total_entries
);
94 if (argv
[1][0] != '-') {
96 nfailed
+= singlehost(argv
[1]);
113 debug
= atoi(argv
[2]);
125 if (hflag
|| tflag
|| lflag
)
127 if (nfailed
== single
) {
129 exit(1); /* all hosts we tried failed */
136 if (hflag
|| tflag
|| lflag
) {
137 printf("collecting responses... ");
141 sv
.cp_time
.cp_time_val
= NULL
;
142 sv
.dk_xfer
.dk_xfer_val
= NULL
;
145 * Null out pointers in the statsvar struct
146 * so that we don't follow a random pointer
147 * somewhere when we get our results back.
148 * Set lengths to zero so we don't allocate
149 * some random amount of space we don't need
150 * (in the case where the reply was program
153 sv
.cp_time
.cp_time_len
= 0;
154 sv
.cp_time
.cp_time_val
= NULL
;
155 sv
.dk_xfer
.dk_xfer_len
= 0;
156 sv
.dk_xfer
.dk_xfer_val
= NULL
;
158 vers
= RSTATVERS_VAR
;
159 (void) rpc_broadcast(RSTATPROG
, RSTATVERS_VAR
, RSTATPROC_STATS
,
160 xdr_void
, NULL
, xdr_statsvar
, (caddr_t
)&sv
,
161 (resultproc_t
)collectnames
, (char *)0);
162 vers
= RSTATVERS_TIME
;
163 (void) rpc_broadcast(RSTATPROG
, RSTATVERS_TIME
, RSTATPROC_STATS
,
164 xdr_void
, NULL
, xdr_statstime
, (caddr_t
)&st
,
165 (resultproc_t
)collectnames
, (char *)0);
166 if (hflag
|| tflag
|| lflag
)
183 bool_t is_var_vers
= FALSE
;
186 if (curentry
>= total_entries
) {
189 total_entries
+= SLOTS
;
190 tmp
= reallocarray(entry
, total_entries
, sizeof (struct entry
));
197 sw_var
.cp_time
.cp_time_val
= NULL
;
198 sw_var
.dk_xfer
.dk_xfer_val
= NULL
;
199 err
= (enum clnt_stat
)callrpc(host
, RSTATPROG
, RSTATVERS_VAR
,
200 RSTATPROC_STATS
, xdr_void
, 0, xdr_statsvar
, &sw_var
);
201 if (err
== RPC_SUCCESS
) {
203 } else if (err
== RPC_PROGVERSMISMATCH
) {
204 err
= (enum clnt_stat
)callrpc(host
, RSTATPROG
, RSTATVERS_TIME
,
205 RSTATPROC_STATS
, xdr_void
, 0, xdr_statstime
, &st
);
206 if (err
!= RPC_SUCCESS
)
212 if (!hflag
&& !lflag
&& !tflag
) {
213 printf("%*.*s ", MACHINELEN
, MACHINELEN
, host
);
214 if (is_var_vers
== TRUE
)
215 putline(sw_var
.curtime
.tv_sec
, sw_var
.boottime
,
218 putline(st
.curtime
.tv_sec
, st
.boottime
, st
.avenrun
);
219 return (0); /* success */
221 entry
[curentry
].machine
= host
;
222 if (is_var_vers
== FALSE
) { /* RSTATVERS_TIME */
223 entry
[curentry
].boottime
.tv_sec
= st
.boottime
.tv_sec
;
224 entry
[curentry
].boottime
.tv_usec
=
226 entry
[curentry
].curtime
= st
.curtime
.tv_sec
;
227 memcpy(entry
[curentry
].avenrun
, st
.avenrun
, AVENSIZE
);
228 } else { /* RSTATVERS_VAR */
229 entry
[curentry
].boottime
.tv_sec
=
230 sw_var
.boottime
.tv_sec
;
231 entry
[curentry
].boottime
.tv_usec
=
232 sw_var
.boottime
.tv_usec
;
233 entry
[curentry
].curtime
= sw_var
.curtime
.tv_sec
;
234 memcpy(entry
[curentry
].avenrun
, sw_var
.avenrun
,
239 if (dflag
&& debugcnt
>= debug
)
244 fprintf(stderr
, "%*.*s: ", MACHINELEN
, MACHINELEN
, host
);
247 * clnt_perrno now prints a newline
249 /* fprintf(stderr, "\n"); */
250 return (1); /* a failure */
254 putline(now
, boottime
, avenrun
)
256 struct timeval boottime
;
259 int uptime
, days
, hrs
, mins
, i
;
261 uptime
= now
- boottime
.tv_sec
;
263 if (uptime
< 0) /* unsynchronized clocks */
265 days
= uptime
/ (60*60*24);
266 uptime
%= (60*60*24);
267 hrs
= uptime
/ (60*60);
273 printf(" %2d day%s", days
, days
> 1 ? "s," : ", ");
277 printf(" %2d:%02d, ", hrs
, mins
);
279 printf(" %2d min%s", mins
, mins
> 1 ? "s," : ", ");
282 * Print 1, 5, and 15 minute load averages.
283 * (Found by looking in kernel for avenrun).
285 printf(" load average:");
286 for (i
= 0; i
< (AVENSIZE
/ sizeof (avenrun
[0])); i
++) {
289 printf(" %.2f", (double)avenrun
[i
]/FSCALE
);
295 collectnames(resultsp
, taddr
, nconf
)
297 struct t_bind
*taddr
;
298 struct netconfig
*nconf
;
301 register struct entry
*entryp
, *lim
;
304 struct nd_hostservlist
*hs
;
305 extern struct netbuf
*netbufdup();
306 extern struct netconfig
*netconfigdup();
307 extern int netbufeq();
310 * need to realloc more space if we have more than 256 machines
311 * that responded to the broadcast
314 if (curentry
>= total_entries
) {
317 total_entries
+= SLOTS
;
318 tmp
= reallocarray(entry
, total_entries
, sizeof (struct entry
));
325 * weed out duplicates
327 lim
= entry
+ curentry
;
328 for (entryp
= entry
; entryp
< lim
; entryp
++)
329 if (netbufeq(&taddr
->addr
, entryp
->addr
))
332 if (vers
== RSTATVERS_TIME
) {
333 st
= (statstime
*)resultsp
;
334 } else if (vers
== RSTATVERS_VAR
) {
335 sv
= (statsvar
*)resultsp
;
337 return (0); /* we don't handle this version */
340 entry
[curentry
].nconf
= netconfigdup(nconf
);
341 entry
[curentry
].addr
= netbufdup(&taddr
->addr
);
344 * if raw, print this entry out immediately
345 * otherwise store for later sorting
347 if (!hflag
&& !lflag
&& !tflag
) {
348 if (netdir_getbyaddr(nconf
, &hs
, &taddr
->addr
) == ND_OK
)
349 printf("%*.*s ", MACHINELEN
, MACHINELEN
,
350 hs
->h_hostservs
->h_host
);
352 char *uaddr
= taddr2uaddr(nconf
, &taddr
->addr
);
355 printf(" %*.*s", MACHINELEN
, MACHINELEN
,
359 printf(" %*.*s", MACHINELEN
, MACHINELEN
,
362 if (vers
== RSTATVERS_TIME
) {
363 putline(st
->curtime
.tv_sec
, st
->boottime
, st
->avenrun
);
364 } else if (vers
== RSTATVERS_VAR
) {
365 putline(sv
->curtime
.tv_sec
, sv
->boottime
, sv
->avenrun
);
368 if (vers
== RSTATVERS_TIME
) {
369 entry
[curentry
].boottime
.tv_sec
= st
->boottime
.tv_sec
;
370 entry
[curentry
].boottime
.tv_usec
=
371 st
->boottime
.tv_usec
;
372 entry
[curentry
].curtime
= st
->curtime
.tv_sec
;
373 memcpy(entry
[curentry
].avenrun
, st
->avenrun
, AVENSIZE
);
374 } else if (vers
== RSTATVERS_VAR
) {
375 entry
[curentry
].boottime
.tv_sec
= sv
->boottime
.tv_sec
;
376 entry
[curentry
].boottime
.tv_usec
=
377 sv
->boottime
.tv_usec
;
378 entry
[curentry
].curtime
= sv
->curtime
.tv_sec
;
379 memcpy(entry
[curentry
].avenrun
, sv
->avenrun
, AVENSIZE
);
383 if (dflag
&& debugcnt
>= debug
)
392 register struct entry
*ep
;
396 qsort(entry
, curentry
, sizeof (struct entry
), machinecmp
);
398 qsort(entry
, curentry
, sizeof (struct entry
), loadcmp
);
400 qsort(entry
, curentry
, sizeof (struct entry
), uptimecmp
);
401 for (i
= 0; i
< curentry
; i
++) {
403 printf("%*.*s ", MACHINELEN
, MACHINELEN
, ep
->machine
);
404 putline(ep
->curtime
, ep
->boottime
, ep
->avenrun
);
412 char buf
[MACHINELENMAX
+1];
413 struct nd_hostservlist
*hs
;
415 register struct entry
*ep
;
418 for (i
= 0; i
< curentry
; i
++) {
420 if (netdir_getbyaddr(ep
->nconf
, &hs
, ep
->addr
) == ND_OK
)
421 sprintf(buf
, "%s", hs
->h_hostservs
->h_host
);
423 char *uaddr
= taddr2uaddr(ep
->nconf
, ep
->addr
);
426 sprintf(buf
, "%s", uaddr
);
429 sprintf(buf
, "%s", "unknown");
431 if (ep
->machine
= (char *)malloc(MACHINELENMAX
+ 1))
432 strcpy(ep
->machine
, buf
);
439 machinecmp(struct entry
*a
, struct entry
*b
)
441 return (strcmp(a
->machine
, b
->machine
));
445 uptimecmp(struct entry
*a
, struct entry
*b
)
447 if (a
->boottime
.tv_sec
!= b
->boottime
.tv_sec
)
448 return (a
->boottime
.tv_sec
- b
->boottime
.tv_sec
);
450 return (a
->boottime
.tv_usec
- b
->boottime
.tv_usec
);
454 loadcmp(struct entry
*a
, struct entry
*b
)
458 for (i
= 0; i
< AVENSIZE
/ sizeof (a
->avenrun
[0]); i
++)
459 if (a
->avenrun
[i
] != b
->avenrun
[i
])
460 return (a
->avenrun
[i
] - b
->avenrun
[i
]);
467 register struct netbuf
*ap
;
469 register struct netbuf
*np
;
471 np
= (struct netbuf
*) malloc(sizeof (struct netbuf
) + ap
->len
);
473 np
->maxlen
= np
->len
= ap
->len
;
474 np
->buf
= ((char *)np
) + sizeof (struct netbuf
);
475 (void) memcpy(np
->buf
, ap
->buf
, ap
->len
);
482 register struct netconfig
*onp
;
484 register int nlookupdirs
;
485 register struct netconfig
*nnp
;
486 extern char *strdup();
488 nnp
= (struct netconfig
*)malloc(sizeof (struct netconfig
));
490 nnp
->nc_netid
= strdup(onp
->nc_netid
);
491 nnp
->nc_semantics
= onp
->nc_semantics
;
492 nnp
->nc_flag
= onp
->nc_flag
;
493 nnp
->nc_protofmly
= strdup(onp
->nc_protofmly
);
494 nnp
->nc_proto
= strdup(onp
->nc_proto
);
495 nnp
->nc_device
= strdup(onp
->nc_device
);
496 nnp
->nc_nlookups
= onp
->nc_nlookups
;
497 if (onp
->nc_nlookups
== 0)
498 nnp
->nc_lookups
= (char **)0;
502 nnp
->nc_lookups
= (char **)malloc(onp
->nc_nlookups
*
505 for (i
= 0; i
< onp
->nc_nlookups
; i
++)
507 strdup(onp
->nc_lookups
[i
]);
515 netbufeq(struct netbuf
*ap
, struct netbuf
*bp
)
517 return (ap
->len
== bp
->len
&& !memcmp(ap
->buf
, bp
->buf
, ap
->len
));
523 fprintf(stderr
, "Usage: rup [-h] [-l] [-t] [host ...]\n");