improve performance by using two FILE pointers instead of one
[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
bd7bd7e6 14static char sccsid[] = "@(#)quotacheck.c 5.6 (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;
f7830fd7
KM
71
72main(argc, argv)
690d3151 73 int argc;
f7830fd7
KM
74 char **argv;
75{
690d3151 76 register struct fstab *fs;
04fd056a
KM
77 register struct fileusage *fup;
78 register struct passwd *pw;
690d3151
KM
79 int i, errs = 0;
80
81again:
82 argc--, argv++;
83 if (argc > 0 && strcmp(*argv, "-v") == 0) {
84 vflag++;
85 goto again;
f7830fd7 86 }
690d3151
KM
87 if (argc > 0 && strcmp(*argv, "-a") == 0) {
88 aflag++;
89 goto again;
90 }
8aa23ed4
S
91 if (argc > 0 && strcmp(*argv, "-p") == 0) {
92 pflag++;
93 goto again;
94 }
690d3151
KM
95 if (argc <= 0 && !aflag) {
96 fprintf(stderr, "Usage:\n\t%s\n\t%s\n",
8aa23ed4
S
97 "quotacheck [-v] [-p] -a",
98 "quotacheck [-v] [-p] filesys ...");
f7830fd7
KM
99 exit(1);
100 }
37906c43
S
101
102 setpwent();
103 while ((pw = getpwent()) != 0) {
104 fup = lookup(pw->pw_uid);
8aa23ed4 105 if (fup == 0) {
37906c43 106 fup = adduid(pw->pw_uid);
8aa23ed4
S
107 strncpy(fup->fu_name, pw->pw_name,
108 sizeof(fup->fu_name));
109 }
04fd056a 110 }
37906c43
S
111 endpwent();
112
8aa23ed4
S
113 if (pflag)
114 errs = preen(argc, argv);
115 else {
116 if (setfsent() == 0) {
117 fprintf(stderr, "Can't open ");
118 perror(FSTAB);
119 exit(8);
120 }
121 while ((fs = getfsent()) != NULL) {
122 if (aflag &&
123 (fs->fs_type == 0 ||
124 strcmp(fs->fs_type, FSTAB_RQ) != 0))
125 continue;
126 if (!aflag &&
127 !(oneof(fs->fs_file, argv, argc) ||
128 oneof(fs->fs_spec, argv, argc)))
129 continue;
130 (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname);
131 errs += chkquota(fs->fs_spec, fs->fs_file, quotafile);
132 }
133 endfsent();
f7830fd7 134 }
8aa23ed4 135
690d3151
KM
136 for (i = 0; i < argc; i++)
137 if ((done & (1 << i)) == 0)
7077509b
S
138 fprintf(stderr, "%s not found in %s\n",
139 argv[i], FSTAB);
690d3151
KM
140 exit(errs);
141}
f7830fd7 142
8aa23ed4
S
143preen(argc, argv)
144 int argc;
145 char **argv;
146{
147 register struct fstab *fs;
148 register int passno, anygtr;
149 register int errs;
150 union wait status;
151
152 passno = 1;
153 errs = 0;
154 do {
155 anygtr = 0;
156
157 if (setfsent() == 0) {
158 fprintf(stderr, "Can't open ");
159 perror(FSTAB);
160 exit(8);
161 }
162
163 while ((fs = getfsent()) != NULL) {
164 if (fs->fs_passno > passno)
165 anygtr = 1;
166
167 if (aflag &&
168 (fs->fs_type == 0 ||
169 strcmp(fs->fs_type, FSTAB_RQ) != 0))
170 continue;
171
172 if (!aflag &&
173 !(oneof(fs->fs_file, argv, argc) ||
174 oneof(fs->fs_spec, argv, argc)))
175 continue;
176
177 if (fs->fs_passno != passno)
178 continue;
179
180 switch (fork()) {
181 case -1:
182 perror("fork");
183 exit(8);
184 break;
185
186 case 0:
187 sprintf(quotafile, "%s/%s",
188 fs->fs_file, qfname);
189 exit(chkquota(fs->fs_spec,
190 fs->fs_file, quotafile));
191 }
192 }
193
194 while (wait(&status) != -1)
195 errs += status.w_retcode;
196
197 passno++;
198 } while (anygtr);
199
200 return (errs);
201}
202
37906c43 203chkquota(fsdev, fsfile, qffile)
690d3151 204 char *fsdev;
37906c43 205 char *fsfile;
690d3151
KM
206 char *qffile;
207{
208 register struct fileusage *fup;
209 dev_t quotadev;
210 FILE *qf;
211 u_short uid;
212 int cg, i;
213 char *rawdisk;
214 struct stat statb;
215 struct dqblk dqbuf;
824e2e71
KM
216 static int warned = 0;
217 extern int errno;
f7830fd7 218
690d3151
KM
219 rawdisk = makerawname(fsdev);
220 if (vflag)
8aa23ed4 221 fprintf(stdout, "*** Checking quotas for %s (%s)\n", rawdisk, fsfile);
690d3151
KM
222 fi = open(rawdisk, 0);
223 if (fi < 0) {
224 perror(rawdisk);
225 return (1);
f7830fd7 226 }
690d3151
KM
227 qf = fopen(qffile, "r+");
228 if (qf == NULL) {
229 perror(qffile);
37906c43 230 close(fi);
690d3151 231 return (1);
f7830fd7 232 }
690d3151
KM
233 if (fstat(fileno(qf), &statb) < 0) {
234 perror(qffile);
37906c43
S
235 fclose(qf);
236 close(fi);
690d3151
KM
237 return (1);
238 }
239 quotadev = statb.st_dev;
240 if (stat(fsdev, &statb) < 0) {
241 perror(fsdev);
37906c43
S
242 fclose(qf);
243 close(fi);
690d3151
KM
244 return (1);
245 }
246 if (quotadev != statb.st_rdev) {
247 fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n",
248 qffile, quotadev, fsdev, statb.st_rdev);
37906c43
S
249 fclose(qf);
250 close(fi);
690d3151
KM
251 return (1);
252 }
8aa23ed4 253 if (quota(Q_SYNC, 0, quotadev, (caddr_t)0) < 0 &&
824e2e71
KM
254 errno == EINVAL && !warned && vflag) {
255 warned++;
256 fprintf(stdout,
257 "*** Warning: Quotas are not compiled into this kernel\n");
258 }
f7830fd7
KM
259 sync();
260 bread(SBLOCK, (char *)&sblock, SBSIZE);
261 ino = 0;
262 for (cg = 0; cg < sblock.fs_ncg; cg++) {
f7830fd7
KM
263 dp = NULL;
264 for (i = 0; i < sblock.fs_ipg; i++)
265 acct(ginode());
266 }
690d3151 267 for (uid = 0; uid <= highuid; uid++) {
37906c43 268 fseek(qf, (long)uid * sizeof(struct dqblk), 0);
690d3151
KM
269 i = fread(&dqbuf, sizeof(struct dqblk), 1, qf);
270 if (i == 0)
04fd056a 271 dqbuf = zerodqbuf;
c2a9ff1c 272 fup = lookup(uid);
8aa23ed4
S
273 if (fup == 0)
274 fup = &zerofileusage;
690d3151 275 if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes &&
04fd056a
KM
276 dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) {
277 fup->fu_usage.du_curinodes = 0;
278 fup->fu_usage.du_curblocks = 0;
690d3151 279 continue;
04fd056a 280 }
690d3151 281 if (vflag) {
8aa23ed4
S
282 if (pflag)
283 printf("%s: ", rawdisk);
04fd056a 284 if (fup->fu_name[0] != '\0')
8aa23ed4 285 printf("%-8s fixed:", fup->fu_name);
04fd056a 286 else
8aa23ed4
S
287 printf("#%-7d fixed:", uid);
288 if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes)
289 fprintf(stdout, " inodes %d -> %d",
290 dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes);
291 if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks)
292 fprintf(stdout, " blocks %d -> %d",
293 dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks);
294 fprintf(stdout, "\n");
f7830fd7 295 }
690d3151
KM
296 dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes;
297 dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks;
37906c43 298 fseek(qf, (long)uid * sizeof(struct dqblk), 0);
690d3151
KM
299 fwrite(&dqbuf, sizeof(struct dqblk), 1, qf);
300 quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage);
6053d885
KM
301 fup->fu_usage.du_curinodes = 0;
302 fup->fu_usage.du_curblocks = 0;
f7830fd7 303 }
37906c43 304 fflush(qf);
c2a9ff1c 305 ftruncate(fileno(qf), (highuid + 1) * sizeof(struct dqblk));
37906c43
S
306 fclose(qf);
307 close(fi);
690d3151 308 return (0);
f7830fd7
KM
309}
310
311acct(ip)
312 register struct dinode *ip;
313{
690d3151 314 register struct fileusage *fup;
f7830fd7
KM
315
316 if (ip == NULL)
317 return;
318 if (ip->di_mode == 0)
f7830fd7 319 return;
8aa23ed4 320 fup = adduid(ip->di_uid);
690d3151 321 fup->fu_usage.du_curinodes++;
f7830fd7 322 if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK)
f7830fd7 323 return;
690d3151 324 fup->fu_usage.du_curblocks += ip->di_blocks;
f7830fd7
KM
325}
326
690d3151
KM
327oneof(target, list, n)
328 char *target, *list[];
329 register int n;
f7830fd7 330{
690d3151 331 register int i;
f7830fd7 332
690d3151
KM
333 for (i = 0; i < n; i++)
334 if (strcmp(target, list[i]) == 0) {
335 done |= 1 << i;
336 return (1);
337 }
338 return (0);
f7830fd7
KM
339}
340
341struct dinode *
342ginode()
343{
344 register unsigned long iblk;
345
346 if (dp == NULL || ++dp >= &itab[ITABSZ]) {
347 iblk = itod(&sblock, ino);
f7830fd7
KM
348 bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab);
349 dp = &itab[ino % INOPB(&sblock)];
f7830fd7 350 }
f7830fd7
KM
351 if (ino++ < ROOTINO)
352 return(NULL);
353 return(dp);
354}
355
356bread(bno, buf, cnt)
357 long unsigned bno;
358 char *buf;
359{
360
690d3151 361 lseek(fi, (long)dbtob(bno), 0);
f7830fd7 362 if (read(fi, buf, cnt) != cnt) {
8aa23ed4 363 perror("read");
f7830fd7
KM
364 exit(1);
365 }
366}
367
690d3151
KM
368struct fileusage *
369lookup(uid)
370 u_short uid;
f7830fd7 371{
690d3151 372 register struct fileusage *fup;
f7830fd7 373
690d3151
KM
374 for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next)
375 if (fup->fu_uid == uid)
376 return (fup);
377 return ((struct fileusage *)0);
f7830fd7
KM
378}
379
690d3151
KM
380struct fileusage *
381adduid(uid)
382 u_short uid;
f7830fd7 383{
690d3151 384 struct fileusage *fup, **fhp;
37906c43 385 extern char *calloc();
690d3151
KM
386
387 fup = lookup(uid);
388 if (fup != 0)
389 return (fup);
390 fup = (struct fileusage *)calloc(1, sizeof(struct fileusage));
391 if (fup == 0) {
392 fprintf(stderr, "out of memory for fileusage structures\n");
393 exit(1);
394 }
395 fhp = &fuhead[uid % FUHASH];
396 fup->fu_next = *fhp;
397 *fhp = fup;
398 fup->fu_uid = uid;
399 if (uid > highuid)
400 highuid = uid;
401 return (fup);
f7830fd7
KM
402}
403
404char *
690d3151
KM
405makerawname(name)
406 char *name;
f7830fd7 407{
690d3151
KM
408 register char *cp;
409 char tmp, ch, *rindex();
410 static char rawname[MAXPATHLEN];
411
412 strcpy(rawname, name);
37906c43 413 cp = rindex(rawname, '/');
7077509b 414 if (cp == NULL)
690d3151 415 return (name);
37906c43
S
416 else
417 cp++;
690d3151
KM
418 for (ch = 'r'; *cp != '\0'; ) {
419 tmp = *cp;
420 *cp++ = ch;
421 ch = tmp;
422 }
423 *cp++ = ch;
424 *cp = '\0';
425 return (rawname);
f7830fd7 426}