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