summaryrefslogtreecommitdiffstats
path: root/usr.bin/find
diff options
context:
space:
mode:
authortjr <tjr@FreeBSD.org>2002-06-02 12:57:41 +0000
committertjr <tjr@FreeBSD.org>2002-06-02 12:57:41 +0000
commitb93a81cb4e396134e70045351dfc15acda794481 (patch)
treed8bada3366a884688b15fe8bd60e2b4df8d68afb /usr.bin/find
parentb4166dc3bde27b9189bad425881efd176645ea65 (diff)
downloadFreeBSD-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.19
-rw-r--r--usr.bin/find/find.c4
-rw-r--r--usr.bin/find/find.h13
-rw-r--r--usr.bin/find/function.c77
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;
}
OpenPOWER on IntegriCloud