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]
22 #pragma ident "%Z%%M% %I% %E% SMI"
25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
32 #include <sys/param.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
39 #include <rpcsvc/rstat.h>
40 #include <rpc/pmap_clnt.h>
43 #define MACHINELEN 15 /* length of machine name printed out */
44 #define MACHINELENMAX 128 /* maximum machine name length */
45 #define AVENSIZE (3 * sizeof (long))
51 static int collectnames();
52 int singlehost(); /* returns 1 if rup of given host fails */
53 void printsinglehosts();
55 static void putline();
56 int netbufeq(struct netbuf
*ap
, struct netbuf
*bp
);
60 struct netconfig
*nconf
;
63 struct timeval boottime
;
71 int vers
; /* which version did the broadcasting */
72 int lflag
; /* load: sort by load average */
73 int tflag
; /* time: sort by uptime average */
74 int hflag
; /* host: sort by machine name */
75 int dflag
; /* debug: list only first n machines */
79 main(int argc
, char *argv
[])
87 * set number of slots to be 256 to begin with,
88 * this is large enough for most subnets but not all
92 total_entries
= SLOTS
;
93 entry
= malloc(sizeof (struct entry
) * total_entries
);
96 if (argv
[1][0] != '-') {
98 nfailed
+= singlehost(argv
[1]);
100 switch (argv
[1][1]) {
115 debug
= atoi(argv
[2]);
127 if (hflag
|| tflag
|| lflag
)
129 if (nfailed
== single
) {
131 exit(1); /* all hosts we tried failed */
138 if (hflag
|| tflag
|| lflag
) {
139 printf("collecting responses... ");
143 sv
.cp_time
.cp_time_val
= (int *)NULL
;
144 sv
.dk_xfer
.dk_xfer_val
= (int *)NULL
;
147 * Null out pointers in the statsvar struct
148 * so that we don't follow a random pointer
149 * somewhere when we get our results back.
150 * Set lengths to zero so we don't allocate
151 * some random amount of space we don't need
152 * (in the case where the reply was program
155 sv
.cp_time
.cp_time_len
= 0;
156 sv
.cp_time
.cp_time_val
= (int *)NULL
;
157 sv
.dk_xfer
.dk_xfer_len
= 0;
158 sv
.dk_xfer
.dk_xfer_val
= (int *)NULL
;
160 vers
= RSTATVERS_VAR
;
161 bstat
= rpc_broadcast(RSTATPROG
, RSTATVERS_VAR
, RSTATPROC_STATS
,
162 xdr_void
, NULL
, xdr_statsvar
, (caddr_t
)&sv
,
163 (resultproc_t
)collectnames
, (char *)0);
165 if (bstat
!= RPC_SUCCESS
)
166 printf("rpc_broadcast for rstat version %d returned %s\n",
167 vers
, clnt_sperrno(bstat
));
168 fprintf(stderr
, "starting second round of broadcasting\n");
170 vers
= RSTATVERS_TIME
;
171 bstat
= rpc_broadcast(RSTATPROG
, RSTATVERS_TIME
, RSTATPROC_STATS
,
172 xdr_void
, NULL
, xdr_statstime
, (caddr_t
)&st
,
173 (resultproc_t
)collectnames
, (char *)0);
175 if (bstat
!= RPC_SUCCESS
)
176 printf("rpc_broadcast for rstat version %d returned %s\n",
177 vers
, clnt_sperrno(bstat
));
179 if (hflag
|| tflag
|| lflag
)
196 bool_t is_var_vers
= FALSE
;
199 if (curentry
>= total_entries
) {
202 total_entries
+= SLOTS
;
203 tmp
= realloc((struct entry
*)entry
, sizeof (struct entry
)
211 sw_var
.cp_time
.cp_time_val
= (int *)NULL
;
212 sw_var
.dk_xfer
.dk_xfer_val
= (int *)NULL
;
213 err
= (enum clnt_stat
)callrpc(host
, RSTATPROG
, RSTATVERS_VAR
,
214 RSTATPROC_STATS
, xdr_void
, 0, xdr_statsvar
, &sw_var
);
215 if (err
== RPC_SUCCESS
) {
217 } else if (err
== RPC_PROGVERSMISMATCH
) {
218 err
= (enum clnt_stat
)callrpc(host
, RSTATPROG
, RSTATVERS_TIME
,
219 RSTATPROC_STATS
, xdr_void
, 0, xdr_statstime
, &st
);
220 if (err
!= RPC_SUCCESS
)
226 if (!hflag
&& !lflag
&& !tflag
) {
227 printf("%*.*s ", MACHINELEN
, MACHINELEN
, host
);
228 if (is_var_vers
== TRUE
)
229 putline(sw_var
.curtime
.tv_sec
, sw_var
.boottime
,
232 putline(st
.curtime
.tv_sec
, st
.boottime
, st
.avenrun
);
233 return (0); /* success */
235 entry
[curentry
].machine
= host
;
236 if (is_var_vers
== FALSE
) { /* RSTATVERS_TIME */
237 entry
[curentry
].boottime
.tv_sec
= st
.boottime
.tv_sec
;
238 entry
[curentry
].boottime
.tv_usec
=
240 entry
[curentry
].curtime
= st
.curtime
.tv_sec
;
241 memcpy(entry
[curentry
].avenrun
, st
.avenrun
, AVENSIZE
);
242 } else { /* RSTATVERS_VAR */
243 entry
[curentry
].boottime
.tv_sec
=
244 sw_var
.boottime
.tv_sec
;
245 entry
[curentry
].boottime
.tv_usec
=
246 sw_var
.boottime
.tv_usec
;
247 entry
[curentry
].curtime
= sw_var
.curtime
.tv_sec
;
248 memcpy(entry
[curentry
].avenrun
, sw_var
.avenrun
,
253 if (dflag
&& debugcnt
>= debug
)
258 fprintf(stderr
, "%*.*s: ", MACHINELEN
, MACHINELEN
, host
);
261 * clnt_perrno now prints a newline
263 /* fprintf(stderr, "\n"); */
264 return (1); /* a failure */
268 putline(now
, boottime
, avenrun
)
270 struct timeval boottime
;
273 int uptime
, days
, hrs
, mins
, i
;
275 uptime
= now
- boottime
.tv_sec
;
277 if (uptime
< 0) /* unsynchronized clocks */
279 days
= uptime
/ (60*60*24);
280 uptime
%= (60*60*24);
281 hrs
= uptime
/ (60*60);
287 printf(" %2d day%s", days
, days
> 1 ? "s," : ", ");
291 printf(" %2d:%02d, ", hrs
, mins
);
293 printf(" %2d min%s", mins
, mins
> 1 ? "s," : ", ");
296 * Print 1, 5, and 15 minute load averages.
297 * (Found by looking in kernel for avenrun).
299 printf(" load average:");
300 for (i
= 0; i
< (AVENSIZE
/ sizeof (avenrun
[0])); i
++) {
303 printf(" %.2f", (double)avenrun
[i
]/FSCALE
);
309 collectnames(resultsp
, taddr
, nconf
)
311 struct t_bind
*taddr
;
312 struct netconfig
*nconf
;
315 register struct entry
*entryp
, *lim
;
318 struct nd_hostservlist
*hs
;
319 extern struct netbuf
*netbufdup();
320 extern struct netconfig
*netconfigdup();
321 extern int netbufeq();
324 * need to realloc more space if we have more than 256 machines
325 * that responded to the broadcast
328 if (curentry
>= total_entries
) {
331 total_entries
+= SLOTS
;
332 tmp
= realloc((struct entry
*)entry
, sizeof (struct entry
)
340 * weed out duplicates
342 lim
= entry
+ curentry
;
343 for (entryp
= entry
; entryp
< lim
; entryp
++)
344 if (netbufeq(&taddr
->addr
, entryp
->addr
))
347 if (vers
== RSTATVERS_TIME
) {
348 st
= (statstime
*)resultsp
;
349 } else if (vers
== RSTATVERS_VAR
) {
350 sv
= (statsvar
*)resultsp
;
352 return (0); /* we don't handle this version */
355 entry
[curentry
].nconf
= netconfigdup(nconf
);
356 entry
[curentry
].addr
= netbufdup(&taddr
->addr
);
359 * if raw, print this entry out immediately
360 * otherwise store for later sorting
362 if (!hflag
&& !lflag
&& !tflag
) {
363 if (netdir_getbyaddr(nconf
, &hs
, &taddr
->addr
) == ND_OK
)
364 printf("%*.*s ", MACHINELEN
, MACHINELEN
,
365 hs
->h_hostservs
->h_host
);
367 char *uaddr
= taddr2uaddr(nconf
, &taddr
->addr
);
370 printf(" %*.*s", MACHINELEN
, MACHINELEN
,
374 printf(" %*.*s", MACHINELEN
, MACHINELEN
,
377 if (vers
== RSTATVERS_TIME
) {
378 putline(st
->curtime
.tv_sec
, st
->boottime
, st
->avenrun
);
379 } else if (vers
== RSTATVERS_VAR
) {
380 putline(sv
->curtime
.tv_sec
, sv
->boottime
, sv
->avenrun
);
383 if (vers
== RSTATVERS_TIME
) {
384 entry
[curentry
].boottime
.tv_sec
= st
->boottime
.tv_sec
;
385 entry
[curentry
].boottime
.tv_usec
=
386 st
->boottime
.tv_usec
;
387 entry
[curentry
].curtime
= st
->curtime
.tv_sec
;
388 memcpy(entry
[curentry
].avenrun
, st
->avenrun
, AVENSIZE
);
389 } else if (vers
== RSTATVERS_VAR
) {
390 entry
[curentry
].boottime
.tv_sec
= sv
->boottime
.tv_sec
;
391 entry
[curentry
].boottime
.tv_usec
=
392 sv
->boottime
.tv_usec
;
393 entry
[curentry
].curtime
= sv
->curtime
.tv_sec
;
394 memcpy(entry
[curentry
].avenrun
, sv
->avenrun
, AVENSIZE
);
398 if (dflag
&& debugcnt
>= debug
)
407 register struct entry
*ep
;
411 qsort(entry
, curentry
, sizeof (struct entry
), machinecmp
);
413 qsort(entry
, curentry
, sizeof (struct entry
), loadcmp
);
415 qsort(entry
, curentry
, sizeof (struct entry
), uptimecmp
);
416 for (i
= 0; i
< curentry
; i
++) {
418 printf("%*.*s ", MACHINELEN
, MACHINELEN
, ep
->machine
);
419 putline(ep
->curtime
, ep
->boottime
, ep
->avenrun
);
427 char buf
[MACHINELENMAX
+1];
428 struct nd_hostservlist
*hs
;
430 register struct entry
*ep
;
433 for (i
= 0; i
< curentry
; i
++) {
435 if (netdir_getbyaddr(ep
->nconf
, &hs
, ep
->addr
) == ND_OK
)
436 sprintf(buf
, "%s", hs
->h_hostservs
->h_host
);
438 char *uaddr
= taddr2uaddr(ep
->nconf
, ep
->addr
);
441 sprintf(buf
, "%s", uaddr
);
444 sprintf(buf
, "%s", "unknown");
446 if (ep
->machine
= (char *)malloc(MACHINELENMAX
+ 1))
447 strcpy(ep
->machine
, buf
);
454 machinecmp(struct entry
*a
, struct entry
*b
)
456 return (strcmp(a
->machine
, b
->machine
));
460 uptimecmp(struct entry
*a
, struct entry
*b
)
462 if (a
->boottime
.tv_sec
!= b
->boottime
.tv_sec
)
463 return (a
->boottime
.tv_sec
- b
->boottime
.tv_sec
);
465 return (a
->boottime
.tv_usec
- b
->boottime
.tv_usec
);
469 loadcmp(struct entry
*a
, struct entry
*b
)
473 for (i
= 0; i
< AVENSIZE
/ sizeof (a
->avenrun
[0]); i
++)
474 if (a
->avenrun
[i
] != b
->avenrun
[i
])
475 return (a
->avenrun
[i
] - b
->avenrun
[i
]);
482 register struct netbuf
*ap
;
484 register struct netbuf
*np
;
486 np
= (struct netbuf
*) malloc(sizeof (struct netbuf
) + ap
->len
);
488 np
->maxlen
= np
->len
= ap
->len
;
489 np
->buf
= ((char *)np
) + sizeof (struct netbuf
);
490 (void) memcpy(np
->buf
, ap
->buf
, ap
->len
);
497 register struct netconfig
*onp
;
499 register int nlookupdirs
;
500 register struct netconfig
*nnp
;
501 extern char *strdup();
503 nnp
= (struct netconfig
*)malloc(sizeof (struct netconfig
));
505 nnp
->nc_netid
= strdup(onp
->nc_netid
);
506 nnp
->nc_semantics
= onp
->nc_semantics
;
507 nnp
->nc_flag
= onp
->nc_flag
;
508 nnp
->nc_protofmly
= strdup(onp
->nc_protofmly
);
509 nnp
->nc_proto
= strdup(onp
->nc_proto
);
510 nnp
->nc_device
= strdup(onp
->nc_device
);
511 nnp
->nc_nlookups
= onp
->nc_nlookups
;
512 if (onp
->nc_nlookups
== 0)
513 nnp
->nc_lookups
= (char **)0;
517 nnp
->nc_lookups
= (char **)malloc(onp
->nc_nlookups
*
520 for (i
= 0; i
< onp
->nc_nlookups
; i
++)
522 strdup(onp
->nc_lookups
[i
]);
530 netbufeq(struct netbuf
*ap
, struct netbuf
*bp
)
532 return (ap
->len
== bp
->len
&& !memcmp(ap
->buf
, bp
->buf
, ap
->len
));
538 fprintf(stderr
, "Usage: rup [-h] [-l] [-t] [host ...]\n");