xref: /onnv-gate/usr/src/cmd/acct/diskusg.c (revision 0:68f95e015346)
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();
main(argc,argv)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 
adduser(fd)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 
ilist(file,fd)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 
ignore(str)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 }
bread(fd,bno,buf,cnt,dev)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 
count(j,dev)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 
output()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
blocks(j,dev)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
hash(j)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 
hashinit()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 
setup(pfile)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 
todo(fname)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	*
skip(str)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 
stpwent(pfile)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
end_pwent()412 end_pwent()
413 {
414 	if(pwf != NULL) {
415 		(void) fclose(pwf);
416 		pwf = NULL;
417 	}
418 }
419 
420