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 2005 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 int
main(int argc,char ** argv)73 main(int argc, char **argv)
74 {
75 struct dirent *dp;
76 int f, i;
77 struct whod *buf;
78 int cc;
79 char *name;
80 struct hs *hs;
81 struct hs *hsp;
82 struct whod *wd;
83 struct whoent *we;
84 int maxloadav = 0;
85 int (*cmp)() = hscmp;
86 ptrdiff_t hoff;
87
88 name = *argv;
89 while (*++argv)
90 while (**argv)
91 switch (*(*argv)++) {
92 case 'a':
93 aflg++;
94 break;
95 case 'l':
96 cmp = lcmp;
97 break;
98 case 'u':
99 cmp = ucmp;
100 break;
101 case 't':
102 cmp = tcmp;
103 break;
104 case 'r':
105 rflg = -rflg;
106 break;
107 case '-':
108 break;
109 default:
110 (void) fprintf(stderr, "Usage: %s [ -alrtu ]"
111 " (choose at most one of l, t, or u)\n",
112 name);
113 exit(1);
114 }
115
116 if ((hs = malloc(hostslim * sizeof (struct hs))) == NULL) {
117 (void) fprintf(stderr, "initial hs malloc failed\n");
118 exit(1);
119 }
120 hsp = hs;
121 if ((buf = malloc(sizeof (struct whod))) == NULL) {
122 (void) fprintf(stderr, "initial buf malloc failed\n");
123 exit(1);
124 }
125
126 if (chdir(RWHODIR) < 0) {
127 perror(RWHODIR);
128 exit(1);
129 }
130 dirp = opendir(".");
131 if (dirp == NULL) {
132 perror(RWHODIR);
133 exit(1);
134 }
135 while (dp = readdir(dirp)) {
136 if (dp->d_ino == 0)
137 continue;
138 if (strncmp(dp->d_name, "whod.", 5))
139 continue;
140 if (nhosts == hostslim) {
141 /*
142 * We trust that the file system's limit on the number
143 * of files in a directory will kick in long before
144 * integer overflow.
145 */
146 hostslim = hostslim << 1;
147
148 /*
149 * hsp points into an area about to be moved,
150 * so we first remember its offset into hs[],
151 * then restore it after realloc() has moved
152 * the data.
153 */
154 hoff = hsp - hs;
155 hs = realloc(hs, hostslim * sizeof (struct hs));
156 if (hs == NULL) {
157 (void) fprintf(stderr, "too many hosts\n");
158 exit(1);
159 }
160 hsp = hs + hoff;
161 }
162 f = open(dp->d_name, 0);
163 if (f > 0) {
164 int whdrsize = sizeof (*buf) - sizeof (buf->wd_we);
165
166 cc = read(f, buf, sizeof (struct whod));
167 if (cc >= whdrsize) {
168 hsp->hs_wd = malloc(whdrsize);
169 wd = buf;
170 bcopy((char *)buf, (char *)hsp->hs_wd,
171 whdrsize);
172 hsp->hs_nusers = 0;
173 for (i = 0; i < 2; i++)
174 if (wd->wd_loadav[i] > maxloadav)
175 maxloadav = wd->wd_loadav[i];
176 /* LINTED: pointer alignment */
177 we = (struct whoent *)(((char *)buf)+cc);
178 while (--we >= wd->wd_we)
179 if (aflg || we->we_idle < 3600)
180 hsp->hs_nusers++;
181 nhosts++; hsp++;
182 }
183 }
184 (void) close(f);
185 }
186 (void) time(&now);
187 qsort((char *)hs, nhosts, sizeof (hs[0]), cmp);
188 if (nhosts == 0) {
189 (void) printf("no hosts!?!\n");
190 exit(1);
191 }
192 for (i = 0; i < nhosts; i++) {
193 hsp = &hs[i];
194 if (down(hsp)) {
195 (void) printf("%-12s%s\n", hsp->hs_wd->wd_hostname,
196 interval((int)(now - hsp->hs_wd->wd_recvtime),
197 "down"));
198 continue;
199 }
200 (void) printf("%-12s%s, %4d user%s load %*.2f,"
201 " %*.2f, %*.2f\n",
202 hsp->hs_wd->wd_hostname,
203 interval(hsp->hs_wd->wd_sendtime -
204 hsp->hs_wd->wd_boottime, " up"),
205 hsp->hs_nusers,
206 hsp->hs_nusers == 1 ? ", " : "s,",
207 maxloadav >= 1000 ? 5 : 4,
208 hsp->hs_wd->wd_loadav[0] / 100.0,
209 maxloadav >= 1000 ? 5 : 4,
210 hsp->hs_wd->wd_loadav[1] / 100.0,
211 maxloadav >= 1000 ? 5 : 4,
212 hsp->hs_wd->wd_loadav[2] / 100.0);
213 free(hsp->hs_wd);
214 }
215
216 return (0);
217 }
218
219 static char *
interval(int time,char * updown)220 interval(int time, char *updown)
221 {
222 static char resbuf[32];
223 int days, hours, minutes;
224
225 if (time < 0 || time > 10*365*24*60*60) {
226 (void) sprintf(resbuf, " %s ??:??", updown);
227 return (resbuf);
228 }
229 minutes = (time + 59) / 60; /* round to minutes */
230 hours = minutes / 60; minutes %= 60;
231 days = hours / 24; hours %= 24;
232 if (days)
233 (void) sprintf(resbuf, "%s %2d+%02d:%02d",
234 updown, days, hours, minutes);
235 else
236 (void) sprintf(resbuf, "%s %2d:%02d",
237 updown, hours, minutes);
238 return (resbuf);
239 }
240
241 static int
hscmp(struct hs * h1,struct hs * h2)242 hscmp(struct hs *h1, struct hs *h2)
243 {
244
245 return (rflg * strcmp(h1->hs_wd->wd_hostname, h2->hs_wd->wd_hostname));
246 }
247
248 /*
249 * Compare according to load average.
250 */
251 static int
lcmp(struct hs * h1,struct hs * h2)252 lcmp(struct hs *h1, struct hs *h2)
253 {
254
255 if (down(h1))
256 if (down(h2))
257 return (tcmp(h1, h2));
258 else
259 return (rflg);
260 else if (down(h2))
261 return (-rflg);
262 else
263 return (rflg *
264 (h2->hs_wd->wd_loadav[0] - h1->hs_wd->wd_loadav[0]));
265 }
266
267 /*
268 * Compare according to number of users.
269 */
270 static int
ucmp(struct hs * h1,struct hs * h2)271 ucmp(struct hs *h1, struct hs *h2)
272 {
273
274 if (down(h1))
275 if (down(h2))
276 return (tcmp(h1, h2));
277 else
278 return (rflg);
279 else if (down(h2))
280 return (-rflg);
281 else
282 return (rflg * (h2->hs_nusers - h1->hs_nusers));
283 }
284
285 /*
286 * Compare according to uptime.
287 */
288 static int
tcmp(struct hs * h1,struct hs * h2)289 tcmp(struct hs *h1, struct hs *h2)
290 {
291
292 return (rflg * (
293 (down(h2) ? h2->hs_wd->wd_recvtime - now :
294 h2->hs_wd->wd_sendtime - h2->hs_wd->wd_boottime)
295 -
296 (down(h1) ? h1->hs_wd->wd_recvtime - now :
297 h1->hs_wd->wd_sendtime - h1->hs_wd->wd_boottime)));
298 }
299