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 }