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 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 * 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 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 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 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 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 }