1 /* 2 * Copyright (c) 1983, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1983, 1993, 1994\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)ruptime.c 8.2 (Berkeley) 04/05/94"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 20 #include <protocols/rwhod.h> 21 22 #include <dirent.h> 23 #include <err.h> 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <time.h> 30 #include <tzfile.h> 31 #include <unistd.h> 32 33 struct hs { 34 struct whod *hs_wd; 35 int hs_nusers; 36 } *hs; 37 struct whod awhod; 38 39 #define ISDOWN(h) (now - (h)->hs_wd->wd_recvtime > 11 * 60) 40 #define WHDRSIZE (sizeof (awhod) - sizeof (awhod.wd_we)) 41 42 size_t nhosts; 43 time_t now; 44 int rflg = 1; 45 46 int hscmp __P((const void *, const void *)); 47 char *interval __P((time_t, char *)); 48 int lcmp __P((const void *, const void *)); 49 void morehosts __P((void)); 50 int tcmp __P((const void *, const void *)); 51 int ucmp __P((const void *, const void *)); 52 void usage __P((void)); 53 54 int 55 main(argc, argv) 56 int argc; 57 char **argv; 58 { 59 extern int optind; 60 struct dirent *dp; 61 struct hs *hsp; 62 struct whod *wd; 63 struct whoent *we; 64 DIR *dirp; 65 size_t hspace; 66 int aflg, cc, ch, fd, i, maxloadav; 67 char buf[sizeof(struct whod)]; 68 int (*cmp) __P((const void *, const void *)); 69 70 aflg = 0; 71 cmp = hscmp; 72 while ((ch = getopt(argc, argv, "alrut")) != EOF) 73 switch (ch) { 74 case 'a': 75 aflg = 1; 76 break; 77 case 'l': 78 cmp = lcmp; 79 break; 80 case 'r': 81 rflg = -1; 82 break; 83 case 't': 84 cmp = tcmp; 85 break; 86 case 'u': 87 cmp = ucmp; 88 break; 89 default: 90 usage(); 91 } 92 argc -= optind; 93 argv += optind; 94 95 if (argc != 0) 96 usage(); 97 98 if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL) 99 err(1, "%s", _PATH_RWHODIR); 100 101 maxloadav = -1; 102 for (nhosts = hspace = 0; (dp = readdir(dirp)) != NULL;) { 103 if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5)) 104 continue; 105 if ((fd = open(dp->d_name, O_RDONLY, 0)) < 0) { 106 warn("%s", dp->d_name); 107 continue; 108 } 109 cc = read(fd, buf, sizeof(struct whod)); 110 (void)close(fd); 111 112 if (cc < WHDRSIZE) 113 continue; 114 if (nhosts == hspace) { 115 if ((hs = 116 realloc(hs, (hspace += 40) * sizeof(*hs))) == NULL) 117 err(1, NULL); 118 hsp = hs + nhosts; 119 } 120 121 if ((hsp->hs_wd = malloc((size_t)WHDRSIZE)) == NULL) 122 err(1, NULL); 123 memmove(hsp->hs_wd, buf, (size_t)WHDRSIZE); 124 125 for (wd = (struct whod *)buf, i = 0; i < 2; ++i) 126 if (wd->wd_loadav[i] > maxloadav) 127 maxloadav = wd->wd_loadav[i]; 128 129 for (hsp->hs_nusers = 0, 130 we = (struct whoent *)(buf + cc); --we >= wd->wd_we;) 131 if (aflg || we->we_idle < 3600) 132 ++hsp->hs_nusers; 133 ++hsp; 134 ++nhosts; 135 } 136 if (nhosts == 0) 137 errx(0, "no hosts in %s.", _PATH_RWHODIR); 138 139 (void)time(&now); 140 qsort(hs, nhosts, sizeof(hs[0]), cmp); 141 for (i = 0; i < nhosts; i++) { 142 hsp = &hs[i]; 143 if (ISDOWN(hsp)) { 144 (void)printf("%-12.12s%s\n", hsp->hs_wd->wd_hostname, 145 interval(now - hsp->hs_wd->wd_recvtime, "down")); 146 continue; 147 } 148 (void)printf( 149 "%-12.12s%s, %4d user%s load %*.2f, %*.2f, %*.2f\n", 150 hsp->hs_wd->wd_hostname, 151 interval((time_t)hsp->hs_wd->wd_sendtime - 152 (time_t)hsp->hs_wd->wd_boottime, " up"), 153 hsp->hs_nusers, 154 hsp->hs_nusers == 1 ? ", " : "s,", 155 maxloadav >= 1000 ? 5 : 4, 156 hsp->hs_wd->wd_loadav[0] / 100.0, 157 maxloadav >= 1000 ? 5 : 4, 158 hsp->hs_wd->wd_loadav[1] / 100.0, 159 maxloadav >= 1000 ? 5 : 4, 160 hsp->hs_wd->wd_loadav[2] / 100.0); 161 } 162 exit(0); 163 } 164 165 char * 166 interval(tval, updown) 167 time_t tval; 168 char *updown; 169 { 170 static char resbuf[32]; 171 int days, hours, minutes; 172 173 if (tval < 0 || tval > DAYSPERNYEAR * SECSPERDAY) { 174 (void)snprintf(resbuf, sizeof(resbuf), " %s ??:??", updown); 175 return (resbuf); 176 } 177 /* round to minutes. */ 178 minutes = (tval + (SECSPERMIN - 1)) / SECSPERMIN; 179 hours = minutes / MINSPERHOUR; 180 minutes %= MINSPERHOUR; 181 days = hours / HOURSPERDAY; 182 hours %= HOURSPERDAY; 183 if (days) 184 (void)snprintf(resbuf, sizeof(resbuf), 185 "%s %2d+%02d:%02d", updown, days, hours, minutes); 186 else 187 (void)snprintf(resbuf, sizeof(resbuf), 188 "%s %2d:%02d", updown, hours, minutes); 189 return (resbuf); 190 } 191 192 #define HS(a) ((struct hs *)(a)) 193 194 /* Alphabetical comparison. */ 195 int 196 hscmp(a1, a2) 197 const void *a1, *a2; 198 { 199 return (rflg * 200 strcmp(HS(a1)->hs_wd->wd_hostname, HS(a2)->hs_wd->wd_hostname)); 201 } 202 203 /* Load average comparison. */ 204 int 205 lcmp(a1, a2) 206 const void *a1, *a2; 207 { 208 if (ISDOWN(HS(a1))) 209 if (ISDOWN(HS(a2))) 210 return (tcmp(a1, a2)); 211 else 212 return (rflg); 213 else if (ISDOWN(HS(a2))) 214 return (-rflg); 215 else 216 return (rflg * 217 (HS(a2)->hs_wd->wd_loadav[0] - HS(a1)->hs_wd->wd_loadav[0])); 218 } 219 220 /* Number of users comparison. */ 221 int 222 ucmp(a1, a2) 223 const void *a1, *a2; 224 { 225 if (ISDOWN(HS(a1))) 226 if (ISDOWN(HS(a2))) 227 return (tcmp(a1, a2)); 228 else 229 return (rflg); 230 else if (ISDOWN(HS(a2))) 231 return (-rflg); 232 else 233 return (rflg * (HS(a2)->hs_nusers - HS(a1)->hs_nusers)); 234 } 235 236 /* Uptime comparison. */ 237 int 238 tcmp(a1, a2) 239 const void *a1, *a2; 240 { 241 return (rflg * ( 242 (ISDOWN(HS(a2)) ? HS(a2)->hs_wd->wd_recvtime - now 243 : HS(a2)->hs_wd->wd_sendtime - HS(a2)->hs_wd->wd_boottime) 244 - 245 (ISDOWN(HS(a1)) ? HS(a1)->hs_wd->wd_recvtime - now 246 : HS(a1)->hs_wd->wd_sendtime - HS(a1)->hs_wd->wd_boottime) 247 )); 248 } 249 250 void 251 usage() 252 { 253 (void)fprintf(stderr, "usage: ruptime [-alrut]\n"); 254 exit(1); 255 } 256