From 60c35c486a2ea1c6ea8920c599abf992b27542c5 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 3 Aug 2014 15:50:10 -0500 Subject: Implement exec -user, -group, and -newer. Enable find in defconfig. --- lib/lib.h | 1 + lib/xwrap.c | 8 ++++ toys/posix/find.c | 138 +++++++++++++++++++++++++++++------------------------- 3 files changed, 82 insertions(+), 65 deletions(-) diff --git a/lib/lib.h b/lib/lib.h index 521a8d6b..de5f5470 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -119,6 +119,7 @@ void xchroot(char *path); 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); diff --git a/lib/xwrap.c b/lib/xwrap.c index 4d8ad711..c9d1876f 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -455,6 +455,14 @@ struct passwd *xgetpwnam(char *name) 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. diff --git a/toys/posix/find.c b/toys/posix/find.c index 663d2e2f..dedf3ede 100644 --- a/toys/posix/find.c +++ b/toys/posix/find.c @@ -12,7 +12,7 @@ USE_FIND(NEWTOY(find, "?^HL", TOYFLAG_USR|TOYFLAG_BIN)) config FIND bool "find" - default n + default y help usage: find [-HL] [DIR...] [] @@ -46,19 +46,6 @@ config FIND 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 @@ static void do_print(struct dirtree *new, char c) free(s); } -void todo_store_argument(void) -{ - error_exit("NOP"); -} - char *strlower(char *s) { char *try, *new; @@ -340,12 +322,40 @@ static int do_find(struct dirtree *new) 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 @@ static int do_find(struct dirtree *new) 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; - - // 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); - - // 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; - } - - // 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; - - // 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? - - 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); + } 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; + + // 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; + + 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) + ddl = (struct double_list **)&new->parent->extra; + else ddl = &aa->names; + + // 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? + + 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. -- cgit v1.2.3