Further extend the quotafile API.
This commit is contained in:
parent
4085a92bc9
commit
5666aadb3d
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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 ,
|
||||
|
@ -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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user