convert SBLOCK to SBOFF; generalize use of dev_bsize
[unix-history] / usr / src / sbin / quotacheck / quotacheck.c
CommitLineData
2a18434a
KM
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
690d3151 13#ifndef lint
a66ab591 14static char sccsid[] = "@(#)quotacheck.c 5.7 (Berkeley) %G%";
2a18434a 15#endif not lint
f7830fd7
KM
16
17/*
18 * Fix up / report on disc quotas & usage
19 */
20#include <stdio.h>
21#include <ctype.h>
22#include <signal.h>
824e2e71 23#include <errno.h>
f7830fd7
KM
24#include <sys/param.h>
25#include <sys/inode.h>
26#include <sys/fs.h>
f7830fd7
KM
27#include <sys/quota.h>
28#include <sys/stat.h>
8aa23ed4 29#include <sys/wait.h>
690d3151 30#include <fstab.h>
04fd056a 31#include <pwd.h>
f7830fd7 32
f7830fd7
KM
33union {
34 struct fs sblk;
690d3151 35 char dummy[MAXBSIZE];
f7830fd7
KM
36} un;
37#define sblock un.sblk
690d3151
KM
38
39#define ITABSZ 256
f7830fd7
KM
40struct dinode itab[ITABSZ];
41struct dinode *dp;
f7830fd7 42
04fd056a 43#define LOGINNAMESIZE 8
690d3151 44struct fileusage {
04fd056a 45 struct fileusage *fu_next;
690d3151
KM
46 struct dqusage fu_usage;
47 u_short fu_uid;
04fd056a 48 char fu_name[LOGINNAMESIZE + 1];
690d3151
KM
49};
50#define FUHASH 997
51struct fileusage *fuhead[FUHASH];
52struct fileusage *lookup();
53struct fileusage *adduid();
54int highuid;
55
56int fi;
57ino_t ino;
58long done;
f7830fd7
KM
59struct passwd *getpwent();
60struct dinode *ginode();
690d3151
KM
61char *malloc(), *makerawname();
62
63int vflag; /* verbose */
64int aflag; /* all file systems */
8aa23ed4 65int pflag; /* fsck like parallel check */
690d3151
KM
66
67char *qfname = "quotas";
68char quotafile[MAXPATHLEN + 1];
04fd056a 69struct dqblk zerodqbuf;
8aa23ed4 70struct fileusage zerofileusage;
a66ab591 71long dev_bsize = 1;
f7830fd7
KM
72
73main(argc, argv)
690d3151 74 int argc;
f7830fd7
KM
75 char **argv;
76{
690d3151 77 register struct fstab *fs;
04fd056a
KM
78 register struct fileusage *fup;
79 register struct passwd *pw;
690d3151
KM
80 int i, errs = 0;
81
82again:
83 argc--, argv++;
84 if (argc > 0 && strcmp(*argv, "-v") == 0) {
85 vflag++;
86 goto again;
f7830fd7 87 }
690d3151
KM
88 if (argc > 0 && strcmp(*argv, "-a") == 0) {
89 aflag++;
90 goto again;
91 }
8aa23ed4
S
92 if (argc > 0 && strcmp(*argv, "-p") == 0) {
93 pflag++;
94 goto again;
95 }
690d3151
KM
96 if (argc <= 0 && !aflag) {
97 fprintf(stderr, "Usage:\n\t%s\n\t%s\n",
8aa23ed4
S
98 "quotacheck [-v] [-p] -a",
99 "quotacheck [-v] [-p] filesys ...");
f7830fd7
KM
100 exit(1);
101 }
37906c43
S
102
103 setpwent();
104 while ((pw = getpwent()) != 0) {
105 fup = lookup(pw->pw_uid);
8aa23ed4 106 if (fup == 0) {
37906c43 107 fup = adduid(pw->pw_uid);
8aa23ed4
S
108 strncpy(fup->fu_name, pw->pw_name,
109 sizeof(fup->fu_name));
110 }
04fd056a 111 }
37906c43
S
112 endpwent();
113
8aa23ed4
S
114 if (pflag)
115 errs = preen(argc, argv);
116 else {
117 if (setfsent() == 0) {
118 fprintf(stderr, "Can't open ");
119 perror(FSTAB);
120 exit(8);
121 }
122 while ((fs = getfsent()) != NULL) {
123 if (aflag &&
124 (fs->fs_type == 0 ||
125 strcmp(fs->fs_type, FSTAB_RQ) != 0))
126 continue;
127 if (!aflag &&
128 !(oneof(fs->fs_file, argv, argc) ||
129 oneof(fs->fs_spec, argv, argc)))
130 continue;
131 (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname);
132 errs += chkquota(fs->fs_spec, fs->fs_file, quotafile);
133 }
134 endfsent();
f7830fd7 135 }
8aa23ed4 136
690d3151
KM
137 for (i = 0; i < argc; i++)
138 if ((done & (1 << i)) == 0)
7077509b
S
139 fprintf(stderr, "%s not found in %s\n",
140 argv[i], FSTAB);
690d3151
KM
141 exit(errs);
142}
f7830fd7 143
8aa23ed4
S
144preen(argc, argv)
145 int argc;
146 char **argv;
147{
148 register struct fstab *fs;
149 register int passno, anygtr;
150 register int errs;
151 union wait status;
152
153 passno = 1;
154 errs = 0;
155 do {
156 anygtr = 0;
157
158 if (setfsent() == 0) {
159 fprintf(stderr, "Can't open ");
160 perror(FSTAB);
161 exit(8);
162 }
163
164 while ((fs = getfsent()) != NULL) {
165 if (fs->fs_passno > passno)
166 anygtr = 1;
167
168 if (aflag &&
169 (fs->fs_type == 0 ||
170 strcmp(fs->fs_type, FSTAB_RQ) != 0))
171 continue;
172
173 if (!aflag &&
174 !(oneof(fs->fs_file, argv, argc) ||
175 oneof(fs->fs_spec, argv, argc)))
176 continue;
177
178 if (fs->fs_passno != passno)
179 continue;
180
181 switch (fork()) {
182 case -1:
183 perror("fork");
184 exit(8);
185 break;
186
187 case 0:
188 sprintf(quotafile, "%s/%s",
189 fs->fs_file, qfname);
190 exit(chkquota(fs->fs_spec,
191 fs->fs_file, quotafile));
192 }
193 }
194
195 while (wait(&status) != -1)
196 errs += status.w_retcode;
197
198 passno++;
199 } while (anygtr);
200
201 return (errs);
202}
203
37906c43 204chkquota(fsdev, fsfile, qffile)
690d3151 205 char *fsdev;
37906c43 206 char *fsfile;
690d3151
KM
207 char *qffile;
208{
209 register struct fileusage *fup;
210 dev_t quotadev;
9cdc0128 211 register FILE *qfi, *qfo;
690d3151 212 u_short uid;
9cdc0128 213 int cg, i, fdo;
690d3151
KM
214 char *rawdisk;
215 struct stat statb;
216 struct dqblk dqbuf;
824e2e71
KM
217 static int warned = 0;
218 extern int errno;
f7830fd7 219
690d3151
KM
220 rawdisk = makerawname(fsdev);
221 if (vflag)
8aa23ed4 222 fprintf(stdout, "*** Checking quotas for %s (%s)\n", rawdisk, fsfile);
690d3151
KM
223 fi = open(rawdisk, 0);
224 if (fi < 0) {
225 perror(rawdisk);
226 return (1);
f7830fd7 227 }
9cdc0128
S
228 qfi = fopen(qffile, "r");
229 if (qfi == NULL) {
690d3151 230 perror(qffile);
37906c43 231 close(fi);
690d3151 232 return (1);
f7830fd7 233 }
9cdc0128 234 if (fstat(fileno(qfi), &statb) < 0) {
690d3151 235 perror(qffile);
9cdc0128 236 fclose(qfi);
37906c43 237 close(fi);
690d3151
KM
238 return (1);
239 }
240 quotadev = statb.st_dev;
241 if (stat(fsdev, &statb) < 0) {
242 perror(fsdev);
9cdc0128 243 fclose(qfi);
37906c43 244 close(fi);
690d3151
KM
245 return (1);
246 }
247 if (quotadev != statb.st_rdev) {
248 fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n",
249 qffile, quotadev, fsdev, statb.st_rdev);
9cdc0128
S
250 fclose(qfi);
251 close(fi);
252 return (1);
253 }
254 /*
255 * Must do fdopen(open(qffile, 1), "w") instead of fopen(qffile, "w")
256 * because fopen(qffile, "w") would truncate the quota file.
257 */
258 fdo = open(qffile, 1);
259 if (fdo < 0 || (qfo = fdopen(fdo, "w")) == NULL) {
260 perror(qffile);
261 if (fdo >= 0)
262 close(fdo);
263 fclose(qfi);
37906c43 264 close(fi);
690d3151
KM
265 return (1);
266 }
8aa23ed4 267 if (quota(Q_SYNC, 0, quotadev, (caddr_t)0) < 0 &&
824e2e71
KM
268 errno == EINVAL && !warned && vflag) {
269 warned++;
270 fprintf(stdout,
271 "*** Warning: Quotas are not compiled into this kernel\n");
272 }
f7830fd7 273 sync();
a66ab591
KM
274 bread(SBOFF, (char *)&sblock, SBSIZE);
275 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
f7830fd7
KM
276 ino = 0;
277 for (cg = 0; cg < sblock.fs_ncg; cg++) {
f7830fd7
KM
278 dp = NULL;
279 for (i = 0; i < sblock.fs_ipg; i++)
280 acct(ginode());
281 }
690d3151 282 for (uid = 0; uid <= highuid; uid++) {
9cdc0128 283 i = fread(&dqbuf, sizeof(struct dqblk), 1, qfi);
690d3151 284 if (i == 0)
04fd056a 285 dqbuf = zerodqbuf;
c2a9ff1c 286 fup = lookup(uid);
8aa23ed4
S
287 if (fup == 0)
288 fup = &zerofileusage;
690d3151 289 if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes &&
04fd056a
KM
290 dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) {
291 fup->fu_usage.du_curinodes = 0;
292 fup->fu_usage.du_curblocks = 0;
9cdc0128 293 fseek(qfo, (long)sizeof(struct dqblk), 1);
690d3151 294 continue;
04fd056a 295 }
690d3151 296 if (vflag) {
8aa23ed4
S
297 if (pflag)
298 printf("%s: ", rawdisk);
04fd056a 299 if (fup->fu_name[0] != '\0')
8aa23ed4 300 printf("%-8s fixed:", fup->fu_name);
04fd056a 301 else
8aa23ed4
S
302 printf("#%-7d fixed:", uid);
303 if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes)
9cdc0128 304 fprintf(stdout, "\tinodes %d -> %d",
8aa23ed4
S
305 dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes);
306 if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks)
9cdc0128 307 fprintf(stdout, "\tblocks %d -> %d",
8aa23ed4
S
308 dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks);
309 fprintf(stdout, "\n");
f7830fd7 310 }
690d3151
KM
311 dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes;
312 dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks;
9cdc0128 313 fwrite(&dqbuf, sizeof(struct dqblk), 1, qfo);
690d3151 314 quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage);
6053d885
KM
315 fup->fu_usage.du_curinodes = 0;
316 fup->fu_usage.du_curblocks = 0;
f7830fd7 317 }
9cdc0128
S
318 fflush(qfo);
319 ftruncate(fileno(qfo), (off_t)((highuid + 1) * sizeof(struct dqblk)));
320 fclose(qfi);
321 fclose(qfo);
37906c43 322 close(fi);
690d3151 323 return (0);
f7830fd7
KM
324}
325
326acct(ip)
327 register struct dinode *ip;
328{
690d3151 329 register struct fileusage *fup;
f7830fd7
KM
330
331 if (ip == NULL)
332 return;
333 if (ip->di_mode == 0)
f7830fd7 334 return;
8aa23ed4 335 fup = adduid(ip->di_uid);
690d3151 336 fup->fu_usage.du_curinodes++;
f7830fd7 337 if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK)
f7830fd7 338 return;
690d3151 339 fup->fu_usage.du_curblocks += ip->di_blocks;
f7830fd7
KM
340}
341
690d3151
KM
342oneof(target, list, n)
343 char *target, *list[];
344 register int n;
f7830fd7 345{
690d3151 346 register int i;
f7830fd7 347
690d3151
KM
348 for (i = 0; i < n; i++)
349 if (strcmp(target, list[i]) == 0) {
350 done |= 1 << i;
351 return (1);
352 }
353 return (0);
f7830fd7
KM
354}
355
356struct dinode *
357ginode()
358{
359 register unsigned long iblk;
360
361 if (dp == NULL || ++dp >= &itab[ITABSZ]) {
362 iblk = itod(&sblock, ino);
f7830fd7
KM
363 bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab);
364 dp = &itab[ino % INOPB(&sblock)];
f7830fd7 365 }
f7830fd7
KM
366 if (ino++ < ROOTINO)
367 return(NULL);
368 return(dp);
369}
370
371bread(bno, buf, cnt)
372 long unsigned bno;
373 char *buf;
374{
9cdc0128 375
a66ab591 376 if (lseek(fi, bno * dev_bsize, 0) < 0) {
9cdc0128
S
377 perror("lseek");
378 exit(1);
379 }
f7830fd7 380
f7830fd7 381 if (read(fi, buf, cnt) != cnt) {
8aa23ed4 382 perror("read");
f7830fd7
KM
383 exit(1);
384 }
385}
386
690d3151
KM
387struct fileusage *
388lookup(uid)
389 u_short uid;
f7830fd7 390{
690d3151 391 register struct fileusage *fup;
f7830fd7 392
690d3151
KM
393 for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next)
394 if (fup->fu_uid == uid)
395 return (fup);
396 return ((struct fileusage *)0);
f7830fd7
KM
397}
398
690d3151
KM
399struct fileusage *
400adduid(uid)
401 u_short uid;
f7830fd7 402{
690d3151 403 struct fileusage *fup, **fhp;
37906c43 404 extern char *calloc();
690d3151
KM
405
406 fup = lookup(uid);
407 if (fup != 0)
408 return (fup);
409 fup = (struct fileusage *)calloc(1, sizeof(struct fileusage));
410 if (fup == 0) {
411 fprintf(stderr, "out of memory for fileusage structures\n");
412 exit(1);
413 }
414 fhp = &fuhead[uid % FUHASH];
415 fup->fu_next = *fhp;
416 *fhp = fup;
417 fup->fu_uid = uid;
418 if (uid > highuid)
419 highuid = uid;
420 return (fup);
f7830fd7
KM
421}
422
423char *
690d3151
KM
424makerawname(name)
425 char *name;
f7830fd7 426{
690d3151
KM
427 register char *cp;
428 char tmp, ch, *rindex();
429 static char rawname[MAXPATHLEN];
430
431 strcpy(rawname, name);
37906c43 432 cp = rindex(rawname, '/');
7077509b 433 if (cp == NULL)
690d3151 434 return (name);
37906c43
S
435 else
436 cp++;
690d3151
KM
437 for (ch = 'r'; *cp != '\0'; ) {
438 tmp = *cp;
439 *cp++ = ch;
440 ch = tmp;
441 }
442 *cp++ = ch;
443 *cp = '\0';
444 return (rawname);
f7830fd7 445}