]>
git.cameronkatri.com Git - apple_cmds.git/blob - diskdev_cmds/quotacheck.tproj/quotacheck.c
2 * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright (c) 1980, 1990, 1993
25 * The Regents of the University of California. All rights reserved.
27 * This code is derived from software contributed to Berkeley by
28 * Robert Elz at The University of Melbourne.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * Fix up / report on disk quotas & usage
63 #include <sys/param.h>
65 #include <sys/queue.h>
67 #include <sys/mount.h>
68 #endif /* __APPLE__ */
70 #include <sys/quota.h>
84 #include <libkern/OSByteOrder.h>
85 #endif /* __APPLE__ */
87 #include "quotacheck.h"
89 char *qfname
= QUOTAFILENAME
;
90 char *qfextension
[] = INITQFNAMES
;
91 char *quotagroup
= QUOTAGROUP
;
94 u_int32_t quotamagic
[MAXQUOTAS
] = INITQMAGICS
;
95 #endif /* __APPLE__ */
98 #define FUHASH 1024 /* must be power of two */
99 struct fileusage
*fuhead
[MAXQUOTAS
][FUHASH
];
101 int aflag
; /* all file systems */
102 int gflag
; /* check group quotas */
103 int uflag
; /* check user quotas */
104 int vflag
; /* verbose */
107 int maxentries
; /* maximum entries in disk quota file */
109 u_long highid
[MAXQUOTAS
]; /* highest addid()'ed identifier per type */
110 #endif /* __APPLE__ */
114 char * blockcheck(char *);
115 int chkquota(char *, char *, char *, struct quotaname
*);
116 int getquotagid(void);
117 int hasquota(struct statfs
*, int, char **);
120 void * needchk(struct statfs
*);
121 int oneof(char *, char*[], int);
122 int qfinsert(FILE *, struct dqblk
*, int, int);
123 int qfmaxentries(char *, int);
125 void dqbuftohost(struct dqblk
*dqbp
);
129 addid
__P((uid_t
, int, char *));
130 char *blockcheck
__P((char *));
131 int chkquota
__P((char *, char *, struct quotaname
*));
132 int getquotagid
__P((void));
133 int hasquota
__P((struct fstab
*, int, char **));
135 lookup
__P((u_long
, int));
136 void *needchk
__P((struct fstab
*));
137 int oneof
__P((char *, char*[], int));
138 int update
__P((char *, char *, int));
139 void usage
__P((void));
140 #endif /* __APPLE__ */
149 register struct fstab
*fs
;
150 register struct passwd
*pw
;
151 register struct group
*gr
;
152 #endif /* !__APPLE__ */
153 struct quotaname
*auxdata
;
154 int i
, argnum
, maxrun
, errs
;
161 #endif /* __APPLE__ */
164 while ((ch
= getopt(argc
, argv
, "aguvl:")) != EOF
) {
179 maxrun
= atoi(optarg
);
187 if ((argc
== 0 && !aflag
) || (argc
> 0 && aflag
))
189 if (!gflag
&& !uflag
) {
195 nfst
= getmntinfo(&fst
, MNT_WAIT
);
197 fprintf(stderr
, "quotacheck: no mounted filesystems\n");
201 for (i
=0; i
<nfst
; i
++) {
202 if(strcmp(fst
[i
].f_fstypename
, "hfs")) {
207 if ((auxdata
= needchk(&fst
[i
])) &&
208 (name
= blockcheck(fst
[i
].f_mntfromname
))) {
209 errs
+= chkquota(fst
[i
].f_fstypename
, name
, fst
[i
].f_mntonname
, auxdata
);
218 if (((argnum
= oneof(fst
[i
].f_mntonname
, argv
, argc
)) >= 0 ||
219 (argnum
= oneof(fst
[i
].f_mntfromname
, argv
, argc
)) >= 0) &&
220 (auxdata
= needchk(&fst
[i
])) &&
221 (name
= blockcheck(fst
[i
].f_mntfromname
))) {
223 errs
+= chkquota(fst
[i
].f_fstypename
, name
, fst
[i
].f_mntonname
, auxdata
);
227 for (i
= 0; i
< argc
; i
++)
228 if ((done
& (1 << i
)) == 0)
229 fprintf(stderr
, "%s not identified as a quota filesystem\n",
236 while ((gr
= getgrent()) != 0)
237 (void) addid((u_long
)gr
->gr_gid
, GRPQUOTA
, gr
->gr_name
);
242 while ((pw
= getpwent()) != 0)
243 (void) addid((u_long
)pw
->pw_uid
, USRQUOTA
, pw
->pw_name
);
247 exit(checkfstab(1, maxrun
, needchk
, chkquota
));
249 err(1, "%s: can't open", FSTAB
);
250 while ((fs
= getfsent()) != NULL
) {
251 if (((argnum
= oneof(fs
->fs_file
, argv
, argc
)) >= 0 ||
252 (argnum
= oneof(fs
->fs_spec
, argv
, argc
)) >= 0) &&
253 (auxdata
= needchk(fs
)) &&
254 (name
= blockcheck(fs
->fs_spec
))) {
256 errs
+= chkquota(name
, fs
->fs_file
, auxdata
);
260 for (i
= 0; i
< argc
; i
++)
261 if ((done
& (1 << i
)) == 0)
262 fprintf(stderr
, "%s not found in %s\n",
265 #endif /* __APPLE__ */
271 (void)fprintf(stderr
, "usage:\t%s\n\t%s\n",
272 "quotacheck -a [-guv]",
273 "quotacheck [-guv] filesys ...");
282 register struct quotaname
*qnp
;
285 if(strcmp(fst
->f_fstypename
, "hfs")) {
288 if(fst
->f_flags
& MNT_RDONLY
)
290 if ((qnp
= malloc(sizeof(*qnp
))) == NULL
)
291 err(1, "%s", strerror(errno
));
293 if (gflag
&& hasquota(fst
, GRPQUOTA
, &qfnp
)) {
294 strlcpy(qnp
->grpqfname
, qfnp
, sizeof(qnp
->grpqfname
));
295 qnp
->flags
|= HASGRP
;
297 if (uflag
&& hasquota(fst
, USRQUOTA
, &qfnp
)) {
298 strlcpy(qnp
->usrqfname
, qfnp
, sizeof(qnp
->usrqfname
));
299 qnp
->flags
|= HASUSR
;
309 register struct fstab
*fs
;
311 register struct quotaname
*qnp
;
314 if (strcmp(fs
->fs_type
, FSTAB_RW
))
317 if ((qnp
= malloc(sizeof(*qnp
))) == NULL
)
318 err(1, "%s", strerror(errno
));
320 if (gflag
&& hasquota(fs
, GRPQUOTA
, &qfnp
)) {
321 strlcpy(qnp
->grpqfname
, qfnp
, sizeof(qnp
->grpqfname
));
322 qnp
->flags
|= HASGRP
;
324 if (uflag
&& hasquota(fs
, USRQUOTA
, &qfnp
)) {
325 strlcpy(qnp
->usrqfname
, qfnp
, sizeof(qnp
->usrqfname
));
326 qnp
->flags
|= HASUSR
;
333 #endif /* __APPLE__ */
336 * Scan the specified filesystem to check quota(s) present on it.
339 chkquota(fstype
, fsname
, mntpt
, qnp
)
340 char *fstype
, *fsname
, *mntpt
;
341 register struct quotaname
*qnp
;
346 fprintf(stdout
, "*** Checking ");
347 if (qnp
->flags
& HASUSR
)
348 fprintf(stdout
, "%s%s", qfextension
[USRQUOTA
],
349 (qnp
->flags
& HASGRP
) ? " and " : "");
350 if (qnp
->flags
& HASGRP
)
351 fprintf(stdout
, "%s", qfextension
[GRPQUOTA
]);
352 fprintf(stdout
, " quotas for %s (%s)\n", fsname
, mntpt
);
355 if(strcmp(fstype
, "hfs") == 0)
356 errs
= chkquota_hfs(fsname
, mntpt
, qnp
);
362 * Update a specified quota file.
366 update(fsname
, quotafile
, type
)
367 char *fsname
, *quotafile
;
370 register struct fileusage
*fup
;
371 register FILE *qfi
, *qfo
;
374 struct dqfilehdr dqhdr
= {0};
377 static int warned
= 0;
378 static struct dqblk zerodqbuf
;
379 static struct fileusage zerofileusage
;
381 if ((qfo
= fopen(quotafile
, "r+")) == NULL
) {
383 qfo
= fopen(quotafile
, "w+");
386 "quotacheck: creating quota file %s\n", quotafile
);
387 #define MODE (S_IRUSR|S_IWUSR|S_IRGRP)
388 (void) fchown(fileno(qfo
), getuid(), getquotagid());
389 (void) fchmod(fileno(qfo
), MODE
);
392 "quotacheck: %s: %s\n", quotafile
, strerror(errno
));
396 if ((qfi
= fopen(quotafile
, "r")) == NULL
) {
398 "quotacheck: %s: %s\n", quotafile
, strerror(errno
));
402 if (quotactl(fsname
, QCMD(Q_SYNC
, type
), 0, 0) < 0 &&
403 errno
== ENOTSUP
&& !warned
&& vflag
) {
405 fprintf(stdout
, "*** Warning: %s\n",
406 "Quotas are not compiled into this kernel");
409 /* Read in the quota file header. */
410 if (fread((char *)&dqhdr
, sizeof(struct dqfilehdr
), 1, qfi
) > 0) {
411 /* Check for reverse endian file. */
412 if (OSSwapBigToHostInt32(dqhdr
.dqh_magic
) != quotamagic
[type
] &&
413 OSSwapInt32(dqhdr
.dqh_magic
) == quotamagic
[type
]) {
415 "quotacheck: %s: not in big endian byte order\n",
421 /* Sanity check the quota file header. */
422 if ((OSSwapBigToHostInt32(dqhdr
.dqh_magic
) != quotamagic
[type
]) ||
423 (OSSwapBigToHostInt32(dqhdr
.dqh_version
) > QF_VERSION
) ||
424 (!powerof2(OSSwapBigToHostInt32(dqhdr
.dqh_maxentries
)))) {
426 "quotacheck: %s: not a valid quota file\n",
432 m
= OSSwapBigToHostInt32(dqhdr
.dqh_maxentries
);
433 } else /* empty file */ {
437 m
= qfmaxentries(fsname
, type
);
439 ftruncate(fileno(qfo
), (off_t
)((m
+ 1) * sizeof(struct dqblk
)));
441 /* Initialize file header in big endian. */
442 dqhdr
.dqh_magic
= OSSwapHostToBigInt32(quotamagic
[type
]);
443 dqhdr
.dqh_version
= OSSwapHostToBigConstInt32(QF_VERSION
);
444 dqhdr
.dqh_maxentries
= OSSwapHostToBigInt32(m
);
445 dqhdr
.dqh_btime
= OSSwapHostToBigConstInt32(MAX_DQ_TIME
);
446 dqhdr
.dqh_itime
= OSSwapHostToBigConstInt32(MAX_IQ_TIME
);
447 memmove(dqhdr
.dqh_string
, QF_STRING_TAG
, strlen(QF_STRING_TAG
));
448 goto orphans
; /* just insert all new records */
451 /* Examine all the entries in the quota file. */
452 for (i
= 0; i
< m
; i
++) {
453 if (fread((char *)&dqbuf
, sizeof(struct dqblk
), 1, qfi
) == 0) {
455 "quotacheck: problem reading at index %ld\n", i
);
458 if (dqbuf
.dqb_id
== 0)
462 if ((fup
= lookup(OSSwapBigToHostInt32(dqbuf
.dqb_id
), type
)) == 0)
463 fup
= &zerofileusage
;
467 if (OSSwapBigToHostInt32(dqbuf
.dqb_curinodes
) == fup
->fu_curinodes
&&
468 OSSwapBigToHostInt64(dqbuf
.dqb_curbytes
) == fup
->fu_curbytes
) {
469 fup
->fu_curinodes
= 0;
470 fup
->fu_curbytes
= 0;
475 fprintf(stdout
, "%s: ", fsname
);
476 fprintf(stdout
, "%-12s fixed:", fup
->fu_name
);
477 if (OSSwapBigToHostInt32(dqbuf
.dqb_curinodes
) != fup
->fu_curinodes
)
478 fprintf(stdout
, "\tinodes %u -> %u",
479 OSSwapBigToHostInt32(dqbuf
.dqb_curinodes
), fup
->fu_curinodes
);
480 if (OSSwapBigToHostInt64(dqbuf
.dqb_curbytes
) != fup
->fu_curbytes
)
481 fprintf(stdout
, "\t1K blocks %qd -> %qd",
482 (OSSwapBigToHostInt64(dqbuf
.dqb_curbytes
)/1024), (fup
->fu_curbytes
/1024));
483 fprintf(stdout
, "\n");
486 * Reset time limit if have a soft limit and were
487 * previously under it, but are now over it.
489 if (dqbuf
.dqb_bsoftlimit
!= 0 &&
490 OSSwapBigToHostInt64(dqbuf
.dqb_curbytes
) < OSSwapBigToHostInt64(dqbuf
.dqb_bsoftlimit
) &&
491 fup
->fu_curbytes
>= OSSwapBigToHostInt64(dqbuf
.dqb_bsoftlimit
))
493 if (dqbuf
.dqb_isoftlimit
!= 0 &&
494 OSSwapBigToHostInt32(dqbuf
.dqb_curinodes
) < OSSwapBigToHostInt32(dqbuf
.dqb_isoftlimit
) &&
495 fup
->fu_curinodes
>= OSSwapBigToHostInt32(dqbuf
.dqb_isoftlimit
))
497 dqbuf
.dqb_curinodes
= OSSwapHostToBigInt32(fup
->fu_curinodes
);
498 dqbuf
.dqb_curbytes
= OSSwapHostToBigInt64(fup
->fu_curbytes
);
500 /* Write dqblk in big endian. */
501 fseek(qfo
, dqoffset(i
), SEEK_SET
);
502 fwrite((char *)&dqbuf
, sizeof(struct dqblk
), 1, qfo
);
505 (void) quotactl(fsname
, QCMD(Q_SETUSE
, type
), dqbuf
.dqb_id
,
507 fup
->fu_curinodes
= 0;
508 fup
->fu_curbytes
= 0;
511 /* Look for any fileusage orphans */
513 shift
= dqhashshift(m
);
514 for (i
= 0; i
< FUHASH
; ++i
) {
515 for (fup
= fuhead
[type
][i
]; fup
!= 0; fup
= fup
->fu_next
) {
516 if (fup
->fu_checked
|| fup
->fu_id
== 0)
520 fprintf(stdout
, "%s: ", fsname
);
522 "%-12s added:\tinodes %u\t1K blocks %qd\n",
523 fup
->fu_name
, fup
->fu_curinodes
,
524 (fup
->fu_curbytes
/1024));
526 /* Initialize dqbuf in big endian. */
528 dqbuf
.dqb_id
= OSSwapHostToBigInt32(fup
->fu_id
);
529 dqbuf
.dqb_curinodes
= OSSwapHostToBigInt32(fup
->fu_curinodes
);
530 dqbuf
.dqb_curbytes
= OSSwapHostToBigInt64(fup
->fu_curbytes
);
531 /* insert this dqb */
532 if (qfinsert(qfo
, &dqbuf
, m
, shift
)) {
538 (void) quotactl(fsname
, QCMD(Q_SETUSE
, type
),
539 dqbuf
.dqb_id
, (caddr_t
)&dqbuf
);
544 /* Write the quota file header */
545 dqhdr
.dqh_entrycnt
= OSSwapHostToBigInt32(idcnt
);
546 fseek(qfo
, (long)0, SEEK_SET
);
547 fwrite((char *)&dqhdr
, sizeof(struct dqfilehdr
), 1, qfo
);
555 /* Convert a dqblk to host native byte order. */
557 dqbuftohost(struct dqblk
*dqbp
)
559 dqbp
->dqb_bhardlimit
= OSSwapBigToHostInt64(dqbp
->dqb_bhardlimit
);
560 dqbp
->dqb_bsoftlimit
= OSSwapBigToHostInt64(dqbp
->dqb_bsoftlimit
);
561 dqbp
->dqb_curbytes
= OSSwapBigToHostInt64(dqbp
->dqb_curbytes
);
562 dqbp
->dqb_ihardlimit
= OSSwapBigToHostInt32(dqbp
->dqb_ihardlimit
);
563 dqbp
->dqb_isoftlimit
= OSSwapBigToHostInt32(dqbp
->dqb_isoftlimit
);
564 dqbp
->dqb_curinodes
= OSSwapBigToHostInt32(dqbp
->dqb_curinodes
);
565 dqbp
->dqb_btime
= OSSwapBigToHostInt32(dqbp
->dqb_btime
);
566 dqbp
->dqb_itime
= OSSwapBigToHostInt32(dqbp
->dqb_itime
);
567 dqbp
->dqb_id
= OSSwapBigToHostInt32(dqbp
->dqb_id
);
572 update(fsname
, quotafile
, type
)
573 char *fsname
, *quotafile
;
576 register struct fileusage
*fup
;
577 register FILE *qfi
, *qfo
;
578 register u_long id
, lastid
;
580 static int warned
= 0;
581 static struct dqblk zerodqbuf
;
582 static struct fileusage zerofileusage
;
584 if ((qfo
= fopen(quotafile
, "r+")) == NULL
) {
586 qfo
= fopen(quotafile
, "w+");
588 (void) fprintf(stderr
,
589 "quotacheck: creating quota file %s\n", quotafile
);
590 #define MODE (S_IRUSR|S_IWUSR|S_IRGRP)
591 (void) fchown(fileno(qfo
), getuid(), getquotagid());
592 (void) fchmod(fileno(qfo
), MODE
);
594 (void) fprintf(stderr
,
595 "quotacheck: %s: %s\n", quotafile
, strerror(errno
));
599 if ((qfi
= fopen(quotafile
, "r")) == NULL
) {
600 (void) fprintf(stderr
,
601 "quotacheck: %s: %s\n", quotafile
, strerror(errno
));
605 if (quotactl(fsname
, QCMD(Q_SYNC
, type
), (u_long
)0, (caddr_t
)0) < 0 &&
606 errno
== ENOTSUP
&& !warned
&& vflag
) {
608 (void)printf("*** Warning: %s\n",
609 "Quotas are not compiled into this kernel");
611 for (lastid
= highid
[type
], id
= 0; id
<= lastid
; id
++) {
612 if (fread((char *)&dqbuf
, sizeof(struct dqblk
), 1, qfi
) == 0)
614 if ((fup
= lookup(id
, type
)) == 0)
615 fup
= &zerofileusage
;
616 if (dqbuf
.dqb_curinodes
== fup
->fu_curinodes
&&
617 dqbuf
.dqb_curblocks
== fup
->fu_curblocks
) {
618 fup
->fu_curinodes
= 0;
619 fup
->fu_curblocks
= 0;
620 fseek(qfo
, (long)sizeof(struct dqblk
), 1);
625 printf("%s: ", fsname
);
626 printf("%-8s fixed:", fup
->fu_name
);
627 if (dqbuf
.dqb_curinodes
!= fup
->fu_curinodes
)
628 (void)printf("\tinodes %d -> %d",
629 dqbuf
.dqb_curinodes
, fup
->fu_curinodes
);
630 if (dqbuf
.dqb_curblocks
!= fup
->fu_curblocks
)
631 (void)printf("\tblocks %d -> %d",
632 dqbuf
.dqb_curblocks
, fup
->fu_curblocks
);
636 * Reset time limit if have a soft limit and were
637 * previously under it, but are now over it.
639 if (dqbuf
.dqb_bsoftlimit
&&
640 dqbuf
.dqb_curblocks
< dqbuf
.dqb_bsoftlimit
&&
641 fup
->fu_curblocks
>= dqbuf
.dqb_bsoftlimit
)
643 if (dqbuf
.dqb_isoftlimit
&&
644 dqbuf
.dqb_curblocks
< dqbuf
.dqb_isoftlimit
&&
645 fup
->fu_curblocks
>= dqbuf
.dqb_isoftlimit
)
647 dqbuf
.dqb_curinodes
= fup
->fu_curinodes
;
648 dqbuf
.dqb_curblocks
= fup
->fu_curblocks
;
649 fwrite((char *)&dqbuf
, sizeof(struct dqblk
), 1, qfo
);
650 (void) quotactl(fsname
, QCMD(Q_SETUSE
, type
), id
,
652 fup
->fu_curinodes
= 0;
653 fup
->fu_curblocks
= 0;
657 ftruncate(fileno(qfo
),
658 (off_t
)((highid
[type
] + 1) * sizeof(struct dqblk
)));
662 #endif /* __APPLE__ */
666 * Insert an entry into a quota file.
668 * The dqblk pointed to by dqbp is in big endian.
671 qfinsert(file
, dqbp
, maxentries
, shift
)
674 int maxentries
, shift
;
682 id
= OSSwapBigToHostInt32(dqbp
->dqb_id
);
685 mask
= maxentries
- 1;
686 i
= dqhash1(id
, dqhashshift(maxentries
), mask
);
687 skip
= dqhash2(id
, mask
);
689 for (last
= (i
+ (maxentries
-1) * skip
) & mask
;
691 i
= (i
+ skip
) & mask
) {
692 offset
= dqoffset(i
);
693 fseek(file
, (long)offset
, SEEK_SET
);
694 if (fread((char *)&dqbuf
, sizeof(struct dqblk
), 1, file
) == 0) {
695 fprintf(stderr
, "quotacheck: read error at index %d\n", i
);
699 * Stop when an empty entry is found
700 * or we encounter a matching id.
702 if (dqbuf
.dqb_id
== 0 || dqbuf
.dqb_id
== dqbp
->dqb_id
) {
704 fseek(file
, (long)offset
, SEEK_SET
);
705 fwrite((char *)&dqbuf
, sizeof(struct dqblk
), 1, file
);
709 fprintf(stderr
, "quotacheck: exceeded maximum entries (%d)\n", maxentries
);
713 #define ONEGIGABYTE (1024*1024*1024)
716 * Calculate the size of the hash table from the size of
717 * the file system. The open addressing hashing used on
718 * the quota file assumes that this table will never be
719 * more than 90% full.
722 qfmaxentries(mntpt
, type
)
726 struct statfs fs_stat
;
730 if (statfs(mntpt
, &fs_stat
)) {
731 fprintf(stderr
, "quotacheck: %s: %s\n",
732 mntpt
, strerror(errno
));
735 fs_size
= (u_int64_t
)fs_stat
.f_blocks
* (u_int64_t
)fs_stat
.f_bsize
;
737 if (type
== USRQUOTA
) {
738 max
= QF_USERS_PER_GB
* (fs_size
/ ONEGIGABYTE
);
740 if (max
< QF_MIN_USERS
)
742 else if (max
> QF_MAX_USERS
)
744 } else if (type
== GRPQUOTA
) {
745 max
= QF_GROUPS_PER_GB
* (fs_size
/ ONEGIGABYTE
);
747 if (max
< QF_MIN_GROUPS
)
749 else if (max
> QF_MAX_GROUPS
)
752 /* Round up to a power of 2 */
753 if (max
&& !powerof2(max
)) {
763 #endif /* __APPLE__ */
766 * Check to see if target appears in list of size cnt.
769 oneof(target
, list
, cnt
)
770 register char *target
, *list
[];
775 for (i
= 0; i
< cnt
; i
++)
776 if (strcmp(target
, list
[i
]) == 0)
782 * Determine the group identifier for quota files.
789 if ((gr
= getgrnam(quotagroup
)))
795 * Check to see if a particular quota is to be enabled.
799 hasquota(fst
, type
, qfnamep
)
805 static char initname
, usrname
[100], grpname
[100];
806 static char buf
[BUFSIZ
];
809 (void)snprintf(usrname
, sizeof(usrname
),
810 "%s%s", qfextension
[USRQUOTA
], qfname
);
811 (void)snprintf(grpname
, sizeof(grpname
),
812 "%s%s", qfextension
[GRPQUOTA
], qfname
);
817 We only support the default path to the
821 (void)snprintf(buf
, sizeof(buf
), "%s/%s.%s", fst
->f_mntonname
,
822 QUOTAOPSNAME
, qfextension
[type
] );
823 if (stat(buf
, &sb
) != 0) {
824 /* There appears to be no mount option file */
828 (void)snprintf(buf
, sizeof(buf
),
829 "%s/%s.%s", fst
->f_mntonname
, qfname
, qfextension
[type
]);
836 hasquota(fs
, type
, qfnamep
)
837 register struct fstab
*fs
;
843 static char initname
, usrname
[100], grpname
[100];
844 static char buf
[BUFSIZ
];
847 (void)snprintf(usrname
, sizeof(usrname
),
848 "%s%s", qfextension
[USRQUOTA
], qfname
);
849 (void)snprintf(grpname
, sizeof(grpname
),
850 "%s%s", qfextension
[GRPQUOTA
], qfname
);
853 strlcpy(buf
, fs
->fs_mntops
, sizeof(buf
));
854 for (opt
= strtok(buf
, ","); opt
; opt
= strtok(NULL
, ",")) {
855 if (cp
= strchr(opt
, '='))
857 if (type
== USRQUOTA
&& strcmp(opt
, usrname
) == 0)
859 if (type
== GRPQUOTA
&& strcmp(opt
, grpname
) == 0)
867 (void)snprintf(buf
, sizeof(buf
),
868 "%s/%s.%s", fs
->fs_file
, qfname
, qfextension
[type
]);
873 #endif /* __APPLE__ */
876 * Routines to manage the file usage table.
878 * Lookup an id of a specific type.
885 register struct fileusage
*fup
;
887 for (fup
= fuhead
[type
][id
& (FUHASH
-1)]; fup
!= 0; fup
= fup
->fu_next
)
888 if (fup
->fu_id
== id
)
894 * Add a new file usage id if it does not already exist.
902 struct fileusage
*fup
, **fhp
;
908 if ((fup
= lookup(id
, type
)))
915 if ((pw
= getpwuid(id
)) != 0) {
921 if ((gr
= getgrgid(id
)) != 0) {
928 if ((fup
= calloc(1, sizeof(*fup
) + len
)) == NULL
)
929 err(1, "%s", strerror(errno
));
930 fhp
= &fuhead
[type
][id
& (FUHASH
- 1)];
935 memmove(fup
->fu_name
, name
, len
+ 1);
937 (void)snprintf(fup
->fu_name
, len
+ 1, "%u", (unsigned int)id
);
943 addid(id
, type
, name
)
948 struct fileusage
*fup
, **fhp
;
951 if (fup
= lookup(id
, type
))
957 if ((fup
= calloc(1, sizeof(*fup
) + len
)) == NULL
)
958 err(1, "%s", strerror(errno
));
959 fhp
= &fuhead
[type
][id
& (FUHASH
- 1)];
963 if (id
> highid
[type
])
966 memmove(fup
->fu_name
, name
, len
+ 1);
968 (void)snprintf(fup
->fu_name
, len
+ 1, "%u", id
);
971 #endif /* __APPLE__ */