Further extend the quotafile API.

This commit is contained in:
Dag-Erling Smørgrav 2009-09-26 23:16:06 +00:00
parent 4085a92bc9
commit 5666aadb3d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/quota64/; revision=197532
4 changed files with 137 additions and 42 deletions

View File

@ -60,8 +60,12 @@ MLINKS+=pidfile.3 pidfile_open.3 \
pidfile.3 pidfile_close.3 \
pidfile.3 pidfile_remove.3
MLINKS+=quotafile.3 quota_open.3 \
quotafile.3 quota_fsname.3 \
quotafile.3 quota_qfname.3 \
quotafile.3 quota_statfs.3 \
quotafile.3 quota_read.3 \
quotafile.3 quota_write.3 \
quotafile.3 quota_write_limits.3 \
quotafile.3 quota_write_usage.3 \
quotafile.3 quota_close.3
.include <bsd.lib.mk>

View File

@ -144,10 +144,13 @@ int pidfile_remove(struct pidfh *pfh);
struct quotafile;
struct fstab;
struct quotafile *quota_open(struct fstab *, int, int);
void quota_close(struct quotafile *);
const char *quota_fsname(const struct quotafile *);
const char *quota_qfname(const struct quotafile *);
int quota_check_path(const struct quotafile *, const char *path);
int quota_read(struct quotafile *, struct dqblk *, int);
int quota_write_limits(struct quotafile *, struct dqblk *, int);
int quota_write_usage(struct quotafile *, struct dqblk *, int);
void quota_close(struct quotafile *);
#endif
__END_DECLS

View File

@ -25,11 +25,14 @@
.\"
.\" $FreeBSD$
.\"
.Dd February 14, 2009
.Dd September 26, 2009
.Dt QUOTAFILE 3
.Os
.Sh NAME
.Nm quota_open
.Nm quota_fsname
.Nm quota_qfname
.Nm quota_check_path
.Nm quota_read
.Nm quota_write_limits
.Nm quota_write_usage
@ -38,11 +41,19 @@
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In sys/param.h
.In sys/mount.h
.In ufs/ufs/quota.h
.In libutil.h
.In fstab.h
.Ft "struct quotafile *"
.Fn quota_open "struct fstab *fs" "int quotatype" "int openflags"
.Ft "const char *"
.Fn quota_fsname "const struct quotafile *qf"
.Ft "const char *"
.Fn quota_qfname "const struct quotafile *qf"
.Ft int
.Fn quota_check_path "const struct quotafile *qf" "const char *path"
.Ft int
.Fn quota_read "struct quotafile *qf" "struct dqblk *dqb" "int id"
.Ft int
@ -84,12 +95,42 @@ if the quotas are just to be read, or
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.
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_fsname
function returns a pointer to a buffer containing the path to the root
of the file system that corresponds to its
.Va qf
argument, as listed in
.Pa /etc/fstab .
Note that this may be a symbolic link to the actual directory.
.Pp
The
.Fn quota_qfname
function returns a pointer to a buffer containing the name of the
quota file that corresponds to its
.Va qf
argument.
Note that this may be a symbolic link to the actual file.
.Pp
The
.Fn quota_check_path
function checks if the specified path is within the filesystem that
corresponds to its
.Va qf
argument.
If the
.Va path
argument refers to a symbolic link,
.Fn quota_check_path
will follow it.
.Pp
The
.Fn quota_read
function reads the quota from the filesystem and quota type referenced by
function reads the quota from the filesystem and quota type referenced
by
.Va qf
for the user (or group) specified by
.Va id
@ -127,6 +168,9 @@ The
function closes any open file descriptors and frees any storage
associated with the filesystem and quota type referenced by
.Va qf .
.Sh IMPLEMENTATION NOTES
If the underlying quota file is in the old 32-bit format, limit and
usage values written to the quota file will be clipped to 32 bits.
.Sh RETURN VALUES
If the filesystem has quotas associated with it,
.Fn quota_open
@ -137,7 +181,15 @@ 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.
is set to indicate the error.
.Pp
The
.Fn quota_check_path
function returns\~1 for a positive result and\~0 for a negative
result.
If an error occurs, it returns\~-1 and sets
.Va errno
to indicate the error.
.Pp
The
.Fn quota_read ,
@ -146,11 +198,10 @@ The
and
.Fn quota_close
functions return zero on success.
On error they return
.Dv -1
On error they return\~-1
and set
.Va errno
to indicate the cause of failure.
to indicate the error.
.Sh SEE ALSO
.Xr quotactl 2 ,
.Xr quota.user 5 ,

View File

@ -49,8 +49,10 @@
struct quotafile {
int fd; /* -1 means using quotactl for access */
int accmode; /* access mode */
int wordsize; /* 32-bit or 64-bit limits */
int quotatype; /* USRQUOTA or GRPQUOTA */
dev_t dev; /* device */
char fsname[MAXPATHLEN + 1]; /* mount point of filesystem */
char qfname[MAXPATHLEN + 1]; /* quota file if not using quotactl */
};
@ -59,6 +61,7 @@ static const char *qfextension[] = INITQFNAMES;
/*
* Check to see if a particular quota is to be enabled.
* XXX merge into quota_open
*/
static int
hasquota(struct fstab *fs, int type, char *qfnamep, int qfbufsize)
@ -69,6 +72,11 @@ hasquota(struct fstab *fs, int type, char *qfnamep, int qfbufsize)
char buf[BUFSIZ];
static char initname, usrname[100], grpname[100];
/*
* XXX
* 1) we only need one of these
* 2) fstab may specify a different filename
*/
if (!initname) {
(void)snprintf(usrname, sizeof(usrname), "%s%s",
qfextension[USRQUOTA], QUOTAFILENAME);
@ -109,12 +117,17 @@ quota_open(struct fstab *fs, int quotatype, int openflags)
struct quotafile *qf;
struct dqhdr64 dqh;
struct group *grp;
struct stat st;
int qcmd, serrno;
if ((qf = calloc(1, sizeof(*qf))) == NULL)
return (NULL);
qf->fd = -1;
qf->quotatype = quotatype;
strncpy(qf->fsname, fs->fs_file, sizeof(qf->fsname));
if (stat(qf->fsname, &st) != 0)
goto error;
qf->dev = st.st_dev;
qcmd = QCMD(Q_GETQUOTA, quotatype);
if (quotactl(fs->fs_file, qcmd, 0, &dqh) == 0) {
qf->wordsize = 64;
@ -122,27 +135,19 @@ quota_open(struct fstab *fs, int quotatype, int openflags)
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);
goto error;
}
qf->accmode = openflags & O_ACCMODE;
if ((qf->fd = open(qf->qfname, qf->accmode)) < 0 &&
(openflags & O_CREAT) != O_CREAT)
goto error;
/* 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);
goto error;
case sizeof(dqh):
if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) {
/* no magic, assume 32 bits */
@ -153,10 +158,8 @@ quota_open(struct fstab *fs, int quotatype, int openflags)
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);
goto error;
}
qf->wordsize = 64;
return (qf);
@ -166,31 +169,33 @@ quota_open(struct fstab *fs, int quotatype, int openflags)
}
/* 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);
}
/* open failed, but O_CREAT was specified, so create a new file */
if ((qf->fd = open(qf->qfname, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0)
goto error;
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);
dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
serrno = errno;
unlink(qf->qfname);
close(qf->fd);
free(qf);
errno = serrno;
return (NULL);
}
if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh))
goto error;
grp = getgrnam(QUOTAGROUP);
fchown(qf->fd, 0, grp ? grp->gr_gid : 0);
fchmod(qf->fd, 0640);
return (qf);
error:
serrno = errno;
/* did we have an open file? */
if (qf->fd != -1) {
/* was it one we created ourselves? */
if ((openflags & O_CREAT) == O_CREAT)
unlink(qf->qfname);
close(qf->fd);
}
free(qf);
errno = serrno;
return (NULL);
}
void
@ -202,6 +207,30 @@ quota_close(struct quotafile *qf)
free(qf);
}
const char *
quota_fsname(const struct quotafile *qf)
{
return (qf->fsname);
}
const char *
quota_qfname(const struct quotafile *qf)
{
return (qf->qfname);
}
int
quota_check_path(const struct quotafile *qf, const char *path)
{
struct stat st;
if (stat(path, &st) == -1)
return (-1);
return (st.st_dev == qf->dev);
}
static int
quota_read32(struct quotafile *qf, struct dqblk *dqb, int id)
{
@ -333,6 +362,10 @@ quota_write_usage(struct quotafile *qf, struct dqblk *dqb, int id)
struct dqblk dqbuf;
int qcmd;
if ((qf->accmode & O_RDWR) != O_RDWR) {
errno = EBADF;
return (-1);
}
if (qf->fd == -1) {
qcmd = QCMD(Q_SETUSE, qf->quotatype);
return (quotactl(qf->fsname, qcmd, id, dqb));
@ -377,6 +410,10 @@ quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id)
struct dqblk dqbuf;
int qcmd;
if ((qf->accmode & O_RDWR) != O_RDWR) {
errno = EBADF;
return (-1);
}
if (qf->fd == -1) {
qcmd = QCMD(Q_SETQUOTA, qf->quotatype);
return (quotactl(qf->fsname, qcmd, id, dqb));