Update the quotafile library to manage both active quotas via the
quotactl(2) interface and inactive quotas by accessing the quota files directly. Update the edquota program to use this new interface as proof of concept.
This commit is contained in:
parent
a88984f248
commit
8bd6a3ab4b
@ -143,12 +143,11 @@ int pidfile_remove(struct pidfh *pfh);
|
||||
#ifdef _UFS_UFS_QUOTA_H_
|
||||
struct quotafile;
|
||||
struct fstab;
|
||||
struct quotafile *quota_open(const char *);
|
||||
struct quotafile *quota_create(const char *);
|
||||
struct quotafile *quota_open(struct fstab *, int, int);
|
||||
void quota_close(struct quotafile *);
|
||||
int quota_read(struct quotafile *, struct dqblk *, int);
|
||||
int quota_write(struct quotafile *, const struct dqblk *, int);
|
||||
int hasquota(struct fstab *, int, char *, int);
|
||||
int quota_write_limits(struct quotafile *, struct dqblk *, int);
|
||||
int quota_write_usage(struct quotafile *, struct dqblk *, int);
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
@ -25,35 +25,132 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 4, 2008
|
||||
.Dd February 14, 2009
|
||||
.Dt QUOTAFILE 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm quota_open
|
||||
.Nm quota_create
|
||||
.Nm quota_read
|
||||
.Nm quota_write
|
||||
.Nm quota_write_limits
|
||||
.Nm quota_write_usage
|
||||
.Nm quota_close
|
||||
.Nd "Manipulate quota files"
|
||||
.Nd "Manipulate quotas"
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In ufs/ufs/quota.h
|
||||
.In libutil.h
|
||||
.In fstab.h
|
||||
.Ft "struct quotafile *"
|
||||
.Fn quota_open "const char *path"
|
||||
.Ft "struct quotafile *"
|
||||
.Fn quota_create "const char *path"
|
||||
.Fn quota_open "struct fstab *fs" "int quotatype" "int openflags"
|
||||
.Ft int
|
||||
.Fn quota_read "struct quotafile *qf" "struct dqblk *dqb" "int id"
|
||||
.Ft int
|
||||
.Fn quota_write "struct quotafile *qf" "const struct dqblk *dqb" "int id"
|
||||
.Fn quota_write_limits "struct quotafile *qf" "struct dqblk *dqb" "int id"
|
||||
.Ft int
|
||||
.Fn quota_write_usage "struct quotafile *qf" "struct dqblk *dqb" "int id"
|
||||
.Ft int
|
||||
.Fn quota_close "struct quotafile *qf"
|
||||
.Ft int
|
||||
.Fn hasquota "struct fstab *fs" "int type" "char **qfnamep"
|
||||
.Sh DESCRIPTION
|
||||
These functions are designed to simplify access to filesystem quotas.
|
||||
If quotas are active on a filesystem,
|
||||
these functions will access them directly from the kernel using the
|
||||
.Fn quotactl
|
||||
system call.
|
||||
If quotas are not active,
|
||||
these functions will access them by reading and writing
|
||||
the quota files directly.
|
||||
.Pp
|
||||
The
|
||||
.Fn quota_open
|
||||
function takes a pointer to an
|
||||
.Vt fstab
|
||||
entry corresponding to the filesystem on which quotas
|
||||
are to be accessed.
|
||||
The
|
||||
.Va quotatype
|
||||
field indicates the type of quotas being sought, either
|
||||
.Dv USRQUOTA
|
||||
or
|
||||
.Dv GRPQUOTA .
|
||||
The
|
||||
.Va openflags
|
||||
are those used by the
|
||||
.Fn open
|
||||
system call, usually either
|
||||
.Dv O_RDONLY
|
||||
if the quotas are just to be read, or
|
||||
.Dv O_RDWR
|
||||
if the quotas are to be updated.
|
||||
The
|
||||
.Dv O_CREAT
|
||||
flag should be specified if a new quota file of the requested type should
|
||||
be created if it does not already exist.
|
||||
.Pp
|
||||
The
|
||||
.Fn quota_read
|
||||
function reads the quota from the filesystem and quota type referenced by
|
||||
.Va qf
|
||||
for the user (or group) specified by
|
||||
.Va id
|
||||
into the
|
||||
.Vt dqblk
|
||||
quota structure pointed to by
|
||||
.Va dqb .
|
||||
.Pp
|
||||
The
|
||||
.Fn quota_write_limits
|
||||
function updates the limit fields (but not the usage fields)
|
||||
for the filesystem and quota type referenced by
|
||||
.Va qf
|
||||
for the user (or group) specified by
|
||||
.Va id
|
||||
from the
|
||||
.Vt dqblk
|
||||
quota structure pointed to by
|
||||
.Va dqb .
|
||||
.Pp
|
||||
The
|
||||
.Fn quota_write_usage
|
||||
function updates the usage fields (but not the limit fields)
|
||||
for the filesystem and quota type referenced by
|
||||
.Va qf
|
||||
for the user (or group) specified by
|
||||
.Va id
|
||||
from the
|
||||
.Vt dqblk
|
||||
quota structure pointed to by
|
||||
.Va dqb .
|
||||
.Pp
|
||||
The
|
||||
.Fn quota_close
|
||||
function closes any open file descriptors and frees any storage
|
||||
associated with the filesystem and quota type referenced by
|
||||
.Va qf .
|
||||
.Sh RETURN VALUES
|
||||
If the filesystem has quotas associated with it,
|
||||
.Fn quota_open
|
||||
returns a pointer to a
|
||||
.Vt quotafile
|
||||
structure used in subsequent quota access calls.
|
||||
If the filesystem has no quotas, or access permission is denied
|
||||
.Dv NULL
|
||||
is returned and
|
||||
.Va errno
|
||||
is set to indicate the cause of failure.
|
||||
.Pp
|
||||
The
|
||||
.Fn quota_read ,
|
||||
.Fn quota_write_limits ,
|
||||
.Fn quota_write_usage ,
|
||||
and
|
||||
.Fn quota_close
|
||||
functions return zero on success.
|
||||
On error they return
|
||||
.Dv -1
|
||||
and set
|
||||
.Va errno
|
||||
to indicate the cause of failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr quotactl 2 ,
|
||||
.Xr quota.user 5 ,
|
||||
@ -68,4 +165,6 @@ functions first appeared in
|
||||
The
|
||||
.Nm
|
||||
functions and this manual page were written by
|
||||
.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org .
|
||||
.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org
|
||||
and
|
||||
.An Marshall Kirk McKusick .
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*-
|
||||
* Copyright (c) 2008 Dag-Erling Coïdan Smørgrav
|
||||
* Copyright (c) 2008 Marshall Kirk McKusick
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -47,76 +48,132 @@
|
||||
#include <unistd.h>
|
||||
|
||||
struct quotafile {
|
||||
int fd;
|
||||
int type; /* 32 or 64 */
|
||||
int fd; /* -1 means using quotactl for access */
|
||||
int wordsize; /* 32-bit or 64-bit limits */
|
||||
int quotatype; /* USRQUOTA or GRPQUOTA */
|
||||
char fsname[MAXPATHLEN + 1]; /* mount point of filesystem */
|
||||
char qfname[MAXPATHLEN + 1]; /* quota file if not using quotactl */
|
||||
};
|
||||
|
||||
static const char *qfextension[] = INITQFNAMES;
|
||||
|
||||
struct quotafile *
|
||||
quota_open(const char *fn)
|
||||
/*
|
||||
* Check to see if a particular quota is to be enabled.
|
||||
*/
|
||||
static int
|
||||
hasquota(struct fstab *fs, int type, char *qfnamep, int qfbufsize)
|
||||
{
|
||||
struct quotafile *qf;
|
||||
struct dqhdr64 dqh;
|
||||
int serrno;
|
||||
char *opt;
|
||||
char *cp;
|
||||
struct statfs sfb;
|
||||
char buf[BUFSIZ];
|
||||
static char initname, usrname[100], grpname[100];
|
||||
|
||||
if ((qf = calloc(1, sizeof(*qf))) == NULL)
|
||||
return (NULL);
|
||||
if ((qf->fd = open(fn, O_RDWR)) < 0) {
|
||||
serrno = errno;
|
||||
free(qf);
|
||||
errno = serrno;
|
||||
return (NULL);
|
||||
if (!initname) {
|
||||
(void)snprintf(usrname, sizeof(usrname), "%s%s",
|
||||
qfextension[USRQUOTA], QUOTAFILENAME);
|
||||
(void)snprintf(grpname, sizeof(grpname), "%s%s",
|
||||
qfextension[GRPQUOTA], QUOTAFILENAME);
|
||||
initname = 1;
|
||||
}
|
||||
qf->type = 32;
|
||||
switch (read(qf->fd, &dqh, sizeof(dqh))) {
|
||||
case -1:
|
||||
serrno = errno;
|
||||
close(qf->fd);
|
||||
free(qf);
|
||||
errno = serrno;
|
||||
return (NULL);
|
||||
case sizeof(dqh):
|
||||
if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) {
|
||||
/* no magic, assume 32 bits */
|
||||
qf->type = 32;
|
||||
return (qf);
|
||||
}
|
||||
if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION ||
|
||||
be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) ||
|
||||
be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) {
|
||||
/* correct magic, wrong version / lengths */
|
||||
close(qf->fd);
|
||||
free(qf);
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
qf->type = 64;
|
||||
return (qf);
|
||||
default:
|
||||
qf->type = 32;
|
||||
return (qf);
|
||||
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;
|
||||
}
|
||||
/* not reached */
|
||||
if (!opt)
|
||||
return (0);
|
||||
/*
|
||||
* Ensure that the filesystem is mounted.
|
||||
*/
|
||||
if (statfs(fs->fs_file, &sfb) != 0 ||
|
||||
strcmp(fs->fs_file, sfb.f_mntonname)) {
|
||||
return (0);
|
||||
}
|
||||
if (cp) {
|
||||
strncpy(qfnamep, cp, qfbufsize);
|
||||
} else {
|
||||
(void)snprintf(qfnamep, qfbufsize, "%s/%s.%s", fs->fs_file,
|
||||
QUOTAFILENAME, qfextension[type]);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
struct quotafile *
|
||||
quota_create(const char *fn)
|
||||
quota_open(struct fstab *fs, int quotatype, int openflags)
|
||||
{
|
||||
struct quotafile *qf;
|
||||
struct dqhdr64 dqh;
|
||||
struct group *grp;
|
||||
int serrno;
|
||||
int qcmd, serrno;
|
||||
|
||||
if ((qf = calloc(1, sizeof(*qf))) == NULL)
|
||||
return (NULL);
|
||||
if ((qf->fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
|
||||
qf->quotatype = quotatype;
|
||||
strncpy(qf->fsname, fs->fs_file, sizeof(qf->fsname));
|
||||
qcmd = QCMD(Q_GETQUOTA, quotatype);
|
||||
if (quotactl(fs->fs_file, qcmd, 0, &dqh) == 0) {
|
||||
qf->wordsize = 64;
|
||||
qf->fd = -1;
|
||||
return (qf);
|
||||
}
|
||||
if (!hasquota(fs, quotatype, qf->qfname, sizeof(qf->qfname))) {
|
||||
free(qf);
|
||||
errno = EOPNOTSUPP;
|
||||
return (NULL);
|
||||
}
|
||||
if ((qf->fd = open(qf->qfname, openflags & O_ACCMODE)) < 0 &&
|
||||
(openflags & O_CREAT) == 0) {
|
||||
serrno = errno;
|
||||
free(qf);
|
||||
errno = serrno;
|
||||
return (NULL);
|
||||
}
|
||||
qf->type = 64;
|
||||
/* File open worked, so process it */
|
||||
if (qf->fd != -1) {
|
||||
qf->wordsize = 32;
|
||||
switch (read(qf->fd, &dqh, sizeof(dqh))) {
|
||||
case -1:
|
||||
serrno = errno;
|
||||
close(qf->fd);
|
||||
free(qf);
|
||||
errno = serrno;
|
||||
return (NULL);
|
||||
case sizeof(dqh):
|
||||
if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) {
|
||||
/* no magic, assume 32 bits */
|
||||
qf->wordsize = 32;
|
||||
return (qf);
|
||||
}
|
||||
if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION ||
|
||||
be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) ||
|
||||
be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) {
|
||||
/* correct magic, wrong version / lengths */
|
||||
close(qf->fd);
|
||||
free(qf);
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
qf->wordsize = 64;
|
||||
return (qf);
|
||||
default:
|
||||
qf->wordsize = 32;
|
||||
return (qf);
|
||||
}
|
||||
/* not reached */
|
||||
}
|
||||
/* Open failed above, but O_CREAT specified, so create a new file */
|
||||
if ((qf->fd = open(qf->qfname, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
|
||||
serrno = errno;
|
||||
free(qf);
|
||||
errno = serrno;
|
||||
return (NULL);
|
||||
}
|
||||
qf->wordsize = 64;
|
||||
memset(&dqh, 0, sizeof(dqh));
|
||||
memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
|
||||
dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
|
||||
@ -124,7 +181,7 @@ quota_create(const char *fn)
|
||||
dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
|
||||
if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
|
||||
serrno = errno;
|
||||
unlink(fn);
|
||||
unlink(qf->qfname);
|
||||
close(qf->fd);
|
||||
free(qf);
|
||||
errno = serrno;
|
||||
@ -140,7 +197,8 @@ void
|
||||
quota_close(struct quotafile *qf)
|
||||
{
|
||||
|
||||
close(qf->fd);
|
||||
if (qf->fd != -1)
|
||||
close(qf->fd);
|
||||
free(qf);
|
||||
}
|
||||
|
||||
@ -203,8 +261,13 @@ quota_read64(struct quotafile *qf, struct dqblk *dqb, int id)
|
||||
int
|
||||
quota_read(struct quotafile *qf, struct dqblk *dqb, int id)
|
||||
{
|
||||
int qcmd;
|
||||
|
||||
switch (qf->type) {
|
||||
if (qf->fd == -1) {
|
||||
qcmd = QCMD(Q_GETQUOTA, qf->quotatype);
|
||||
return (quotactl(qf->fsname, qcmd, id, dqb));
|
||||
}
|
||||
switch (qf->wordsize) {
|
||||
case 32:
|
||||
return quota_read32(qf, dqb, id);
|
||||
case 64:
|
||||
@ -236,7 +299,9 @@ quota_write32(struct quotafile *qf, const struct dqblk *dqb, int id)
|
||||
off = id * sizeof(struct dqblk32);
|
||||
if (lseek(qf->fd, off, SEEK_SET) == -1)
|
||||
return (-1);
|
||||
return (write(qf->fd, &dqb32, sizeof(dqb32)) == sizeof(dqb32));
|
||||
if (write(qf->fd, &dqb32, sizeof(dqb32)) == sizeof(dqb32))
|
||||
return (0);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -257,14 +322,98 @@ quota_write64(struct quotafile *qf, const struct dqblk *dqb, int id)
|
||||
off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64);
|
||||
if (lseek(qf->fd, off, SEEK_SET) == -1)
|
||||
return (-1);
|
||||
return (write(qf->fd, &dqb64, sizeof(dqb64)) == sizeof(dqb64));
|
||||
if (write(qf->fd, &dqb64, sizeof(dqb64)) == sizeof(dqb64))
|
||||
return (0);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
quota_write(struct quotafile *qf, const struct dqblk *dqb, int id)
|
||||
quota_write_usage(struct quotafile *qf, struct dqblk *dqb, int id)
|
||||
{
|
||||
struct dqblk dqbuf;
|
||||
int qcmd;
|
||||
|
||||
switch (qf->type) {
|
||||
if (qf->fd == -1) {
|
||||
qcmd = QCMD(Q_SETUSE, qf->quotatype);
|
||||
return (quotactl(qf->fsname, qcmd, id, dqb));
|
||||
}
|
||||
/*
|
||||
* Have to do read-modify-write of quota in file.
|
||||
*/
|
||||
if (quota_read(qf, &dqbuf, id) != 0)
|
||||
return (-1);
|
||||
/*
|
||||
* Reset time limit if have a soft limit and were
|
||||
* previously under it, but are now over it.
|
||||
*/
|
||||
if (dqbuf.dqb_bsoftlimit && id != 0 &&
|
||||
dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
|
||||
dqb->dqb_curblocks >= dqbuf.dqb_bsoftlimit)
|
||||
dqbuf.dqb_btime = 0;
|
||||
if (dqbuf.dqb_isoftlimit && id != 0 &&
|
||||
dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit &&
|
||||
dqb->dqb_curinodes >= dqbuf.dqb_isoftlimit)
|
||||
dqbuf.dqb_itime = 0;
|
||||
dqbuf.dqb_curinodes = dqb->dqb_curinodes;
|
||||
dqbuf.dqb_curblocks = dqb->dqb_curblocks;
|
||||
/*
|
||||
* Write it back.
|
||||
*/
|
||||
switch (qf->wordsize) {
|
||||
case 32:
|
||||
return quota_write32(qf, &dqbuf, id);
|
||||
case 64:
|
||||
return quota_write64(qf, &dqbuf, id);
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
/* not reached */
|
||||
}
|
||||
|
||||
int
|
||||
quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id)
|
||||
{
|
||||
struct dqblk dqbuf;
|
||||
int qcmd;
|
||||
|
||||
if (qf->fd == -1) {
|
||||
qcmd = QCMD(Q_SETQUOTA, qf->quotatype);
|
||||
return (quotactl(qf->fsname, qcmd, id, dqb));
|
||||
}
|
||||
/*
|
||||
* Have to do read-modify-write of quota in file.
|
||||
*/
|
||||
if (quota_read(qf, &dqbuf, id) != 0)
|
||||
return (-1);
|
||||
/*
|
||||
* Reset time limit if have a soft limit and were
|
||||
* previously under it, but are now over it
|
||||
* or if there previously was no soft limit, but
|
||||
* now have one and are over it.
|
||||
*/
|
||||
if (dqbuf.dqb_bsoftlimit && id != 0 &&
|
||||
dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
|
||||
dqbuf.dqb_curblocks >= dqb->dqb_bsoftlimit)
|
||||
dqb->dqb_btime = 0;
|
||||
if (dqbuf.dqb_bsoftlimit == 0 && id != 0 &&
|
||||
dqb->dqb_bsoftlimit > 0 &&
|
||||
dqbuf.dqb_curblocks >= dqb->dqb_bsoftlimit)
|
||||
dqb->dqb_btime = 0;
|
||||
if (dqbuf.dqb_isoftlimit && id != 0 &&
|
||||
dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit &&
|
||||
dqbuf.dqb_curinodes >= dqb->dqb_isoftlimit)
|
||||
dqb->dqb_itime = 0;
|
||||
if (dqbuf.dqb_isoftlimit == 0 && id !=0 &&
|
||||
dqb->dqb_isoftlimit > 0 &&
|
||||
dqbuf.dqb_curinodes >= dqb->dqb_isoftlimit)
|
||||
dqb->dqb_itime = 0;
|
||||
dqb->dqb_curinodes = dqbuf.dqb_curinodes;
|
||||
dqb->dqb_curblocks = dqbuf.dqb_curblocks;
|
||||
/*
|
||||
* Write it back.
|
||||
*/
|
||||
switch (qf->wordsize) {
|
||||
case 32:
|
||||
return quota_write32(qf, dqb, id);
|
||||
case 64:
|
||||
@ -275,49 +424,3 @@ quota_write(struct quotafile *qf, const struct dqblk *dqb, int id)
|
||||
}
|
||||
/* not reached */
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if a particular quota is to be enabled.
|
||||
*/
|
||||
int
|
||||
hasquota(struct fstab *fs, int type, char *qfnamep, int qfbufsize)
|
||||
{
|
||||
char *opt;
|
||||
char *cp;
|
||||
struct statfs sfb;
|
||||
char buf[BUFSIZ];
|
||||
static char initname, usrname[100], grpname[100];
|
||||
|
||||
if (!initname) {
|
||||
(void)snprintf(usrname, sizeof(usrname), "%s%s",
|
||||
qfextension[USRQUOTA], QUOTAFILENAME);
|
||||
(void)snprintf(grpname, sizeof(grpname), "%s%s",
|
||||
qfextension[GRPQUOTA], QUOTAFILENAME);
|
||||
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);
|
||||
/*
|
||||
* Ensure that the filesystem is mounted.
|
||||
*/
|
||||
if (statfs(fs->fs_file, &sfb) != 0 ||
|
||||
strcmp(fs->fs_file, sfb.f_mntonname)) {
|
||||
return (0);
|
||||
}
|
||||
if (cp) {
|
||||
strncpy(qfnamep, cp, qfbufsize);
|
||||
} else {
|
||||
(void)snprintf(qfnamep, qfbufsize, "%s/%s.%s", fs->fs_file,
|
||||
QUOTAFILENAME, qfextension[type]);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
@ -84,16 +84,15 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
|
||||
const char *qfextension[] = INITQFNAMES;
|
||||
const char *quotagroup = QUOTAGROUP;
|
||||
char tmpfil[] = _PATH_TMP;
|
||||
int hflag;
|
||||
|
||||
struct quotause {
|
||||
struct quotause *next;
|
||||
long flags;
|
||||
struct quotafile *qf;
|
||||
struct dqblk dqblk;
|
||||
int flags;
|
||||
char fsname[MAXPATHLEN + 1];
|
||||
char qfname[1]; /* actually longer */
|
||||
};
|
||||
#define FOUND 0x01
|
||||
|
||||
@ -108,7 +107,7 @@ char *fmthumanvalinos(int64_t);
|
||||
void freeprivs(struct quotause *);
|
||||
int getentry(const char *, int);
|
||||
struct quotause *getprivs(long, int, char *);
|
||||
void putprivs(long, int, struct quotause *);
|
||||
void putprivs(long, struct quotause *);
|
||||
int readprivs(struct quotause *, char *);
|
||||
int readtimes(struct quotause *, char *);
|
||||
static void usage(void);
|
||||
@ -142,6 +141,11 @@ main(int argc, char *argv[])
|
||||
fspath = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
if (eflag) {
|
||||
warnx("cannot specify both -e and -p");
|
||||
usage();
|
||||
/* not reached */
|
||||
}
|
||||
protoname = optarg;
|
||||
pflag++;
|
||||
break;
|
||||
@ -158,7 +162,12 @@ main(int argc, char *argv[])
|
||||
tflag++;
|
||||
break;
|
||||
case 'e':
|
||||
if ((qup = calloc(1, sizeof(*qup) + BUFSIZ)) == NULL)
|
||||
if (pflag) {
|
||||
warnx("cannot specify both -e and -p");
|
||||
usage();
|
||||
/* not reached */
|
||||
}
|
||||
if ((qup = calloc(1, sizeof(*qup))) == NULL)
|
||||
errx(2, "out of memory");
|
||||
oldoptarg = optarg;
|
||||
for (i = 0, cp = optarg;
|
||||
@ -214,7 +223,6 @@ main(int argc, char *argv[])
|
||||
curprivs = qup;
|
||||
}
|
||||
eflag++;
|
||||
pflag++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
@ -223,8 +231,8 @@ main(int argc, char *argv[])
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (pflag) {
|
||||
if (protoprivs == NULL) {
|
||||
if (pflag || eflag) {
|
||||
if (pflag) {
|
||||
if ((protoid = getentry(protoname, quotatype)) == -1)
|
||||
exit(1);
|
||||
protoprivs = getprivs(protoid, quotatype, fspath);
|
||||
@ -259,22 +267,23 @@ main(int argc, char *argv[])
|
||||
*argv);
|
||||
if ((id = getentry(buf, quotatype)) < 0)
|
||||
continue;
|
||||
if (!eflag) {
|
||||
putprivs(id, quotatype, protoprivs);
|
||||
if (pflag) {
|
||||
putprivs(id, protoprivs);
|
||||
continue;
|
||||
}
|
||||
for (qup = protoprivs; qup;
|
||||
qup = qup->next) {
|
||||
for (qup = protoprivs; qup; qup = qup->next) {
|
||||
curprivs = getprivs(id, quotatype,
|
||||
qup->fsname);
|
||||
if (curprivs == NULL)
|
||||
continue;
|
||||
strcpy(qup->qfname, curprivs->qfname);
|
||||
strcpy(qup->fsname, curprivs->fsname);
|
||||
putprivs(id, quotatype, protoprivs);
|
||||
curprivs->dqblk = qup->dqblk;
|
||||
putprivs(id, curprivs);
|
||||
freeprivs(curprivs);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pflag)
|
||||
freeprivs(protoprivs);
|
||||
exit(0);
|
||||
}
|
||||
tmpfd = mkstemp(tmpfil);
|
||||
@ -283,7 +292,7 @@ main(int argc, char *argv[])
|
||||
if ((protoprivs = getprivs(0, quotatype, fspath)) != NULL) {
|
||||
if (writetimes(protoprivs, tmpfd, quotatype) != 0 &&
|
||||
editit(tmpfil) && readtimes(protoprivs, tmpfil))
|
||||
putprivs(0L, quotatype, protoprivs);
|
||||
putprivs(0L, protoprivs);
|
||||
freeprivs(protoprivs);
|
||||
}
|
||||
close(tmpfd);
|
||||
@ -298,7 +307,7 @@ main(int argc, char *argv[])
|
||||
if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0)
|
||||
continue;
|
||||
if (editit(tmpfil) && readprivs(curprivs, tmpfil))
|
||||
putprivs(id, quotatype, curprivs);
|
||||
putprivs(id, curprivs);
|
||||
freeprivs(curprivs);
|
||||
}
|
||||
close(tmpfd);
|
||||
@ -366,46 +375,29 @@ getprivs(long id, int quotatype, char *fspath)
|
||||
struct fstab *fs;
|
||||
struct quotause *qup, *quptail;
|
||||
struct quotause *quphead;
|
||||
int qcmd, qupsize;
|
||||
char *qfpathname;
|
||||
static int warned = 0;
|
||||
|
||||
setfsent();
|
||||
quphead = quptail = NULL;
|
||||
qcmd = QCMD(Q_GETQUOTA, quotatype);
|
||||
while ((fs = getfsent())) {
|
||||
if (fspath && *fspath && strcmp(fspath, fs->fs_spec) &&
|
||||
strcmp(fspath, fs->fs_file))
|
||||
continue;
|
||||
if (strcmp(fs->fs_vfstype, "ufs"))
|
||||
continue;
|
||||
if (!hasquota(fs, quotatype, &qfpathname))
|
||||
if ((qf = quota_open(fs, quotatype, O_CREAT|O_RDWR)) == NULL) {
|
||||
if (errno != EOPNOTSUPP)
|
||||
warn("cannot open quotas on %s", fs->fs_file);
|
||||
continue;
|
||||
}
|
||||
if ((qup = (struct quotause *)calloc(1, sizeof(*qup))) == NULL)
|
||||
errx(2, "out of memory");
|
||||
qup->qf = qf;
|
||||
strncpy(qup->fsname, fs->fs_file, sizeof(qup->fsname));
|
||||
if (quota_read(qf, &qup->dqblk, id) == -1) {
|
||||
warn("cannot read quotas on %s", fs->fs_file);
|
||||
freeprivs(qup);
|
||||
continue;
|
||||
qupsize = sizeof(*qup) + strlen(qfpathname);
|
||||
if ((qup = (struct quotause *)malloc(qupsize)) == NULL)
|
||||
errx(2, "out of memory");
|
||||
if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
|
||||
if (errno == EOPNOTSUPP && !warned) {
|
||||
warned++;
|
||||
warnx("warning: quotas are not compiled into this kernel");
|
||||
sleep(3);
|
||||
}
|
||||
if ((qf = quota_open(qfpathname)) == NULL &&
|
||||
(qf = quota_create(qfpathname)) == NULL) {
|
||||
warn("%s", qfpathname);
|
||||
free(qup);
|
||||
continue;
|
||||
}
|
||||
if (quota_read(qf, &qup->dqblk, id) != 0) {
|
||||
warn("read error in %s", qfpathname);
|
||||
quota_close(qf);
|
||||
free(qup);
|
||||
continue;
|
||||
}
|
||||
quota_close(qf);
|
||||
}
|
||||
strcpy(qup->qfname, qfpathname);
|
||||
strcpy(qup->fsname, fs->fs_file);
|
||||
if (quphead == NULL)
|
||||
quphead = qup;
|
||||
else
|
||||
@ -424,53 +416,13 @@ getprivs(long id, int quotatype, char *fspath)
|
||||
* Store the requested quota information.
|
||||
*/
|
||||
void
|
||||
putprivs(long id, int quotatype, struct quotause *quplist)
|
||||
putprivs(long id, struct quotause *quplist)
|
||||
{
|
||||
struct quotafile *qf;
|
||||
struct quotause *qup;
|
||||
int qcmd;
|
||||
struct dqblk dqbuf;
|
||||
|
||||
qcmd = QCMD(Q_SETQUOTA, quotatype);
|
||||
for (qup = quplist; qup; qup = qup->next) {
|
||||
if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0)
|
||||
continue;
|
||||
if ((qf = quota_open(qup->qfname)) == NULL) {
|
||||
warn("%s", qup->qfname);
|
||||
continue;
|
||||
}
|
||||
if (quota_read(qf, &dqbuf, id) != 0) {
|
||||
warn("read error in %s", qup->qfname);
|
||||
quota_close(qf);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Reset time limit if have a soft limit and were
|
||||
* previously under it, but are now over it
|
||||
* or if there previously was no soft limit, but
|
||||
* now have one and are over it.
|
||||
*/
|
||||
if (dqbuf.dqb_bsoftlimit && id != 0 &&
|
||||
dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
|
||||
dqbuf.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit)
|
||||
qup->dqblk.dqb_btime = 0;
|
||||
if (dqbuf.dqb_bsoftlimit == 0 && id != 0 &&
|
||||
dqbuf.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit)
|
||||
qup->dqblk.dqb_btime = 0;
|
||||
if (dqbuf.dqb_isoftlimit && id != 0 &&
|
||||
dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit &&
|
||||
dqbuf.dqb_curinodes >= qup->dqblk.dqb_isoftlimit)
|
||||
qup->dqblk.dqb_itime = 0;
|
||||
if (dqbuf.dqb_isoftlimit == 0 && id !=0 &&
|
||||
dqbuf.dqb_curinodes >= qup->dqblk.dqb_isoftlimit)
|
||||
qup->dqblk.dqb_itime = 0;
|
||||
qup->dqblk.dqb_curinodes = dqbuf.dqb_curinodes;
|
||||
qup->dqblk.dqb_curblocks = dqbuf.dqb_curblocks;
|
||||
if (quota_write(qf, &qup->dqblk, id) == 0) {
|
||||
warn("%s", qup->qfname);
|
||||
}
|
||||
quota_close(qf);
|
||||
}
|
||||
for (qup = quplist; qup; qup = qup->next)
|
||||
if (quota_write_limits(qup->qf, &qup->dqblk, id) == -1)
|
||||
warn("%s", qup->fsname);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -978,6 +930,7 @@ freeprivs(struct quotause *quplist)
|
||||
struct quotause *qup, *nextqup;
|
||||
|
||||
for (qup = quplist; qup; qup = nextqup) {
|
||||
quota_close(qup->qf);
|
||||
nextqup = qup->next;
|
||||
free(qup);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user