Deleted Added
sdiff udiff text old ( 180187 ) new ( 207736 )
full compact
1/*
2 * Copyright (c) 1980, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Robert Elz at The University of Melbourne.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 28 unchanged lines hidden (view full) ---

37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)quotacheck.c 8.3 (Berkeley) 1/29/94";
42#endif /* not lint */
43#endif
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD: head/sbin/quotacheck/quotacheck.c 207736 2010-05-07 00:41:12Z mckusick $");
46
47/*
48 * Fix up / report on disk quotas & usage
49 */
50#include <sys/param.h>
51#include <sys/disklabel.h>
52#include <sys/mount.h>
53#include <sys/stat.h>
54
55#include <ufs/ufs/dinode.h>
56#include <ufs/ufs/quota.h>
57#include <ufs/ffs/fs.h>
58
59#include <err.h>
60#include <errno.h>
61#include <fcntl.h>
62#include <fstab.h>
63#include <grp.h>
64#include <libutil.h>
65#include <pwd.h>
66#include <stdio.h>
67#include <stdlib.h>
68#include <string.h>
69#include <unistd.h>
70
71#include "quotacheck.h"
72

--- 32 unchanged lines hidden (view full) ---

105 u_long fu_id;
106 char fu_name[1];
107 /* actually bigger */
108};
109#define FUHASH 1024 /* must be power of two */
110struct fileusage *fuhead[MAXQUOTAS][FUHASH];
111
112int aflag; /* all file systems */
113int cflag; /* convert format to 32 or 64 bit size */
114int gflag; /* check group quotas */
115int uflag; /* check user quotas */
116int vflag; /* verbose */
117int fi; /* open disk file descriptor */
118
119struct fileusage *
120 addid(u_long, int, char *, const char *);
121void bread(ufs2_daddr_t, char *, long);
122void freeinodebuf(void);
123union dinode *
124 getnextinode(ino_t);
125int getquotagid(void);
126struct fileusage *
127 lookup(u_long, int);
128int oneof(char *, char*[], int);
129void printchanges(const char *, int, struct dqblk *, struct fileusage *,
130 u_long);
131void setinodebuf(ino_t);
132int update(const char *, struct quotafile *, int);
133void usage(void);
134
135int
136main(int argc, char *argv[])
137{
138 struct fstab *fs;
139 struct passwd *pw;
140 struct group *gr;
141 struct quotafile *qfu, *qfg;
142 int i, argnum, maxrun, errs, ch;
143 long done = 0;
144 char *name;
145
146 errs = maxrun = 0;
147 while ((ch = getopt(argc, argv, "ac:guvl:")) != -1) {
148 switch(ch) {
149 case 'a':
150 aflag++;
151 break;
152 case 'c':
153 if (cflag)
154 usage();
155 cflag = atoi(optarg);
156 break;
157 case 'g':
158 gflag++;
159 break;
160 case 'u':
161 uflag++;
162 break;
163 case 'v':
164 vflag++;

--- 4 unchanged lines hidden (view full) ---

169 default:
170 usage();
171 }
172 }
173 argc -= optind;
174 argv += optind;
175 if ((argc == 0 && !aflag) || (argc > 0 && aflag))
176 usage();
177 if (cflag && cflag != 32 && cflag != 64)
178 usage();
179 if (!gflag && !uflag) {
180 gflag++;
181 uflag++;
182 }
183 if (gflag) {
184 setgrent();
185 while ((gr = getgrent()) != NULL)
186 (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name,

--- 8 unchanged lines hidden (view full) ---

195 endpwent();
196 }
197 /*
198 * The maxrun (-l) option is now deprecated.
199 */
200 if (maxrun > 0)
201 warnx("the -l option is now deprecated");
202 if (aflag)
203 exit(checkfstab(uflag, gflag));
204 if (setfsent() == 0)
205 errx(1, "%s: can't open", FSTAB);
206 while ((fs = getfsent()) != NULL) {
207 if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
208 (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) &&
209 (name = blockcheck(fs->fs_spec))) {
210 done |= 1 << argnum;
211 qfu = NULL;
212 if (uflag)
213 qfu = quota_open(fs, USRQUOTA, O_CREAT|O_RDWR);
214 qfg = NULL;
215 if (gflag)
216 qfg = quota_open(fs, GRPQUOTA, O_CREAT|O_RDWR);
217 if (qfu == NULL && qfg == NULL)
218 continue;
219 errs += chkquota(name, qfu, qfg);
220 if (qfu)
221 quota_close(qfu);
222 if (qfg)
223 quota_close(qfg);
224 }
225 }
226 endfsent();
227 for (i = 0; i < argc; i++)
228 if ((done & (1 << i)) == 0)
229 fprintf(stderr, "%s not found in %s\n",
230 argv[i], FSTAB);
231 exit(errs);
232}
233
234void
235usage(void)
236{
237 (void)fprintf(stderr, "%s\n%s\n",
238 "usage: quotacheck [-guv] [-c 32 | 64] [-l maxrun] -a",
239 " quotacheck [-guv] [-c 32 | 64] filesystem ...");
240 exit(1);
241}
242
243/*
244 * Possible superblock locations ordered from most to least likely.
245 */
246static int sblock_try[] = SBLOCKSEARCH;
247
248/*
249 * Scan the specified file system to check quota(s) present on it.
250 */
251int
252chkquota(char *specname, struct quotafile *qfu, struct quotafile *qfg)
253{
254 struct fileusage *fup;
255 union dinode *dp;
256 int cg, i, mode, errs = 0;
257 ino_t ino, inosused, userino = 0, groupino = 0;
258 dev_t dev, userdev = 0, groupdev = 0;
259 struct stat sb;
260 const char *mntpt;
261 char *cp;
262
263 if (qfu != NULL)
264 mntpt = quota_fsname(qfu);
265 else if (qfg != NULL)
266 mntpt = quota_fsname(qfg);
267 else
268 errx(1, "null quotafile information passed to chkquota()\n");
269 if (cflag) {
270 if (vflag && qfu != NULL)
271 printf("%s: convert user quota to %d bits\n",
272 mntpt, cflag);
273 if (qfu != NULL && quota_convert(qfu, cflag) < 0) {
274 if (errno == EBADF)
275 errx(1,
276 "%s: cannot convert an active quota file",
277 mntpt);
278 err(1, "user quota conversion to size %d failed",
279 cflag);
280 }
281 if (vflag && qfg != NULL)
282 printf("%s: convert group quota to %d bits\n",
283 mntpt, cflag);
284 if (qfg != NULL && quota_convert(qfg, cflag) < 0) {
285 if (errno == EBADF)
286 errx(1,
287 "%s: cannot convert an active quota file",
288 mntpt);
289 err(1, "group quota conversion to size %d failed",
290 cflag);
291 }
292 }
293 if ((fi = open(specname, O_RDONLY, 0)) < 0) {
294 warn("%s", specname);
295 return (1);
296 }
297 if ((stat(mntpt, &sb)) < 0) {
298 warn("%s", mntpt);
299 return (1);
300 }
301 dev = sb.st_dev;
302 if (vflag) {
303 (void)printf("*** Checking ");
304 if (qfu)
305 (void)printf("user%s", qfg ? " and " : "");
306 if (qfg)
307 (void)printf("group");
308 (void)printf(" quotas for %s (%s)\n", specname, mntpt);
309 }
310 if (qfu) {
311 if (stat(quota_qfname(qfu), &sb) == 0) {
312 userino = sb.st_ino;
313 userdev = sb.st_dev;
314 }
315 }
316 if (qfg) {
317 if (stat(quota_qfname(qfg), &sb) == 0) {
318 groupino = sb.st_ino;
319 groupdev = sb.st_dev;
320 }
321 }
322 sync();
323 dev_bsize = 1;
324 for (i = 0; sblock_try[i] != -1; i++) {
325 bread(sblock_try[i], (char *)&sblock, (long)SBLOCKSIZE);

--- 71 unchanged lines hidden (view full) ---

397 */
398#ifdef SF_SNAPSHOT
399 if (DIP(dp, di_flags) & SF_SNAPSHOT)
400 continue;
401#endif
402 if ((ino == userino && dev == userdev) ||
403 (ino == groupino && dev == groupdev))
404 continue;
405 if (qfg) {
406 fup = addid((u_long)DIP(dp, di_gid), GRPQUOTA,
407 (char *)0, mntpt);
408 fup->fu_curinodes++;
409 if (mode == IFREG || mode == IFDIR ||
410 mode == IFLNK)
411 fup->fu_curblocks += DIP(dp, di_blocks);
412 }
413 if (qfu) {
414 fup = addid((u_long)DIP(dp, di_uid), USRQUOTA,
415 (char *)0, mntpt);
416 fup->fu_curinodes++;
417 if (mode == IFREG || mode == IFDIR ||
418 mode == IFLNK)
419 fup->fu_curblocks += DIP(dp, di_blocks);
420 }
421 }
422 }
423 freeinodebuf();
424 if (qfu)
425 errs += update(mntpt, qfu, USRQUOTA);
426 if (qfg)
427 errs += update(mntpt, qfg, GRPQUOTA);
428 close(fi);
429 (void)fflush(stdout);
430 return (errs);
431}
432
433/*
434 * Update a specified quota file.
435 */
436int
437update(const char *fsname, struct quotafile *qf, int type)
438{
439 struct fileusage *fup;
440 u_long id, lastid, highid = 0;
441 struct dqblk dqbuf;
442 struct stat sb;
443 static struct dqblk zerodqbuf;
444 static struct fileusage zerofileusage;
445
446 /*
447 * Scan the on-disk quota file and record any usage changes.
448 */
449 lastid = quota_maxid(qf);
450 for (id = 0; id <= lastid; id++) {
451 if (quota_read(qf, &dqbuf, id) < 0)
452 dqbuf = zerodqbuf;
453 if ((fup = lookup(id, type)) == NULL)
454 fup = &zerofileusage;
455 if (fup->fu_curinodes || fup->fu_curblocks ||
456 dqbuf.dqb_bsoftlimit || dqbuf.dqb_bhardlimit ||
457 dqbuf.dqb_isoftlimit || dqbuf.dqb_ihardlimit)
458 highid = id;
459 if (dqbuf.dqb_curinodes == fup->fu_curinodes &&
460 dqbuf.dqb_curblocks == fup->fu_curblocks) {
461 fup->fu_curinodes = 0;
462 fup->fu_curblocks = 0;
463 continue;
464 }
465 printchanges(fsname, type, &dqbuf, fup, id);
466 dqbuf.dqb_curinodes = fup->fu_curinodes;
467 dqbuf.dqb_curblocks = fup->fu_curblocks;
468 (void) quota_write_usage(qf, &dqbuf, id);
469 fup->fu_curinodes = 0;
470 fup->fu_curblocks = 0;
471 }
472
473 /*
474 * Walk the hash table looking for ids with non-zero usage
475 * that are not currently recorded in the quota file. E.g.
476 * ids that are past the end of the current file.
477 */
478 for (id = 0; id < FUHASH; id++) {
479 for (fup = fuhead[type][id]; fup != NULL; fup = fup->fu_next) {
480 if (fup->fu_id <= lastid)
481 continue;
482 if (fup->fu_curinodes == 0 && fup->fu_curblocks == 0)
483 continue;
484 bzero(&dqbuf, sizeof(struct dqblk));
485 if (fup->fu_id > highid)
486 highid = fup->fu_id;
487 printchanges(fsname, type, &dqbuf, fup, fup->fu_id);
488 dqbuf.dqb_curinodes = fup->fu_curinodes;
489 dqbuf.dqb_curblocks = fup->fu_curblocks;
490 (void) quota_write_usage(qf, &dqbuf, fup->fu_id);
491 fup->fu_curinodes = 0;
492 fup->fu_curblocks = 0;
493 }
494 }
495 /*
496 * If this is old format file, then size may be smaller,
497 * so ensure that we only truncate when it will make things
498 * smaller, and not if it will grow an old format file.
499 */
500 if (highid < lastid &&
501 stat(quota_qfname(qf), &sb) == 0 &&
502 sb.st_size > (((off_t)highid + 2) * sizeof(struct dqblk)))
503 truncate(quota_qfname(qf),
504 (((off_t)highid + 2) * sizeof(struct dqblk)));
505 return (0);
506}
507
508/*
509 * Check to see if target appears in list of size cnt.
510 */
511int
512oneof(char *target, char *list[], int cnt)

--- 15 unchanged lines hidden (view full) ---

528 struct group *gr;
529
530 if ((gr = getgrnam(quotagroup)) != NULL)
531 return (gr->gr_gid);
532 return (-1);
533}
534
535/*
536 * Routines to manage the file usage table.
537 *
538 * Lookup an id of a specific type.
539 */
540struct fileusage *
541lookup(u_long id, int type)
542{
543 struct fileusage *fup;
544
545 for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
546 if (fup->fu_id == id)
547 return (fup);
548 return (NULL);
549}
550
551/*
552 * Add a new file usage id if it does not already exist.
553 */
554struct fileusage *
555addid(u_long id, int type, char *name, const char *fsname)
556{
557 struct fileusage *fup, **fhp;
558 int len;
559
560 if ((fup = lookup(id, type)) != NULL)
561 return (fup);
562 if (name)
563 len = strlen(name);

--- 118 unchanged lines hidden (view full) ---

682 read(fi, buf, cnt) != cnt)
683 errx(1, "bread failed on block %ld", (long)bno);
684}
685
686/*
687 * Display updated block and i-node counts.
688 */
689void
690printchanges(const char *fsname, int type, struct dqblk *dp,
691 struct fileusage *fup, u_long id)
692{
693 if (!vflag)
694 return;
695 if (aflag)
696 (void)printf("%s: ", fsname);
697 if (fup->fu_name[0] == '\0')
698 (void)printf("%-8lu fixed ", id);

--- 25 unchanged lines hidden ---