From a58761459f7485f275ecca5fd26b9a63c33f1089 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 2 Oct 2013 23:10:49 +0200 Subject: Add support for CVS and XML output formats to repquota(8) JK: Fixup localization and handling of multiple output filesystems / types. Signed-off-by: Jonathan Overholt Signed-off-by: Jan Kara --- quotasys.c | 31 +++++++++++++++++ quotasys.h | 12 +++++++ repquota.8 | 10 ++++++ repquota.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 151 insertions(+), 18 deletions(-) diff --git a/quotasys.c b/quotasys.c index e583437..a1ac392 100644 --- a/quotasys.c +++ b/quotasys.c @@ -37,6 +37,7 @@ #define min(x,y) (((x) < (y)) ? (x) : (y)) #define QFMT_NAMES 5 +#define QOFMT_NAMES 3 static char extensions[MAXQUOTAS + 2][20] = INITQFNAMES; static char *basenames[] = INITQFBASENAMES; @@ -46,6 +47,10 @@ static char *fmtnames[] = { "vfsold", "rpc", "xfs", }; +static char *ofmtnames[] = { "default", + "csv", + "xml" +}; /* * Check for various kinds of NFS filesystem @@ -239,6 +244,32 @@ char *fmt2name(int fmt) return fmtnames[fmt]; } +/* + * Convert output format name to number + */ +int name2ofmt(char *str) +{ + int fmt; + + for (fmt = 0; fmt < QOFMT_NAMES; fmt++) + if (!strcmp(str, ofmtnames[fmt])) + return fmt; + errstr(_("Unknown output format: %s\nSupported formats are:\n\ + default - default\n\ + csv - comma-separated values\n\ + xml - simple XML\n"), str); + return QOF_ERROR; +} + +/* + * Convert output format number to name + */ +char *ofmt2name(int fmt) +{ + return ofmtnames[fmt]; +} + + /* * Convert kernel to utility quota format number */ diff --git a/quotasys.h b/quotasys.h index 505ea77..5ca26e6 100644 --- a/quotasys.h +++ b/quotasys.h @@ -88,6 +88,12 @@ int name2fmt(char *str); /* Convert quota format number to name */ char *fmt2name(int fmt); +/* Convert output format name to number */ +int name2ofmt(char *str); + +/* Convert output format number to name */ +char *ofmt2name(int fmt); + /* Convert utility to kernel format numbers */ int util2kernfmt(int fmt); @@ -168,4 +174,10 @@ struct mount_entry *get_next_mount(void); /* Free all structures associated with mountpoints scan */ void end_mounts_scan(void); +/* Quota output formats */ +#define QOF_ERROR -1 +#define QOF_DEFAULT 0 +#define QOF_CSV 1 +#define QOF_XML 2 + #endif /* GUARD_QUOTASYS_H */ diff --git a/repquota.8 b/repquota.8 index bb6d7ab..89cd896 100644 --- a/repquota.8 +++ b/repquota.8 @@ -127,6 +127,16 @@ Report quotas for groups. .TP .B -u, --user Report quotas for users. This is the default. +.TP +.B -O, --output=\f2format-name\f1 +Output quota report in the specified format. +Possible format names are: +.B default +The default format, optimized for console viewing +.B csv +Comma-separated values, a text file with the columns delimited by commas +.B xml +Output is XML encoded, useful for processing with XSLT .LP Only the super-user may view quotas which are not their own. .SH FILES diff --git a/repquota.c b/repquota.c index 50683b9..db4f6da 100644 --- a/repquota.c +++ b/repquota.c @@ -38,7 +38,7 @@ #define FL_NOAUTOFS 256 /* Ignore autofs mountpoints */ #define FL_RAWGRACE 512 /* Print grace times in seconds since epoch */ -static int flags, fmt = -1; +static int flags, fmt = -1, ofmt = QOF_DEFAULT; static char **mnt; static int mntcnt; static int cached_dquots; @@ -47,7 +47,7 @@ char *progname; static void usage(void) { - errstr(_("Utility for reporting quotas.\nUsage:\n%s [-vugsi] [-c|C] [-t|n] [-F quotaformat] (-a | mntpoint)\n\n\ + errstr(_("Utility for reporting quotas.\nUsage:\n%s [-vugsi] [-c|C] [-t|n] [-F quotaformat] [-O (default | xml | csv)] (-a | mntpoint)\n\n\ -v, --verbose display also users/groups without any usage\n\ -u, --user display information about users\n\ -g, --group display information about groups\n\ @@ -59,6 +59,7 @@ static void usage(void) -c, --cache translate big number of ids at once\n\ -C, --no-cache translate ids one by one\n\ -F, --format=formatname report information for specific format\n\ +-O, --output=format format output as xml or csv\n\ -a, --all report information for all mount points with quotas\n\ -h, --help display this help message and exit\n\ -V, --version display version information and exit\n\n"), progname); @@ -85,10 +86,11 @@ static void parse_options(int argcnt, char **argstr) { "no-cache", 0, NULL, 'C' }, { "no-autofs", 0, NULL, 'i' }, { "format", 1, NULL, 'F' }, + { "output", 1, NULL, 'O' }, { NULL, 0, NULL, 0 } }; - while ((ret = getopt_long(argcnt, argstr, "VavughtspncCiF:", long_opts, NULL)) != -1) { + while ((ret = getopt_long(argcnt, argstr, "VavughtspncCiFO:", long_opts, NULL)) != -1) { switch (ret) { case '?': case 'h': @@ -131,6 +133,10 @@ static void parse_options(int argcnt, char **argstr) if ((fmt = name2fmt(optarg)) == QF_ERROR) exit(1); break; + case 'O': + if ((ofmt = name2ofmt(optarg)) == QOF_ERROR) + exit(1); + break; case 'n': flags |= FL_NONAME; break; @@ -168,18 +174,29 @@ static char overlim(qsize_t usage, qsize_t softlim, qsize_t hardlim) return '-'; } +/* Are we over soft or hard limit? More descriptive */ +static char * overlimd(qsize_t usage, qsize_t softlim, qsize_t hardlim) +{ + if (usage > hardlim && hardlim) + return "hard"; + else if (usage > softlim && softlim) + return "soft"; + else + return "ok"; +} + /* Print one quota entry */ static void print(struct dquot *dquot, char *name) { char pname[MAXNAMELEN]; char time[MAXTIMELEN]; char numbuf[3][MAXNUMLEN]; - struct util_dqblk *entry = &dquot->dq_dqb; if (!entry->dqb_curspace && !entry->dqb_curinodes && !(flags & FL_VERBOSE)) return; sstrncpy(pname, name, sizeof(pname)); + if (flags & FL_TRUNCNAMES) pname[PRINTNAMELEN] = 0; if (entry->dqb_bsoftlimit && toqb(entry->dqb_curspace) >= entry->dqb_bsoftlimit) @@ -195,10 +212,42 @@ static void print(struct dquot *dquot, char *name) space2str(toqb(entry->dqb_curspace), numbuf[0], flags & FL_SHORTNUMS); space2str(entry->dqb_bsoftlimit, numbuf[1], flags & FL_SHORTNUMS); space2str(entry->dqb_bhardlimit, numbuf[2], flags & FL_SHORTNUMS); - printf("%-*s %c%c %7s %7s %7s %6s", PRINTNAMELEN, pname, - overlim(qb2kb(toqb(entry->dqb_curspace)), qb2kb(entry->dqb_bsoftlimit), qb2kb(entry->dqb_bhardlimit)), - overlim(entry->dqb_curinodes, entry->dqb_isoftlimit, entry->dqb_ihardlimit), - numbuf[0], numbuf[1], numbuf[2], time); + + if (ofmt == QOF_DEFAULT) { + printf("%-*s %c%c %7s %7s %7s %6s", PRINTNAMELEN, pname, + overlim(qb2kb(toqb(entry->dqb_curspace)), qb2kb(entry->dqb_bsoftlimit), qb2kb(entry->dqb_bhardlimit)), + overlim(entry->dqb_curinodes, entry->dqb_isoftlimit, entry->dqb_ihardlimit), + numbuf[0], numbuf[1], numbuf[2], time); + } else if (ofmt == QOF_CSV) { + printf("%s,%s,%s,%s,%s,%s,%s", pname, + overlimd(qb2kb(toqb(entry->dqb_curspace)), + qb2kb(entry->dqb_bsoftlimit), + qb2kb(entry->dqb_bhardlimit)), + overlimd(entry->dqb_curinodes, + entry->dqb_isoftlimit, + entry->dqb_ihardlimit), + numbuf[0], numbuf[1], numbuf[2], time); + } else if (ofmt == QOF_XML) { + char *spacehdr; + + if (flags & FL_SHORTNUMS) + spacehdr = "Space"; + else + spacehdr = "Block"; + + printf(" \n\ + \n\ + <%sLimits used='%s' soft='%s' hard='%s' grace='%s' />\n", + pname, spacehdr, + overlimd(qb2kb(toqb(entry->dqb_curspace)), + qb2kb(entry->dqb_bsoftlimit), + qb2kb(entry->dqb_bhardlimit)), + overlimd(entry->dqb_curinodes, + entry->dqb_isoftlimit, + entry->dqb_ihardlimit), + spacehdr, numbuf[0], numbuf[1], numbuf[2], time); + } + if (entry->dqb_isoftlimit && entry->dqb_curinodes >= entry->dqb_isoftlimit) if (flags & FL_RAWGRACE) sprintf(time, "%llu", (unsigned long long)entry->dqb_itime); @@ -212,7 +261,12 @@ static void print(struct dquot *dquot, char *name) number2str(entry->dqb_curinodes, numbuf[0], flags & FL_SHORTNUMS); number2str(entry->dqb_isoftlimit, numbuf[1], flags & FL_SHORTNUMS); number2str(entry->dqb_ihardlimit, numbuf[2], flags & FL_SHORTNUMS); - printf(" %7s %5s %5s %6s\n", numbuf[0], numbuf[1], numbuf[2], time); + if (ofmt == QOF_DEFAULT) + printf(" %7s %5s %5s %6s\n", numbuf[0], numbuf[1], numbuf[2], time); + else if (ofmt == QOF_CSV) + printf(",%s,%s,%s,%s\n", numbuf[0], numbuf[1], numbuf[2], time); + else if (ofmt == QOF_XML) + printf(" \n \n", numbuf[0], numbuf[1], numbuf[2], time); } /* Print all dquots in the cache */ @@ -288,28 +342,51 @@ static void report_it(struct quota_handle *h, int type) { char bgbuf[MAXTIMELEN], igbuf[MAXTIMELEN]; char *spacehdr; + char *typestr; - if (flags & FL_SHORTNUMS) - spacehdr = _("Space"); + if (type == USRQUOTA) + typestr = _("User"); else - spacehdr = _("Block"); + typestr = _("Group"); + + if (ofmt == QOF_DEFAULT ) + printf(_("*** Report for %s quotas on device %s\n"), _(type2name(type)), h->qh_quotadev); + else if (ofmt == QOF_XML) + printf("\n", type2name(type), h->qh_quotadev); - printf(_("*** Report for %s quotas on device %s\n"), _(type2name(type)), h->qh_quotadev); time2str(h->qh_info.dqi_bgrace, bgbuf, TF_ROUND); time2str(h->qh_info.dqi_igrace, igbuf, TF_ROUND); - printf(_("Block grace time: %s; Inode grace time: %s\n"), bgbuf, igbuf); - printf(_(" %s limits File limits\n"), spacehdr); - printf(_("%-9s used soft hard grace used soft hard grace\n"), (type == USRQUOTA)?_("User"):_("Group")); - printf("----------------------------------------------------------------------\n"); + + if (ofmt == QOF_DEFAULT) { + if (flags & FL_SHORTNUMS) + spacehdr = _("Space"); + else + spacehdr = _("Block"); + printf(_("Block grace time: %s; Inode grace time: %s\n"), bgbuf, igbuf); + printf(_(" %s limits File limits\n"), spacehdr); + printf(_("%-9s used soft hard grace used soft hard grace\n"), typestr); + printf("----------------------------------------------------------------------\n"); + } else if (ofmt == QOF_XML) { + printf(" %s\n %s\n", bgbuf, igbuf); + } else if (ofmt == QOF_CSV) { + if (flags & FL_SHORTNUMS) + spacehdr = "Space"; + else + spacehdr = "Block"; + printf("%s,%sStatus,FileStatus,%sUsed,%sSoftLimit,%sHardLimit,%sGrace,FileUsed,FileSoftLimit,FileHardLimit,FileGrace\n", + typestr,spacehdr, spacehdr, spacehdr, spacehdr, spacehdr); + } if (h->qh_ops->scan_dquots(h, output) < 0) return; dump_cached_dquots(type); - if (h->qh_ops->report) { + if (h->qh_ops->report && ofmt == QOF_DEFAULT) { putchar('\n'); h->qh_ops->report(h, flags & FL_VERBOSE); putchar('\n'); } + if (ofmt == QOF_XML) + printf("\n"); } static void report(int type) @@ -334,6 +411,9 @@ int main(int argc, char **argv) parse_options(argc, argv); init_kernel_interface(); + if (ofmt == QOF_XML) + printf("\n"); + if (flags & FL_USER) report(USRQUOTA); -- cgit v1.2.3