Move /var/svc/log to /var/log/svc
[unleashed/lotheac.git] / usr / src / cmd / rpcsvc / rup.c
blobbc64181578ed454e6ed85811222c1d87ac975636
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
24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <netdb.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <rpc/rpc.h>
37 #include <netdir.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))
45 #define SLOTS 256
47 int machinecmp();
48 int loadcmp();
49 int uptimecmp();
50 static int collectnames();
51 int singlehost(); /* returns 1 if rup of given host fails */
52 void printsinglehosts();
53 void printnames();
54 static void putline();
55 int netbufeq(struct netbuf *ap, struct netbuf *bp);
56 void usage(void);
58 struct entry {
59 struct netconfig *nconf;
60 struct netbuf *addr;
61 char *machine;
62 struct timeval boottime;
63 time_t curtime;
64 long avenrun[3];
67 int total_entries;
68 int curentry;
69 struct entry *entry;
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 */
75 int debug;
77 int
78 main(int argc, char *argv[])
80 statsvar sv;
81 statstime st;
82 int single, nfailed;
85 * set number of slots to be 256 to begin with,
86 * this is large enough for most subnets but not all
89 curentry = 0;
90 total_entries = SLOTS;
91 entry = malloc(sizeof (struct entry) * total_entries);
92 single = nfailed = 0;
93 while (argc > 1) {
94 if (argv[1][0] != '-') {
95 single++;
96 nfailed += singlehost(argv[1]);
97 } else {
98 switch (argv[1][1]) {
100 case 'l':
101 lflag++;
102 break;
103 case 't':
104 tflag++;
105 break;
106 case 'h':
107 hflag++;
108 break;
109 case 'd':
110 dflag++;
111 if (argc < 3)
112 usage();
113 debug = atoi(argv[2]);
114 argc--;
115 argv++;
116 break;
117 default:
118 usage();
121 argv++;
122 argc--;
124 if (single > 0) {
125 if (hflag || tflag || lflag)
126 printsinglehosts();
127 if (nfailed == single) {
128 free(entry);
129 exit(1); /* all hosts we tried failed */
130 } else {
131 free(entry);
132 exit(0);
136 if (hflag || tflag || lflag) {
137 printf("collecting responses... ");
138 fflush(stdout);
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
151 * not registered).
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)
167 printnames();
171 free(entry);
172 return (0);
176 singlehost(host)
177 char *host;
179 static int debugcnt;
180 enum clnt_stat err;
181 statstime st;
182 statsvar sw_var;
183 bool_t is_var_vers = FALSE;
186 if (curentry >= total_entries) {
187 struct entry *tmp;
189 total_entries += SLOTS;
190 tmp = reallocarray(entry, total_entries, sizeof (struct entry));
191 if (tmp == NULL) {
192 return (1);
194 entry = tmp;
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) {
202 is_var_vers = TRUE;
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)
207 goto error;
208 } else
209 goto error;
211 debugcnt++;
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,
216 sw_var.avenrun);
217 else
218 putline(st.curtime.tv_sec, st.boottime, st.avenrun);
219 return (0); /* success */
220 } else {
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 =
225 st.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,
235 AVENSIZE);
238 curentry++;
239 if (dflag && debugcnt >= debug)
240 return (1);
241 return (0);
243 error:
244 fprintf(stderr, "%*.*s: ", MACHINELEN, MACHINELEN, host);
245 clnt_perrno(err);
247 * clnt_perrno now prints a newline
249 /* fprintf(stderr, "\n"); */
250 return (1); /* a failure */
253 static void
254 putline(now, boottime, avenrun)
255 time_t now;
256 struct timeval boottime;
257 long avenrun[];
259 int uptime, days, hrs, mins, i;
261 uptime = now - boottime.tv_sec;
262 uptime += 30;
263 if (uptime < 0) /* unsynchronized clocks */
264 uptime = 0;
265 days = uptime / (60*60*24);
266 uptime %= (60*60*24);
267 hrs = uptime / (60*60);
268 uptime %= (60*60);
269 mins = uptime / 60;
271 printf(" up");
272 if (days > 0)
273 printf(" %2d day%s", days, days > 1 ? "s," : ", ");
274 else
275 printf(" ");
276 if (hrs > 0)
277 printf(" %2d:%02d, ", hrs, mins);
278 else
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++) {
287 if (i > 0)
288 printf(",");
289 printf(" %.2f", (double)avenrun[i]/FSCALE);
291 printf("\n");
294 static int
295 collectnames(resultsp, taddr, nconf)
296 char *resultsp;
297 struct t_bind *taddr;
298 struct netconfig *nconf;
300 static int debugcnt;
301 register struct entry *entryp, *lim;
302 statstime *st;
303 statsvar *sv;
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) {
315 struct entry *tmp;
317 total_entries += SLOTS;
318 tmp = reallocarray(entry, total_entries, sizeof (struct entry));
319 if (tmp == NULL) {
320 return (1);
322 entry = tmp;
325 * weed out duplicates
327 lim = entry + curentry;
328 for (entryp = entry; entryp < lim; entryp++)
329 if (netbufeq(&taddr->addr, entryp->addr))
330 return (0);
332 if (vers == RSTATVERS_TIME) {
333 st = (statstime *)resultsp;
334 } else if (vers == RSTATVERS_VAR) {
335 sv = (statsvar *)resultsp;
336 } else {
337 return (0); /* we don't handle this version */
339 debugcnt++;
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);
351 else {
352 char *uaddr = taddr2uaddr(nconf, &taddr->addr);
354 if (uaddr) {
355 printf(" %*.*s", MACHINELEN, MACHINELEN,
356 uaddr);
357 (void) free(uaddr);
358 } else
359 printf(" %*.*s", MACHINELEN, MACHINELEN,
360 "unknown");
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);
367 } else {
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);
382 curentry++;
383 if (dflag && debugcnt >= debug)
384 return (1);
385 return (0);
388 void
389 printsinglehosts()
391 register int i;
392 register struct entry *ep;
395 if (hflag)
396 qsort(entry, curentry, sizeof (struct entry), machinecmp);
397 else if (lflag)
398 qsort(entry, curentry, sizeof (struct entry), loadcmp);
399 else
400 qsort(entry, curentry, sizeof (struct entry), uptimecmp);
401 for (i = 0; i < curentry; i++) {
402 ep = &entry[i];
403 printf("%*.*s ", MACHINELEN, MACHINELEN, ep->machine);
404 putline(ep->curtime, ep->boottime, ep->avenrun);
409 void
410 printnames()
412 char buf[MACHINELENMAX+1];
413 struct nd_hostservlist *hs;
414 register int i;
415 register struct entry *ep;
418 for (i = 0; i < curentry; i++) {
419 ep = &entry[i];
420 if (netdir_getbyaddr(ep->nconf, &hs, ep->addr) == ND_OK)
421 sprintf(buf, "%s", hs->h_hostservs->h_host);
422 else {
423 char *uaddr = taddr2uaddr(ep->nconf, ep->addr);
425 if (uaddr) {
426 sprintf(buf, "%s", uaddr);
427 (void) free(uaddr);
428 } else
429 sprintf(buf, "%s", "unknown");
431 if (ep->machine = (char *)malloc(MACHINELENMAX + 1))
432 strcpy(ep->machine, buf);
434 printf("\n");
435 printsinglehosts();
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);
449 else
450 return (a->boottime.tv_usec - b->boottime.tv_usec);
454 loadcmp(struct entry *a, struct entry *b)
456 register int i;
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]);
462 return (0);
465 struct netbuf *
466 netbufdup(ap)
467 register struct netbuf *ap;
469 register struct netbuf *np;
471 np = (struct netbuf *) malloc(sizeof (struct netbuf) + ap->len);
472 if (np) {
473 np->maxlen = np->len = ap->len;
474 np->buf = ((char *)np) + sizeof (struct netbuf);
475 (void) memcpy(np->buf, ap->buf, ap->len);
477 return (np);
480 struct netconfig *
481 netconfigdup(onp)
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));
489 if (nnp) {
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;
499 else {
500 register int i;
502 nnp->nc_lookups = (char **)malloc(onp->nc_nlookups *
503 sizeof (char *));
504 if (nnp->nc_lookups)
505 for (i = 0; i < onp->nc_nlookups; i++)
506 nnp->nc_lookups[i] =
507 strdup(onp->nc_lookups[i]);
511 return (nnp);
515 netbufeq(struct netbuf *ap, struct netbuf *bp)
517 return (ap->len == bp->len && !memcmp(ap->buf, bp->buf, ap->len));
520 void
521 usage(void)
523 fprintf(stderr, "Usage: rup [-h] [-l] [-t] [host ...]\n");
524 free(entry);
525 exit(1);