diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
commit | f9ab90d9d6d02989a075d0f0074496d5b1045e4b (patch) | |
tree | add7e996bac5289cdc55e6935750c352505560a9 /usr.bin/quota | |
parent | be22b15ae2ff8d7fe06b6e14fddf0c5b444a95da (diff) | |
download | FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.zip FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.tar.gz |
BSD 4.4 Lite Usr.bin Sources
Diffstat (limited to 'usr.bin/quota')
-rw-r--r-- | usr.bin/quota/Makefile | 7 | ||||
-rw-r--r-- | usr.bin/quota/quota.1 | 131 | ||||
-rw-r--r-- | usr.bin/quota/quota.c | 510 |
3 files changed, 648 insertions, 0 deletions
diff --git a/usr.bin/quota/Makefile b/usr.bin/quota/Makefile new file mode 100644 index 0000000..2ee365e --- /dev/null +++ b/usr.bin/quota/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= quota +BINOWN= root +BINMODE=4555 + +.include <bsd.prog.mk> diff --git a/usr.bin/quota/quota.1 b/usr.bin/quota/quota.1 new file mode 100644 index 0000000..e87a3a4 --- /dev/null +++ b/usr.bin/quota/quota.1 @@ -0,0 +1,131 @@ +.\" Copyright (c) 1983, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Robert Elz at The University of Melbourne. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)quota.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt QUOTA 1 +.Os BSD 4.2 +.Sh NAME +.Nm quota +.Nd display disk usage and limits +.Sh SYNOPSIS +.Nm quota +.Op Fl g +.Op Fl u +.Op Fl v | Fl q +.Nm quota +.Op Fl u +.Op Fl v | Fl q +.Ar user +.Nm quota +.Op Fl g +.Op Fl v | Fl q +.Ar group +.Sh DESCRIPTION +.Nm Quota +displays users' disk usage and limits. +By default only the user quotas are printed. +.Pp +Options: +.Pp +.Bl -tag -width Ds +.It Fl g +Print group quotas for the group +of which the user is a member. +The optional +.Fl u +flag is equivalent to the default. +.It Fl v +.Nm quota +will display quotas on filesystems +where no storage is allocated. +.It Fl q +Print a more terse message, +containing only information +on filesystems where usage is over quota. +.El +.Pp +Specifying both +.Fl g +and +.Fl u +displays both the user quotas and the group quotas (for +the user). +.Pp +Only the super-user may use the +.Fl u +flag and the optional +.Ar user +argument to view the limits of other users. +Non-super-users can use the the +.Fl g +flag and optional +.Ar group +argument to view only the limits of groups of which they are members. +.Pp +The +.Fl q +flag takes precedence over the +.Fl v +flag. +.Pp +.Nm Quota +reports the quotas of all the filesystems listed in +.Pa /etc/fstab . +If +.Nm quota +exits with a non-zero status, one or more filesystems +are over quota. +.Sh FILES +.Bl -tag -width quota.group -compact +.It Pa quota.user +located at the filesystem root with user quotas +.It Pa quota.group +located at the filesystem root with group quotas +.It Pa /etc/fstab +to find filesystem names and locations +.El +.Sh HISTORY +The +.Nm quota +command appeared in +.Bx 4.2 . +.Sh SEE ALSO +.Xr quotactl 2 , +.Xr fstab 5 , +.Xr edquota 8 , +.Xr quotacheck 8 , +.Xr quotaon 8 , +.Xr repquota 8 diff --git a/usr.bin/quota/quota.c b/usr.bin/quota/quota.c new file mode 100644 index 0000000..1d18a13 --- /dev/null +++ b/usr.bin/quota/quota.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 1980, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)quota.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Disk quota reporting program. + */ +#include <sys/param.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <ufs/ufs/quota.h> +#include <stdio.h> +#include <fstab.h> +#include <ctype.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> + +char *qfname = QUOTAFILENAME; +char *qfextension[] = INITQFNAMES; + +struct quotause { + struct quotause *next; + long flags; + struct dqblk dqblk; + char fsname[MAXPATHLEN + 1]; +} *getprivs(); +#define FOUND 0x01 + +int qflag; +int vflag; + +main(argc, argv) + char *argv[]; +{ + int ngroups, gidset[NGROUPS]; + int i, gflag = 0, uflag = 0; + char ch; + extern char *optarg; + extern int optind, errno; + + if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == EOPNOTSUPP) { + fprintf(stderr, "There are no quotas on this system\n"); + exit(0); + } + while ((ch = getopt(argc, argv, "ugvq")) != EOF) { + switch(ch) { + case 'g': + gflag++; + break; + case 'u': + uflag++; + break; + case 'v': + vflag++; + break; + case 'q': + qflag++; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (!uflag && !gflag) + uflag++; + if (argc == 0) { + if (uflag) + showuid(getuid()); + if (gflag) { + ngroups = getgroups(NGROUPS, gidset); + if (ngroups < 0) { + perror("quota: getgroups"); + exit(1); + } + for (i = 1; i < ngroups; i++) + showgid(gidset[i]); + } + exit(0); + } + if (uflag && gflag) + usage(); + if (uflag) { + for (; argc > 0; argc--, argv++) { + if (alldigits(*argv)) + showuid(atoi(*argv)); + else + showusrname(*argv); + } + exit(0); + } + if (gflag) { + for (; argc > 0; argc--, argv++) { + if (alldigits(*argv)) + showgid(atoi(*argv)); + else + showgrpname(*argv); + } + exit(0); + } +} + +usage() +{ + + fprintf(stderr, "%s\n%s\n%s\n", + "Usage: quota [-guqv]", + "\tquota [-qv] -u username ...", + "\tquota [-qv] -g groupname ..."); + exit(1); +} + +/* + * Print out quotas for a specified user identifier. + */ +showuid(uid) + u_long uid; +{ + struct passwd *pwd = getpwuid(uid); + u_long myuid; + char *name; + + if (pwd == NULL) + name = "(no account)"; + else + name = pwd->pw_name; + myuid = getuid(); + if (uid != myuid && myuid != 0) { + printf("quota: %s (uid %d): permission denied\n", name, uid); + return; + } + showquotas(USRQUOTA, uid, name); +} + +/* + * Print out quotas for a specifed user name. + */ +showusrname(name) + char *name; +{ + struct passwd *pwd = getpwnam(name); + u_long myuid; + + if (pwd == NULL) { + fprintf(stderr, "quota: %s: unknown user\n", name); + return; + } + myuid = getuid(); + if (pwd->pw_uid != myuid && myuid != 0) { + fprintf(stderr, "quota: %s (uid %d): permission denied\n", + name, pwd->pw_uid); + return; + } + showquotas(USRQUOTA, pwd->pw_uid, name); +} + +/* + * Print out quotas for a specified group identifier. + */ +showgid(gid) + u_long gid; +{ + struct group *grp = getgrgid(gid); + int ngroups, gidset[NGROUPS]; + register int i; + char *name; + + if (grp == NULL) + name = "(no entry)"; + else + name = grp->gr_name; + ngroups = getgroups(NGROUPS, gidset); + if (ngroups < 0) { + perror("quota: getgroups"); + return; + } + for (i = 1; i < ngroups; i++) + if (gid == gidset[i]) + break; + if (i >= ngroups && getuid() != 0) { + fprintf(stderr, "quota: %s (gid %d): permission denied\n", + name, gid); + return; + } + showquotas(GRPQUOTA, gid, name); +} + +/* + * Print out quotas for a specifed group name. + */ +showgrpname(name) + char *name; +{ + struct group *grp = getgrnam(name); + int ngroups, gidset[NGROUPS]; + register int i; + + if (grp == NULL) { + fprintf(stderr, "quota: %s: unknown group\n", name); + return; + } + ngroups = getgroups(NGROUPS, gidset); + if (ngroups < 0) { + perror("quota: getgroups"); + return; + } + for (i = 1; i < ngroups; i++) + if (grp->gr_gid == gidset[i]) + break; + if (i >= ngroups && getuid() != 0) { + fprintf(stderr, "quota: %s (gid %d): permission denied\n", + name, grp->gr_gid); + return; + } + showquotas(GRPQUOTA, grp->gr_gid, name); +} + +showquotas(type, id, name) + int type; + u_long id; + char *name; +{ + register struct quotause *qup; + struct quotause *quplist, *getprivs(); + char *msgi, *msgb, *timeprt(); + int myuid, fd, lines = 0; + static int first; + static time_t now; + + if (now == 0) + time(&now); + quplist = getprivs(id, type); + for (qup = quplist; qup; qup = qup->next) { + if (!vflag && + qup->dqblk.dqb_isoftlimit == 0 && + qup->dqblk.dqb_ihardlimit == 0 && + qup->dqblk.dqb_bsoftlimit == 0 && + qup->dqblk.dqb_bhardlimit == 0) + continue; + msgi = (char *)0; + if (qup->dqblk.dqb_ihardlimit && + qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) + msgi = "File limit reached on"; + else if (qup->dqblk.dqb_isoftlimit && + qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) + if (qup->dqblk.dqb_itime > now) + msgi = "In file grace period on"; + else + msgi = "Over file quota on"; + msgb = (char *)0; + if (qup->dqblk.dqb_bhardlimit && + qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) + msgb = "Block limit reached on"; + else if (qup->dqblk.dqb_bsoftlimit && + qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) + if (qup->dqblk.dqb_btime > now) + msgb = "In block grace period on"; + else + msgb = "Over block quota on"; + if (qflag) { + if ((msgi != (char *)0 || msgb != (char *)0) && + lines++ == 0) + heading(type, id, name, ""); + if (msgi != (char *)0) + printf("\t%s %s\n", msgi, qup->fsname); + if (msgb != (char *)0) + printf("\t%s %s\n", msgb, qup->fsname); + continue; + } + if (vflag || + qup->dqblk.dqb_curblocks || + qup->dqblk.dqb_curinodes) { + if (lines++ == 0) + heading(type, id, name, ""); + printf("%15s%8d%c%7d%8d%8s" + , qup->fsname + , dbtob(qup->dqblk.dqb_curblocks) / 1024 + , (msgb == (char *)0) ? ' ' : '*' + , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024 + , dbtob(qup->dqblk.dqb_bhardlimit) / 1024 + , (msgb == (char *)0) ? "" + : timeprt(qup->dqblk.dqb_btime)); + printf("%8d%c%7d%8d%8s\n" + , qup->dqblk.dqb_curinodes + , (msgi == (char *)0) ? ' ' : '*' + , qup->dqblk.dqb_isoftlimit + , qup->dqblk.dqb_ihardlimit + , (msgi == (char *)0) ? "" + : timeprt(qup->dqblk.dqb_itime) + ); + continue; + } + } + if (!qflag && lines == 0) + heading(type, id, name, "none"); +} + +heading(type, id, name, tag) + int type; + u_long id; + char *name, *tag; +{ + + printf("Disk quotas for %s %s (%cid %d): %s\n", qfextension[type], + name, *qfextension[type], id, tag); + if (!qflag && tag[0] == '\0') { + printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n" + , "Filesystem" + , "blocks" + , "quota" + , "limit" + , "grace" + , "files" + , "quota" + , "limit" + , "grace" + ); + } +} + +/* + * Calculate the grace period and return a printable string for it. + */ +char * +timeprt(seconds) + time_t seconds; +{ + time_t hours, minutes; + static char buf[20]; + static time_t now; + + if (now == 0) + time(&now); + if (now > seconds) + return ("none"); + seconds -= now; + minutes = (seconds + 30) / 60; + hours = (minutes + 30) / 60; + if (hours >= 36) { + sprintf(buf, "%ddays", (hours + 12) / 24); + return (buf); + } + if (minutes >= 60) { + sprintf(buf, "%2d:%d", minutes / 60, minutes % 60); + return (buf); + } + sprintf(buf, "%2d", minutes); + return (buf); +} + +/* + * Collect the requested quota information. + */ +struct quotause * +getprivs(id, quotatype) + register long id; + int quotatype; +{ + register struct fstab *fs; + register struct quotause *qup, *quptail; + struct quotause *quphead; + char *qfpathname; + int qcmd, fd; + + setfsent(); + quphead = (struct quotause *)0; + qcmd = QCMD(Q_GETQUOTA, quotatype); + while (fs = getfsent()) { + if (strcmp(fs->fs_vfstype, "ufs")) + continue; + if (!hasquota(fs, quotatype, &qfpathname)) + continue; + if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) { + fprintf(stderr, "quota: out of memory\n"); + exit(2); + } + if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { + if ((fd = open(qfpathname, O_RDONLY)) < 0) { + perror(qfpathname); + free(qup); + continue; + } + lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET); + switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { + case 0: /* EOF */ + /* + * Convert implicit 0 quota (EOF) + * into an explicit one (zero'ed dqblk) + */ + bzero((caddr_t)&qup->dqblk, + sizeof(struct dqblk)); + break; + + case sizeof(struct dqblk): /* OK */ + break; + + default: /* ERROR */ + fprintf(stderr, "quota: read error"); + perror(qfpathname); + close(fd); + free(qup); + continue; + } + close(fd); + } + strcpy(qup->fsname, fs->fs_file); + if (quphead == NULL) + quphead = qup; + else + quptail->next = qup; + quptail = qup; + qup->next = 0; + } + endfsent(); + return (quphead); +} + +/* + * Check to see if a particular quota is to be enabled. + */ +hasquota(fs, type, qfnamep) + register struct fstab *fs; + int type; + char **qfnamep; +{ + register char *opt; + char *cp, *index(), *strtok(); + static char initname, usrname[100], grpname[100]; + static char buf[BUFSIZ]; + + if (!initname) { + sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); + sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); + initname = 1; + } + strcpy(buf, fs->fs_mntops); + for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { + if (cp = index(opt, '=')) + *cp++ = '\0'; + if (type == USRQUOTA && strcmp(opt, usrname) == 0) + break; + if (type == GRPQUOTA && strcmp(opt, grpname) == 0) + break; + } + if (!opt) + return (0); + if (cp) { + *qfnamep = cp; + return (1); + } + (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); + *qfnamep = buf; + return (1); +} + +alldigits(s) + register char *s; +{ + register c; + + c = *s++; + do { + if (!isdigit(c)) + return (0); + } while (c = *s++); + return (1); +} |