8672 proc_t changes broke genunix dmods and walker
[unleashed.git] / usr / src / cmd / rpcsvc / rup.c
blobf17443b53ced45750ae80bdd6f5798b44fe5776a
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
22 #pragma ident "%Z%%M% %I% %E% SMI"
25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <netdb.h>
32 #include <sys/param.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <rpc/rpc.h>
38 #include <netdir.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))
46 #define SLOTS 256
48 int machinecmp();
49 int loadcmp();
50 int uptimecmp();
51 static int collectnames();
52 int singlehost(); /* returns 1 if rup of given host fails */
53 void printsinglehosts();
54 void printnames();
55 static void putline();
56 int netbufeq(struct netbuf *ap, struct netbuf *bp);
57 void usage(void);
59 struct entry {
60 struct netconfig *nconf;
61 struct netbuf *addr;
62 char *machine;
63 struct timeval boottime;
64 time_t curtime;
65 long avenrun[3];
68 int total_entries;
69 int curentry;
70 struct entry *entry;
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 */
76 int debug;
78 int
79 main(int argc, char *argv[])
81 statsvar sv;
82 statstime st;
83 int single, nfailed;
84 enum clnt_stat bstat;
87 * set number of slots to be 256 to begin with,
88 * this is large enough for most subnets but not all
91 curentry = 0;
92 total_entries = SLOTS;
93 entry = malloc(sizeof (struct entry) * total_entries);
94 single = nfailed = 0;
95 while (argc > 1) {
96 if (argv[1][0] != '-') {
97 single++;
98 nfailed += singlehost(argv[1]);
99 } else {
100 switch (argv[1][1]) {
102 case 'l':
103 lflag++;
104 break;
105 case 't':
106 tflag++;
107 break;
108 case 'h':
109 hflag++;
110 break;
111 case 'd':
112 dflag++;
113 if (argc < 3)
114 usage();
115 debug = atoi(argv[2]);
116 argc--;
117 argv++;
118 break;
119 default:
120 usage();
123 argv++;
124 argc--;
126 if (single > 0) {
127 if (hflag || tflag || lflag)
128 printsinglehosts();
129 if (nfailed == single) {
130 free(entry);
131 exit(1); /* all hosts we tried failed */
132 } else {
133 free(entry);
134 exit(0);
138 if (hflag || tflag || lflag) {
139 printf("collecting responses... ");
140 fflush(stdout);
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
153 * not registered).
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);
164 #ifdef TESTING
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");
169 #endif
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);
174 #ifdef TESTING
175 if (bstat != RPC_SUCCESS)
176 printf("rpc_broadcast for rstat version %d returned %s\n",
177 vers, clnt_sperrno(bstat));
178 #endif
179 if (hflag || tflag || lflag)
180 printnames();
184 free(entry);
185 return (0);
189 singlehost(host)
190 char *host;
192 static int debugcnt;
193 enum clnt_stat err;
194 statstime st;
195 statsvar sw_var;
196 bool_t is_var_vers = FALSE;
199 if (curentry >= total_entries) {
200 struct entry *tmp;
202 total_entries += SLOTS;
203 tmp = realloc((struct entry *)entry, sizeof (struct entry)
204 * total_entries);
205 if (tmp == NULL) {
206 return (1);
208 entry = tmp;
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) {
216 is_var_vers = TRUE;
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)
221 goto error;
222 } else
223 goto error;
225 debugcnt++;
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,
230 sw_var.avenrun);
231 else
232 putline(st.curtime.tv_sec, st.boottime, st.avenrun);
233 return (0); /* success */
234 } else {
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 =
239 st.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,
249 AVENSIZE);
252 curentry++;
253 if (dflag && debugcnt >= debug)
254 return (1);
255 return (0);
257 error:
258 fprintf(stderr, "%*.*s: ", MACHINELEN, MACHINELEN, host);
259 clnt_perrno(err);
261 * clnt_perrno now prints a newline
263 /* fprintf(stderr, "\n"); */
264 return (1); /* a failure */
267 static void
268 putline(now, boottime, avenrun)
269 time_t now;
270 struct timeval boottime;
271 long avenrun[];
273 int uptime, days, hrs, mins, i;
275 uptime = now - boottime.tv_sec;
276 uptime += 30;
277 if (uptime < 0) /* unsynchronized clocks */
278 uptime = 0;
279 days = uptime / (60*60*24);
280 uptime %= (60*60*24);
281 hrs = uptime / (60*60);
282 uptime %= (60*60);
283 mins = uptime / 60;
285 printf(" up");
286 if (days > 0)
287 printf(" %2d day%s", days, days > 1 ? "s," : ", ");
288 else
289 printf(" ");
290 if (hrs > 0)
291 printf(" %2d:%02d, ", hrs, mins);
292 else
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++) {
301 if (i > 0)
302 printf(",");
303 printf(" %.2f", (double)avenrun[i]/FSCALE);
305 printf("\n");
308 static int
309 collectnames(resultsp, taddr, nconf)
310 char *resultsp;
311 struct t_bind *taddr;
312 struct netconfig *nconf;
314 static int debugcnt;
315 register struct entry *entryp, *lim;
316 statstime *st;
317 statsvar *sv;
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) {
329 struct entry *tmp;
331 total_entries += SLOTS;
332 tmp = realloc((struct entry *)entry, sizeof (struct entry)
333 * total_entries);
334 if (tmp == NULL) {
335 return (1);
337 entry = tmp;
340 * weed out duplicates
342 lim = entry + curentry;
343 for (entryp = entry; entryp < lim; entryp++)
344 if (netbufeq(&taddr->addr, entryp->addr))
345 return (0);
347 if (vers == RSTATVERS_TIME) {
348 st = (statstime *)resultsp;
349 } else if (vers == RSTATVERS_VAR) {
350 sv = (statsvar *)resultsp;
351 } else {
352 return (0); /* we don't handle this version */
354 debugcnt++;
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);
366 else {
367 char *uaddr = taddr2uaddr(nconf, &taddr->addr);
369 if (uaddr) {
370 printf(" %*.*s", MACHINELEN, MACHINELEN,
371 uaddr);
372 (void) free(uaddr);
373 } else
374 printf(" %*.*s", MACHINELEN, MACHINELEN,
375 "unknown");
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);
382 } else {
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);
397 curentry++;
398 if (dflag && debugcnt >= debug)
399 return (1);
400 return (0);
403 void
404 printsinglehosts()
406 register int i;
407 register struct entry *ep;
410 if (hflag)
411 qsort(entry, curentry, sizeof (struct entry), machinecmp);
412 else if (lflag)
413 qsort(entry, curentry, sizeof (struct entry), loadcmp);
414 else
415 qsort(entry, curentry, sizeof (struct entry), uptimecmp);
416 for (i = 0; i < curentry; i++) {
417 ep = &entry[i];
418 printf("%*.*s ", MACHINELEN, MACHINELEN, ep->machine);
419 putline(ep->curtime, ep->boottime, ep->avenrun);
424 void
425 printnames()
427 char buf[MACHINELENMAX+1];
428 struct nd_hostservlist *hs;
429 register int i;
430 register struct entry *ep;
433 for (i = 0; i < curentry; i++) {
434 ep = &entry[i];
435 if (netdir_getbyaddr(ep->nconf, &hs, ep->addr) == ND_OK)
436 sprintf(buf, "%s", hs->h_hostservs->h_host);
437 else {
438 char *uaddr = taddr2uaddr(ep->nconf, ep->addr);
440 if (uaddr) {
441 sprintf(buf, "%s", uaddr);
442 (void) free(uaddr);
443 } else
444 sprintf(buf, "%s", "unknown");
446 if (ep->machine = (char *)malloc(MACHINELENMAX + 1))
447 strcpy(ep->machine, buf);
449 printf("\n");
450 printsinglehosts();
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);
464 else
465 return (a->boottime.tv_usec - b->boottime.tv_usec);
469 loadcmp(struct entry *a, struct entry *b)
471 register int i;
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]);
477 return (0);
480 struct netbuf *
481 netbufdup(ap)
482 register struct netbuf *ap;
484 register struct netbuf *np;
486 np = (struct netbuf *) malloc(sizeof (struct netbuf) + ap->len);
487 if (np) {
488 np->maxlen = np->len = ap->len;
489 np->buf = ((char *)np) + sizeof (struct netbuf);
490 (void) memcpy(np->buf, ap->buf, ap->len);
492 return (np);
495 struct netconfig *
496 netconfigdup(onp)
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));
504 if (nnp) {
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;
514 else {
515 register int i;
517 nnp->nc_lookups = (char **)malloc(onp->nc_nlookups *
518 sizeof (char *));
519 if (nnp->nc_lookups)
520 for (i = 0; i < onp->nc_nlookups; i++)
521 nnp->nc_lookups[i] =
522 strdup(onp->nc_lookups[i]);
526 return (nnp);
530 netbufeq(struct netbuf *ap, struct netbuf *bp)
532 return (ap->len == bp->len && !memcmp(ap->buf, bp->buf, ap->len));
535 void
536 usage(void)
538 fprintf(stderr, "Usage: rup [-h] [-l] [-t] [host ...]\n");
539 free(entry);
540 exit(1);