Hi, Long time ago I've submitted xfs project quota id support through patches interface (https://savannah.gnu.org/patch/?6698).
Topic isn't exciting as I got no comments ;) Anyway I would like to clean up the patch and make it into mergeable state iif such feature patches have a chance to be merged. Little review of the patch would be welcome. Thanks, From 11745d10f0c0c702716b7d40ecd3c2a7e5994313 Mon Sep 17 00:00:00 2001 From: Arkadiusz Miskiewicz <[email protected]> Date: Tue, 16 Dec 2008 17:12:55 +0100 Subject: [PATCH] find: "XFS project quota" support XFS filesystem provides three different quota types. UID-based, GID-based and "project quota" path name based. Add support for test parameter "-xfsprojquota N" which allows looking for files with specified project quota ID. Add support for "%q" format which allows project quota ID to be displayed. Note that issuing ioctl(2) requires file to be open(2) which is bad for some type of files (exclude these as xfs_quota does). Example: $ ./find /home/users/arekm/xtest -printf "name=%f projquotaid=%q\n" name=xtest projquotaid=0 name=proj50 projquotaid=50 name=aaa projquotaid=50 name=aaadsfdsf projquotaid=50 name=something projquotaid=50 name=34knjf projquotaid=50 name=proj60 projquotaid=60 name=34knjf projquotaid=60 name=34knjfwenhwjqe projquotaid=60 name=dsfdsfknjfwenhwjqe projquotaid=60 name=proj70 projquotaid=70 name=7sfdsfdsf projquotaid=70 name=7sf4344 projquotaid=70 name=7sf4344ad projquotaid=70 $ ./find /home/users/arekm/xtest -xfsprojquota 50 /home/users/arekm/xtest/proj50 /home/users/arekm/xtest/proj50/aaa /home/users/arekm/xtest/proj50/aaadsfdsf /home/users/arekm/xtest/proj50/something /home/users/arekm/xtest/proj50/34knjf --- find/defs.h | 25 +++++++++++++++++- find/find.1 | 2 + find/parser.c | 20 +++++++++++++- find/pred.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ find/tree.c | 1 + 5 files changed, 125 insertions(+), 3 deletions(-) diff --git a/find/defs.h b/find/defs.h index 1708d83..ccdddc3 100644 --- a/find/defs.h +++ b/find/defs.h @@ -39,6 +39,7 @@ Please stop compiling the program now /* XXX: some of these includes probably don't belong in a common header file */ #include <sys/stat.h> +#include <sys/ioctl.h> #include <stdio.h> /* for FILE* */ #include <string.h> #include <stdlib.h> @@ -65,6 +66,27 @@ typedef bool boolean; #include "buildcmd.h" #include "quotearg.h" +#ifndef XFS_IOC_FSGETXATTR +struct fsxattr +{ + uint32_t fsx_xflags; /* xflags field value (get/set) */ + uint32_t fsx_extsize; /* extsize field value (get/set)*/ + uint32_t fsx_nextents; /* nextents field value (get) */ + uint32_t fsx_projid; /* project identifier (get/set) */ + unsigned char fsx_pad[12]; +}; + +#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) +#endif + +#define XFS_EXCLUDED_FILE_TYPES(x) \ + (S_ISCHR((x)) \ + || S_ISBLK((x)) \ + || S_ISFIFO((x)) \ + || S_ISLNK((x)) \ + || S_ISSOCK((x))) + + /* These days we will assume ANSI/ISO C protootypes work on our compiler. */ #define PARAMS(Args) Args @@ -306,7 +328,7 @@ struct predicate const char *str; /* fstype [i]lname [i]name [i]path */ struct re_pattern_buffer *regex; /* regex */ struct exec_val exec_vec; /* exec ok */ - struct long_val numinfo; /* gid inum links uid */ + struct long_val numinfo; /* gid inum links uid xfsprojquota */ struct size_val size; /* size */ uid_t uid; /* user */ gid_t gid; /* group */ @@ -458,6 +480,7 @@ PREDICATEFUNCTION pred_uid; PREDICATEFUNCTION pred_used; PREDICATEFUNCTION pred_user; PREDICATEFUNCTION pred_writable; +PREDICATEFUNCTION pred_xfsprojquota; PREDICATEFUNCTION pred_xtype; diff --git a/find/find.1 b/find/find.1 index 25953fc..a4a783f 100644 --- a/find/find.1 +++ b/find/find.1 @@ -1327,6 +1327,8 @@ File's name. .IP %P File's name with the name of the command line argument under which it was found removed. +.IP %q +XFS filesystem project quota ID. .IP %s File's size in bytes. .IP %S diff --git a/find/parser.c b/find/parser.c index 102eb7d..feb3fea 100644 --- a/find/parser.c +++ b/find/parser.c @@ -145,6 +145,7 @@ static boolean parse_time PARAMS((const struct parser_table*, char *arg static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); +static boolean parse_xfsprojquota PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); @@ -320,6 +321,7 @@ static struct parser_table const parse_table[] = PARSE_TEST_NP ("wholename", wholename), /* GNU, replaced -path, but anyway -path will soon be in POSIX */ {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */ PARSE_OPTION ("xdev", xdev), /* POSIX */ + PARSE_TEST ("xfsprojquota", xfsprojquota), /* XFS Project Quota ID */ PARSE_TEST ("xtype", xtype), /* GNU */ #ifdef UNIMPLEMENTED_UNIX /* It's pretty ugly for find to know about archive formats. @@ -1127,7 +1129,7 @@ tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\ -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\ -readable -writable -executable\n\ -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\ - -used N -user NAME -xtype [bcdpfls]\n")); + -used N -user NAME -xfsprojquota N -xtype [bcdpfls]\n")); puts (_("\ actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\ -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\ @@ -2562,6 +2564,19 @@ parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr) } static boolean +parse_xfsprojquota (const struct parser_table* entry, char **argv, int *arg_ptr) +{ + struct predicate *p = insert_num (argv, arg_ptr, entry); + if (p) + { + /* XXX: how to do if (parent dir has xfsprojid) { est_success_rate = 99 } else { 0.2 } ? */ + p->est_success_rate = 0.2; + return true; + } + return false; +} + +static boolean parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr) { return insert_type (argv, arg_ptr, entry, pred_xtype); @@ -2784,7 +2799,7 @@ insert_fprintf (struct format_val *vec, if (*scan2 == '.') for (scan2++; ISDIGIT (*scan2); scan2++) /* Do nothing. */ ; - if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2)) + if (strchr ("abcdDfFgGhHiklmMnpPqsStuUyY", *scan2)) { segmentp = make_segment (segmentp, format, scan2 - format, KIND_FORMAT, *scan2, 0, @@ -2927,6 +2942,7 @@ make_segment (struct segment **segment, case 'D': /* Filesystem device on which the file exits */ case 'k': /* size in 1K blocks */ case 'n': /* number of links */ + case 'q': /* XFS Project Quota ID */ pred->need_stat = true; mycost = NeedsStatInfo; *fmt++ = 's'; diff --git a/find/pred.c b/find/pred.c index a458803..a51adbd 100644 --- a/find/pred.c +++ b/find/pred.c @@ -26,6 +26,7 @@ #include <grp.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/ioctl.h> #include <errno.h> #include <assert.h> #include <stdarg.h> @@ -229,6 +230,7 @@ struct pred_assoc pred_table[] = {pred_used, "used "}, {pred_user, "user "}, {pred_writable, "writable "}, + {pred_xfsprojquota, "xfsprojquota "}, {pred_xtype, "xtype "}, {0, "none "} }; @@ -954,6 +956,32 @@ do_fprintf(struct format_val *dest, checked_print_quoted (dest, segment->text, cp); break; + case 'q': + { + if (!XFS_EXCLUDED_FILE_TYPES(stat_buf->st_mode) + && (strcmp (filesystem_type (stat_buf, pathname), "xfs") == 0)) { + int fd; + struct fsxattr fsx; + + if ((fd = openat(state.cwd_dir_fd, state.rel_pathname, O_RDONLY|O_NOCTTY +#if defined O_LARGEFILE + |O_LARGEFILE +#endif + )) >= 0) { + if ((ioctl(fd, XFS_IOC_FSGETXATTR, &fsx)) >= 0) { + checked_fprintf (dest, segment->text, + human_readable ((uintmax_t) fsx.fsx_projid, hbuf, + human_ceiling, 1, 1)); + } + close(fd); + } + } + + /* Do nothing. */ + /*FALLTHROUGH*/ + break; + } + case 's': /* size in bytes */ /* UNTRUSTED, probably unexploitable */ checked_fprintf (dest, segment->text, @@ -1804,6 +1832,58 @@ pred_user (const char *pathname, struct stat *stat_buf, struct predicate *pred_p else return (false); } + +boolean +pred_xfsprojquota(const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +{ + int fd; + struct fsxattr fsx; + + if (XFS_EXCLUDED_FILE_TYPES(stat_buf->st_mode)) + return false; + + if (strcmp (filesystem_type (stat_buf, pathname), "xfs")) + return false; + + if ((fd = openat(state.cwd_dir_fd, state.rel_pathname, O_RDONLY|O_NOCTTY +#if defined O_LARGEFILE + |O_LARGEFILE +#endif + )) < 0) + { + error (0, errno, "%s", safely_quote_err_filename(0, pathname)); + state.exit_status = 1; + return false; + } + + if ((ioctl(fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) { + error (0, errno, "%s", safely_quote_err_filename(0, pathname)); + state.exit_status = 1; + close(fd); + return false; + } + + close(fd); + + switch (pred_ptr->args.numinfo.kind) + { + case COMP_GT: + if (fsx.fsx_projid > pred_ptr->args.numinfo.l_val) + return (true); + break; + case COMP_LT: + if (fsx.fsx_projid < pred_ptr->args.numinfo.l_val) + return (true); + break; + case COMP_EQ: + if (fsx.fsx_projid == pred_ptr->args.numinfo.l_val) + return (true); + break; + } + return (false); + +} + boolean pred_xtype (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) diff --git a/find/tree.c b/find/tree.c index 7420c60..e5c0683 100644 --- a/find/tree.c +++ b/find/tree.c @@ -950,6 +950,7 @@ static struct pred_cost_lookup costlookup[] = { pred_true , NeedsNothing }, { pred_type , NeedsType }, { pred_uid , NeedsStatInfo }, + { pred_xfsprojquota, NeedsNothing }, { pred_used , NeedsStatInfo }, { pred_user , NeedsStatInfo }, { pred_writable , NeedsAccessInfo }, -- 1.6.0.5 -- Arkadiusz MiĆkiewicz PLD/Linux Team arekm / maven.pl http://ftp.pld-linux.org/
