add UNLEASHED_OBJ to unleashed.mk
[unleashed/tickless.git] / usr / src / cmd / rpcsvc / rup.c
blob25f74d8d9fa36deacb6505492ae4c6c867388087
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 = NULL;
144 sv.dk_xfer.dk_xfer_val = 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 = NULL;
157 sv.dk_xfer.dk_xfer_len = 0;
158 sv.dk_xfer.dk_xfer_val = 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 = reallocarray(entry, total_entries, sizeof (struct entry));
204 if (tmp == NULL) {
205 return (1);
207 entry = tmp;
210 sw_var.cp_time.cp_time_val = NULL;
211 sw_var.dk_xfer.dk_xfer_val = NULL;
212 err = (enum clnt_stat)callrpc(host, RSTATPROG, RSTATVERS_VAR,
213 RSTATPROC_STATS, xdr_void, 0, xdr_statsvar, &sw_var);
214 if (err == RPC_SUCCESS) {
215 is_var_vers = TRUE;
216 } else if (err == RPC_PROGVERSMISMATCH) {
217 err = (enum clnt_stat)callrpc(host, RSTATPROG, RSTATVERS_TIME,
218 RSTATPROC_STATS, xdr_void, 0, xdr_statstime, &st);
219 if (err != RPC_SUCCESS)
220 goto error;
221 } else
222 goto error;
224 debugcnt++;
225 if (!hflag && !lflag && !tflag) {
226 printf("%*.*s ", MACHINELEN, MACHINELEN, host);
227 if (is_var_vers == TRUE)
228 putline(sw_var.curtime.tv_sec, sw_var.boottime,
229 sw_var.avenrun);
230 else
231 putline(st.curtime.tv_sec, st.boottime, st.avenrun);
232 return (0); /* success */
233 } else {
234 entry[curentry].machine = host;
235 if (is_var_vers == FALSE) { /* RSTATVERS_TIME */
236 entry[curentry].boottime.tv_sec = st.boottime.tv_sec;
237 entry[curentry].boottime.tv_usec =
238 st.boottime.tv_usec;
239 entry[curentry].curtime = st.curtime.tv_sec;
240 memcpy(entry[curentry].avenrun, st.avenrun, AVENSIZE);
241 } else { /* RSTATVERS_VAR */
242 entry[curentry].boottime.tv_sec =
243 sw_var.boottime.tv_sec;
244 entry[curentry].boottime.tv_usec =
245 sw_var.boottime.tv_usec;
246 entry[curentry].curtime = sw_var.curtime.tv_sec;
247 memcpy(entry[curentry].avenrun, sw_var.avenrun,
248 AVENSIZE);
251 curentry++;
252 if (dflag && debugcnt >= debug)
253 return (1);
254 return (0);
256 error:
257 fprintf(stderr, "%*.*s: ", MACHINELEN, MACHINELEN, host);
258 clnt_perrno(err);
260 * clnt_perrno now prints a newline
262 /* fprintf(stderr, "\n"); */
263 return (1); /* a failure */
266 static void
267 putline(now, boottime, avenrun)
268 time_t now;
269 struct timeval boottime;
270 long avenrun[];
272 int uptime, days, hrs, mins, i;
274 uptime = now - boottime.tv_sec;
275 uptime += 30;
276 if (uptime < 0) /* unsynchronized clocks */
277 uptime = 0;
278 days = uptime / (60*60*24);
279 uptime %= (60*60*24);
280 hrs = uptime / (60*60);
281 uptime %= (60*60);
282 mins = uptime / 60;
284 printf(" up");
285 if (days > 0)
286 printf(" %2d day%s", days, days > 1 ? "s," : ", ");
287 else
288 printf(" ");
289 if (hrs > 0)
290 printf(" %2d:%02d, ", hrs, mins);
291 else
292 printf(" %2d min%s", mins, mins > 1 ? "s," : ", ");
295 * Print 1, 5, and 15 minute load averages.
296 * (Found by looking in kernel for avenrun).
298 printf(" load average:");
299 for (i = 0; i < (AVENSIZE / sizeof (avenrun[0])); i++) {
300 if (i > 0)
301 printf(",");
302 printf(" %.2f", (double)avenrun[i]/FSCALE);
304 printf("\n");
307 static int
308 collectnames(resultsp, taddr, nconf)
309 char *resultsp;
310 struct t_bind *taddr;
311 struct netconfig *nconf;
313 static int debugcnt;
314 register struct entry *entryp, *lim;
315 statstime *st;
316 statsvar *sv;
317 struct nd_hostservlist *hs;
318 extern struct netbuf *netbufdup();
319 extern struct netconfig *netconfigdup();
320 extern int netbufeq();
323 * need to realloc more space if we have more than 256 machines
324 * that responded to the broadcast
327 if (curentry >= total_entries) {
328 struct entry *tmp;
330 total_entries += SLOTS;
331 tmp = reallocarray(entry, total_entries, sizeof (struct entry));
332 if (tmp == NULL) {
333 return (1);
335 entry = tmp;
338 * weed out duplicates
340 lim = entry + curentry;
341 for (entryp = entry; entryp < lim; entryp++)
342 if (netbufeq(&taddr->addr, entryp->addr))
343 return (0);
345 if (vers == RSTATVERS_TIME) {
346 st = (statstime *)resultsp;
347 } else if (vers == RSTATVERS_VAR) {
348 sv = (statsvar *)resultsp;
349 } else {
350 return (0); /* we don't handle this version */
352 debugcnt++;
353 entry[curentry].nconf = netconfigdup(nconf);
354 entry[curentry].addr = netbufdup(&taddr->addr);
357 * if raw, print this entry out immediately
358 * otherwise store for later sorting
360 if (!hflag && !lflag && !tflag) {
361 if (netdir_getbyaddr(nconf, &hs, &taddr->addr) == ND_OK)
362 printf("%*.*s ", MACHINELEN, MACHINELEN,
363 hs->h_hostservs->h_host);
364 else {
365 char *uaddr = taddr2uaddr(nconf, &taddr->addr);
367 if (uaddr) {
368 printf(" %*.*s", MACHINELEN, MACHINELEN,
369 uaddr);
370 (void) free(uaddr);
371 } else
372 printf(" %*.*s", MACHINELEN, MACHINELEN,
373 "unknown");
375 if (vers == RSTATVERS_TIME) {
376 putline(st->curtime.tv_sec, st->boottime, st->avenrun);
377 } else if (vers == RSTATVERS_VAR) {
378 putline(sv->curtime.tv_sec, sv->boottime, sv->avenrun);
380 } else {
381 if (vers == RSTATVERS_TIME) {
382 entry[curentry].boottime.tv_sec = st->boottime.tv_sec;
383 entry[curentry].boottime.tv_usec =
384 st->boottime.tv_usec;
385 entry[curentry].curtime = st->curtime.tv_sec;
386 memcpy(entry[curentry].avenrun, st->avenrun, AVENSIZE);
387 } else if (vers == RSTATVERS_VAR) {
388 entry[curentry].boottime.tv_sec = sv->boottime.tv_sec;
389 entry[curentry].boottime.tv_usec =
390 sv->boottime.tv_usec;
391 entry[curentry].curtime = sv->curtime.tv_sec;
392 memcpy(entry[curentry].avenrun, sv->avenrun, AVENSIZE);
395 curentry++;
396 if (dflag && debugcnt >= debug)
397 return (1);
398 return (0);
401 void
402 printsinglehosts()
404 register int i;
405 register struct entry *ep;
408 if (hflag)
409 qsort(entry, curentry, sizeof (struct entry), machinecmp);
410 else if (lflag)
411 qsort(entry, curentry, sizeof (struct entry), loadcmp);
412 else
413 qsort(entry, curentry, sizeof (struct entry), uptimecmp);
414 for (i = 0; i < curentry; i++) {
415 ep = &entry[i];
416 printf("%*.*s ", MACHINELEN, MACHINELEN, ep->machine);
417 putline(ep->curtime, ep->boottime, ep->avenrun);
422 void
423 printnames()
425 char buf[MACHINELENMAX+1];
426 struct nd_hostservlist *hs;
427 register int i;
428 register struct entry *ep;
431 for (i = 0; i < curentry; i++) {
432 ep = &entry[i];
433 if (netdir_getbyaddr(ep->nconf, &hs, ep->addr) == ND_OK)
434 sprintf(buf, "%s", hs->h_hostservs->h_host);
435 else {
436 char *uaddr = taddr2uaddr(ep->nconf, ep->addr);
438 if (uaddr) {
439 sprintf(buf, "%s", uaddr);
440 (void) free(uaddr);
441 } else
442 sprintf(buf, "%s", "unknown");
444 if (ep->machine = (char *)malloc(MACHINELENMAX + 1))
445 strcpy(ep->machine, buf);
447 printf("\n");
448 printsinglehosts();
452 machinecmp(struct entry *a, struct entry *b)
454 return (strcmp(a->machine, b->machine));
458 uptimecmp(struct entry *a, struct entry *b)
460 if (a->boottime.tv_sec != b->boottime.tv_sec)
461 return (a->boottime.tv_sec - b->boottime.tv_sec);
462 else
463 return (a->boottime.tv_usec - b->boottime.tv_usec);
467 loadcmp(struct entry *a, struct entry *b)
469 register int i;
471 for (i = 0; i < AVENSIZE / sizeof (a->avenrun[0]); i++)
472 if (a->avenrun[i] != b->avenrun[i])
473 return (a->avenrun[i] - b->avenrun[i]);
475 return (0);
478 struct netbuf *
479 netbufdup(ap)
480 register struct netbuf *ap;
482 register struct netbuf *np;
484 np = (struct netbuf *) malloc(sizeof (struct netbuf) + ap->len);
485 if (np) {
486 np->maxlen = np->len = ap->len;
487 np->buf = ((char *)np) + sizeof (struct netbuf);
488 (void) memcpy(np->buf, ap->buf, ap->len);
490 return (np);
493 struct netconfig *
494 netconfigdup(onp)
495 register struct netconfig *onp;
497 register int nlookupdirs;
498 register struct netconfig *nnp;
499 extern char *strdup();
501 nnp = (struct netconfig *)malloc(sizeof (struct netconfig));
502 if (nnp) {
503 nnp->nc_netid = strdup(onp->nc_netid);
504 nnp->nc_semantics = onp->nc_semantics;
505 nnp->nc_flag = onp->nc_flag;
506 nnp->nc_protofmly = strdup(onp->nc_protofmly);
507 nnp->nc_proto = strdup(onp->nc_proto);
508 nnp->nc_device = strdup(onp->nc_device);
509 nnp->nc_nlookups = onp->nc_nlookups;
510 if (onp->nc_nlookups == 0)
511 nnp->nc_lookups = (char **)0;
512 else {
513 register int i;
515 nnp->nc_lookups = (char **)malloc(onp->nc_nlookups *
516 sizeof (char *));
517 if (nnp->nc_lookups)
518 for (i = 0; i < onp->nc_nlookups; i++)
519 nnp->nc_lookups[i] =
520 strdup(onp->nc_lookups[i]);
524 return (nnp);
528 netbufeq(struct netbuf *ap, struct netbuf *bp)
530 return (ap->len == bp->len && !memcmp(ap->buf, bp->buf, ap->len));
533 void
534 usage(void)
536 fprintf(stderr, "Usage: rup [-h] [-l] [-t] [host ...]\n");
537 free(entry);
538 exit(1);