Morgan Weetman 
Consultant 
Red Hat Consulting 
http://www.apac.redhat.com/products/consulting/ 
From b6c74c78f20929fff5c92e5277ea0a6dc0f4bc7f Mon Sep 17 00:00:00 2001
From: Morgan Weetman <mweet...@redhat.com>
Date: Fri, 7 Nov 2014 18:59:45 +1100
Subject: [PATCH 1/8] find: added extended attribute predicate

* find/defs.h (typedef PREDICATEFUNCTION): added pred_xattr
* find/parser.c (parse_xattr): added function, added an entry to parse_table[]
* find/pred.c (pred_xattr): added function, added an entry to pred_table[]
* find/tree.c (costlookup[]): added pred_xattr entry
---
 find/defs.h   |  1 +
 find/parser.c | 28 ++++++++++++++++++++++++++++
 find/pred.c   | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 find/tree.c   |  1 +
 4 files changed, 86 insertions(+)

diff --git a/find/defs.h b/find/defs.h
index caccd2b..4ab1bb1 100644
--- a/find/defs.h
+++ b/find/defs.h
@@ -457,6 +457,7 @@ PREDICATEFUNCTION pred_uid;
 PREDICATEFUNCTION pred_used;
 PREDICATEFUNCTION pred_user;
 PREDICATEFUNCTION pred_writable;
+PREDICATEFUNCTION pred_xattr;
 PREDICATEFUNCTION pred_xtype;
 PREDICATEFUNCTION pred_context;
 
diff --git a/find/parser.c b/find/parser.c
index dc6c47c..bb43286 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -149,6 +149,7 @@ static bool parse_xdev          (const struct parser_table*, char *argv[], int *
 static bool parse_ignore_race   (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_noignore_race (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_warn          (const struct parser_table*, char *argv[], int *arg_ptr);
+static bool parse_xattr         (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_xtype         (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_quit          (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_context       (const struct parser_table*, char *argv[], int *arg_ptr);
@@ -306,6 +307,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       ("xattr",                 xattr),	     /* GNU */
   PARSE_TEST       ("xtype",                 xtype),	     /* GNU */
 #ifdef UNIMPLEMENTED_UNIX
   /* It's pretty ugly for find to know about archive formats.
@@ -2757,6 +2759,32 @@ parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
 }
 
 static bool
+parse_xattr (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+  const char *name;
+  const int saved_argc = *arg_ptr;
+
+  if (collect_arg (argv, arg_ptr, &name))
+    {
+      fnmatch_sanitycheck ();
+      if (check_name_arg ("-xattr", name))
+	{
+	  struct predicate *our_pred = insert_primary (entry, name);
+	  our_pred->need_stat = our_pred->need_type = false;
+	  our_pred->args.str = name;
+	  our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
+	  return true;
+	}
+      else
+	{
+	  *arg_ptr = saved_argc; /* don't consume the invalid argument. */
+	}
+    }
+  return false;
+}
+
+
+static bool
 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
 {
   return insert_type (argv, arg_ptr, entry, pred_xtype);
diff --git a/find/pred.c b/find/pred.c
index 3a89679..048e263 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -141,6 +141,7 @@ struct pred_assoc pred_table[] =
   {pred_used, "used    "},
   {pred_user, "user    "},
   {pred_writable, "writable "},
+  {pred_xattr, "xattr   "},
   {pred_xtype, "xtype   "},
   {pred_context, "context"},
   {0, "none    "}
@@ -1156,6 +1157,61 @@ pred_user (const char *pathname, struct stat *stat_buf, struct predicate *pred_p
 }
 
 bool
+pred_xattr (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+{
+  (void) pathname;
+  const char *re_string = pred_ptr->args.str;
+  char empty[0];
+  char *list;
+  char *substrings;
+  ssize_t list_size;
+  int i, j;
+  bool ret = false;
+  regex_t re_pattern;
+
+  // get size of xattr list for the given path by passing an empty list
+  list_size = listxattr(pathname, empty, 0);
+
+  // allocate just enough memory to hold all xattrs
+  list = malloc(list_size);
+
+  // used to hold individual attributes (substrings)
+  // allocate same size as list just in case there's only one xattr
+  substrings = malloc(list_size);
+
+  // retrieve the list of xattrs
+  listxattr(pathname, list, list_size);
+
+  // compile regex pattern
+  if (regcomp(&re_pattern, re_string, REG_ICASE|REG_NOSUB|REG_NEWLINE) != 0) {
+    free(list);
+    free(substrings);
+    return(ret);
+  }
+
+  // break list into asciiz strings
+  for (i = 0, j = 0; i < list_size; i++) {
+    substrings[j] = list[i];
+    if (list[i] == 0) {
+      // perform regex match against substring
+      j = 0;
+      if (regexec(&re_pattern, substrings, (size_t) 0, NULL, 0) == 0) {
+        ret = true;
+      }
+      continue;
+    }
+    j++;
+  }
+
+  // clean up
+  free(list);
+  free(substrings);
+  regfree(&re_pattern);
+  return(ret);
+
+}
+
+bool
 pred_xtype (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
 {
   struct stat sbuf;		/* local copy, not stat_buf because we're using a different stat method */
diff --git a/find/tree.c b/find/tree.c
index 026dead..2dba99d 100644
--- a/find/tree.c
+++ b/find/tree.c
@@ -1001,6 +1001,7 @@ static struct pred_cost_lookup costlookup[] =
     { pred_used      ,  NeedsStatInfo        },
     { pred_user      ,  NeedsStatInfo        },
     { pred_writable  ,  NeedsAccessInfo      },
+    { pred_xattr     ,  NeedsNothing         },
     { pred_xtype     ,  NeedsType            } /* roughly correct unless most files are symlinks */
   };
 static int pred_table_sorted = 0;
-- 
1.9.3

From 0e3fadc728a35265002379220a4ae5423a0075ca Mon Sep 17 00:00:00 2001
From: Morgan Weetman <mweet...@redhat.com>
Date: Tue, 9 Dec 2014 23:52:24 +1100
Subject: [PATCH 2/8] find: updated man page with xattr information

* find/find.1: added extended attribute predicate information
---
 find/find.1 | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/find/find.1 b/find/find.1
index f49218e..8c4c187 100644
--- a/find/find.1
+++ b/find/find.1
@@ -920,6 +920,11 @@ mapping (or root-squashing), since many systems implement
 in the client's kernel and so cannot make use of the UID mapping
 information held on the server.
 
+.IP "\-xattr \fIpattern\fR"
+Match extended attributes against the regular expression
+\fIpattern\fR. For example to search for files that have
+capabilities set you could use '.*capa.*'
+
 .IP "\-xtype \fIc\fR"
 The same as
 .B \-type
-- 
1.9.3

From c90c87217455f584090ab5c517ae6bf1468a5649 Mon Sep 17 00:00:00 2001
From: Morgan Weetman <mweet...@redhat.com>
Date: Sat, 13 Dec 2014 20:14:05 +1100
Subject: [PATCH 3/8] find: -xattr now obeys -regextype

* find/pred.c: removed regcomp call
* find/parser.c: parse_xattr function altered to obey -regextype
                 added insert_xattr function
                 added parse_ixattr function
* find/find.1: updated -xattr entry
---
 find/find.1   |  4 +++-
 find/parser.c | 57 ++++++++++++++++++++++++++++++++++++++++-----------------
 find/pred.c   | 13 ++-----------
 3 files changed, 45 insertions(+), 29 deletions(-)

diff --git a/find/find.1 b/find/find.1
index 8c4c187..096a3ed 100644
--- a/find/find.1
+++ b/find/find.1
@@ -923,7 +923,9 @@ information held on the server.
 .IP "\-xattr \fIpattern\fR"
 Match extended attributes against the regular expression
 \fIpattern\fR. For example to search for files that have
-capabilities set you could use '.*capa.*'
+capabilities set you could use '.*capab.*'. This option
+also takes advantage of
+.B \-regextype
 
 .IP "\-xtype \fIc\fR"
 The same as
diff --git a/find/parser.c b/find/parser.c
index bb43286..16163f5 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -110,6 +110,7 @@ static bool parse_iname         (const struct parser_table*, char *argv[], int *
 static bool parse_inum          (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_ipath         (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_iregex        (const struct parser_table*, char *argv[], int *arg_ptr);
+static bool parse_ixattr        (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_iwholename    (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_links         (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_lname         (const struct parser_table*, char *argv[], int *arg_ptr);
@@ -165,6 +166,9 @@ static bool insert_type (char **argv, int *arg_ptr,
 static bool insert_regex (char *argv[], int *arg_ptr,
 			  const struct parser_table *entry,
 			  int regex_options);
+static bool insert_xattr (char *argv[], int *arg_ptr,
+			  const struct parser_table *entry,
+			  int regex_options);
 static bool insert_exec_ok (const char *action,
 			    const struct parser_table *entry,
 			    char *argv[],
@@ -260,6 +264,7 @@ static struct parser_table const parse_table[] =
   PARSE_TEST       ("inum",                  inum),    /* GNU, Unix */
   PARSE_TEST       ("ipath",                 ipath), /* GNU, deprecated in favour of iwholename */
   PARSE_TEST_NP    ("iregex",                iregex),	     /* GNU */
+  PARSE_TEST_NP    ("ixattr",                ixattr),	     /* GNU */
   PARSE_TEST_NP    ("iwholename",            iwholename),    /* GNU */
   PARSE_TEST       ("links",                 links), /* POSIX */
   PARSE_TEST       ("lname",                 lname),	     /* GNU */
@@ -1384,6 +1389,12 @@ parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
 }
 
 static bool
+parse_ixattr (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+  return insert_xattr (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
+}
+
+static bool
 parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
 {
   struct predicate *p = insert_num (argv, arg_ptr, entry);
@@ -2761,29 +2772,41 @@ parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
 static bool
 parse_xattr (const struct parser_table* entry, char **argv, int *arg_ptr)
 {
-  const char *name;
-  const int saved_argc = *arg_ptr;
+  return insert_xattr (argv, arg_ptr, entry, options.regex_options);
+}
 
-  if (collect_arg (argv, arg_ptr, &name))
+static bool
+insert_xattr (char **argv,
+              int *arg_ptr,
+              const struct parser_table *entry,
+              int regex_options)
+{
+  const char *rx;
+  if (collect_arg (argv, arg_ptr, &rx))
     {
-      fnmatch_sanitycheck ();
-      if (check_name_arg ("-xattr", name))
-	{
-	  struct predicate *our_pred = insert_primary (entry, name);
-	  our_pred->need_stat = our_pred->need_type = false;
-	  our_pred->args.str = name;
-	  our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
-	  return true;
-	}
-      else
-	{
-	  *arg_ptr = saved_argc; /* don't consume the invalid argument. */
-	}
+      struct re_pattern_buffer *re;
+      const char *error_message;
+      struct predicate *our_pred = insert_primary_withpred (entry, pred_xattr, rx);
+      our_pred->need_stat = our_pred->need_type = false;
+      re = xmalloc (sizeof (struct re_pattern_buffer));
+      our_pred->args.regex = re;
+      re->allocated = 100;
+      re->buffer = xmalloc (re->allocated);
+      re->fastmap = NULL;
+
+      re_set_syntax (regex_options);
+      re->syntax = regex_options;
+      re->translate = NULL;
+
+      error_message = re_compile_pattern (rx, strlen (rx), re);
+      if (error_message)
+        error (EXIT_FAILURE, 0, "%s", error_message);
+      our_pred->est_success_rate = estimate_pattern_match_rate (rx, 1);
+      return true;
     }
   return false;
 }
 
-
 static bool
 parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
 {
diff --git a/find/pred.c b/find/pred.c
index 048e263..37e9f0e 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -33,6 +33,7 @@
 #include <stdarg.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <attr/xattr.h>
 #include <sys/wait.h>
 #include <unistd.h> /* for unlinkat() */
 
@@ -1160,14 +1161,12 @@ bool
 pred_xattr (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
 {
   (void) pathname;
-  const char *re_string = pred_ptr->args.str;
   char empty[0];
   char *list;
   char *substrings;
   ssize_t list_size;
   int i, j;
   bool ret = false;
-  regex_t re_pattern;
 
   // get size of xattr list for the given path by passing an empty list
   list_size = listxattr(pathname, empty, 0);
@@ -1182,20 +1181,13 @@ pred_xattr (const char *pathname, struct stat *stat_buf, struct predicate *pred_
   // retrieve the list of xattrs
   listxattr(pathname, list, list_size);
 
-  // compile regex pattern
-  if (regcomp(&re_pattern, re_string, REG_ICASE|REG_NOSUB|REG_NEWLINE) != 0) {
-    free(list);
-    free(substrings);
-    return(ret);
-  }
-
   // break list into asciiz strings
   for (i = 0, j = 0; i < list_size; i++) {
     substrings[j] = list[i];
     if (list[i] == 0) {
       // perform regex match against substring
       j = 0;
-      if (regexec(&re_pattern, substrings, (size_t) 0, NULL, 0) == 0) {
+      if (regexec(pred_ptr->args.regex, substrings, (size_t) 0, NULL, 0) == 0) {
         ret = true;
       }
       continue;
@@ -1206,7 +1198,6 @@ pred_xattr (const char *pathname, struct stat *stat_buf, struct predicate *pred_
   // clean up
   free(list);
   free(substrings);
-  regfree(&re_pattern);
   return(ret);
 
 }
-- 
1.9.3

From f017b99a77032d7da6ac3de854d9ac7185cb8f0c Mon Sep 17 00:00:00 2001
From: Morgan Weetman <mweet...@redhat.com>
Date: Tue, 6 Jan 2015 13:54:49 +1100
Subject: [PATCH 4/8] find: -xattr now obeys symlink handling options

* find/pred.c (pred_xattr): added tests for options.symlink_handling
---
 find/pred.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/find/pred.c b/find/pred.c
index 37e9f0e..ddf9917 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -1169,7 +1169,11 @@ pred_xattr (const char *pathname, struct stat *stat_buf, struct predicate *pred_
   bool ret = false;
 
   // get size of xattr list for the given path by passing an empty list
-  list_size = listxattr(pathname, empty, 0);
+  if (options.symlink_handling == SYMLINK_NEVER_DEREF) {
+    list_size = llistxattr(pathname, empty, 0);
+  } else {
+    list_size = listxattr(pathname, empty, 0);
+  }
 
   // allocate just enough memory to hold all xattrs
   list = malloc(list_size);
@@ -1179,7 +1183,11 @@ pred_xattr (const char *pathname, struct stat *stat_buf, struct predicate *pred_
   substrings = malloc(list_size);
 
   // retrieve the list of xattrs
-  listxattr(pathname, list, list_size);
+  if (options.symlink_handling == SYMLINK_NEVER_DEREF) {
+    llistxattr(pathname, list, list_size);
+  } else {
+    listxattr(pathname, list, list_size);
+  }
 
   // break list into asciiz strings
   for (i = 0, j = 0; i < list_size; i++) {
-- 
1.9.3

From 6fe70075fe7ebc5d0e457831bc65fd1d8538610d Mon Sep 17 00:00:00 2001
From: Morgan Weetman <mweet...@redhat.com>
Date: Wed, 7 Jan 2015 15:31:55 +1100
Subject: [PATCH 5/8] find: added capability predicate

* find/defs.h (typedef PREDICATEFUNCTION): added pred_cap
* find/parser.c: added parse_cap function
                 added parse_icap function
                 added insert_cap function
                 added an entry to parse_table
* find/pred.c (pred_cap): added function, added an entry to pred_table[]
* find/tree.c (costlookup[]): added pred_cap entry
* find/find.1: added -cap and -icap entries
---
 find/defs.h   |  1 +
 find/find.1   | 12 ++++++++++++
 find/parser.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 find/pred.c   | 29 +++++++++++++++++++++++++++++
 find/tree.c   |  1 +
 5 files changed, 95 insertions(+)

diff --git a/find/defs.h b/find/defs.h
index 4ab1bb1..cd57544 100644
--- a/find/defs.h
+++ b/find/defs.h
@@ -405,6 +405,7 @@ PREDICATEFUNCTION pred_and;
 PREDICATEFUNCTION pred_anewer;
 PREDICATEFUNCTION pred_atime;
 PREDICATEFUNCTION pred_closeparen;
+PREDICATEFUNCTION pred_cap;
 PREDICATEFUNCTION pred_cmin;
 PREDICATEFUNCTION pred_cnewer;
 PREDICATEFUNCTION pred_comma;
diff --git a/find/find.1 b/find/find.1
index 096a3ed..6d03d85 100644
--- a/find/find.1
+++ b/find/find.1
@@ -521,6 +521,13 @@ a file has to have been accessed at least
 .I two
 days ago.
 
+.IP "\-cap \fIpattern\fR"
+Match file capabilities against the regular expression
+\fIpattern\fR. For example to search for files that have
+CAP_SETUID you could use '.*setuid.*'. This option
+also takes advantage of
+.B \-regextype
+
 .IP "\-cmin \fIn\fR"
 File's status was last changed \fIn\fR minutes ago.
 
@@ -577,6 +584,11 @@ File's numeric group ID is \fIn\fR.
 .IP "\-group \fIgname\fR"
 File belongs to group \fIgname\fR (numeric group ID allowed).
 
+.IP "\-icap \fIpattern\fR"
+Like
+.BR \-cap ,
+but the match is case insensitive.
+
 .IP "\-ilname \fIpattern\fR"
 Like
 .BR \-lname ,
diff --git a/find/parser.c b/find/parser.c
index 16163f5..d5b5731 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -85,6 +85,7 @@ static bool parse_accesscheck   (const struct parser_table*, char *argv[], int *
 static bool parse_amin          (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_and           (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_anewer        (const struct parser_table*, char *argv[], int *arg_ptr);
+static bool parse_cap           (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_cmin          (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_cnewer        (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_comma         (const struct parser_table*, char *argv[], int *arg_ptr);
@@ -105,6 +106,7 @@ static bool parse_fstype        (const struct parser_table*, char *argv[], int *
 static bool parse_gid           (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_group         (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_help          (const struct parser_table*, char *argv[], int *arg_ptr);
+static bool parse_icap          (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_ilname        (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_iname         (const struct parser_table*, char *argv[], int *arg_ptr);
 static bool parse_inum          (const struct parser_table*, char *argv[], int *arg_ptr);
@@ -169,6 +171,9 @@ static bool insert_regex (char *argv[], int *arg_ptr,
 static bool insert_xattr (char *argv[], int *arg_ptr,
 			  const struct parser_table *entry,
 			  int regex_options);
+static bool insert_cap (char *argv[], int *arg_ptr,
+			  const struct parser_table *entry,
+			  int regex_options);
 static bool insert_exec_ok (const char *action,
 			    const struct parser_table *entry,
 			    char *argv[],
@@ -238,6 +243,7 @@ static struct parser_table const parse_table[] =
   PARSE_PUNCTUATION("and",                   and),		/* GNU */
   PARSE_TEST       ("anewer",                anewer),	     /* GNU */
   {ARG_TEST,       "atime",                  parse_time, pred_atime}, /* POSIX */
+  PARSE_TEST       ("cap",                   cap),	     /* GNU */
   PARSE_TEST       ("cmin",                  cmin),	     /* GNU */
   PARSE_TEST       ("cnewer",                cnewer),	     /* GNU */
   {ARG_TEST,       "ctime",                  parse_time, pred_ctime}, /* POSIX */
@@ -258,6 +264,7 @@ static struct parser_table const parse_table[] =
   PARSE_TEST       ("fstype",                fstype),  /* GNU, Unix */
   PARSE_TEST       ("gid",                   gid),	     /* GNU */
   PARSE_TEST       ("group",                 group), /* POSIX */
+  PARSE_TEST_NP    ("icap",                  icap),	     /* GNU */
   PARSE_OPTION     ("ignore_readdir_race",   ignore_race),   /* GNU */
   PARSE_TEST       ("ilname",                ilname),	     /* GNU */
   PARSE_TEST       ("iname",                 iname),	     /* GNU */
@@ -797,6 +804,12 @@ parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
   return false;
 }
 
+static bool
+parse_cap (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+  return insert_cap (argv, arg_ptr, entry, options.regex_options);
+}
+
 bool
 parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
 {
@@ -1277,6 +1290,12 @@ estimate_pattern_match_rate (const char *pattern, int is_regex)
 }
 
 static bool
+parse_icap (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+  return insert_cap (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
+}
+
+static bool
 parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
 {
   const char *name;
@@ -2924,6 +2943,39 @@ insert_type (char **argv, int *arg_ptr,
   return false;
 }
 
+static bool
+insert_cap (char **argv,
+              int *arg_ptr,
+              const struct parser_table *entry,
+              int regex_options)
+{
+  const char *rx;
+  if (collect_arg (argv, arg_ptr, &rx))
+    {
+      struct re_pattern_buffer *re;
+      const char *error_message;
+      struct predicate *our_pred = insert_primary_withpred (entry, pred_cap, rx);
+      our_pred->need_stat = true;
+      our_pred->need_type = false;
+      re = xmalloc (sizeof (struct re_pattern_buffer));
+      our_pred->args.regex = re;
+      re->allocated = 100;
+      re->buffer = xmalloc (re->allocated);
+      re->fastmap = NULL;
+
+      re_set_syntax (regex_options);
+      re->syntax = regex_options;
+      re->translate = NULL;
+
+      error_message = re_compile_pattern (rx, strlen (rx), re);
+      if (error_message)
+        error (EXIT_FAILURE, 0, "%s", error_message);
+      our_pred->est_success_rate = estimate_pattern_match_rate (rx, 1);
+      return true;
+    }
+  return false;
+}
+
 
 /* Return true if the file accessed via FP is a terminal.
  */
diff --git a/find/pred.c b/find/pred.c
index ddf9917..83c8286 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -36,6 +36,7 @@
 #include <attr/xattr.h>
 #include <sys/wait.h>
 #include <unistd.h> /* for unlinkat() */
+#include <sys/capability.h> /* for pred_cap() */
 
 /* gnulib headers. */
 #include "areadlink.h"
@@ -90,6 +91,7 @@ struct pred_assoc pred_table[] =
   {pred_and, "and     "},
   {pred_anewer, "anewer  "},
   {pred_atime, "atime   "},
+  {pred_cap, "cap    "},
   {pred_closeparen, ")       "},
   {pred_cmin, "cmin    "},
   {pred_cnewer, "cnewer  "},
@@ -261,6 +263,33 @@ pred_atime (const char *pathname, struct stat *stat_buf, struct predicate *pred_
 }
 
 bool
+pred_cap (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
+{
+  (void) pathname;
+  char *cap_str;
+  cap_t caps;
+  bool ret = false;
+
+  // get capabilities
+  caps = cap_get_file(pathname);
+  cap_str = cap_to_text(caps, NULL);
+  if ( cap_str == NULL ) {
+    cap_free(caps);
+    return(ret);
+  }
+
+  // perform regex match
+  if (regexec(pred_ptr->args.regex, cap_str, (size_t) 0, NULL, 0) == 0)
+    ret = true;
+
+  // clean up
+  cap_free(caps);
+  cap_free(cap_str);
+  return(ret);
+
+}
+
+bool
 pred_closeparen (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
 {
   (void) &pathname;
diff --git a/find/tree.c b/find/tree.c
index 2dba99d..d91b080 100644
--- a/find/tree.c
+++ b/find/tree.c
@@ -947,6 +947,7 @@ static struct pred_cost_lookup costlookup[] =
     { pred_and       ,  NeedsNothing,        },
     { pred_anewer    ,  NeedsStatInfo,       },
     { pred_atime     ,  NeedsStatInfo,       },
+    { pred_cap       ,  NeedsNothing,        },
     { pred_closeparen,  NeedsNothing         },
     { pred_cmin      ,  NeedsStatInfo,       },
     { pred_cnewer    ,  NeedsStatInfo,       },
-- 
1.9.3

From 8ba406c43244415504c1831e849d3ff3be07bf1e Mon Sep 17 00:00:00 2001
From: Morgan Weetman <mweet...@redhat.com>
Date: Wed, 7 Jan 2015 15:44:37 +1100
Subject: [PATCH 6/8] find: added -ixattr entry to the man page

---
 find/find.1 | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/find/find.1 b/find/find.1
index 6d03d85..2e3979c 100644
--- a/find/find.1
+++ b/find/find.1
@@ -628,6 +628,11 @@ but the match is case insensitive.
 See \-ipath.    This alternative is less portable than
 .BR \-ipath .
 
+.IP "\-ixattr \fIpattern\fR"
+Like
+.BR \-xattr ,
+but the match is case insensitive.
+
 .IP "\-links \fIn\fR"
 File has \fIn\fR links.
 
-- 
1.9.3

From 27a798d0eb1cbde2f418252c9e0dcac1e112e47d Mon Sep 17 00:00:00 2001
From: Morgan Weetman <mweet...@redhat.com>
Date: Wed, 7 Jan 2015 15:49:33 +1100
Subject: [PATCH 7/8] find: added xattr and cap to excuses.txt

* find/testsuite/excuses.txt: xattr and cap require root privileges
                              to test, may require some planning
---
 find/testsuite/excuses.txt | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/find/testsuite/excuses.txt b/find/testsuite/excuses.txt
index 07dd8dc..0ea2a74 100644
--- a/find/testsuite/excuses.txt
+++ b/find/testsuite/excuses.txt
@@ -23,18 +23,20 @@ g
 
 ## Things that are hard to test because they rely on features of
 ## the environment
+"cap",                   cap),	     /* GNU */
 "gid",                   gid),	     /* GNU */
-"uid",                   uid),	     /* GNU */
-"user",                  user),
 "group",                 group),
+"ignore_readdir_race",   ignore_race),   /* GNU */
 "mount",                 xdev),	    /* Unix */
 "nogroup",               nogroup),
 "nouser",                nouser),
 "ok",                    ok),
-"xdev",                  xdev),
-"ignore_readdir_race",   ignore_race),   /* GNU */
 "noignore_readdir_race", noignore_race), /* GNU */
 "noleaf",                noleaf),	     /* GNU */
+"uid",                   uid),	     /* GNU */
+"user",                  user),
+"xattr",                 xattr),	     /* GNU */
+"xdev",                  xdev),
 
 ## Things that might be testable but which I have not yet thought
 ## about enough.
-- 
1.9.3

From f7c7fd8233aaaac1b002376821998384958049e6 Mon Sep 17 00:00:00 2001
From: Morgan Weetman <mweet...@redhat.com>
Date: Wed, 7 Jan 2015 23:11:59 +1100
Subject: [PATCH 8/8] find: updated find/Makefile.am to include libcap for -cap

---
 find/Makefile.am | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/find/Makefile.am b/find/Makefile.am
index 30eba1d..0782d7c 100644
--- a/find/Makefile.am
+++ b/find/Makefile.am
@@ -4,6 +4,8 @@ localedir = $(datadir)/locale
 # noinst_PROGRAMS = regexprops
 # regexprops_SOURCES = regexprops.c
 
+LIBCAP = -lcap
+
 noinst_LIBRARIES = libfindtools.a
 libfindtools_a_SOURCES = finddata.c fstype.c parser.c pred.c exec.c tree.c util.c sharefile.c print.c
 
@@ -30,7 +32,7 @@ endif
 # man_MANS is not always the same, we want to distribute all of those files.
 EXTRA_DIST = defs.h sharefile.h print.h find.1 ftsfind.1 oldfind.1
 AM_CPPFLAGS = -I../gl/lib -I$(top_srcdir)/lib -I$(top_srcdir)/gl/lib -I../intl -DLOCALEDIR=\"$(localedir)\"
-LDADD = ./libfindtools.a ../lib/libfind.a ../gl/lib/libgnulib.a $(LIBINTL) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS) $(LIB_SELINUX) $(LIB_CLOSE) $(MODF_LIBM) $(FINDLIBS) $(GETHOSTNAME_LIB) $(LIB_EACCESS)
+LDADD = ./libfindtools.a ../lib/libfind.a ../gl/lib/libgnulib.a $(LIBCAP) $(LIBINTL) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS) $(LIB_SELINUX) $(LIB_CLOSE) $(MODF_LIBM) $(FINDLIBS) $(GETHOSTNAME_LIB) $(LIB_EACCESS)
 # gnulib advises we link against <first> because we use <second>:
 # $(GETHOSTNAME_LIB)            uname
 # $(LIB_CLOCK_GETTIME)          (some inditrect dependency)
-- 
1.9.3

Reply via email to