diff options
author | Jan Kara <jack@suse.cz> | 2016-03-30 11:35:07 +0200 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2016-03-31 09:46:40 +0200 |
commit | 6206e37f8f478d0908bfb93045b5b303a09f8a9b (patch) | |
tree | fecf1a83a55b510c6fbe4400a986d3b6272c9a37 /quotasys.c | |
parent | c4b56ee58b9b76d2598535cf6109a27b22e60abe (diff) | |
download | linuxquota-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.c | 152 |
1 files changed, 148 insertions, 4 deletions
@@ -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; } |