changeset 1420:9d760c092c41 draft

Implement exec -user, -group, and -newer. Enable find in defconfig.
author Rob Landley <rob@landley.net>
date Sun, 03 Aug 2014 15:50:10 -0500
parents e22e9eee9346
children 30014454681f
files lib/lib.h lib/xwrap.c toys/posix/find.c
diffstat 3 files changed, 74 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/lib/lib.h	Sat Aug 02 21:07:43 2014 -0500
+++ b/lib/lib.h	Sun Aug 03 15:50:10 2014 -0500
@@ -119,6 +119,7 @@
 struct passwd *xgetpwuid(uid_t uid);
 struct group *xgetgrgid(gid_t gid);
 struct passwd *xgetpwnam(char *name);
+struct group *xgetgrnam(char *name);
 void xsetuser(struct passwd *pwd);
 char *xreadlink(char *name);
 long xparsetime(char *arg, long units, long *fraction);
--- a/lib/xwrap.c	Sat Aug 02 21:07:43 2014 -0500
+++ b/lib/xwrap.c	Sun Aug 03 15:50:10 2014 -0500
@@ -455,6 +455,14 @@
   return up;
 }
 
+struct group *xgetgrnam(char *name)
+{
+  struct group *gr = getgrnam(name);
+
+  if (!gr) perror_exit("group '%s'", name);
+  return gr;
+}
+
 // setuid() can fail (for example, too many processes belonging to that user),
 // which opens a security hole if the process continues as the original user.
 
--- a/toys/posix/find.c	Sat Aug 02 21:07:43 2014 -0500
+++ b/toys/posix/find.c	Sun Aug 03 15:50:10 2014 -0500
@@ -12,7 +12,7 @@
 
 config FIND
   bool "find"
-  default n
+  default y
   help
     usage: find [-HL] [DIR...] [<options>]
 
@@ -46,19 +46,6 @@
     or "+" (next argument after "{}") to collect and run with multiple files.
 */
 
-// find . ! \( -name blah -print \)
-// find . -o
-// find -type f
-
-// pending issues:
-// old false -a ! new false does not yield true.
-// 
-// -user -group -newer evaluate once and save result (where?)
-// add -print if no action (-exec, -ok, -print)
-// find . -print -xdev (should xdev before print)
-// -exec {} + accepts any + after {}, not just immediately after. ";" optional
-// posix wants loop detection?
-
 #define FOR_find
 #include "toys.h"
 
@@ -146,11 +133,6 @@
   free(s);
 }
 
-void todo_store_argument(void)
-{
-  error_exit("NOP");
-}
-
 char *strlower(char *s)
 {
   char *try, *new;
@@ -340,12 +322,40 @@
           test = compare_numsign(new->st.st_size, 512, ss[1]);
       } else if (!strcmp(s, "links")) {
         if (check) test = compare_numsign(new->st.st_nlink, 0, ss[1]);
-      } else if (!strcmp(s, "user")) {
-        todo_store_argument();
-      } else if (!strcmp(s, "group")) {
-        todo_store_argument();
-      } else if (!strcmp(s, "newer")) {
-        todo_store_argument();
+      } else if (!strcmp(s, "user") || !strcmp(s, "group")
+              || !strcmp(s, "newer"))
+      {
+        struct {
+          void *next, *prev;
+          union {
+            uid_t uid;
+            gid_t gid;
+            struct timespec tm;
+          } u;
+        } *udl;
+
+        if (!new && ss[1]) {
+          udl = xmalloc(sizeof(*udl));
+          dlist_add_nomalloc(&TT.argdata, (void *)udl);
+
+          if (*s == 'u') udl->u.uid = xgetpwnam(ss[1])->pw_uid;
+          else if (*s == 'g') udl->u.gid = xgetgrnam(ss[1])->gr_gid;
+          else {
+            struct stat st;
+
+            xstat(ss[1], &st);
+            udl->u.tm = st.st_mtim;
+          }
+        } else if (check) {
+          udl = (void *)llist_pop(&argdata);
+          if (*s == 'u') test = new->st.st_uid == udl->u.uid;
+          else if (*s == 'g') test = new->st.st_gid == udl->u.gid;
+          else {
+            test = new->st.st_mtim.tv_sec > udl->u.tm.tv_sec;
+            if (new->st.st_mtim.tv_sec == udl->u.tm.tv_sec)
+              test = new->st.st_mtim.tv_nsec > udl->u.tm.tv_nsec;
+          }
+        }
       } else if (!strcmp(s, "exec") || !strcmp("ok", s)
               || !strcmp(s, "execdir") || !strcmp(s, "okdir"))
       {
@@ -392,47 +402,45 @@
           if (aa->dir && TT.topdir == -1) TT.topdir = xopen(".", 0);
 
         // collect names and execute commands
-        } else {
-          if (check) {
-            char *name, *ss1 = ss[1];
-            struct double_list **dl;
+        } else if (check) {
+          char *name, *ss1 = ss[1];
+          struct double_list **ddl;
 
-            // Grab command line exec argument list
-            aa = (void *)llist_pop(&argdata);
-            ss += aa->arglen + 1;
+          // Grab command line exec argument list
+          aa = (void *)llist_pop(&argdata);
+          ss += aa->arglen + 1;
 
-            // name is always a new malloc, so we can always free it.
-            name = aa->dir ? xstrdup(new->name) : dirtree_path(new, 0);
+          // name is always a new malloc, so we can always free it.
+          name = aa->dir ? xstrdup(new->name) : dirtree_path(new, 0);
 
-            // Mark entry so COMEAGAIN can call flush_exec() in parent.
-            // This is never a valid pointer valud for prev to have otherwise
-            if (aa->dir) aa->prev = (void *)1;
+          // Mark entry so COMEAGAIN can call flush_exec() in parent.
+          // This is never a valid pointer valud for prev to have otherwise
+          if (aa->dir) aa->prev = (void *)1;
 
-            if (*s == 'o') {
-              char *prompt = xmprintf("[%s] %s", ss1, name);
-              if(!(test = yesno(prompt, 0))) goto cont;
-            }
+          if (*s == 'o') {
+            char *prompt = xmprintf("[%s] %s", ss1, name);
+            if(!(test = yesno(prompt, 0))) goto cont;
+          }
 
-            // Add next name to list (global list without -dir, local with)
-            if (aa->dir && new->parent)
-              dl = (struct double_list **)&new->parent->extra;
-            else dl = &aa->names;
+          // Add next name to list (global list without -dir, local with)
+          if (aa->dir && new->parent)
+            ddl = (struct double_list **)&new->parent->extra;
+          else ddl = &aa->names;
 
-            // Is this + mode?
-            if (aa->plus) {
-              int size = sizeof(char *)+strlen(name)+1;
+          // Is this + mode?
+          if (aa->plus) {
+            int size = sizeof(char *)+strlen(name)+1;
 
-              // Linux caps environment space (env vars + args) at 32 4k pages.
-              // todo: is there a way to probe this instead of constant here?
+            // Linux caps environment space (env vars + args) at 32 4k pages.
+            // todo: is there a way to probe this instead of constant here?
 
-              if (TT.envsize+aa->argsize+aa->namesize+size >= 131072)
-                toys.exitval |= flush_exec(new, aa);
-              aa->namesize += size;
-            }
-            dlist_add(dl, name);
-            aa->namecount++;
-            if (!aa->plus) test = flush_exec(new, aa);
+            if (TT.envsize+aa->argsize+aa->namesize+size >= 131072)
+              toys.exitval |= flush_exec(new, aa);
+            aa->namesize += size;
           }
+          dlist_add(ddl, name);
+          aa->namecount++;
+          if (!aa->plus) test = flush_exec(new, aa);
         }
 
         // Argument consumed, skip the check.