]>
git.cameronkatri.com Git - apple_cmds.git/blob - diskdev_cmds/edquota.tproj/edquota.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
59 #include <sys/cdefs.h>
62 __unused
static char copyright
[] =
63 "@(#) Copyright (c) 1980, 1990, 1993\n\
64 The Regents of the University of California. All rights reserved.\n";
68 __unused
static char sccsid
[] = "@(#)edquota.c 8.3 (Berkeley) 4/27/95";
74 #include <sys/param.h>
78 #include <sys/mount.h>
79 #endif /* __APPLE__ */
81 #include <sys/queue.h>
82 #include <sys/quota.h>
93 #include "pathnames.h"
96 #include <libkern/OSByteOrder.h>
97 #endif /* __APPLE__ */
99 #include <libiosexec.h>
101 char *qfname
= QUOTAFILENAME
;
102 char *qfextension
[] = INITQFNAMES
;
103 char *quotagroup
= QUOTAGROUP
;
104 char tmpfil
[] = _PATH_TMP
;
107 u_int32_t quotamagic
[MAXQUOTAS
] = INITQMAGICS
;
108 #endif /* __APPLE__ */
111 struct quotause
*next
;
114 char fsname
[MAXPATHLEN
+ 1];
115 char qfname
[1]; /* actually longer */
119 int alldigits
__P((char *));
120 int cvtatos
__P((time_t, char *, time_t *));
121 int editit
__P((char *));
122 void freeprivs
__P((struct quotause
*));
123 int getentry
__P((char *, int));
124 int hasquota
__P((struct statfs
*, int, char **));
125 void putprivs
__P((uid_t
, int, struct quotause
*));
126 int readprivs
__P((struct quotause
*, int));
127 int readtimes
__P((struct quotause
*, int));
128 void usage
__P((void));
129 int writeprivs
__P((struct quotause
*, int, char *, int));
130 int writetimes
__P((struct quotause
*, int, int));
133 int qfinit(int, struct statfs
*, int);
134 int qflookup(int, uid_t
, int, struct dqblk
*);
135 int qfupdate(int, uid_t
, int, struct dqblk
*);
136 #endif /* __APPLE__ */
141 register char **argv
;
144 register struct quotause
*qup
, *protoprivs
, *curprivs
;
147 register uid_t id
, protoid
;
148 register int quotatype
, tmpfd
;
149 char *protoname
= NULL
, ch
;
150 int tflag
= 0, pflag
= 0;
155 fprintf(stderr
, "edquota: permission denied\n");
158 quotatype
= USRQUOTA
;
160 while ((ch
= getopt(argc
, argv
, "ugtp:")) != EOF
) {
167 quotatype
= GRPQUOTA
;
170 quotatype
= USRQUOTA
;
182 if ((protoid
= getentry(protoname
, quotatype
)) == -1)
184 protoprivs
= getprivs(protoid
, quotatype
);
186 if (protoprivs
== (struct quotause
*) NULL
)
188 #endif /* __APPLE__ */
189 for (qup
= protoprivs
; qup
; qup
= qup
->next
) {
190 qup
->dqblk
.dqb_btime
= 0;
191 qup
->dqblk
.dqb_itime
= 0;
194 if ((id
= getentry(*argv
++, quotatype
)) == -1)
197 * Set the ID in each disk quota block to match
198 * the ID it's supposed to go with.
200 for (qup
= protoprivs
; qup
; qup
= qup
->next
) {
201 qup
->dqblk
.dqb_id
= id
;
203 putprivs(id
, quotatype
, protoprivs
);
207 tmpfd
= mkstemp(tmpfil
);
208 fchown(tmpfd
, getuid(), getgid());
210 protoprivs
= getprivs(0, quotatype
);
212 if (protoprivs
== (struct quotause
*) NULL
)
214 #endif /* __APPLE__ */
215 if (writetimes(protoprivs
, tmpfd
, quotatype
) == 0)
217 if (editit(tmpfil
)) {
219 * Re-open tmpfil to be editor independent.
222 tmpfd
= open(tmpfil
, O_RDWR
, 0);
224 freeprivs(protoprivs
);
228 if (readtimes(protoprivs
, tmpfd
))
229 putprivs(0, quotatype
, protoprivs
);
231 freeprivs(protoprivs
);
234 for ( ; argc
> 0; argc
--, argv
++) {
235 if ((id
= getentry(*argv
, quotatype
)) == -1)
237 curprivs
= getprivs(id
, quotatype
);
239 if (curprivs
== (struct quotause
*) NULL
)
241 #endif /* __APPLE__ */
244 if (writeprivs(curprivs
, tmpfd
, *argv
, quotatype
) == 0) {
248 if (editit(tmpfil
)) {
250 * Re-open tmpfil to be editor independent.
253 tmpfd
= open(tmpfil
, O_RDWR
, 0);
259 if (readprivs(curprivs
, tmpfd
))
260 putprivs(id
, quotatype
, curprivs
);
272 fprintf(stderr
, "%s%s%s%s",
273 "Usage: edquota [-u] [-p username] username ...\n",
274 "\tedquota -g [-p groupname] groupname ...\n",
275 "\tedquota [-u] -t\n", "\tedquota -g -t\n");
277 fprintf(stderr
, "\nQuota file editing triggers only on filesystems with a\n");
278 fprintf(stderr
, "%s.%s or %s.%s file located at its root.\n",
279 QUOTAOPSNAME
, qfextension
[USRQUOTA
],
280 QUOTAOPSNAME
, qfextension
[GRPQUOTA
]);
281 #endif /* __APPLE__ */
286 * This routine converts a name for a particular quota type to
287 * an identifier. This routine must agree with the kernel routine
288 * getinoquota as to the interpretation of quota types.
291 getentry(name
, quotatype
)
302 if ((pw
= getpwnam(name
)) != NULL
)
304 fprintf(stderr
, "%s: no such user\n", name
);
307 if ((gr
= getgrnam(name
)))
309 fprintf(stderr
, "%s: no such group\n", name
);
312 fprintf(stderr
, "%d: unknown quota type\n", quotatype
);
320 * Collect the requested quota information.
324 getprivs(id
, quotatype
)
329 register struct quotause
*qup
, *quptail
;
330 struct quotause
*quphead
;
334 size_t qfpathname_len
;
335 static int warned
= 0;
340 quptail
= quphead
= (struct quotause
*)0;
341 qcmd
= QCMD(Q_GETQUOTA
, quotatype
);
343 nfst
= getmntinfo(&fst
, MNT_WAIT
);
345 fprintf(stderr
, "edquota: no mounted filesystems\n");
349 for (i
=0; i
<nfst
; i
++) {
350 if (strcmp(fst
[i
].f_fstypename
, "hfs")) {
353 if (!hasquota(&fst
[i
], quotatype
, &qfpathname
))
355 qfpathname_len
= strlen(qfpathname
);
356 qupsize
= sizeof(*qup
) + qfpathname_len
;
357 if ((qup
= (struct quotause
*)malloc(qupsize
)) == NULL
) {
358 fprintf(stderr
, "edquota: out of memory\n");
361 if (quotactl(fst
[i
].f_mntonname
, qcmd
, id
, (char *)&qup
->dqblk
) != 0) {
362 if (errno
== ENOTSUP
&& !warned
) {
364 fprintf(stderr
, "Warning: %s\n",
365 "Quotas are not compiled into this kernel");
368 if ((fd
= open(qfpathname
, O_RDONLY
)) < 0) {
369 fd
= open(qfpathname
, O_RDWR
|O_CREAT
, 0640);
370 if (fd
< 0 && errno
!= ENOENT
) {
375 fprintf(stderr
, "Creating quota file %s\n",
378 (void) fchown(fd
, getuid(),
379 getentry(quotagroup
, GRPQUOTA
));
380 (void) fchmod(fd
, 0640);
381 if (qfinit(fd
, &fst
[i
], quotatype
)) {
388 if (qflookup(fd
, id
, quotatype
, &qup
->dqblk
) != 0) {
389 fprintf(stderr
, "edquota: lookup error in ");
397 strlcpy(qup
->qfname
, qfpathname
, qfpathname_len
); // malloc'd size is correct for this
398 strlcpy(qup
->fsname
, fst
[i
].f_mntonname
, sizeof(qup
->fsname
));
411 getprivs(id
, quotatype
)
415 register struct fstab
*fs
;
416 register struct quotause
*qup
, *quptail
;
417 struct quotause
*quphead
;
421 size_t qfpathname_len
;
422 static int warned
= 0;
426 quphead
= (struct quotause
*)0;
427 qcmd
= QCMD(Q_GETQUOTA
, quotatype
);
428 while (fs
= getfsent()) {
429 if (!hasquota(fs
, quotatype
, &qfpathname
))
431 qfpathname_len
= strlen(qfpathname
);
432 qupsize
= sizeof(*qup
) + qfpathname_len
;
433 if ((qup
= (struct quotause
*)malloc(qupsize
)) == NULL
) {
434 fprintf(stderr
, "edquota: out of memory\n");
437 if (quotactl(fs
->fs_file
, qcmd
, id
, &qup
->dqblk
) != 0) {
438 if (errno
== ENOTSUP
&& !warned
) {
440 fprintf(stderr
, "Warning: %s\n",
441 "Quotas are not compiled into this kernel");
444 if ((fd
= open(qfpathname
, O_RDONLY
)) < 0) {
445 fd
= open(qfpathname
, O_RDWR
|O_CREAT
, 0640);
446 if (fd
< 0 && errno
!= ENOENT
) {
451 fprintf(stderr
, "Creating quota file %s\n",
454 (void) fchown(fd
, getuid(),
455 getentry(quotagroup
, GRPQUOTA
));
456 (void) fchmod(fd
, 0640);
458 lseek(fd
, (off_t
)(id
* sizeof(struct dqblk
)), L_SET
);
459 switch (read(fd
, &qup
->dqblk
, sizeof(struct dqblk
))) {
462 * Convert implicit 0 quota (EOF)
463 * into an explicit one (zero'ed dqblk)
465 bzero((caddr_t
)&qup
->dqblk
,
466 sizeof(struct dqblk
));
469 case sizeof(struct dqblk
): /* OK */
473 fprintf(stderr
, "edquota: read error in ");
481 strlcpy(qup
->qfname
, qfpathname
, qfpathname_len
); // malloc'd size is correct for this
482 strlcpy(qup
->fsname
, fs
->fs_file
, sizeof(qup
->fsname
));
497 #define ONEGIGABYTE (1024*1024*1024)
499 * Initialize a new quota file.
502 qfinit(fd
, fst
, type
)
507 struct dqfilehdr dqhdr
= {0};
512 * Calculate the size of the hash table from the size of
513 * the file system. Note that the open addressing hashing
514 * used by the quota file assumes that this table will not
515 * be more than 90% full.
517 fs_size
= (u_int64_t
)fst
->f_blocks
* (u_int64_t
)fst
->f_bsize
;
519 if (type
== USRQUOTA
) {
520 max
= QF_USERS_PER_GB
* (fs_size
/ ONEGIGABYTE
);
522 if (max
< QF_MIN_USERS
)
524 else if (max
> QF_MAX_USERS
)
526 } else if (type
== GRPQUOTA
) {
527 max
= QF_GROUPS_PER_GB
* (fs_size
/ ONEGIGABYTE
);
529 if (max
< QF_MIN_GROUPS
)
531 else if (max
> QF_MAX_GROUPS
)
534 /* Round up to a power of 2 */
535 if (max
&& !powerof2(max
)) {
544 (void) ftruncate(fd
, (off_t
)((max
+ 1) * sizeof(struct dqblk
)));
545 dqhdr
.dqh_magic
= OSSwapHostToBigInt32(quotamagic
[type
]);
546 dqhdr
.dqh_version
= OSSwapHostToBigConstInt32(QF_VERSION
);
547 dqhdr
.dqh_maxentries
= OSSwapHostToBigInt32((int32_t)max
);
548 dqhdr
.dqh_btime
= OSSwapHostToBigConstInt32(MAX_DQ_TIME
);
549 dqhdr
.dqh_itime
= OSSwapHostToBigConstInt32(MAX_IQ_TIME
);
550 memmove(dqhdr
.dqh_string
, QF_STRING_TAG
, strlen(QF_STRING_TAG
));
551 (void) lseek(fd
, 0, L_SET
);
552 (void) write(fd
, &dqhdr
, sizeof(dqhdr
));
558 * Lookup an entry in a quota file.
561 qflookup(fd
, id
, type
, dqbp
)
567 struct dqfilehdr dqhdr
;
568 int i
, skip
, last
, m
;
571 bzero(dqbp
, sizeof(struct dqblk
));
577 if (read(fd
, &dqhdr
, sizeof(struct dqfilehdr
)) != sizeof(struct dqfilehdr
))
580 /* Sanity check the quota file header. */
581 if ((OSSwapBigToHostInt32(dqhdr
.dqh_magic
) != quotamagic
[type
]) ||
582 (OSSwapBigToHostInt32(dqhdr
.dqh_version
) > 1) ||
583 (!powerof2(OSSwapBigToHostInt32(dqhdr
.dqh_maxentries
)))) {
584 fprintf(stderr
, "quota: invalid quota file header\n");
588 m
= OSSwapBigToHostInt32(dqhdr
.dqh_maxentries
);
590 i
= dqhash1(id
, dqhashshift(m
), mask
);
591 skip
= dqhash2(id
, mask
);
593 for (last
= (i
+ (m
-1) * skip
) & mask
;
595 i
= (i
+ skip
) & mask
) {
596 lseek(fd
, dqoffset(i
), L_SET
);
597 if (read(fd
, dqbp
, sizeof(struct dqblk
)) < sizeof(struct dqblk
))
600 * Stop when an empty entry is found
601 * or we encounter a matching id.
603 if (dqbp
->dqb_id
== 0 || OSSwapBigToHostInt32(dqbp
->dqb_id
) == id
)
606 /* Put data in host native byte order. */
607 dqbp
->dqb_bhardlimit
= OSSwapBigToHostInt64(dqbp
->dqb_bhardlimit
);
608 dqbp
->dqb_bsoftlimit
= OSSwapBigToHostInt64(dqbp
->dqb_bsoftlimit
);
609 dqbp
->dqb_curbytes
= OSSwapBigToHostInt64(dqbp
->dqb_curbytes
);
610 dqbp
->dqb_ihardlimit
= OSSwapBigToHostInt32(dqbp
->dqb_ihardlimit
);
611 dqbp
->dqb_isoftlimit
= OSSwapBigToHostInt32(dqbp
->dqb_isoftlimit
);
612 dqbp
->dqb_curinodes
= OSSwapBigToHostInt32(dqbp
->dqb_curinodes
);
613 dqbp
->dqb_btime
= OSSwapBigToHostInt32(dqbp
->dqb_btime
);
614 dqbp
->dqb_itime
= OSSwapBigToHostInt32(dqbp
->dqb_itime
);
615 dqbp
->dqb_id
= OSSwapBigToHostInt32(dqbp
->dqb_id
);
623 * Store the requested quota information.
626 putprivs(id
, quotatype
, quplist
)
629 struct quotause
*quplist
;
631 register struct quotause
*qup
;
634 qcmd
= QCMD(Q_SETQUOTA
, quotatype
);
635 for (qup
= quplist
; qup
; qup
= qup
->next
) {
636 if (quotactl(qup
->fsname
, qcmd
, id
, (char *)&qup
->dqblk
) == 0)
639 if ((fd
= open(qup
->qfname
, O_RDWR
)) < 0) {
642 if (qfupdate(fd
, id
, quotatype
, &qup
->dqblk
) != 0) {
643 fprintf(stderr
, "edquota: ");
647 if ((fd
= open(qup
->qfname
, O_WRONLY
)) < 0) {
651 (off_t
)(id
* (long)sizeof (struct dqblk
)), L_SET
);
652 if (write(fd
, &qup
->dqblk
, sizeof (struct dqblk
)) !=
653 sizeof (struct dqblk
)) {
654 fprintf(stderr
, "edquota: ");
665 * Update an entry in a quota file.
668 qfupdate(fd
, id
, type
, dqbp
)
675 struct dqfilehdr dqhdr
;
676 int i
, skip
, last
, m
;
683 if (read(fd
, &dqhdr
, sizeof(struct dqfilehdr
)) != sizeof(struct dqfilehdr
))
686 /* Sanity check the quota file header. */
687 if ((OSSwapBigToHostInt32(dqhdr
.dqh_magic
) != quotamagic
[type
]) ||
688 (OSSwapBigToHostInt32(dqhdr
.dqh_version
) > QF_VERSION
) ||
689 (!powerof2(OSSwapBigToHostInt32(dqhdr
.dqh_maxentries
)))) {
690 fprintf(stderr
, "quota: invalid quota file header\n");
694 m
= OSSwapBigToHostInt32(dqhdr
.dqh_maxentries
);
696 i
= dqhash1(id
, dqhashshift(m
), mask
);
697 skip
= dqhash2(id
, mask
);
699 for (last
= (i
+ (m
-1) * skip
) & mask
;
701 i
= (i
+ skip
) & mask
) {
702 lseek(fd
, dqoffset(i
), L_SET
);
703 if (read(fd
, &dqbuf
, sizeof(struct dqblk
)) < sizeof(struct dqblk
))
706 * Stop when an empty entry is found
707 * or we encounter a matching id.
709 if (dqbuf
.dqb_id
== 0 || OSSwapBigToHostInt32(dqbuf
.dqb_id
) == id
) {
710 /* Convert buffer to big endian before writing. */
713 tblk
.dqb_bhardlimit
= OSSwapHostToBigInt64(dqbp
->dqb_bhardlimit
);
714 tblk
.dqb_bsoftlimit
= OSSwapHostToBigInt64(dqbp
->dqb_bsoftlimit
);
715 tblk
.dqb_curbytes
= OSSwapHostToBigInt64(dqbp
->dqb_curbytes
);
716 tblk
.dqb_ihardlimit
= OSSwapHostToBigInt32(dqbp
->dqb_ihardlimit
);
717 tblk
.dqb_isoftlimit
= OSSwapHostToBigInt32(dqbp
->dqb_isoftlimit
);
718 tblk
.dqb_curinodes
= OSSwapHostToBigInt32(dqbp
->dqb_curinodes
);
719 tblk
.dqb_btime
= OSSwapHostToBigInt32((int)dqbp
->dqb_btime
);
720 tblk
.dqb_itime
= OSSwapHostToBigInt32((int)dqbp
->dqb_itime
);
721 tblk
.dqb_id
= OSSwapHostToBigInt32(id
);
723 lseek(fd
, dqoffset(i
), L_SET
);
724 if (write(fd
, &tblk
, sizeof (struct dqblk
)) !=
725 sizeof (struct dqblk
)) {
734 #endif /* __APPLE__ */
737 * Take a list of priviledges and get it edited.
745 extern char *getenv();
747 omask
= sigblock(sigmask(SIGINT
)|sigmask(SIGQUIT
)|sigmask(SIGHUP
));
749 if ((pid
= fork()) < 0) {
752 if (errno
== EPROCLIM
) {
753 fprintf(stderr
, "You have too many processes\n");
756 if (errno
== EAGAIN
) {
765 struct passwd
*pwd
= getpwuid(getuid());
766 gid_t newgid
= getgid();
769 if (pwd
) initgroups(pwd
->pw_name
, newgid
);
773 if ((ed
= getenv("EDITOR")) == (char *)0)
775 execlp(ed
, ed
, tmpfile
, NULL
);
779 waitpid(pid
, &stat
, 0);
781 if (!WIFEXITED(stat
) || WEXITSTATUS(stat
) != 0)
787 * Convert a quotause list to an ASCII file.
790 writeprivs(quplist
, outfd
, name
, quotatype
)
791 struct quotause
*quplist
;
796 register struct quotause
*qup
;
800 lseek(outfd
, 0, L_SET
);
801 if ((fd
= fdopen(dup(outfd
), "w")) == NULL
) {
802 fprintf(stderr
, "edquota: ");
806 fprintf(fd
, "Quotas for %s %s:\n", qfextension
[quotatype
], name
);
807 for (qup
= quplist
; qup
; qup
= qup
->next
) {
809 fprintf(fd
, "%s: %s %qd, limits (soft = %qd, hard = %qd)\n",
810 qup
->fsname
, "1K blocks in use:",
811 qup
->dqblk
.dqb_curbytes
/ 1024,
812 qup
->dqblk
.dqb_bsoftlimit
/ 1024,
813 qup
->dqblk
.dqb_bhardlimit
/ 1024);
815 fprintf(fd
, "%s: %s %d, limits (soft = %d, hard = %d)\n",
816 qup
->fsname
, "blocks in use:",
817 dbtob(qup
->dqblk
.dqb_curblocks
) / 1024,
818 dbtob(qup
->dqblk
.dqb_bsoftlimit
) / 1024,
819 dbtob(qup
->dqblk
.dqb_bhardlimit
) / 1024);
820 #endif /* __APPLE__ */
822 fprintf(fd
, "%s %d, limits (soft = %d, hard = %d)\n",
823 "\tinodes in use:", qup
->dqblk
.dqb_curinodes
,
824 qup
->dqblk
.dqb_isoftlimit
, qup
->dqblk
.dqb_ihardlimit
);
831 * Merge changes to an ASCII file into a quotause list.
834 readprivs(quplist
, infd
)
835 struct quotause
*quplist
;
838 register struct quotause
*qup
;
843 char fsp
[BUFSIZ
], line1
[BUFSIZ
], line2
[BUFSIZ
];
845 lseek(infd
, 0, L_SET
);
846 fd
= fdopen(dup(infd
), "r");
848 fprintf(stderr
, "Can't re-read temp file!!\n");
852 * Discard title line, then read pairs of lines to process.
854 (void) fgets(line1
, sizeof (line1
), fd
);
855 while (fgets(line1
, sizeof (line1
), fd
) != NULL
&&
856 fgets(line2
, sizeof (line2
), fd
) != NULL
) {
857 cp
= strstr(line1
, ": 1K blocks in use:");
859 fprintf(stderr
, "%s: bad format for line\n", line1
);
862 /* Copy up to the template text */
863 strlcpy(fsp
, line1
, cp
- line1
+ 1);
864 /* And point cp right after it. */
865 cp
= line1
+ strlen(fsp
) + 1;
867 /* We expect input to be in 1K blocks */
869 " 1K blocks in use: %qd, limits (soft = %qd, hard = %qd)",
870 &dqblk
.dqb_curbytes
, &dqblk
.dqb_bsoftlimit
,
871 &dqblk
.dqb_bhardlimit
);
873 fprintf(stderr
, "%s:%s: bad format\n", fsp
, cp
);
877 /* convert default 1K blocks to byte count */
878 dqblk
.dqb_curbytes
= dqblk
.dqb_curbytes
* 1024;
879 dqblk
.dqb_bsoftlimit
= dqblk
.dqb_bsoftlimit
* 1024;
880 dqblk
.dqb_bhardlimit
= dqblk
.dqb_bhardlimit
* 1024;
883 " blocks in use: %d, limits (soft = %d, hard = %d)",
884 &dqblk
.dqb_curblocks
, &dqblk
.dqb_bsoftlimit
,
885 &dqblk
.dqb_bhardlimit
);
887 fprintf(stderr
, "%s:%s: bad format\n", fsp
, cp
);
890 dqblk
.dqb_curblocks
= btodb(dqblk
.dqb_curblocks
* 1024);
891 dqblk
.dqb_bsoftlimit
= btodb(dqblk
.dqb_bsoftlimit
* 1024);
892 dqblk
.dqb_bhardlimit
= btodb(dqblk
.dqb_bhardlimit
* 1024);
893 #endif /* __APPLE__ */
895 if ((cp
= strtok(line2
, "\n")) == NULL
) {
896 fprintf(stderr
, "%s: %s: bad format\n", fsp
, line2
);
900 "\tinodes in use: %d, limits (soft = %d, hard = %d)",
901 &dqblk
.dqb_curinodes
, &dqblk
.dqb_isoftlimit
,
902 &dqblk
.dqb_ihardlimit
);
904 fprintf(stderr
, "%s: %s: bad format\n", fsp
, line2
);
907 for (qup
= quplist
; qup
; qup
= qup
->next
) {
908 if (strcmp(fsp
, qup
->fsname
))
911 * Cause time limit to be reset when the quota
912 * is next used if previously had no soft limit
913 * or were under it, but now have a soft limit
917 if (dqblk
.dqb_bsoftlimit
&&
918 qup
->dqblk
.dqb_curbytes
>= dqblk
.dqb_bsoftlimit
&&
919 (qup
->dqblk
.dqb_bsoftlimit
== 0 ||
920 qup
->dqblk
.dqb_curbytes
<
921 qup
->dqblk
.dqb_bsoftlimit
))
922 qup
->dqblk
.dqb_btime
= 0;
924 if (dqblk
.dqb_bsoftlimit
&&
925 qup
->dqblk
.dqb_curblocks
>= dqblk
.dqb_bsoftlimit
&&
926 (qup
->dqblk
.dqb_bsoftlimit
== 0 ||
927 qup
->dqblk
.dqb_curblocks
<
928 qup
->dqblk
.dqb_bsoftlimit
))
929 qup
->dqblk
.dqb_btime
= 0;
930 #endif /* __APPLE__ */
931 if (dqblk
.dqb_isoftlimit
&&
932 qup
->dqblk
.dqb_curinodes
>= dqblk
.dqb_isoftlimit
&&
933 (qup
->dqblk
.dqb_isoftlimit
== 0 ||
934 qup
->dqblk
.dqb_curinodes
<
935 qup
->dqblk
.dqb_isoftlimit
))
936 qup
->dqblk
.dqb_itime
= 0;
937 qup
->dqblk
.dqb_bsoftlimit
= dqblk
.dqb_bsoftlimit
;
938 qup
->dqblk
.dqb_bhardlimit
= dqblk
.dqb_bhardlimit
;
939 qup
->dqblk
.dqb_isoftlimit
= dqblk
.dqb_isoftlimit
;
940 qup
->dqblk
.dqb_ihardlimit
= dqblk
.dqb_ihardlimit
;
943 if (dqblk
.dqb_curbytes
== qup
->dqblk
.dqb_curbytes
&&
944 dqblk
.dqb_curinodes
== qup
->dqblk
.dqb_curinodes
)
947 if (dqblk
.dqb_curblocks
== qup
->dqblk
.dqb_curblocks
&&
948 dqblk
.dqb_curinodes
== qup
->dqblk
.dqb_curinodes
)
950 #endif /* __APPLE__ */
952 "%s: cannot change current allocation\n", fsp
);
958 * Disable quotas for any filesystems that have not been found.
960 for (qup
= quplist
; qup
; qup
= qup
->next
) {
961 if (qup
->flags
& FOUND
) {
962 qup
->flags
&= ~FOUND
;
965 qup
->dqblk
.dqb_bsoftlimit
= 0;
966 qup
->dqblk
.dqb_bhardlimit
= 0;
967 qup
->dqblk
.dqb_isoftlimit
= 0;
968 qup
->dqblk
.dqb_ihardlimit
= 0;
974 * Convert a quotause list to an ASCII file of grace times.
977 writetimes(quplist
, outfd
, quotatype
)
978 struct quotause
*quplist
;
982 register struct quotause
*qup
;
987 lseek(outfd
, 0, L_SET
);
988 if ((fd
= fdopen(dup(outfd
), "w")) == NULL
) {
989 fprintf(stderr
, "edquota: ");
993 fprintf(fd
, "Time units may be: days, hours, minutes, or seconds\n");
994 fprintf(fd
, "Grace period before enforcing soft limits for %ss:\n",
995 qfextension
[quotatype
]);
996 for (qup
= quplist
; qup
; qup
= qup
->next
) {
997 fprintf(fd
, "%s: block grace period: %s, ",
998 qup
->fsname
, cvtstoa(qup
->dqblk
.dqb_btime
));
999 fprintf(fd
, "file grace period: %s\n",
1000 cvtstoa(qup
->dqblk
.dqb_itime
));
1007 * Merge changes of grace times in an ASCII file into a quotause list.
1010 readtimes(quplist
, infd
)
1011 struct quotause
*quplist
;
1014 register struct quotause
*qup
;
1018 time_t itime
, btime
, iseconds
, bseconds
;
1019 char *fsp
, bunits
[10], iunits
[10], line1
[BUFSIZ
];
1021 lseek(infd
, 0, L_SET
);
1022 fd
= fdopen(dup(infd
), "r");
1024 fprintf(stderr
, "Can't re-read temp file!!\n");
1028 * Discard two title lines, then read lines to process.
1030 (void) fgets(line1
, sizeof (line1
), fd
);
1031 (void) fgets(line1
, sizeof (line1
), fd
);
1032 while (fgets(line1
, sizeof (line1
), fd
) != NULL
) {
1033 if ((fsp
= strtok(line1
, " \t:")) == NULL
) {
1034 fprintf(stderr
, "%s: bad format\n", line1
);
1037 if ((cp
= strtok((char *)0, "\n")) == NULL
) {
1038 fprintf(stderr
, "%s: %s: bad format\n", fsp
,
1039 &fsp
[strlen(fsp
) + 1]);
1043 " block grace period: %ld %s file grace period: %ld %s",
1044 &btime
, bunits
, &itime
, iunits
);
1046 fprintf(stderr
, "%s:%s: bad format\n", fsp
, cp
);
1049 if (cvtatos(btime
, bunits
, &bseconds
) == 0)
1051 if (cvtatos(itime
, iunits
, &iseconds
) == 0)
1053 for (qup
= quplist
; qup
; qup
= qup
->next
) {
1054 if (strcmp(fsp
, qup
->fsname
))
1056 qup
->dqblk
.dqb_btime
= (uint32_t) bseconds
;
1057 qup
->dqblk
.dqb_itime
= (uint32_t) iseconds
;
1058 qup
->flags
|= FOUND
;
1064 * reset default grace periods for any filesystems
1065 * that have not been found.
1067 for (qup
= quplist
; qup
; qup
= qup
->next
) {
1068 if (qup
->flags
& FOUND
) {
1069 qup
->flags
&= ~FOUND
;
1072 qup
->dqblk
.dqb_btime
= 0;
1073 qup
->dqblk
.dqb_itime
= 0;
1079 * Convert seconds to ASCII times.
1085 static char buf
[20];
1087 if (time
% (24 * 60 * 60) == 0) {
1088 time
/= 24 * 60 * 60;
1089 snprintf(buf
, sizeof(buf
), "%d day%s", (int)time
, time
== 1 ? "" : "s");
1090 } else if (time
% (60 * 60) == 0) {
1092 snprintf(buf
, sizeof(buf
), "%d hour%s", (int)time
, time
== 1 ? "" : "s");
1093 } else if (time
% 60 == 0) {
1095 snprintf(buf
, sizeof(buf
), "%d minute%s", (int)time
, time
== 1 ? "" : "s");
1097 snprintf(buf
, sizeof(buf
), "%d second%s", (int)time
, time
== 1 ? "" : "s");
1102 * Convert ASCII input times to seconds.
1105 cvtatos(time
, units
, seconds
)
1111 if (bcmp(units
, "second", 6) == 0)
1113 else if (bcmp(units
, "minute", 6) == 0)
1114 *seconds
= time
* 60;
1115 else if (bcmp(units
, "hour", 4) == 0)
1116 *seconds
= time
* 60 * 60;
1117 else if (bcmp(units
, "day", 3) == 0)
1118 *seconds
= time
* 24 * 60 * 60;
1120 printf("%s: bad units, specify %s\n", units
,
1121 "days, hours, minutes, or seconds");
1128 * Free a list of quotause structures.
1132 struct quotause
*quplist
;
1134 register struct quotause
*qup
, *nextqup
;
1136 for (qup
= quplist
; qup
; qup
= nextqup
) {
1137 nextqup
= qup
->next
;
1143 * Check whether a string is completely composed of digits.
1155 } while ((c
= *s
++));
1160 * Check to see if a particular quota is to be enabled.
1164 hasquota(fst
, type
, qfnamep
)
1165 register struct statfs
*fst
;
1170 static char initname
, usrname
[100], grpname
[100];
1171 static char buf
[BUFSIZ
];
1174 snprintf(usrname
, sizeof(usrname
), "%s%s", qfextension
[USRQUOTA
], qfname
);
1175 snprintf(grpname
, sizeof(grpname
), "%s%s", qfextension
[GRPQUOTA
], qfname
);
1180 We only support the default path to the
1181 on disk quota files.
1184 (void)snprintf(buf
, sizeof(buf
), "%s/%s.%s", fst
->f_mntonname
,
1185 QUOTAOPSNAME
, qfextension
[type
] );
1186 if (stat(buf
, &sb
) != 0) {
1187 /* There appears to be no mount option file */
1191 (void) snprintf(buf
, sizeof(buf
), "%s/%s.%s", fst
->f_mntonname
, qfname
, qfextension
[type
]);
1196 hasquota(fs
, type
, qfnamep
)
1197 register struct fstab
*fs
;
1202 char *cp
, *index(), *strtok();
1203 static char initname
, usrname
[100], grpname
[100];
1204 static char buf
[BUFSIZ
];
1207 snprintf(usrname
, sizeof(usrname
), "%s%s", qfextension
[USRQUOTA
], qfname
);
1208 snprintf(grpname
, sizeof(grpname
), "%s%s", qfextension
[GRPQUOTA
], qfname
);
1211 strlcpy(buf
, fs
->fs_mntops
, sizeof(buf
));
1212 for (opt
= strtok(buf
, ","); opt
; opt
= strtok(NULL
, ",")) {
1213 if (cp
= index(opt
, '='))
1215 if (type
== USRQUOTA
&& strcmp(opt
, usrname
) == 0)
1217 if (type
== GRPQUOTA
&& strcmp(opt
, grpname
) == 0)
1226 (void) snprintf(buf
, sizeof(buf
), "%s/%s.%s", fs
->fs_file
, qfname
, qfextension
[type
]);
1230 #endif /* __APPLE */