xref: /titanic_52/usr/src/cmd/rpcsvc/rup.c (revision 1a7c1b724419d3cb5fa6eea75123c6b2060ba31b)
1 /*
2  * CDDL HEADER START
3  *
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.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 #pragma ident	"%Z%%M%	%I%	%E% SMI"
23 
24 /*
25  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
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>
41 
42 
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
47 
48 int machinecmp();
49 int loadcmp();
50 int uptimecmp();
51 int collectnames();
52 int singlehost();		/* returns 1 if rup of given host fails */
53 void printsinglehosts();
54 void printnames();
55 
56 
57 struct entry {
58 	struct netconfig *nconf;
59 	struct netbuf *addr;
60 	char *machine;
61 	struct timeval boottime;
62 	time_t curtime;
63 	long avenrun[3];
64 };
65 
66 int total_entries;
67 int curentry;
68 struct entry *entry;
69 int vers;			/* which version did the broadcasting */
70 int lflag;			/* load: sort by load average */
71 int tflag;			/* time: sort by uptime average */
72 int hflag;			/* host: sort by machine name */
73 int dflag;			/* debug: list only first n machines */
74 int debug;
75 
76 main(argc, argv)
77 	char **argv;
78 {
79 	statsvar sv;
80 	statstime st;
81 	int single, nfailed;
82 	enum clnt_stat bstat;
83 
84 	/*
85 	 * set number of slots to be 256 to begin with,
86 	 * this is large enough for most subnets but not all
87 	 */
88 
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]) {
99 
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();
119 			}
120 		}
121 		argv++;
122 		argc--;
123 	}
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);
133 		}
134 
135 	}
136 	if (hflag || tflag || lflag) {
137 		printf("collecting responses... ");
138 		fflush(stdout);
139 	}
140 
141 	sv.cp_time.cp_time_val = (int *)NULL;
142 	sv.dk_xfer.dk_xfer_val = (int *)NULL;
143 
144 	/*
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).
152 	 */
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;
157 
158 	vers = RSTATVERS_VAR;
159 	bstat = rpc_broadcast(RSTATPROG, RSTATVERS_VAR, RSTATPROC_STATS,
160 			xdr_void, NULL, xdr_statsvar, (caddr_t)&sv,
161 			(resultproc_t)collectnames, (char *)0);
162 #ifdef TESTING
163 	if (bstat != RPC_SUCCESS)
164 		printf("rpc_broadcast for rstat version %d returned %s\n",
165 			vers, clnt_sperrno(bstat));
166 	fprintf(stderr, "starting second round of broadcasting\n");
167 #endif
168 	vers = RSTATVERS_TIME;
169 	bstat = rpc_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
170 			xdr_void, NULL, xdr_statstime, (caddr_t)&st,
171 			(resultproc_t)collectnames, (char *)0);
172 #ifdef	TESTING
173 	if (bstat != RPC_SUCCESS)
174 		printf("rpc_broadcast for rstat version %d returned %s\n",
175 			vers, clnt_sperrno(bstat));
176 #endif
177 	if (hflag || tflag || lflag)
178 		printnames();
179 
180 
181 
182 	free(entry);
183 	exit(0);
184 	/* NOTREACHED */
185 }
186 
187 int
188 singlehost(host)
189 	char *host;
190 {
191 	static int debugcnt;
192 	enum clnt_stat err;
193 	statstime st;
194 	statsvar sw_var;
195 	bool_t is_var_vers = FALSE;
196 
197 
198 	if (curentry >= total_entries) {
199 		struct entry *tmp;
200 
201 		total_entries += SLOTS;
202 		tmp = realloc((struct entry *)entry, sizeof (struct entry)
203 						* total_entries);
204 		if (tmp == NULL) {
205 			return (1);
206 		}
207 		entry = tmp;
208 	}
209 
210 	sw_var.cp_time.cp_time_val = (int *)NULL;
211 	sw_var.dk_xfer.dk_xfer_val = (int *)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;
223 
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);
249 		}
250 	}
251 	curentry++;
252 	if (dflag && debugcnt >= debug)
253 		return (1);
254 	return (0);
255 
256 error:
257 	fprintf(stderr, "%*.*s: ", MACHINELEN, MACHINELEN, host);
258 	clnt_perrno(err);
259 	/*
260 	 * clnt_perrno now prints a newline
261 	 */
262 	/* fprintf(stderr, "\n"); */
263 	return (1);		/* a failure */
264 }
265 
266 putline(now, boottime, avenrun)
267 	time_t now;
268 	struct timeval boottime;
269 	long avenrun[];
270 {
271 	int uptime, days, hrs, mins, i;
272 
273 	uptime = now - boottime.tv_sec;
274 	uptime += 30;
275 	if (uptime < 0)		/* unsynchronized clocks */
276 		uptime = 0;
277 	days = uptime / (60*60*24);
278 	uptime %= (60*60*24);
279 	hrs = uptime / (60*60);
280 	uptime %= (60*60);
281 	mins = uptime / 60;
282 
283 	printf("  up");
284 	if (days > 0)
285 		printf(" %2d day%s", days, days > 1 ? "s," : ", ");
286 	else
287 		printf("         ");
288 	if (hrs > 0)
289 		printf(" %2d:%02d,  ", hrs, mins);
290 	else
291 		printf(" %2d min%s", mins, mins > 1 ? "s," : ", ");
292 
293 	/*
294 	 * Print 1, 5, and 15 minute load averages.
295 	 * (Found by looking in kernel for avenrun).
296 	 */
297 	printf("  load average:");
298 	for (i = 0; i < (AVENSIZE / sizeof (avenrun[0])); i++) {
299 		if (i > 0)
300 			printf(",");
301 		printf(" %.2f", (double)avenrun[i]/FSCALE);
302 	}
303 	printf("\n");
304 }
305 
306 collectnames(resultsp, taddr, nconf)
307 	char *resultsp;
308 	struct t_bind	*taddr;
309 	struct netconfig	*nconf;
310 {
311 	static int debugcnt;
312 	register struct entry *entryp, *lim;
313 	statstime *st;
314 	statsvar *sv;
315 	struct nd_hostservlist *hs;
316 	extern struct netbuf *netbufdup();
317 	extern struct netconfig *netconfigdup();
318 	extern int netbufeq();
319 
320 	/*
321 	 * need to realloc more space if we have more than 256 machines
322 	 * that responded to the broadcast
323 	 */
324 
325 	if (curentry >= total_entries) {
326 		struct entry *tmp;
327 
328 		total_entries += SLOTS;
329 		tmp = realloc((struct entry *)entry, sizeof (struct entry)
330 						* total_entries);
331 		if (tmp == NULL) {
332 			return (1);
333 		}
334 		entry = tmp;
335 	}
336 	/*
337 	 * weed out duplicates
338 	 */
339 	lim = entry + curentry;
340 	for (entryp = entry; entryp < lim; entryp++)
341 		if (netbufeq(&taddr->addr, entryp->addr))
342 			return (0);
343 
344 	if (vers == RSTATVERS_TIME) {
345 		st = (statstime *)resultsp;
346 	} else if (vers == RSTATVERS_VAR) {
347 		sv = (statsvar *)resultsp;
348 	} else {
349 		return (0);	/* we don't handle this version */
350 	}
351 	debugcnt++;
352 	entry[curentry].nconf = netconfigdup(nconf);
353 	entry[curentry].addr = netbufdup(&taddr->addr);
354 
355 	/*
356 	 * if raw, print this entry out immediately
357 	 * otherwise store for later sorting
358 	 */
359 	if (!hflag && !lflag && !tflag) {
360 		if (netdir_getbyaddr(nconf, &hs, &taddr->addr) == ND_OK)
361 			printf("%*.*s  ", MACHINELEN, MACHINELEN,
362 				hs->h_hostservs->h_host);
363 		else {
364 			char *uaddr = taddr2uaddr(nconf, &taddr->addr);
365 
366 			if (uaddr) {
367 				printf("  %*.*s", MACHINELEN, MACHINELEN,
368 					uaddr);
369 				(void) free(uaddr);
370 			} else
371 				printf("  %*.*s", MACHINELEN, MACHINELEN,
372 					"unknown");
373 		}
374 		if (vers == RSTATVERS_TIME) {
375 			putline(st->curtime.tv_sec, st->boottime, st->avenrun);
376 		} else if (vers == RSTATVERS_VAR) {
377 			putline(sv->curtime.tv_sec, sv->boottime, sv->avenrun);
378 		}
379 	} else {
380 		if (vers == RSTATVERS_TIME) {
381 			entry[curentry].boottime.tv_sec = st->boottime.tv_sec;
382 			entry[curentry].boottime.tv_usec =
383 				st->boottime.tv_usec;
384 			entry[curentry].curtime = st->curtime.tv_sec;
385 			memcpy(entry[curentry].avenrun, st->avenrun, AVENSIZE);
386 		} else if (vers == RSTATVERS_VAR) {
387 			entry[curentry].boottime.tv_sec = sv->boottime.tv_sec;
388 			entry[curentry].boottime.tv_usec =
389 				sv->boottime.tv_usec;
390 			entry[curentry].curtime = sv->curtime.tv_sec;
391 			memcpy(entry[curentry].avenrun, sv->avenrun, AVENSIZE);
392 		}
393 	}
394 	curentry++;
395 	if (dflag && debugcnt >= debug)
396 		return (1);
397 	return (0);
398 }
399 
400 void
401 printsinglehosts()
402 {
403 	register int i;
404 	register struct entry *ep;
405 
406 
407 	if (hflag)
408 		qsort(entry, curentry, sizeof (struct entry), machinecmp);
409 	else if (lflag)
410 		qsort(entry, curentry, sizeof (struct entry), loadcmp);
411 	else
412 		qsort(entry, curentry, sizeof (struct entry), uptimecmp);
413 	for (i = 0; i < curentry; i++) {
414 		ep = &entry[i];
415 		printf("%*.*s  ", MACHINELEN, MACHINELEN, ep->machine);
416 		putline(ep->curtime, ep->boottime, ep->avenrun);
417 
418 	}
419 }
420 
421 void
422 printnames()
423 {
424 	char buf[MACHINELENMAX+1];
425 	struct nd_hostservlist *hs;
426 	register int i;
427 	register struct entry *ep;
428 
429 
430 	for (i = 0; i < curentry; i++) {
431 		ep = &entry[i];
432 		if (netdir_getbyaddr(ep->nconf, &hs, ep->addr) == ND_OK)
433 			sprintf(buf, "%s", hs->h_hostservs->h_host);
434 		else {
435 			char *uaddr = taddr2uaddr(ep->nconf, ep->addr);
436 
437 			if (uaddr) {
438 				sprintf(buf, "%s", uaddr);
439 				(void) free(uaddr);
440 			} else
441 				sprintf(buf, "%s", "unknown");
442 		}
443 		if (ep->machine = (char *)malloc(MACHINELENMAX + 1))
444 			strcpy(ep->machine, buf);
445 	}
446 	printf("\n");
447 	printsinglehosts();
448 }
449 
450 machinecmp(a, b)
451 	struct entry *a, *b;
452 {
453 	return (strcmp(a->machine, b->machine));
454 }
455 
456 uptimecmp(a, b)
457 	struct entry *a, *b;
458 {
459 	if (a->boottime.tv_sec != b->boottime.tv_sec)
460 		return (a->boottime.tv_sec - b->boottime.tv_sec);
461 	else
462 		return (a->boottime.tv_usec - b->boottime.tv_usec);
463 }
464 
465 loadcmp(a, b)
466 	struct entry *a, *b;
467 {
468 	register int i;
469 
470 	for (i = 0; i < AVENSIZE / sizeof (a->avenrun[0]); i++)
471 		if (a->avenrun[i] != b->avenrun[i])
472 			return (a->avenrun[i] - b->avenrun[i]);
473 
474 	return (0);
475 }
476 
477 struct netbuf *
478 netbufdup(ap)
479 	register struct netbuf	*ap;
480 {
481 	register struct netbuf	*np;
482 
483 	np = (struct netbuf *) malloc(sizeof (struct netbuf) + ap->len);
484 	if (np) {
485 		np->maxlen = np->len = ap->len;
486 		np->buf = ((char *)np) + sizeof (struct netbuf);
487 		(void) memcpy(np->buf, ap->buf, ap->len);
488 	}
489 	return (np);
490 }
491 
492 struct netconfig *
493 netconfigdup(onp)
494 	register struct netconfig *onp;
495 {
496 	register int nlookupdirs;
497 	register struct netconfig *nnp;
498 	extern char *strdup();
499 
500 	nnp = (struct netconfig *)malloc(sizeof (struct netconfig));
501 	if (nnp) {
502 		nnp->nc_netid = strdup(onp->nc_netid);
503 		nnp->nc_semantics = onp->nc_semantics;
504 		nnp->nc_flag = onp->nc_flag;
505 		nnp->nc_protofmly = strdup(onp->nc_protofmly);
506 		nnp->nc_proto = strdup(onp->nc_proto);
507 		nnp->nc_device = strdup(onp->nc_device);
508 		nnp->nc_nlookups = onp->nc_nlookups;
509 		if (onp->nc_nlookups == 0)
510 			nnp->nc_lookups = (char **)0;
511 		else {
512 			register int i;
513 
514 			nnp->nc_lookups = (char **)malloc(onp->nc_nlookups *
515 			    sizeof (char *));
516 			if (nnp->nc_lookups)
517 				for (i = 0; i < onp->nc_nlookups; i++)
518 					nnp->nc_lookups[i] =
519 						strdup(onp->nc_lookups[i]);
520 		}
521 	}
522 
523 	return (nnp);
524 }
525 
526 netbufeq(ap, bp)
527 	register struct netbuf *ap, *bp;
528 {
529 	return (ap->len == bp->len && !memcmp(ap->buf, bp->buf, ap->len));
530 }
531 
532 usage()
533 {
534 	fprintf(stderr, "Usage: rup [-h] [-l] [-t] [host ...]\n");
535 	free(entry);
536 	exit(1);
537 }
538