diff options
author | tjr <tjr@FreeBSD.org> | 2002-06-02 12:57:41 +0000 |
---|---|---|
committer | tjr <tjr@FreeBSD.org> | 2002-06-02 12:57:41 +0000 |
commit | b93a81cb4e396134e70045351dfc15acda794481 (patch) | |
tree | d8bada3366a884688b15fe8bd60e2b4df8d68afb /usr.bin/find | |
parent | b4166dc3bde27b9189bad425881efd176645ea65 (diff) | |
download | FreeBSD-src-b93a81cb4e396134e70045351dfc15acda794481.zip FreeBSD-src-b93a81cb4e396134e70045351dfc15acda794481.tar.gz |
Support the SysV-style -exec utility args.. {} + function, required by
SUSv3. This is similar to find foo -print0 | xargs -0 utility args.
Diffstat (limited to 'usr.bin/find')
-rw-r--r-- | usr.bin/find/find.1 | 9 | ||||
-rw-r--r-- | usr.bin/find/find.c | 4 | ||||
-rw-r--r-- | usr.bin/find/find.h | 13 | ||||
-rw-r--r-- | usr.bin/find/function.c | 77 |
4 files changed, 95 insertions, 8 deletions
diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1 index 33fb540..c80b7ad 100644 --- a/usr.bin/find/find.1 +++ b/usr.bin/find/find.1 @@ -294,6 +294,15 @@ and .Ar arguments are not subject to the further expansion of shell patterns and constructs. +.It Ic -exec Ar utility Oo Ar argument ... Oc {} + +Same as +.Ic -exec , +except that +.Dq Li {} +is replaced with as many pathnames as possible for each invocation of +.Ar utility . +This behaviour is similar to that of +.Xr xargs 1 . .It Ic -execdir Ar utility Op Ar argument ... ; The .Ic -execdir diff --git a/usr.bin/find/find.c b/usr.bin/find/find.c index f100f88..5006e9e 100644 --- a/usr.bin/find/find.c +++ b/usr.bin/find/find.c @@ -235,6 +235,10 @@ find_execute(plan, paths) continue; } } + /* Finish any pending -exec ... {} + functions. */ + for (p = plan; p != NULL; p = p->next) + if (p->execute == f_exec && p->flags & F_EXECPLUS) + (p->execute)(p, NULL); if (errno) err(1, "fts_read"); return (rval); diff --git a/usr.bin/find/find.h b/usr.bin/find/find.h index 1a210d0..2944278 100644 --- a/usr.bin/find/find.h +++ b/usr.bin/find/find.h @@ -70,6 +70,7 @@ typedef struct _plandata *creat_f(struct _option *, char ***); #define F_MTUNKNOWN 0x00002000 #define F_IGNCASE 0x00010000 /* iname ipath iregex */ #define F_EXACTTIME F_IGNCASE /* -[acm]time units syntax */ +#define F_EXECPLUS 0x00020000 /* -exec ... {} + */ /* node definition */ typedef struct _plandata { @@ -94,6 +95,12 @@ typedef struct _plandata { char **_e_argv; /* argv array */ char **_e_orig; /* original strings */ int *_e_len; /* allocated length */ + int _e_pbnum; /* base num. of args. used */ + int _e_ppos; /* number of arguments used */ + int _e_pnummax; /* max. number of arguments */ + int _e_psize; /* number of bytes of args. */ + int _e_pbsize; /* base num. of bytes of args */ + int _e_psizemax; /* max num. of bytes of args */ } ex; char *_a_data[2]; /* array of char pointers */ char *_c_data; /* char pointer */ @@ -117,6 +124,12 @@ typedef struct _plandata { #define e_argv p_un.ex._e_argv #define e_orig p_un.ex._e_orig #define e_len p_un.ex._e_len +#define e_pbnum p_un.ex._e_pbnum +#define e_ppos p_un.ex._e_ppos +#define e_pnummax p_un.ex._e_pnummax +#define e_psize p_un.ex._e_psize +#define e_pbsize p_un.ex._e_pbsize +#define e_psizemax p_un.ex._e_psizemax typedef struct _option { const char *name; /* option name */ diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c index 3bb9271..2cd35ae 100644 --- a/usr.bin/find/function.c +++ b/usr.bin/find/function.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <fnmatch.h> #include <fts.h> #include <grp.h> +#include <limits.h> #include <pwd.h> #include <regex.h> #include <stdio.h> @@ -528,6 +529,13 @@ f_exec(plan, entry) int status; char *file; + if (entry == NULL && plan->flags & F_EXECPLUS) { + if (plan->e_ppos == plan->e_pbnum) + return (1); + plan->e_argv[plan->e_ppos] = NULL; + goto doexec; + } + /* XXX - if file/dir ends in '/' this will not work -- can it? */ if ((plan->flags & F_EXECDIR) && \ (file = strrchr(entry->fts_path, '/'))) @@ -535,12 +543,24 @@ f_exec(plan, entry) else file = entry->fts_path; - for (cnt = 0; plan->e_argv[cnt]; ++cnt) - if (plan->e_len[cnt]) - brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt], - file, plan->e_len[cnt]); + if (plan->flags & F_EXECPLUS) { + if ((plan->e_argv[plan->e_ppos] = strdup(file)) == NULL) + err(1, NULL); + plan->e_len[plan->e_ppos] = strlen(file); + plan->e_psize += plan->e_len[plan->e_ppos]; + if (++plan->e_ppos < plan->e_pnummax && + plan->e_psize < plan->e_psizemax) + return (1); + plan->e_argv[plan->e_ppos] = NULL; + } else { + for (cnt = 0; plan->e_argv[cnt]; ++cnt) + if (plan->e_len[cnt]) + brace_subst(plan->e_orig[cnt], + &plan->e_argv[cnt], file, + plan->e_len[cnt]); + } - if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv)) +doexec: if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv)) return 0; /* make sure find output is interspersed correctly with subprocesses */ @@ -561,6 +581,12 @@ f_exec(plan, entry) warn("%s", plan->e_argv[0]); _exit(1); } + if (plan->flags & F_EXECPLUS) { + while (--plan->e_ppos >= plan->e_pbnum) + free(plan->e_argv[plan->e_ppos]); + plan->e_ppos = plan->e_pbnum; + plan->e_psize = plan->e_pbsize; + } pid = waitpid(pid, &status, 0); return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status)); } @@ -578,7 +604,8 @@ c_exec(option, argvp) char ***argvp; { PLAN *new; /* node returned */ - int cnt; + long argmax; + int cnt, i; char **argv, **ap, *p; /* XXX - was in c_execdir, but seems unnecessary!? @@ -595,12 +622,32 @@ c_exec(option, argvp) "%s: no terminating \";\"", option->name); if (**ap == ';') break; + if (**ap == '+' && ap != argv && strcmp(*(ap - 1), "{}") == 0) { + new->flags |= F_EXECPLUS; + break; + } } if (ap == argv) errx(1, "%s: no command specified", option->name); cnt = ap - *argvp + 1; + if (new->flags & F_EXECPLUS) { + new->e_ppos = new->e_pbnum = cnt - 2; + if ((argmax = sysconf(_SC_ARG_MAX)) == -1) { + warn("sysconf(_SC_ARG_MAX)"); + argmax = _POSIX_ARG_MAX; + } + /* + * Estimate the maximum number of arguments as {ARG_MAX}/10, + * and the maximum number of bytes to use for arguments as + * {ARG_MAX}*(3/4). + */ + new->e_pnummax = argmax / 10; + new->e_psizemax = (argmax / 4) * 3; + new->e_pbsize = 0; + cnt += new->e_pnummax + 1; + } if ((new->e_argv = malloc(cnt * sizeof(char *))) == NULL) err(1, NULL); if ((new->e_orig = malloc(cnt * sizeof(char *))) == NULL) @@ -610,8 +657,11 @@ c_exec(option, argvp) for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) { new->e_orig[cnt] = *argv; + if (new->flags & F_EXECPLUS) + new->e_pbsize += strlen(*argv) + 1; for (p = *argv; *p; ++p) - if (p[0] == '{' && p[1] == '}') { + if (!(new->flags & F_EXECPLUS) && p[0] == '{' && + p[1] == '}') { if ((new->e_argv[cnt] = malloc(MAXPATHLEN)) == NULL) err(1, NULL); @@ -623,9 +673,20 @@ c_exec(option, argvp) new->e_len[cnt] = 0; } } + if (new->flags & F_EXECPLUS) { + new->e_psize = new->e_pbsize; + cnt--; + for (i = 0; i < new->e_pnummax; i++) { + new->e_argv[cnt] = NULL; + new->e_len[cnt] = 0; + cnt++; + } + argv = ap; + goto done; + } new->e_argv[cnt] = new->e_orig[cnt] = NULL; - *argvp = argv + 1; +done: *argvp = argv + 1; return new; } |