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