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 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  23 /*        All Rights Reserved   */
  24 /*      Copyright (c) 1999 by Sun Microsystems, Inc. */
  25 /*      All rights reserved. */
  26 
  27 
  28 #ident  "%Z%%M% %I%     %E% SMI"        /* SVr4.0 1.18  */
  29 #include <stdio.h>
  30 #include <sys/types.h>
  31 #include <sys/param.h>
  32 #include <sys/fs/s5ino.h>
  33 #include <sys/stat.h>
  34 #include <sys/fs/s5param.h>
  35 #include <sys/fs/s5filsys.h>
  36 #include <sys/fs/s5macros.h>
  37 #include <sys/sysmacros.h>
  38 #include <pwd.h>
  39 #include <fcntl.h>
  40 #include "acctdef.h"
  41 
  42 #ifndef Fs2BLK
  43 #define Fs2BLK  0
  44 #endif
  45 
  46 
  47 #define BLOCK           512     /* Block size for reporting */
  48 
  49 #define         NINODE          2048
  50 
  51 struct  filsys  sblock;
  52 struct  dinode  dinode[NINODE];
  53 
  54 int     VERBOSE = 0;
  55 FILE    *ufd = 0;
  56 int     index;
  57 unsigned ino, nfiles;
  58 
  59 struct acct  {
  60         uid_t   uid;
  61         long    usage;
  62         char    name [NSZ+1];
  63 } userlist[MAXUSERS];
  64 
  65 char    *ignlist[MAXIGN];
  66 int     igncnt = {0};
  67 
  68 char    *cmd;
  69 
  70 unsigned hash();
  71 main(argc, argv)
  72 int argc;
  73 char **argv;
  74 {
  75         extern  int     optind;
  76         extern  char    *optarg;
  77         register c;
  78         register FILE   *fd;
  79         register        rfd;
  80         struct  stat    sb;
  81         int     sflg = {FALSE};
  82         char    *pfile = NULL;
  83         int     errfl = {FALSE};
  84 
  85         cmd = argv[0];
  86         while((c = getopt(argc, argv, "vu:p:si:")) != EOF) switch(c) {
  87         case 's':
  88                 sflg = TRUE;
  89                 break;
  90         case 'v':
  91                 VERBOSE = 1;
  92                 break;
  93         case 'i':
  94                 ignore(optarg);
  95                 break;
  96         case 'u':
  97                 ufd = fopen(optarg, "a");
  98                 break;
  99         case 'p':
 100                 pfile = optarg;
 101                 break;
 102         case '?':
 103                 errfl++;
 104                 break;
 105         }
 106         if(errfl) {
 107                 fprintf(stderr, "Usage: %s [-sv] [-p pw_file] [-u file] [-i ignlist] [file ...]\n", cmd);
 108                 exit(10);
 109         }
 110 
 111         hashinit();
 112         if(sflg == TRUE) {
 113                 if(optind == argc){
 114                         adduser(stdin);
 115                 } else {
 116                         for( ; optind < argc; optind++) {
 117                                 if( (fd = fopen(argv[optind], "r")) == NULL) {
 118                                         fprintf(stderr, "%s: Cannot open %s\n", cmd, argv[optind]);
 119                                         continue;
 120                                 }
 121                                 adduser(fd);
 122                                 fclose(fd);
 123                         }
 124                 }
 125         }
 126         else {
 127                 setup(pfile);
 128                 for( ; optind < argc; optind++) {
 129                         if( (rfd = open(argv[optind], O_RDONLY)) < 0) {
 130                                 fprintf(stderr, "%s: Cannot open %s\n", cmd, argv[optind]);
 131                                 continue;
 132                         }
 133                         if(fstat(rfd, &sb) >= 0){
 134                                 if ( (sb.st_mode & S_IFMT) == S_IFCHR ||
 135                                      (sb.st_mode & S_IFMT) == S_IFBLK ) {
 136                                         ilist(argv[optind], rfd);
 137                                 } else {
 138                                         fprintf(stderr, "%s: %s is not a special file -- ignored\n", cmd, argv[optind]);
 139                                 }
 140                         } else {
 141                                 fprintf(stderr, "%s: Cannot stat %s\n", cmd, argv[optind]);
 142                         }
 143                         close(rfd);
 144                 }
 145         }
 146         output();
 147         exit(0);
 148 }
 149 
 150 adduser(fd)
 151 register FILE   *fd;
 152 {
 153         uid_t   usrid;
 154         long    blcks;
 155         char    login[NSZ+10];
 156 
 157         while(fscanf(fd, "%ld %s %ld\n", &usrid, login, &blcks) == 3) {
 158                 if( (index = hash(usrid)) == FAIL) return(FAIL);
 159                 if(userlist[index].uid == UNUSED) {
 160                         userlist[index].uid = usrid;
 161                         (void) strncpy(userlist[index].name, login, NSZ);
 162                 }
 163                 userlist[index].usage += blcks;
 164         }
 165 }
 166 
 167 ilist(file, fd)
 168 char    *file;
 169 register fd;
 170 {
 171         register dev_t  dev;
 172         register i, j;
 173         int     inopb, inoshift, fsinos, bsize;
 174 
 175         if (fd < 0 ) {
 176                 return (FAIL);
 177         }
 178 
 179         sync();
 180 
 181         /* Fake out block size to be 512 */
 182         dev = 512;
 183 
 184         /* Read in super-block of filesystem */
 185         bread(fd, 1, &sblock, sizeof(sblock), dev);
 186 
 187         /* Check for filesystem names to ignore */
 188         if(!todo(sblock.s_fname))
 189                 return;
 190         /* Check for size of filesystem to be 512 or 1K */
 191         if (sblock.s_magic == FsMAGIC )
 192                 switch (sblock.s_type) {
 193                         case Fs1b:
 194                                 bsize = 512;
 195                                 inoshift = 3;
 196                                 fsinos = (((2)&~07)+1);
 197                                 break;
 198                         case Fs2b:
 199                                 bsize = 1024;
 200                                 inoshift = 4;
 201                                 fsinos = (((2)&~017)+1);
 202                                 break;
 203                         case Fs4b:
 204                                 bsize = 2048;
 205                                 inoshift = 5;
 206                                 fsinos = (((2)&~037)+1);
 207                                 break;
 208                 }
 209 
 210         inopb = bsize/sizeof(struct dinode);
 211 
 212 
 213         nfiles = (sblock.s_isize-2) * inopb;
 214         dev = (dev_t)bsize;
 215 
 216         /* Determine physical block 2 */
 217         i = (daddr_t)(((unsigned)(fsinos)+(2*inopb-1)) >> inoshift);
 218 
 219         /* Start at physical block 2, inode list */
 220         for (ino = 0; ino < nfiles; i += NINODE/inopb) {
 221                 bread(fd, i, dinode, sizeof(dinode), dev);
 222                 for (j = 0; j < NINODE && ino++ < nfiles; j++)
 223                         if (dinode[j].di_mode & S_IFMT)
 224                                 if(count(j, dev) == FAIL) {
 225                                         if(VERBOSE)
 226                                                 fprintf(stderr,"BAD UID: file system = %s, inode = %u, uid = %ld\n",
 227                                                 file, ino, dinode[j].di_uid);
 228                                         if(ufd)
 229                                                 fprintf(ufd, "%s %u %ld\n", file, ino, dinode[j].di_uid);
 230                                 }
 231         }
 232         return (0);
 233 }
 234 
 235 ignore(str)
 236 register char   *str;
 237 {
 238         char    *skip();
 239 
 240         for( ; *str && igncnt < MAXIGN; str = skip(str), igncnt++)
 241                 ignlist[igncnt] = str;
 242         if(igncnt == MAXIGN) {
 243                 fprintf(stderr, "%s: ignore list overflow. Recompile with larger MAXIGN\n", cmd);
 244         }
 245 }
 246 bread(fd, bno, buf, cnt, dev)
 247 register fd;
 248 register unsigned bno;
 249 register struct  dinode  *buf;
 250 register dev_t dev;
 251 {
 252         lseek(fd, (long)bno*dev, 0);
 253         if (read(fd, buf, cnt) != cnt)
 254         {
 255                 fprintf(stderr, "%s: read error %u\n", cmd, bno);
 256                 exit(1);
 257         }
 258 }
 259 
 260 count(j, dev)
 261 register j;
 262 register dev_t dev;
 263 {
 264         long    blocks();
 265 
 266         if ( dinode[j].di_nlink == 0 || dinode[j].di_mode == 0 )
 267                 return(SUCCEED);
 268         if( (index = hash(dinode[j].di_uid)) == FAIL || userlist[index].uid == UNUSED )
 269                 return (FAIL);
 270         userlist[index].usage += blocks(j, dev);
 271         return (SUCCEED);
 272 }
 273 
 274 
 275 output()
 276 {
 277         for (index=0; index < MAXUSERS ; index++)
 278                 if ( userlist[index].uid != UNUSED && userlist[index].usage != 0 )
 279                         printf("%ld     %s      %ld\n",
 280                             userlist[index].uid,
 281                             userlist[index].name,
 282                             userlist[index].usage);
 283 }
 284 
 285 #define SNGLIND(dev)    (dev/sizeof(daddr_t))
 286 #define DBLIND(dev)     ((dev/sizeof(daddr_t))*(dev/sizeof(daddr_t)))
 287 #define TRPLIND(dev)    ((dev/sizeof(daddr_t))*(dev/sizeof(daddr_t))*(dev/sizeof(daddr_t)))
 288 
 289 long
 290 blocks(j, dev)
 291 register int j;
 292 register dev_t dev;
 293 {
 294         register long blks;
 295 
 296         blks = (dinode[j].di_size + dev - 1)/dev;
 297         if(blks > 10) {
 298                 blks += (blks-10+SNGLIND(dev)-1)/SNGLIND(dev);
 299                 blks += (blks-10-SNGLIND(dev)+DBLIND(dev)-1)/DBLIND(dev);
 300                 blks += (blks-10-SNGLIND(dev)-DBLIND(dev)+TRPLIND(dev)-1)/TRPLIND(dev);
 301         }
 302         if(dev != BLOCK) {
 303                 blks = (blks+BLOCK/dev)*(dev/BLOCK);
 304         }
 305         return(blks);
 306 }
 307 
 308 unsigned
 309 hash(j)
 310 uid_t j;
 311 {
 312         register unsigned start;
 313         register unsigned circle;
 314         circle = start = (unsigned)j % MAXUSERS;
 315         do
 316         {
 317                 if ( userlist[circle].uid == j || userlist[circle].uid == UNUSED )
 318                         return (circle);
 319                 circle = (circle + 1) % MAXUSERS;
 320         } while ( circle != start);
 321         return (FAIL);
 322 }
 323 
 324 hashinit() {
 325         for(index=0; index < MAXUSERS ; index++)
 326         {
 327                 userlist[index].uid = UNUSED;
 328                 userlist[index].usage = 0;
 329                 userlist[index].name[0] = '\0';
 330         }
 331 }
 332 
 333 
 334 static FILE *pwf = NULL;
 335 
 336 setup(pfile)
 337 char    *pfile;
 338 {
 339         register struct passwd  *pw;
 340         void end_pwent();
 341         struct passwd * (*getpw)();
 342         void    (*endpw)();
 343 
 344         if (pfile) {
 345                 if( !stpwent(pfile)) {
 346                         fprintf(stderr, "%s: Cannot open %s\n", cmd, pfile);
 347                         exit(5);
 348                 }
 349                 getpw = fgetpwent;
 350                 endpw = end_pwent;
 351         } else {
 352                 setpwent();
 353                 getpw = getpwent;
 354                 endpw = endpwent;
 355         }
 356         while ( (pw=getpw(pwf)) != NULL )
 357         {
 358                 if ( (index=hash(pw->pw_uid)) == FAIL )
 359                 {
 360                         fprintf(stderr,"%s: INCREASE SIZE OF MAXUSERS\n", cmd);
 361                         return (FAIL);
 362                 }
 363                 if ( userlist[index].uid == UNUSED )
 364                 {
 365                         userlist[index].uid = pw->pw_uid;
 366                         (void) strncpy(userlist[index].name, pw->pw_name, NSZ);
 367                 }
 368         }
 369 
 370         endpw();
 371 }
 372 
 373 todo(fname)
 374 register char   *fname;
 375 {
 376         register        i;
 377 
 378         for(i = 0; i < igncnt; i++) {
 379                 if(strncmp(fname, ignlist[i], 6) == 0) return(FALSE);
 380         }
 381         return(TRUE);
 382 }
 383 
 384 char    *
 385 skip(str)
 386 register char   *str;
 387 {
 388         while(*str) {
 389                 if(*str == ' ' ||
 390                     *str == ',') {
 391                         *str = '\0';
 392                         str++;
 393                         break;
 394                 }
 395                 str++;
 396         }
 397         return(str);
 398 }
 399 
 400 
 401 stpwent(pfile)
 402 register char *pfile;
 403 {
 404         if(pwf == NULL)
 405                 pwf = fopen(pfile, "r");
 406         else
 407                 rewind(pwf);
 408         return(pwf != NULL);
 409 }
 410 
 411 void
 412 end_pwent()
 413 {
 414         if(pwf != NULL) {
 415                 (void) fclose(pwf);
 416                 pwf = NULL;
 417         }
 418 }
 419