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