keep npartitions independent of byte order
[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;
9cdc0128 210 register FILE *qfi, *qfo;
690d3151 211 u_short uid;
9cdc0128 212 int cg, i, fdo;
690d3151
KM
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 }
9cdc0128
S
227 qfi = fopen(qffile, "r");
228 if (qfi == NULL) {
690d3151 229 perror(qffile);
37906c43 230 close(fi);
690d3151 231 return (1);
f7830fd7 232 }
9cdc0128 233 if (fstat(fileno(qfi), &statb) < 0) {
690d3151 234 perror(qffile);
9cdc0128 235 fclose(qfi);
37906c43 236 close(fi);
690d3151
KM
237 return (1);
238 }
239 quotadev = statb.st_dev;
240 if (stat(fsdev, &statb) < 0) {
241 perror(fsdev);
9cdc0128 242 fclose(qfi);
37906c43 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);
9cdc0128
S
249 fclose(qfi);
250 close(fi);
251 return (1);
252 }
253 /*
254 * Must do fdopen(open(qffile, 1), "w") instead of fopen(qffile, "w")
255 * because fopen(qffile, "w") would truncate the quota file.
256 */
257 fdo = open(qffile, 1);
258 if (fdo < 0 || (qfo = fdopen(fdo, "w")) == NULL) {
259 perror(qffile);
260 if (fdo >= 0)
261 close(fdo);
262 fclose(qfi);
37906c43 263 close(fi);
690d3151
KM
264 return (1);
265 }
8aa23ed4 266 if (quota(Q_SYNC, 0, quotadev, (caddr_t)0) < 0 &&
824e2e71
KM
267 errno == EINVAL && !warned && vflag) {
268 warned++;
269 fprintf(stdout,
270 "*** Warning: Quotas are not compiled into this kernel\n");
271 }
f7830fd7
KM
272 sync();
273 bread(SBLOCK, (char *)&sblock, SBSIZE);
274 ino = 0;
275 for (cg = 0; cg < sblock.fs_ncg; cg++) {
f7830fd7
KM
276 dp = NULL;
277 for (i = 0; i < sblock.fs_ipg; i++)
278 acct(ginode());
279 }
690d3151 280 for (uid = 0; uid <= highuid; uid++) {
9cdc0128 281 i = fread(&dqbuf, sizeof(struct dqblk), 1, qfi);
690d3151 282 if (i == 0)
04fd056a 283 dqbuf = zerodqbuf;
c2a9ff1c 284 fup = lookup(uid);
8aa23ed4
S
285 if (fup == 0)
286 fup = &zerofileusage;
690d3151 287 if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes &&
04fd056a
KM
288 dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) {
289 fup->fu_usage.du_curinodes = 0;
290 fup->fu_usage.du_curblocks = 0;
9cdc0128 291 fseek(qfo, (long)sizeof(struct dqblk), 1);
690d3151 292 continue;
04fd056a 293 }
690d3151 294 if (vflag) {
8aa23ed4
S
295 if (pflag)
296 printf("%s: ", rawdisk);
04fd056a 297 if (fup->fu_name[0] != '\0')
8aa23ed4 298 printf("%-8s fixed:", fup->fu_name);
04fd056a 299 else
8aa23ed4
S
300 printf("#%-7d fixed:", uid);
301 if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes)
9cdc0128 302 fprintf(stdout, "\tinodes %d -> %d",
8aa23ed4
S
303 dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes);
304 if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks)
9cdc0128 305 fprintf(stdout, "\tblocks %d -> %d",
8aa23ed4
S
306 dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks);
307 fprintf(stdout, "\n");
f7830fd7 308 }
690d3151
KM
309 dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes;
310 dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks;
9cdc0128 311 fwrite(&dqbuf, sizeof(struct dqblk), 1, qfo);
690d3151 312 quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage);
6053d885
KM
313 fup->fu_usage.du_curinodes = 0;
314 fup->fu_usage.du_curblocks = 0;
f7830fd7 315 }
9cdc0128
S
316 fflush(qfo);
317 ftruncate(fileno(qfo), (off_t)((highuid + 1) * sizeof(struct dqblk)));
318 fclose(qfi);
319 fclose(qfo);
37906c43 320 close(fi);
690d3151 321 return (0);
f7830fd7
KM
322}
323
324acct(ip)
325 register struct dinode *ip;
326{
690d3151 327 register struct fileusage *fup;
f7830fd7
KM
328
329 if (ip == NULL)
330 return;
331 if (ip->di_mode == 0)
f7830fd7 332 return;
8aa23ed4 333 fup = adduid(ip->di_uid);
690d3151 334 fup->fu_usage.du_curinodes++;
f7830fd7 335 if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK)
f7830fd7 336 return;
690d3151 337 fup->fu_usage.du_curblocks += ip->di_blocks;
f7830fd7
KM
338}
339
690d3151
KM
340oneof(target, list, n)
341 char *target, *list[];
342 register int n;
f7830fd7 343{
690d3151 344 register int i;
f7830fd7 345
690d3151
KM
346 for (i = 0; i < n; i++)
347 if (strcmp(target, list[i]) == 0) {
348 done |= 1 << i;
349 return (1);
350 }
351 return (0);
f7830fd7
KM
352}
353
354struct dinode *
355ginode()
356{
357 register unsigned long iblk;
358
359 if (dp == NULL || ++dp >= &itab[ITABSZ]) {
360 iblk = itod(&sblock, ino);
f7830fd7
KM
361 bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab);
362 dp = &itab[ino % INOPB(&sblock)];
f7830fd7 363 }
f7830fd7
KM
364 if (ino++ < ROOTINO)
365 return(NULL);
366 return(dp);
367}
368
369bread(bno, buf, cnt)
370 long unsigned bno;
371 char *buf;
372{
9cdc0128
S
373 extern off_t lseek();
374 register off_t pos;
375
376 pos = (off_t)dbtob(bno);
377 if (lseek(fi, pos, 0) != pos) {
378 perror("lseek");
379 exit(1);
380 }
f7830fd7 381
f7830fd7 382 if (read(fi, buf, cnt) != cnt) {
8aa23ed4 383 perror("read");
f7830fd7
KM
384 exit(1);
385 }
386}
387
690d3151
KM
388struct fileusage *
389lookup(uid)
390 u_short uid;
f7830fd7 391{
690d3151 392 register struct fileusage *fup;
f7830fd7 393
690d3151
KM
394 for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next)
395 if (fup->fu_uid == uid)
396 return (fup);
397 return ((struct fileusage *)0);
f7830fd7
KM
398}
399
690d3151
KM
400struct fileusage *
401adduid(uid)
402 u_short uid;
f7830fd7 403{
690d3151 404 struct fileusage *fup, **fhp;
37906c43 405 extern char *calloc();
690d3151
KM
406
407 fup = lookup(uid);
408 if (fup != 0)
409 return (fup);
410 fup = (struct fileusage *)calloc(1, sizeof(struct fileusage));
411 if (fup == 0) {
412 fprintf(stderr, "out of memory for fileusage structures\n");
413 exit(1);
414 }
415 fhp = &fuhead[uid % FUHASH];
416 fup->fu_next = *fhp;
417 *fhp = fup;
418 fup->fu_uid = uid;
419 if (uid > highuid)
420 highuid = uid;
421 return (fup);
f7830fd7
KM
422}
423
424char *
690d3151
KM
425makerawname(name)
426 char *name;
f7830fd7 427{
690d3151
KM
428 register char *cp;
429 char tmp, ch, *rindex();
430 static char rawname[MAXPATHLEN];
431
432 strcpy(rawname, name);
37906c43 433 cp = rindex(rawname, '/');
7077509b 434 if (cp == NULL)
690d3151 435 return (name);
37906c43
S
436 else
437 cp++;
690d3151
KM
438 for (ch = 'r'; *cp != '\0'; ) {
439 tmp = *cp;
440 *cp++ = ch;
441 ch = tmp;
442 }
443 *cp++ = ch;
444 *cp = '\0';
445 return (rawname);
f7830fd7 446}