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