Home | History | Annotate | Download | only in acct
      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 
    420