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