xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.bin/ruptime.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 /*
23  * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include <sys/param.h>
43 #include <stdio.h>
44 #include <dirent.h>
45 #include <stdlib.h>
46 #include <strings.h>
47 #include <unistd.h>
48 #include <fcntl.h>
49 #include <protocols/rwhod.h>
50 
51 static DIR	*dirp;
52 
53 #define	HOSTLIM	100
54 static int	hostslim = HOSTLIM;
55 static int	nhosts;
56 struct	hs {
57 	struct	whod *hs_wd;
58 	int	hs_nusers;
59 };
60 static int	hscmp(), ucmp(), lcmp(), tcmp();
61 
62 #define	RWHODIR		"/var/spool/rwho"
63 
64 static char	*interval();
65 static time_t	now;
66 static int	aflg;
67 static int	rflg = 1;
68 
69 #define	down(h)		(now - (h)->hs_wd->wd_recvtime > 11 * 60)
70 
71 /* ARGSUSED */
72 main(int argc, char **argv)
73 {
74 	struct dirent *dp;
75 	int f, i;
76 	struct whod *buf;
77 	int cc;
78 	char *name;
79 	struct hs *hs;
80 	struct hs *hsp;
81 	struct whod *wd;
82 	struct whoent *we;
83 	int maxloadav = 0;
84 	int (*cmp)() = hscmp;
85 	ptrdiff_t hoff;
86 
87 	name = *argv;
88 	while (*++argv)
89 		while (**argv)
90 			switch (*(*argv)++) {
91 			case 'a':
92 				aflg++;
93 				break;
94 			case 'l':
95 				cmp = lcmp;
96 				break;
97 			case 'u':
98 				cmp = ucmp;
99 				break;
100 			case 't':
101 				cmp = tcmp;
102 				break;
103 			case 'r':
104 				rflg = -rflg;
105 				break;
106 			case '-':
107 				break;
108 			default:
109 				(void) fprintf(stderr, "Usage: %s [ -alrtu ]"
110 				    " (choose at most one of l, t, or u)\n",
111 				    name);
112 				exit(1);
113 			}
114 
115 	if ((hs = malloc(hostslim * sizeof (struct hs))) == NULL) {
116 		(void) fprintf(stderr, "initial hs malloc failed\n");
117 		exit(1);
118 	}
119 	hsp = hs;
120 	if ((buf = malloc(sizeof (struct whod))) == NULL) {
121 		(void) fprintf(stderr, "initial buf malloc failed\n");
122 		exit(1);
123 	}
124 
125 	if (chdir(RWHODIR) < 0) {
126 		perror(RWHODIR);
127 		exit(1);
128 	}
129 	dirp = opendir(".");
130 	if (dirp == NULL) {
131 		perror(RWHODIR);
132 		exit(1);
133 	}
134 	while (dp = readdir(dirp)) {
135 		if (dp->d_ino == 0)
136 			continue;
137 		if (strncmp(dp->d_name, "whod.", 5))
138 			continue;
139 		if (nhosts == hostslim) {
140 			/*
141 			 * We trust that the file system's limit on the number
142 			 * of files in a directory will kick in long before
143 			 * integer overflow.
144 			 */
145 			hostslim = hostslim << 1;
146 
147 			/*
148 			 * hsp points into an area about to be moved,
149 			 * so we first remember its offset into hs[],
150 			 * then restore it after realloc() has moved
151 			 * the data.
152 			 */
153 			hoff = hsp - hs;
154 			hs = realloc(hs, hostslim * sizeof (struct hs));
155 			if (hs == NULL) {
156 				(void) fprintf(stderr, "too many hosts\n");
157 				exit(1);
158 			}
159 			hsp = hs + hoff;
160 		}
161 		f = open(dp->d_name, 0);
162 		if (f > 0) {
163 			int whdrsize = sizeof (*buf) - sizeof (buf->wd_we);
164 
165 			cc = read(f, buf, sizeof (struct whod));
166 			if (cc >= whdrsize) {
167 				hsp->hs_wd = malloc(whdrsize);
168 				wd = buf;
169 				bcopy((char *)buf, (char *)hsp->hs_wd,
170 				    whdrsize);
171 				hsp->hs_nusers = 0;
172 				for (i = 0; i < 2; i++)
173 					if (wd->wd_loadav[i] > maxloadav)
174 						maxloadav = wd->wd_loadav[i];
175 				/* LINTED:  pointer alignment */
176 				we = (struct whoent *)(((char *)buf)+cc);
177 				while (--we >= wd->wd_we)
178 					if (aflg || we->we_idle < 3600)
179 						hsp->hs_nusers++;
180 				nhosts++; hsp++;
181 			}
182 		}
183 		(void) close(f);
184 	}
185 	(void) time(&now);
186 	qsort((char *)hs, nhosts, sizeof (hs[0]), cmp);
187 	if (nhosts == 0) {
188 		(void) printf("no hosts!?!\n");
189 		exit(1);
190 	}
191 	for (i = 0; i < nhosts; i++) {
192 		hsp = &hs[i];
193 		if (down(hsp)) {
194 			(void) printf("%-12s%s\n", hsp->hs_wd->wd_hostname,
195 			    interval((int)(now - hsp->hs_wd->wd_recvtime),
196 				"down"));
197 			continue;
198 		}
199 		(void) printf("%-12s%s,  %4d user%s  load %*.2f,"
200 		    " %*.2f, %*.2f\n",
201 		    hsp->hs_wd->wd_hostname,
202 		    interval(hsp->hs_wd->wd_sendtime -
203 			hsp->hs_wd->wd_boottime, "  up"),
204 		    hsp->hs_nusers,
205 		    hsp->hs_nusers == 1 ? ", " : "s,",
206 		    maxloadav >= 1000 ? 5 : 4,
207 			hsp->hs_wd->wd_loadav[0] / 100.0,
208 		    maxloadav >= 1000 ? 5 : 4,
209 			hsp->hs_wd->wd_loadav[1] / 100.0,
210 		    maxloadav >= 1000 ? 5 : 4,
211 			hsp->hs_wd->wd_loadav[2] / 100.0);
212 		free(hsp->hs_wd);
213 	}
214 
215 	return (0);
216 }
217 
218 static char *
219 interval(int time, char *updown)
220 {
221 	static char resbuf[32];
222 	int days, hours, minutes;
223 
224 	if (time < 0 || time > 10*365*24*60*60) {
225 		(void) sprintf(resbuf, "   %s ??:??", updown);
226 		return (resbuf);
227 	}
228 	minutes = (time + 59) / 60;		/* round to minutes */
229 	hours = minutes / 60; minutes %= 60;
230 	days = hours / 24; hours %= 24;
231 	if (days)
232 		(void) sprintf(resbuf, "%s %2d+%02d:%02d",
233 		    updown, days, hours, minutes);
234 	else
235 		(void) sprintf(resbuf, "%s    %2d:%02d",
236 		    updown, hours, minutes);
237 	return (resbuf);
238 }
239 
240 static int
241 hscmp(struct hs *h1, struct hs *h2)
242 {
243 
244 	return (rflg * strcmp(h1->hs_wd->wd_hostname, h2->hs_wd->wd_hostname));
245 }
246 
247 /*
248  * Compare according to load average.
249  */
250 static int
251 lcmp(struct hs *h1, struct hs *h2)
252 {
253 
254 	if (down(h1))
255 		if (down(h2))
256 			return (tcmp(h1, h2));
257 		else
258 			return (rflg);
259 	else if (down(h2))
260 		return (-rflg);
261 	else
262 		return (rflg *
263 			(h2->hs_wd->wd_loadav[0] - h1->hs_wd->wd_loadav[0]));
264 }
265 
266 /*
267  * Compare according to number of users.
268  */
269 static int
270 ucmp(struct hs *h1, struct hs *h2)
271 {
272 
273 	if (down(h1))
274 		if (down(h2))
275 			return (tcmp(h1, h2));
276 		else
277 			return (rflg);
278 	else if (down(h2))
279 		return (-rflg);
280 	else
281 		return (rflg * (h2->hs_nusers - h1->hs_nusers));
282 }
283 
284 /*
285  * Compare according to uptime.
286  */
287 static int
288 tcmp(struct hs *h1, struct hs *h2)
289 {
290 
291 	return (rflg * (
292 		(down(h2) ? h2->hs_wd->wd_recvtime - now :
293 		    h2->hs_wd->wd_sendtime - h2->hs_wd->wd_boottime)
294 		-
295 		(down(h1) ? h1->hs_wd->wd_recvtime - now :
296 		    h1->hs_wd->wd_sendtime - h1->hs_wd->wd_boottime)));
297 }
298