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
= (int *)NULL
;
142 sv
.dk_xfer
.dk_xfer_val
= (int *)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
= (int *)NULL
;
155 sv
.dk_xfer
.dk_xfer_len
= 0;
156 sv
.dk_xfer
.dk_xfer_val
= (int *)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
= realloc((struct entry
*)entry
, sizeof (struct entry
)
198 sw_var
.cp_time
.cp_time_val
= (int *)NULL
;
199 sw_var
.dk_xfer
.dk_xfer_val
= (int *)NULL
;
200 err
= (enum clnt_stat
)callrpc(host
, RSTATPROG
, RSTATVERS_VAR
,
201 RSTATPROC_STATS
, xdr_void
, 0, xdr_statsvar
, &sw_var
);
202 if (err
== RPC_SUCCESS
) {
204 } else if (err
== RPC_PROGVERSMISMATCH
) {
205 err
= (enum clnt_stat
)callrpc(host
, RSTATPROG
, RSTATVERS_TIME
,
206 RSTATPROC_STATS
, xdr_void
, 0, xdr_statstime
, &st
);
207 if (err
!= RPC_SUCCESS
)
213 if (!hflag
&& !lflag
&& !tflag
) {
214 printf("%*.*s ", MACHINELEN
, MACHINELEN
, host
);
215 if (is_var_vers
== TRUE
)
216 putline(sw_var
.curtime
.tv_sec
, sw_var
.boottime
,
219 putline(st
.curtime
.tv_sec
, st
.boottime
, st
.avenrun
);
220 return (0); /* success */
222 entry
[curentry
].machine
= host
;
223 if (is_var_vers
== FALSE
) { /* RSTATVERS_TIME */
224 entry
[curentry
].boottime
.tv_sec
= st
.boottime
.tv_sec
;
225 entry
[curentry
].boottime
.tv_usec
=
227 entry
[curentry
].curtime
= st
.curtime
.tv_sec
;
228 memcpy(entry
[curentry
].avenrun
, st
.avenrun
, AVENSIZE
);
229 } else { /* RSTATVERS_VAR */
230 entry
[curentry
].boottime
.tv_sec
=
231 sw_var
.boottime
.tv_sec
;
232 entry
[curentry
].boottime
.tv_usec
=
233 sw_var
.boottime
.tv_usec
;
234 entry
[curentry
].curtime
= sw_var
.curtime
.tv_sec
;
235 memcpy(entry
[curentry
].avenrun
, sw_var
.avenrun
,
240 if (dflag
&& debugcnt
>= debug
)
245 fprintf(stderr
, "%*.*s: ", MACHINELEN
, MACHINELEN
, host
);
248 * clnt_perrno now prints a newline
250 /* fprintf(stderr, "\n"); */
251 return (1); /* a failure */
255 putline(now
, boottime
, avenrun
)
257 struct timeval boottime
;
260 int uptime
, days
, hrs
, mins
, i
;
262 uptime
= now
- boottime
.tv_sec
;
264 if (uptime
< 0) /* unsynchronized clocks */
266 days
= uptime
/ (60*60*24);
267 uptime
%= (60*60*24);
268 hrs
= uptime
/ (60*60);
274 printf(" %2d day%s", days
, days
> 1 ? "s," : ", ");
278 printf(" %2d:%02d, ", hrs
, mins
);
280 printf(" %2d min%s", mins
, mins
> 1 ? "s," : ", ");
283 * Print 1, 5, and 15 minute load averages.
284 * (Found by looking in kernel for avenrun).
286 printf(" load average:");
287 for (i
= 0; i
< (AVENSIZE
/ sizeof (avenrun
[0])); i
++) {
290 printf(" %.2f", (double)avenrun
[i
]/FSCALE
);
296 collectnames(resultsp
, taddr
, nconf
)
298 struct t_bind
*taddr
;
299 struct netconfig
*nconf
;
302 register struct entry
*entryp
, *lim
;
305 struct nd_hostservlist
*hs
;
306 extern struct netbuf
*netbufdup();
307 extern struct netconfig
*netconfigdup();
308 extern int netbufeq();
311 * need to realloc more space if we have more than 256 machines
312 * that responded to the broadcast
315 if (curentry
>= total_entries
) {
318 total_entries
+= SLOTS
;
319 tmp
= realloc((struct entry
*)entry
, sizeof (struct entry
)
327 * weed out duplicates
329 lim
= entry
+ curentry
;
330 for (entryp
= entry
; entryp
< lim
; entryp
++)
331 if (netbufeq(&taddr
->addr
, entryp
->addr
))
334 if (vers
== RSTATVERS_TIME
) {
335 st
= (statstime
*)resultsp
;
336 } else if (vers
== RSTATVERS_VAR
) {
337 sv
= (statsvar
*)resultsp
;
339 return (0); /* we don't handle this version */
342 entry
[curentry
].nconf
= netconfigdup(nconf
);
343 entry
[curentry
].addr
= netbufdup(&taddr
->addr
);
346 * if raw, print this entry out immediately
347 * otherwise store for later sorting
349 if (!hflag
&& !lflag
&& !tflag
) {
350 if (netdir_getbyaddr(nconf
, &hs
, &taddr
->addr
) == ND_OK
)
351 printf("%*.*s ", MACHINELEN
, MACHINELEN
,
352 hs
->h_hostservs
->h_host
);
354 char *uaddr
= taddr2uaddr(nconf
, &taddr
->addr
);
357 printf(" %*.*s", MACHINELEN
, MACHINELEN
,
361 printf(" %*.*s", MACHINELEN
, MACHINELEN
,
364 if (vers
== RSTATVERS_TIME
) {
365 putline(st
->curtime
.tv_sec
, st
->boottime
, st
->avenrun
);
366 } else if (vers
== RSTATVERS_VAR
) {
367 putline(sv
->curtime
.tv_sec
, sv
->boottime
, sv
->avenrun
);
370 if (vers
== RSTATVERS_TIME
) {
371 entry
[curentry
].boottime
.tv_sec
= st
->boottime
.tv_sec
;
372 entry
[curentry
].boottime
.tv_usec
=
373 st
->boottime
.tv_usec
;
374 entry
[curentry
].curtime
= st
->curtime
.tv_sec
;
375 memcpy(entry
[curentry
].avenrun
, st
->avenrun
, AVENSIZE
);
376 } else if (vers
== RSTATVERS_VAR
) {
377 entry
[curentry
].boottime
.tv_sec
= sv
->boottime
.tv_sec
;
378 entry
[curentry
].boottime
.tv_usec
=
379 sv
->boottime
.tv_usec
;
380 entry
[curentry
].curtime
= sv
->curtime
.tv_sec
;
381 memcpy(entry
[curentry
].avenrun
, sv
->avenrun
, AVENSIZE
);
385 if (dflag
&& debugcnt
>= debug
)
394 register struct entry
*ep
;
398 qsort(entry
, curentry
, sizeof (struct entry
), machinecmp
);
400 qsort(entry
, curentry
, sizeof (struct entry
), loadcmp
);
402 qsort(entry
, curentry
, sizeof (struct entry
), uptimecmp
);
403 for (i
= 0; i
< curentry
; i
++) {
405 printf("%*.*s ", MACHINELEN
, MACHINELEN
, ep
->machine
);
406 putline(ep
->curtime
, ep
->boottime
, ep
->avenrun
);
414 char buf
[MACHINELENMAX
+1];
415 struct nd_hostservlist
*hs
;
417 register struct entry
*ep
;
420 for (i
= 0; i
< curentry
; i
++) {
422 if (netdir_getbyaddr(ep
->nconf
, &hs
, ep
->addr
) == ND_OK
)
423 sprintf(buf
, "%s", hs
->h_hostservs
->h_host
);
425 char *uaddr
= taddr2uaddr(ep
->nconf
, ep
->addr
);
428 sprintf(buf
, "%s", uaddr
);
431 sprintf(buf
, "%s", "unknown");
433 if (ep
->machine
= (char *)malloc(MACHINELENMAX
+ 1))
434 strcpy(ep
->machine
, buf
);
441 machinecmp(struct entry
*a
, struct entry
*b
)
443 return (strcmp(a
->machine
, b
->machine
));
447 uptimecmp(struct entry
*a
, struct entry
*b
)
449 if (a
->boottime
.tv_sec
!= b
->boottime
.tv_sec
)
450 return (a
->boottime
.tv_sec
- b
->boottime
.tv_sec
);
452 return (a
->boottime
.tv_usec
- b
->boottime
.tv_usec
);
456 loadcmp(struct entry
*a
, struct entry
*b
)
460 for (i
= 0; i
< AVENSIZE
/ sizeof (a
->avenrun
[0]); i
++)
461 if (a
->avenrun
[i
] != b
->avenrun
[i
])
462 return (a
->avenrun
[i
] - b
->avenrun
[i
]);
469 register struct netbuf
*ap
;
471 register struct netbuf
*np
;
473 np
= (struct netbuf
*) malloc(sizeof (struct netbuf
) + ap
->len
);
475 np
->maxlen
= np
->len
= ap
->len
;
476 np
->buf
= ((char *)np
) + sizeof (struct netbuf
);
477 (void) memcpy(np
->buf
, ap
->buf
, ap
->len
);
484 register struct netconfig
*onp
;
486 register int nlookupdirs
;
487 register struct netconfig
*nnp
;
488 extern char *strdup();
490 nnp
= (struct netconfig
*)malloc(sizeof (struct netconfig
));
492 nnp
->nc_netid
= strdup(onp
->nc_netid
);
493 nnp
->nc_semantics
= onp
->nc_semantics
;
494 nnp
->nc_flag
= onp
->nc_flag
;
495 nnp
->nc_protofmly
= strdup(onp
->nc_protofmly
);
496 nnp
->nc_proto
= strdup(onp
->nc_proto
);
497 nnp
->nc_device
= strdup(onp
->nc_device
);
498 nnp
->nc_nlookups
= onp
->nc_nlookups
;
499 if (onp
->nc_nlookups
== 0)
500 nnp
->nc_lookups
= (char **)0;
504 nnp
->nc_lookups
= (char **)malloc(onp
->nc_nlookups
*
507 for (i
= 0; i
< onp
->nc_nlookups
; i
++)
509 strdup(onp
->nc_lookups
[i
]);
517 netbufeq(struct netbuf
*ap
, struct netbuf
*bp
)
519 return (ap
->len
== bp
->len
&& !memcmp(ap
->buf
, bp
->buf
, ap
->len
));
525 fprintf(stderr
, "Usage: rup [-h] [-l] [-t] [host ...]\n");