Commit | Line | Data |
---|---|---|
2a18434a | 1 | /* |
9b9b4298 | 2 | * Copyright (c) 1980, 1990 Regents of the University of California. |
f9ac90b4 KB |
3 | * All rights reserved. |
4 | * | |
9b9b4298 KM |
5 | * This code is derived from software contributed to Berkeley by |
6 | * Robert Elz at The University of Melbourne. | |
7 | * | |
70ab3c27 | 8 | * %sccs.include.redist.c% |
2a18434a KM |
9 | */ |
10 | ||
11 | #ifndef lint | |
12 | char copyright[] = | |
9b9b4298 | 13 | "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\ |
2a18434a | 14 | All rights reserved.\n"; |
f9ac90b4 | 15 | #endif /* not lint */ |
2a18434a | 16 | |
690d3151 | 17 | #ifndef lint |
1a587186 | 18 | static char sccsid[] = "@(#)quotacheck.c 5.18 (Berkeley) %G%"; |
f9ac90b4 | 19 | #endif /* not lint */ |
f7830fd7 KM |
20 | |
21 | /* | |
9b9b4298 | 22 | * Fix up / report on disk quotas & usage |
f7830fd7 | 23 | */ |
f7830fd7 | 24 | #include <sys/param.h> |
8ca0011d | 25 | #include <sys/stat.h> |
1a587186 | 26 | |
54e63ce6 KB |
27 | #include <ufs/ufs/dinode.h> |
28 | #include <ufs/ufs/quota.h> | |
29 | #include <ufs/ffs/fs.h> | |
1a587186 | 30 | |
8ca0011d | 31 | #include <fcntl.h> |
690d3151 | 32 | #include <fstab.h> |
04fd056a | 33 | #include <pwd.h> |
9b9b4298 | 34 | #include <grp.h> |
2785316e | 35 | #include <errno.h> |
8ca0011d KB |
36 | #include <unistd.h> |
37 | #include <stdio.h> | |
38 | #include <stdlib.h> | |
39 | #include <string.h> | |
f7830fd7 | 40 | |
78b244e9 KM |
41 | char *qfname = QUOTAFILENAME; |
42 | char *qfextension[] = INITQFNAMES; | |
43 | char *quotagroup = QUOTAGROUP; | |
44 | ||
f7830fd7 KM |
45 | union { |
46 | struct fs sblk; | |
690d3151 | 47 | char dummy[MAXBSIZE]; |
f7830fd7 KM |
48 | } un; |
49 | #define sblock un.sblk | |
9b9b4298 KM |
50 | long dev_bsize = 1; |
51 | long maxino; | |
690d3151 | 52 | |
daed2b2b KM |
53 | struct quotaname { |
54 | long flags; | |
55 | char grpqfname[MAXPATHLEN + 1]; | |
56 | char usrqfname[MAXPATHLEN + 1]; | |
57 | }; | |
58 | #define HASUSR 1 | |
59 | #define HASGRP 2 | |
60 | ||
690d3151 | 61 | struct fileusage { |
9b9b4298 KM |
62 | struct fileusage *fu_next; |
63 | u_long fu_curinodes; | |
64 | u_long fu_curblocks; | |
65 | u_long fu_id; | |
66 | char fu_name[1]; | |
67 | /* actually bigger */ | |
690d3151 | 68 | }; |
9b9b4298 KM |
69 | #define FUHASH 1024 /* must be power of two */ |
70 | struct fileusage *fuhead[MAXQUOTAS][FUHASH]; | |
9b9b4298 | 71 | |
9b9b4298 KM |
72 | int aflag; /* all file systems */ |
73 | int gflag; /* check group quotas */ | |
74 | int uflag; /* check user quotas */ | |
75 | int vflag; /* verbose */ | |
76 | int fi; /* open disk file descriptor */ | |
77 | u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ | |
f7830fd7 | 78 | |
1a587186 KB |
79 | struct fileusage * |
80 | addid __P((u_long, int, char *)); | |
81 | char *blockcheck __P((char *)); | |
82 | void bread __P((daddr_t, char *, long)); | |
83 | int chkquota __P((char *, char *, struct quotaname *)); | |
84 | void err __P((const char *, ...)); | |
85 | void freeinodebuf __P((void)); | |
86 | struct dinode * | |
87 | getnextinode __P((ino_t)); | |
88 | int getquotagid __P((void)); | |
89 | int hasquota __P((struct fstab *, int, char **)); | |
90 | struct fileusage * | |
91 | lookup __P((u_long, int)); | |
92 | void *needchk __P((struct fstab *)); | |
93 | int oneof __P((char *, char*[], int)); | |
94 | void resetinodebuf __P((void)); | |
95 | int update __P((char *, char *, int)); | |
96 | void usage __P((void)); | |
97 | ||
98 | int | |
f7830fd7 | 99 | main(argc, argv) |
690d3151 | 100 | int argc; |
1a587186 | 101 | char *argv[]; |
f7830fd7 | 102 | { |
690d3151 | 103 | register struct fstab *fs; |
04fd056a | 104 | register struct passwd *pw; |
9b9b4298 | 105 | register struct group *gr; |
1a587186 | 106 | struct quotaname *auxdata; |
9b9b4298 | 107 | int i, argnum, maxrun, errs = 0; |
1a587186 KB |
108 | long done = 0; |
109 | char ch, *name; | |
9b9b4298 KM |
110 | |
111 | while ((ch = getopt(argc, argv, "aguvl:")) != EOF) { | |
112 | switch(ch) { | |
113 | case 'a': | |
114 | aflag++; | |
115 | break; | |
116 | case 'g': | |
117 | gflag++; | |
118 | break; | |
119 | case 'u': | |
120 | uflag++; | |
121 | break; | |
122 | case 'v': | |
123 | vflag++; | |
124 | break; | |
125 | case 'l': | |
126 | maxrun = atoi(optarg); | |
127 | break; | |
128 | default: | |
129 | usage(); | |
130 | } | |
f7830fd7 | 131 | } |
9b9b4298 KM |
132 | argc -= optind; |
133 | argv += optind; | |
134 | if ((argc == 0 && !aflag) || (argc > 0 && aflag)) | |
135 | usage(); | |
136 | if (!gflag && !uflag) { | |
137 | gflag++; | |
138 | uflag++; | |
690d3151 | 139 | } |
9b9b4298 KM |
140 | if (gflag) { |
141 | setgrent(); | |
142 | while ((gr = getgrent()) != 0) | |
143 | (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); | |
144 | endgrent(); | |
8aa23ed4 | 145 | } |
9b9b4298 KM |
146 | if (uflag) { |
147 | setpwent(); | |
148 | while ((pw = getpwent()) != 0) | |
149 | (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); | |
150 | endpwent(); | |
f7830fd7 | 151 | } |
9b9b4298 KM |
152 | if (aflag) |
153 | exit(checkfstab(1, maxrun, needchk, chkquota)); | |
1a587186 KB |
154 | if (setfsent() == 0) |
155 | err("%s: can't open", FSTAB); | |
9b9b4298 KM |
156 | while ((fs = getfsent()) != NULL) { |
157 | if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || | |
158 | (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && | |
159 | (auxdata = needchk(fs)) && | |
160 | (name = blockcheck(fs->fs_spec))) { | |
161 | done |= 1 << argnum; | |
162 | errs += chkquota(name, fs->fs_file, auxdata); | |
8aa23ed4 | 163 | } |
f7830fd7 | 164 | } |
9b9b4298 | 165 | endfsent(); |
690d3151 KM |
166 | for (i = 0; i < argc; i++) |
167 | if ((done & (1 << i)) == 0) | |
7077509b S |
168 | fprintf(stderr, "%s not found in %s\n", |
169 | argv[i], FSTAB); | |
690d3151 KM |
170 | exit(errs); |
171 | } | |
f7830fd7 | 172 | |
1a587186 | 173 | void |
9b9b4298 | 174 | usage() |
8aa23ed4 | 175 | { |
1a587186 | 176 | (void)fprintf(stderr, "usage:\t%s\n\t%s\n", |
8ca0011d KB |
177 | "quotacheck -a [-guv]", |
178 | "quotacheck [-guv] filesys ..."); | |
9b9b4298 KM |
179 | exit(1); |
180 | } | |
181 | ||
1a587186 | 182 | void * |
9b9b4298 | 183 | needchk(fs) |
8aa23ed4 | 184 | register struct fstab *fs; |
9b9b4298 | 185 | { |
daed2b2b KM |
186 | register struct quotaname *qnp; |
187 | char *qfnp; | |
8aa23ed4 | 188 | |
daed2b2b KM |
189 | if (strcmp(fs->fs_vfstype, "ufs") || |
190 | strcmp(fs->fs_type, FSTAB_RW)) | |
1a587186 KB |
191 | return (NULL); |
192 | if ((qnp = malloc(sizeof(*qnp))) == NULL) | |
193 | err("%s", strerror(errno)); | |
daed2b2b KM |
194 | qnp->flags = 0; |
195 | if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) { | |
196 | strcpy(qnp->grpqfname, qfnp); | |
197 | qnp->flags |= HASGRP; | |
198 | } | |
199 | if (uflag && hasquota(fs, USRQUOTA, &qfnp)) { | |
200 | strcpy(qnp->usrqfname, qfnp); | |
201 | qnp->flags |= HASUSR; | |
202 | } | |
203 | if (qnp->flags) | |
1a587186 KB |
204 | return (qnp); |
205 | free(qnp); | |
206 | return (NULL); | |
9b9b4298 | 207 | } |
8aa23ed4 | 208 | |
9b9b4298 KM |
209 | /* |
210 | * Scan the specified filesystem to check quota(s) present on it. | |
211 | */ | |
1a587186 | 212 | int |
daed2b2b | 213 | chkquota(fsname, mntpt, qnp) |
9b9b4298 | 214 | char *fsname, *mntpt; |
daed2b2b | 215 | register struct quotaname *qnp; |
9b9b4298 KM |
216 | { |
217 | register struct fileusage *fup; | |
218 | register struct dinode *dp; | |
219 | int cg, i, mode, errs = 0; | |
220 | ino_t ino; | |
8aa23ed4 | 221 | |
1a587186 | 222 | if ((fi = open(fsname, O_RDONLY, 0)) < 0) { |
9b9b4298 KM |
223 | perror(fsname); |
224 | return (1); | |
225 | } | |
226 | if (vflag) { | |
1a587186 | 227 | (void)printf("*** Checking "); |
daed2b2b | 228 | if (qnp->flags & HASUSR) |
1a587186 | 229 | (void)printf("%s%s", qfextension[USRQUOTA], |
daed2b2b KM |
230 | (qnp->flags & HASGRP) ? " and " : ""); |
231 | if (qnp->flags & HASGRP) | |
1a587186 KB |
232 | (void)printf("%s", qfextension[GRPQUOTA]); |
233 | (void)printf(" quotas for %s (%s)\n", fsname, mntpt); | |
9b9b4298 KM |
234 | } |
235 | sync(); | |
236 | bread(SBOFF, (char *)&sblock, (long)SBSIZE); | |
237 | dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); | |
238 | maxino = sblock.fs_ncg * sblock.fs_ipg; | |
239 | resetinodebuf(); | |
240 | for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { | |
241 | for (i = 0; i < sblock.fs_ipg; i++, ino++) { | |
242 | if (ino < ROOTINO) | |
8aa23ed4 | 243 | continue; |
9b9b4298 | 244 | if ((dp = getnextinode(ino)) == NULL) |
8aa23ed4 | 245 | continue; |
9b9b4298 KM |
246 | if ((mode = dp->di_mode & IFMT) == 0) |
247 | continue; | |
daed2b2b | 248 | if (qnp->flags & HASGRP) { |
9b9b4298 KM |
249 | fup = addid((u_long)dp->di_gid, GRPQUOTA, |
250 | (char *)0); | |
251 | fup->fu_curinodes++; | |
252 | if (mode == IFREG || mode == IFDIR || | |
253 | mode == IFLNK) | |
254 | fup->fu_curblocks += dp->di_blocks; | |
255 | } | |
daed2b2b | 256 | if (qnp->flags & HASUSR) { |
9b9b4298 KM |
257 | fup = addid((u_long)dp->di_uid, USRQUOTA, |
258 | (char *)0); | |
259 | fup->fu_curinodes++; | |
260 | if (mode == IFREG || mode == IFDIR || | |
261 | mode == IFLNK) | |
262 | fup->fu_curblocks += dp->di_blocks; | |
8aa23ed4 S |
263 | } |
264 | } | |
9b9b4298 KM |
265 | } |
266 | freeinodebuf(); | |
daed2b2b KM |
267 | if (qnp->flags & HASUSR) |
268 | errs += update(mntpt, qnp->usrqfname, USRQUOTA); | |
269 | if (qnp->flags & HASGRP) | |
270 | errs += update(mntpt, qnp->grpqfname, GRPQUOTA); | |
9b9b4298 | 271 | close(fi); |
8aa23ed4 S |
272 | return (errs); |
273 | } | |
274 | ||
9b9b4298 KM |
275 | /* |
276 | * Update a specified quota file. | |
277 | */ | |
1a587186 | 278 | int |
daed2b2b KM |
279 | update(fsname, quotafile, type) |
280 | char *fsname, *quotafile; | |
9b9b4298 | 281 | register int type; |
690d3151 KM |
282 | { |
283 | register struct fileusage *fup; | |
9cdc0128 | 284 | register FILE *qfi, *qfo; |
9b9b4298 | 285 | register u_long id, lastid; |
690d3151 | 286 | struct dqblk dqbuf; |
9b9b4298 KM |
287 | static int warned = 0; |
288 | static struct dqblk zerodqbuf; | |
289 | static struct fileusage zerofileusage; | |
290 | ||
9b9b4298 | 291 | if ((qfo = fopen(quotafile, "r+")) == NULL) { |
8ca0011d KB |
292 | if (errno == ENOENT) |
293 | qfo = fopen(quotafile, "w+"); | |
294 | if (qfo) { | |
295 | (void) fprintf(stderr, | |
296 | "quotacheck: creating quota file %s\n", quotafile); | |
297 | #define MODE (S_IRUSR|S_IWUSR|S_IRGRP) | |
298 | (void) fchown(fileno(qfo), getuid(), getquotagid()); | |
299 | (void) fchmod(fileno(qfo), MODE); | |
300 | } else { | |
301 | (void) fprintf(stderr, | |
302 | "quotacheck: %s: %s\n", quotafile, strerror(errno)); | |
9b9b4298 KM |
303 | return (1); |
304 | } | |
9cdc0128 | 305 | } |
9b9b4298 | 306 | if ((qfi = fopen(quotafile, "r")) == NULL) { |
8ca0011d KB |
307 | (void) fprintf(stderr, |
308 | "quotacheck: %s: %s\n", quotafile, strerror(errno)); | |
309 | (void) fclose(qfo); | |
690d3151 KM |
310 | return (1); |
311 | } | |
9b9b4298 KM |
312 | if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 && |
313 | errno == EOPNOTSUPP && !warned && vflag) { | |
824e2e71 | 314 | warned++; |
1a587186 | 315 | (void)printf("*** Warning: %s\n", |
9b9b4298 | 316 | "Quotas are not compiled into this kernel"); |
f7830fd7 | 317 | } |
9b9b4298 KM |
318 | for (lastid = highid[type], id = 0; id <= lastid; id++) { |
319 | if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) | |
04fd056a | 320 | dqbuf = zerodqbuf; |
9b9b4298 | 321 | if ((fup = lookup(id, type)) == 0) |
8aa23ed4 | 322 | fup = &zerofileusage; |
9b9b4298 KM |
323 | if (dqbuf.dqb_curinodes == fup->fu_curinodes && |
324 | dqbuf.dqb_curblocks == fup->fu_curblocks) { | |
325 | fup->fu_curinodes = 0; | |
326 | fup->fu_curblocks = 0; | |
9cdc0128 | 327 | fseek(qfo, (long)sizeof(struct dqblk), 1); |
690d3151 | 328 | continue; |
04fd056a | 329 | } |
690d3151 | 330 | if (vflag) { |
9b9b4298 KM |
331 | if (aflag) |
332 | printf("%s: ", fsname); | |
333 | printf("%-8s fixed:", fup->fu_name); | |
334 | if (dqbuf.dqb_curinodes != fup->fu_curinodes) | |
1a587186 | 335 | (void)printf("\tinodes %d -> %d", |
9b9b4298 KM |
336 | dqbuf.dqb_curinodes, fup->fu_curinodes); |
337 | if (dqbuf.dqb_curblocks != fup->fu_curblocks) | |
1a587186 | 338 | (void)printf("\tblocks %d -> %d", |
9b9b4298 | 339 | dqbuf.dqb_curblocks, fup->fu_curblocks); |
1a587186 | 340 | (void)printf("\n"); |
f7830fd7 | 341 | } |
9b9b4298 KM |
342 | /* |
343 | * Reset time limit if have a soft limit and were | |
344 | * previously under it, but are now over it. | |
345 | */ | |
346 | if (dqbuf.dqb_bsoftlimit && | |
347 | dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && | |
348 | fup->fu_curblocks >= dqbuf.dqb_bsoftlimit) | |
349 | dqbuf.dqb_btime = 0; | |
350 | if (dqbuf.dqb_isoftlimit && | |
351 | dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit && | |
352 | fup->fu_curblocks >= dqbuf.dqb_isoftlimit) | |
353 | dqbuf.dqb_itime = 0; | |
354 | dqbuf.dqb_curinodes = fup->fu_curinodes; | |
355 | dqbuf.dqb_curblocks = fup->fu_curblocks; | |
356 | fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo); | |
357 | (void) quotactl(fsname, QCMD(Q_SETUSE, type), id, | |
358 | (caddr_t)&dqbuf); | |
359 | fup->fu_curinodes = 0; | |
360 | fup->fu_curblocks = 0; | |
f7830fd7 | 361 | } |
9cdc0128 | 362 | fclose(qfi); |
9b9b4298 KM |
363 | fflush(qfo); |
364 | ftruncate(fileno(qfo), | |
365 | (off_t)((highid[type] + 1) * sizeof(struct dqblk))); | |
9cdc0128 | 366 | fclose(qfo); |
690d3151 | 367 | return (0); |
f7830fd7 KM |
368 | } |
369 | ||
9b9b4298 KM |
370 | /* |
371 | * Check to see if target appears in list of size cnt. | |
372 | */ | |
1a587186 | 373 | int |
9b9b4298 KM |
374 | oneof(target, list, cnt) |
375 | register char *target, *list[]; | |
376 | int cnt; | |
f7830fd7 | 377 | { |
690d3151 | 378 | register int i; |
f7830fd7 | 379 | |
9b9b4298 KM |
380 | for (i = 0; i < cnt; i++) |
381 | if (strcmp(target, list[i]) == 0) | |
382 | return (i); | |
383 | return (-1); | |
f7830fd7 KM |
384 | } |
385 | ||
daed2b2b KM |
386 | /* |
387 | * Determine the group identifier for quota files. | |
388 | */ | |
1a587186 | 389 | int |
daed2b2b KM |
390 | getquotagid() |
391 | { | |
392 | struct group *gr; | |
393 | ||
394 | if (gr = getgrnam(quotagroup)) | |
395 | return (gr->gr_gid); | |
396 | return (-1); | |
397 | } | |
398 | ||
9b9b4298 KM |
399 | /* |
400 | * Check to see if a particular quota is to be enabled. | |
401 | */ | |
1a587186 | 402 | int |
daed2b2b KM |
403 | hasquota(fs, type, qfnamep) |
404 | register struct fstab *fs; | |
9b9b4298 | 405 | int type; |
daed2b2b | 406 | char **qfnamep; |
f7830fd7 | 407 | { |
9b9b4298 | 408 | register char *opt; |
1a587186 | 409 | char *cp; |
9b9b4298 | 410 | static char initname, usrname[100], grpname[100]; |
daed2b2b | 411 | static char buf[BUFSIZ]; |
9b9b4298 KM |
412 | |
413 | if (!initname) { | |
1a587186 KB |
414 | (void)snprintf(usrname, sizeof(usrname), |
415 | "%s%s", qfextension[USRQUOTA], qfname); | |
416 | (void)snprintf(grpname, sizeof(grpname), | |
417 | "%s%s", qfextension[GRPQUOTA], qfname); | |
9b9b4298 | 418 | initname = 1; |
f7830fd7 | 419 | } |
daed2b2b | 420 | strcpy(buf, fs->fs_mntops); |
9b9b4298 | 421 | for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { |
daed2b2b KM |
422 | if (cp = index(opt, '=')) |
423 | *cp++ = '\0'; | |
9b9b4298 | 424 | if (type == USRQUOTA && strcmp(opt, usrname) == 0) |
daed2b2b | 425 | break; |
9b9b4298 | 426 | if (type == GRPQUOTA && strcmp(opt, grpname) == 0) |
daed2b2b | 427 | break; |
f7830fd7 | 428 | } |
daed2b2b KM |
429 | if (!opt) |
430 | return (0); | |
1a587186 | 431 | if (cp) |
daed2b2b | 432 | *qfnamep = cp; |
1a587186 KB |
433 | else { |
434 | (void)snprintf(buf, sizeof(buf), | |
435 | "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); | |
436 | *qfnamep = buf; | |
daed2b2b | 437 | } |
daed2b2b | 438 | return (1); |
f7830fd7 KM |
439 | } |
440 | ||
9b9b4298 KM |
441 | /* |
442 | * Routines to manage the file usage table. | |
443 | * | |
444 | * Lookup an id of a specific type. | |
445 | */ | |
690d3151 | 446 | struct fileusage * |
9b9b4298 KM |
447 | lookup(id, type) |
448 | u_long id; | |
449 | int type; | |
f7830fd7 | 450 | { |
690d3151 | 451 | register struct fileusage *fup; |
f7830fd7 | 452 | |
9b9b4298 KM |
453 | for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) |
454 | if (fup->fu_id == id) | |
690d3151 | 455 | return (fup); |
1a587186 | 456 | return (NULL); |
f7830fd7 KM |
457 | } |
458 | ||
9b9b4298 KM |
459 | /* |
460 | * Add a new file usage id if it does not already exist. | |
461 | */ | |
690d3151 | 462 | struct fileusage * |
9b9b4298 KM |
463 | addid(id, type, name) |
464 | u_long id; | |
465 | int type; | |
466 | char *name; | |
f7830fd7 | 467 | { |
690d3151 | 468 | struct fileusage *fup, **fhp; |
9b9b4298 | 469 | int len; |
690d3151 | 470 | |
9b9b4298 | 471 | if (fup = lookup(id, type)) |
690d3151 | 472 | return (fup); |
9b9b4298 KM |
473 | if (name) |
474 | len = strlen(name); | |
475 | else | |
476 | len = 10; | |
1a587186 KB |
477 | if ((fup = calloc(1, sizeof(*fup) + len)) == NULL) |
478 | err("%s", strerror(errno)); | |
9b9b4298 | 479 | fhp = &fuhead[type][id & (FUHASH - 1)]; |
690d3151 KM |
480 | fup->fu_next = *fhp; |
481 | *fhp = fup; | |
9b9b4298 KM |
482 | fup->fu_id = id; |
483 | if (id > highid[type]) | |
484 | highid[type] = id; | |
1a587186 | 485 | if (name) |
9b9b4298 | 486 | bcopy(name, fup->fu_name, len + 1); |
1a587186 KB |
487 | else |
488 | (void)sprintf(fup->fu_name, "%u", id); | |
690d3151 | 489 | return (fup); |
f7830fd7 KM |
490 | } |
491 | ||
9b9b4298 KM |
492 | /* |
493 | * Special purpose version of ginode used to optimize pass | |
494 | * over all the inodes in numerical order. | |
495 | */ | |
496 | ino_t nextino, lastinum; | |
497 | long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; | |
498 | struct dinode *inodebuf; | |
499 | #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ | |
500 | ||
501 | struct dinode * | |
502 | getnextinode(inumber) | |
503 | ino_t inumber; | |
f7830fd7 | 504 | { |
9b9b4298 KM |
505 | long size; |
506 | daddr_t dblk; | |
507 | static struct dinode *dp; | |
508 | ||
1a587186 KB |
509 | if (inumber != nextino++ || inumber > maxino) |
510 | err("bad inode number %d to nextinode", inumber); | |
9b9b4298 KM |
511 | if (inumber >= lastinum) { |
512 | readcnt++; | |
513 | dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); | |
514 | if (readcnt % readpercg == 0) { | |
515 | size = partialsize; | |
516 | lastinum += partialcnt; | |
517 | } else { | |
518 | size = inobufsize; | |
519 | lastinum += fullcnt; | |
520 | } | |
521 | bread(dblk, (char *)inodebuf, size); | |
522 | dp = inodebuf; | |
523 | } | |
524 | return (dp++); | |
525 | } | |
526 | ||
527 | /* | |
528 | * Prepare to scan a set of inodes. | |
529 | */ | |
1a587186 | 530 | void |
9b9b4298 KM |
531 | resetinodebuf() |
532 | { | |
533 | ||
534 | nextino = 0; | |
535 | lastinum = 0; | |
536 | readcnt = 0; | |
537 | inobufsize = blkroundup(&sblock, INOBUFSIZE); | |
538 | fullcnt = inobufsize / sizeof(struct dinode); | |
539 | readpercg = sblock.fs_ipg / fullcnt; | |
540 | partialcnt = sblock.fs_ipg % fullcnt; | |
541 | partialsize = partialcnt * sizeof(struct dinode); | |
542 | if (partialcnt != 0) { | |
543 | readpercg++; | |
544 | } else { | |
545 | partialcnt = fullcnt; | |
546 | partialsize = inobufsize; | |
547 | } | |
548 | if (inodebuf == NULL && | |
1a587186 KB |
549 | (inodebuf = malloc((u_int)inobufsize)) == NULL) |
550 | err("%s", strerror(errno)); | |
9b9b4298 KM |
551 | while (nextino < ROOTINO) |
552 | getnextinode(nextino); | |
553 | } | |
554 | ||
555 | /* | |
556 | * Free up data structures used to scan inodes. | |
557 | */ | |
1a587186 | 558 | void |
9b9b4298 KM |
559 | freeinodebuf() |
560 | { | |
561 | ||
562 | if (inodebuf != NULL) | |
1a587186 | 563 | free(inodebuf); |
9b9b4298 KM |
564 | inodebuf = NULL; |
565 | } | |
566 | ||
567 | /* | |
568 | * Read specified disk blocks. | |
569 | */ | |
1a587186 | 570 | void |
9b9b4298 KM |
571 | bread(bno, buf, cnt) |
572 | daddr_t bno; | |
573 | char *buf; | |
574 | long cnt; | |
575 | { | |
576 | ||
1a587186 KB |
577 | if (lseek(fi, (off_t)bno * dev_bsize, 0) < 0 || |
578 | read(fi, buf, cnt) != cnt) | |
579 | err("block %ld", bno); | |
580 | } | |
9b9b4298 | 581 | |
1a587186 KB |
582 | #if __STDC__ |
583 | #include <stdarg.h> | |
584 | #else | |
585 | #include <varargs.h> | |
586 | #endif | |
587 | ||
588 | void | |
589 | #if __STDC__ | |
590 | err(const char *fmt, ...) | |
591 | #else | |
592 | err(fmt, va_alist) | |
593 | char *fmt; | |
594 | va_dcl | |
595 | #endif | |
596 | { | |
597 | va_list ap; | |
598 | #if __STDC__ | |
599 | va_start(ap, fmt); | |
600 | #else | |
601 | va_start(ap); | |
602 | #endif | |
603 | (void)fprintf(stderr, "quotacheck: "); | |
604 | (void)vfprintf(stderr, fmt, ap); | |
605 | va_end(ap); | |
606 | (void)fprintf(stderr, "\n"); | |
607 | exit(1); | |
608 | /* NOTREACHED */ | |
f7830fd7 | 609 | } |