summaryrefslogtreecommitdiff
path: root/quotasys.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-03-30 11:35:07 +0200
committerJan Kara <jack@suse.cz>2016-03-31 09:46:40 +0200
commit6206e37f8f478d0908bfb93045b5b303a09f8a9b (patch)
treefecf1a83a55b510c6fbe4400a986d3b6272c9a37 /quotasys.c
parentc4b56ee58b9b76d2598535cf6109a27b22e60abe (diff)
downloadlinuxquota-6206e37f8f478d0908bfb93045b5b303a09f8a9b.tar.gz
Add support for project quota into generic code
The support for project quota in generic code is simple. We just need functions to convert project ID to project name and back (we follow what xfsprogs do in that regard), add detection whether project quota is enabled for the filesystem, and increase number of quota types. We also have to update various checks to count with project quotas. Signed-off-by: Li Xi <lixi@ddn.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'quotasys.c')
-rw-r--r--quotasys.c152
1 files changed, 148 insertions, 4 deletions
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;
}