summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--quota.h3
-rw-r--r--quotaio_generic.c16
-rw-r--r--quotaio_xfs.c44
-rw-r--r--quotaio_xfs.h2
-rw-r--r--quotasys.c152
-rw-r--r--quotasys.h20
6 files changed, 224 insertions, 13 deletions
diff --git a/quota.h b/quota.h
index 0607e04..3628614 100644
--- a/quota.h
+++ b/quota.h
@@ -8,7 +8,7 @@ typedef u_int32_t qid_t; /* Type in which we store ids in memory */
typedef int64_t qsize_t; /* Type in which we store size limitations */
#define QSIZE_MAX INT64_MAX /* Maximum value storable in qsize_t */
-#define MAXQUOTAS 2
+#define MAXQUOTAS 3
#define USRQUOTA 0 /* element used for user quotas */
#define GRPQUOTA 1 /* element used for group quotas */
#define PRJQUOTA 2 /* element used for project quotas */
@@ -21,6 +21,7 @@ typedef int64_t qsize_t; /* Type in which we store size limitations */
#define INITQFNAMES { \
N_("user"), /* USRQUOTA */ \
N_("group"), /* GRPQUOTA */ \
+ N_("project"), /* PRJQUOTA */ \
N_("undefined"), \
}
diff --git a/quotaio_generic.c b/quotaio_generic.c
index 4bdf380..025d712 100644
--- a/quotaio_generic.c
+++ b/quotaio_generic.c
@@ -157,6 +157,22 @@ int generic_scan_dquots(struct quota_handle *h,
break;
}
endgrent();
+ } else if (h->qh_type == PRJQUOTA) {
+ struct fs_project *prj;
+
+ setprent();
+ while ((prj = getprent()) != NULL) {
+ dquot->dq_id = prj->pr_id;
+ ret = scan_one_dquot(dquot, get_dquot);
+ if (ret < 0)
+ break;
+ if (ret > 0)
+ continue;
+ ret = process_dquot(dquot, prj->pr_name);
+ if (ret < 0)
+ break;
+ }
+ endprent();
}
free(dquot);
return ret;
diff --git a/quotaio_xfs.c b/quotaio_xfs.c
index 9d90a3e..1374cf4 100644
--- a/quotaio_xfs.c
+++ b/quotaio_xfs.c
@@ -23,6 +23,8 @@
(h)->qh_info.u.xfs_mdqi.qs_flags & XFS_QUOTA_UDQ_ACCT)
#define XFS_GRPQUOTA(h) ((h)->qh_type == GRPQUOTA && \
(h)->qh_info.u.xfs_mdqi.qs_flags & XFS_QUOTA_GDQ_ACCT)
+#define XFS_PRJQUOTA(h) ((h)->qh_type == PRJQUOTA && \
+ (h)->qh_info.u.xfs_mdqi.qs_flags & XFS_QUOTA_PDQ_ACCT)
static int xfs_init_io(struct quota_handle *h);
static int xfs_write_info(struct quota_handle *h);
@@ -97,7 +99,7 @@ static int xfs_write_info(struct quota_handle *h)
struct xfs_kern_dqblk xdqblk;
int qcmd;
- if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
+ if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h) && !XFS_PRJQUOTA(h))
return 0;
memset(&xdqblk, 0, sizeof(struct xfs_kern_dqblk));
@@ -123,7 +125,7 @@ static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id)
dquot->dq_id = id;
dquot->dq_h = h;
- if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
+ if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h) && !XFS_PRJQUOTA(h))
return dquot;
qcmd = QCMD(Q_XFS_GETQUOTA, h->qh_type);
@@ -146,11 +148,16 @@ static int xfs_commit_dquot(struct dquot *dquot, int flags)
qid_t id = dquot->dq_id;
int qcmd;
- if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
+ if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h) && !XFS_PRJQUOTA(h))
return 0;
xfs_util2kerndqblk(&xdqblk, &dquot->dq_dqb);
- xdqblk.d_flags |= XFS_USRQUOTA(h) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA;
+ if (XFS_USRQUOTA(h))
+ xdqblk.d_flags |= XFS_USER_QUOTA;
+ else if (XFS_GRPQUOTA(h))
+ xdqblk.d_flags |= XFS_GROUP_QUOTA;
+ else if (XFS_PRJQUOTA(h))
+ xdqblk.d_flags |= XFS_PROJ_QUOTA;
xdqblk.d_id = id;
if (strcmp(h->qh_fstype, MNTTYPE_GFS2) == 0) {
if (flags & COMMIT_LIMITS) /* warn/limit */
@@ -231,7 +238,7 @@ static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct
ret = quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0,
(void *)&xdqblk);
if (ret < 0 && (errno == ENOSYS || errno == EINVAL)) {
- if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
+ if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h) && !XFS_PRJQUOTA(h))
return 0;
return generic_scan_dquots(h, process_dquot, xfs_get_dquot);
}
@@ -257,10 +264,14 @@ static int xfs_report(struct quota_handle *h, int verbose)
printf(_("Accounting: %s; Enforcement: %s\n"),
XQM_ON(XFS_QUOTA_UDQ_ACCT), XQM_ON(XFS_QUOTA_UDQ_ENFD));
}
- else { /* qh_type == USRQUOTA */
+ else if (h->qh_type == GRPQUOTA) {
printf(_("Accounting: %s; Enforcement: %s\n"),
XQM_ON(XFS_QUOTA_GDQ_ACCT), XQM_ON(XFS_QUOTA_GDQ_ENFD));
}
+ else if (h->qh_type == PRJQUOTA) {
+ printf(_("Accounting: %s; Enforcement: %s\n"),
+ XQM_ON(XFS_QUOTA_PDQ_ACCT), XQM_ON(XFS_QUOTA_PDQ_ENFD));
+ }
#undef XQM_ON
/*
@@ -273,10 +284,14 @@ static int xfs_report(struct quota_handle *h, int verbose)
printf(_("Accounting [ondisk]: %s; Enforcement [ondisk]: %s\n"),
XQM_ONDISK(XFS_QUOTA_UDQ_ACCT), XQM_ONDISK(XFS_QUOTA_UDQ_ENFD));
}
- else { /* qh_type == USRQUOTA */
+ else if (h->qh_type == GRPQUOTA) {
printf(_("Accounting [ondisk]: %s; Enforcement [ondisk]: %s\n"),
XQM_ONDISK(XFS_QUOTA_GDQ_ACCT), XQM_ONDISK(XFS_QUOTA_GDQ_ENFD));
}
+ else if (h->qh_type == PRJQUOTA) {
+ printf(_("Accounting [ondisk]: %s; Enforcement [ondisk]: %s\n"),
+ XQM_ONDISK(XFS_QUOTA_PDQ_ACCT), XQM_ONDISK(XFS_QUOTA_PDQ_ENFD));
+ }
#undef XQM_ONDISK
}
@@ -290,7 +305,20 @@ static int xfs_report(struct quota_handle *h, int verbose)
(unsigned long long)info->qs_uquota.qfs_nblks,
info->qs_uquota.qfs_nextents);
}
- else { /* qh_type == GRPQUOTA */
+ else if (h->qh_type == GRPQUOTA) {
+ if (info->qs_gquota.qfs_ino == -1)
+ printf(_("Inode: none\n"));
+ else
+ printf(_("Inode: #%llu (%llu blocks, %u extents)\n"),
+ (unsigned long long)info->qs_gquota.qfs_ino,
+ (unsigned long long)info->qs_gquota.qfs_nblks,
+ info->qs_gquota.qfs_nextents);
+ }
+ else if (h->qh_type == PRJQUOTA) {
+ /*
+ * FIXME: Older XFS use group files for project quotas, newer
+ * have dedicated file and we should detect that.
+ */
if (info->qs_gquota.qfs_ino == -1)
printf(_("Inode: none\n"));
else
diff --git a/quotaio_xfs.h b/quotaio_xfs.h
index 2236da4..be7f86f 100644
--- a/quotaio_xfs.h
+++ b/quotaio_xfs.h
@@ -121,6 +121,8 @@ typedef struct fs_disk_quota {
#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */
#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */
#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */
+#define XFS_QUOTA_PDQ_ACCT (1<<4) /* group quota accounting */
+#define XFS_QUOTA_PDQ_ENFD (1<<5) /* group quota limits enforcement */
#define XFS_USER_QUOTA (1<<0) /* user quota type */
#define XFS_PROJ_QUOTA (1<<1) /* (IRIX) project quota type */
diff --git a/quotasys.c b/quotasys.c
index 4b49e0e..c78e02c 100644
--- a/quotasys.c
+++ b/quotasys.c
@@ -80,6 +80,93 @@ char *type2name(int type)
}
/*
+ * Project quota handling
+ */
+#define PROJECT_FILE "/etc/projid"
+#define MAX_LINE_LEN 1024
+
+static FILE *project_file;
+
+/* Rewind /etc/projid to the beginning */
+void setprent(void)
+{
+ if (project_file)
+ fclose(project_file);
+ project_file = fopen(PROJECT_FILE, "r");
+}
+
+/* Close /etc/projid file */
+void endprent(void)
+{
+ fclose(project_file);
+ project_file = NULL;
+}
+
+/* Get next entry in /etc/projid */
+struct fs_project *getprent(void)
+{
+ static struct fs_project p;
+ static char linebuf[MAX_LINE_LEN];
+ char *idstart, *idend;
+
+ if (!project_file)
+ return NULL;
+ while (fgets(linebuf, MAX_LINE_LEN, project_file)) {
+ /* Line too long? */
+ if (linebuf[strlen(linebuf) - 1] != '\n')
+ continue;
+ /* Skip comments */
+ if (linebuf[0] == '#')
+ continue;
+ idstart = strchr(linebuf, ':');
+ /* Skip invalid lines... We follow what xfs_quota does */
+ if (!idstart)
+ continue;
+ *idstart = 0;
+ idstart++;
+ /*
+ * Colon can separate name from something else - follow what
+ * xfs_quota does
+ */
+ idend = strchr(idstart, ':');
+ if (idend)
+ *idend = 0;
+ p.pr_name = linebuf;
+ p.pr_id = strtoul(idstart, NULL, 10);
+ return &p;
+ }
+ return NULL;
+}
+
+static struct fs_project *get_project_by_name(char *name)
+{
+ struct fs_project *p;
+
+ setprent();
+ while ((p = getprent())) {
+ if (!strcmp(name, p->pr_name))
+ break;
+ }
+ endprent();
+
+ return p;
+}
+
+static struct fs_project *get_project_by_id(qid_t id)
+{
+ struct fs_project *p;
+
+ setprent();
+ while ((p = getprent())) {
+ if (p->pr_id == id)
+ break;
+ }
+ endprent();
+
+ return p;
+}
+
+/*
* Convert name to uid
*/
uid_t user2uid(char *name, int flag, int *err)
@@ -138,14 +225,46 @@ gid_t group2gid(char *name, int flag, int *err)
}
/*
+ * Convert project name to project id
+ */
+qid_t project2pid(char *name, int flag, int *err)
+{
+ qid_t ret;
+ char *errch;
+ struct fs_project *p;
+
+ if (err)
+ *err = 0;
+ if (!flag) {
+ ret = strtoul(name, &errch, 0);
+ if (!*errch) /* Is name number - we got directly pid? */
+ return ret;
+ }
+ p = get_project_by_name(name);
+ if (!p) {
+ if (!err) {
+ errstr(_("project %s does not exist.\n"), name);
+ exit(1);
+ }
+ else {
+ *err = -1;
+ return 0;
+ }
+ }
+ return p->pr_id;
+}
+
+/*
* Convert name to id
*/
int name2id(char *name, int qtype, int flag, int *err)
{
if (qtype == USRQUOTA)
return user2uid(name, flag, err);
- else
+ else if (qtype == GRPQUOTA)
return group2gid(name, flag, err);
+ else
+ return project2pid(name, flag, err);
}
/*
@@ -181,14 +300,32 @@ int gid2group(gid_t id, char *buf)
}
/*
+ * Convert project id to name
+ */
+int pid2project(qid_t id, char *buf)
+{
+ struct fs_project *p;
+
+ if (!(p = get_project_by_id(id))) {
+ snprintf(buf, MAXNAMELEN, "#%u", (uint) id);
+ return 1;
+ }
+ else
+ sstrncpy(buf, p->pr_name, MAXNAMELEN);
+ return 0;
+}
+
+/*
* Convert id to user/groupname
*/
int id2name(int id, int qtype, char *buf)
{
if (qtype == USRQUOTA)
return uid2user(id, buf);
- else
+ else if (qtype == GRPQUOTA)
return gid2group(id, buf);
+ else
+ return pid2project(id, buf);
}
/*
@@ -531,6 +668,8 @@ static int hasxfsquota(const char *dev, struct mntent *mnt, int type, int flags)
return QF_XFS;
else if (type == GRPQUOTA && (info.qs_flags & XFS_QUOTA_GDQ_ACCT))
return QF_XFS;
+ else if (type == PRJQUOTA && (info.qs_flags & XFS_QUOTA_PDQ_ACCT))
+ return QF_XFS;
#ifdef XFS_ROOTHACK
/*
* Old XFS filesystems (up to XFS 1.2 / Linux 2.5.47) had a
@@ -543,6 +682,8 @@ static int hasxfsquota(const char *dev, struct mntent *mnt, int type, int flags)
return QF_XFS;
else if (type == GRPQUOTA && (sbflags & XFS_QUOTA_GDQ_ACCT))
return QF_XFS;
+ else if (type == PRJQUOTA && (sbflags & XFS_QUOTA_PDQ_ACCT))
+ return QF_XFS;
#endif /* XFS_ROOTHACK */
}
@@ -981,6 +1122,8 @@ static int xfs_kern_quota_on(const char *dev, int type)
return 1;
if (type == GRPQUOTA && (info.qs_flags & XFS_QUOTA_GDQ_ACCT))
return 1;
+ if (type == PRJQUOTA && (info.qs_flags & XFS_QUOTA_PDQ_ACCT))
+ return 1;
}
return 0;
}
@@ -1137,12 +1280,13 @@ alloc:
free((char *)devname);
devname = sstrdup(loopdev);
}
-
/* Further we are not interested in mountpoints without quotas and
we don't want to touch them */
qfmt[USRQUOTA] = hasquota(devname, mnt, USRQUOTA, flags);
qfmt[GRPQUOTA] = hasquota(devname, mnt, GRPQUOTA, flags);
- if (qfmt[USRQUOTA] < 0 && qfmt[GRPQUOTA] < 0) {
+ qfmt[PRJQUOTA] = hasquota(devname, mnt, PRJQUOTA, flags);
+ if (qfmt[USRQUOTA] < 0 && qfmt[GRPQUOTA] < 0 &&
+ qfmt[PRJQUOTA] < 0) {
free((char *)devname);
continue;
}
diff --git a/quotasys.h b/quotasys.h
index 5f188a4..f19b00e 100644
--- a/quotasys.h
+++ b/quotasys.h
@@ -46,6 +46,11 @@ struct mount_entry {
int me_qfmt[MAXQUOTAS]; /* Detected quota formats */
};
+struct fs_project {
+ qid_t pr_id;
+ char *pr_name;
+};
+
/*
* Exported functions
*/
@@ -57,12 +62,24 @@ int meta_qf_fstype(char *type);
/* Convert quota type to written form */
char *type2name(int);
+/* Rewind /etc/projid to the beginning */
+void setprent(void);
+
+/* Close /etc/projid file */
+void endprent(void);
+
+/* Get next entry in /etc/projid */
+struct fs_project *getprent(void);
+
/* Convert username to uid */
uid_t user2uid(char *, int flag, int *err);
/* Convert groupname to gid */
gid_t group2gid(char *, int flag, int *err);
+/* Convert project name to project id */
+qid_t project2pid(char *name, int flag, int *err);
+
/* Convert user/groupname to id */
int name2id(char *name, int qtype, int flag, int *err);
@@ -72,6 +89,9 @@ int uid2user(uid_t, char *);
/* Convert gid to groupname */
int gid2group(gid_t, char *);
+/* Convert project id to name */
+int pid2project(qid_t, char *);
+
/* Convert id to user/group name */
int id2name(int id, int qtype, char *buf);