Extending find(1) to support -printf

Jeremy Chadwick koitsu at FreeBSD.org
Fri Sep 5 10:12:54 UTC 2008


I've been working on $SUBJECT for the past few hours, and have managed
to implement a very crude subset of GNU find's features:

http://www.gnu.org/software/findutils/manual/html_node/find_html/Format-Directives.html#Format-Directives

I've implemented %f and %p (which appear identical to GNU find), and
some escaped characters.

Things I need help with, as string parsing in C has never been my forte
(which will become quite obvious):

1) Getting %h to behave like GNU find.  The GNU find code is
significantly different than ours.  As it stands, %h is broken.

2) find . -printf '\' results in odd output (SHELL=/usr/local/bin/bash
on my box).  Not sure why this is happening, but it's a big concern.

3) Security issues.  I believe use of a large number of formatting
variables could exceed the calloc()'d buffer (of MAXPATHLEN), causing
a segfault at bare minimum.  I'm not sure how to work around this.

Also, some folks on #bsdports asked why I was bothering with this in the
first place: mutt supports backticks to run shell commands inside of
a muttrc file.  See "Building a list of mailboxes on the fly" below:

http://wiki.mutt.org/?ConfigTricks

Note the find ... -printf '%h ' method.  I can accomplish (just
about) the same using `echo $HOME/Maildir/*`, but if I want to
exclude an entry, I can't use | grep -v, because mutt doesn't support
pipes within backticks.  :-)
  
-- 
| Jeremy Chadwick                                jdc at parodius.com |
| Parodius Networking                       http://www.parodius.com/ |
| UNIX Systems Administrator                  Mountain View, CA, USA |
| Making life hard for others since 1977.              PGP: 4BD6C0CB |

diff -ruN find.orig/extern.h find/extern.h
--- find.orig/extern.h	2006-05-14 13:23:00.000000000 -0700
+++ find/extern.h	2008-09-04 20:55:17.000000000 -0700
@@ -73,6 +73,7 @@
 creat_f	c_nouser;
 creat_f	c_perm;
 creat_f	c_print;
+creat_f	c_printf;
 creat_f	c_regex;
 creat_f	c_simple;
 creat_f	c_size;
@@ -107,6 +108,7 @@
 exec_f	f_perm;
 exec_f	f_print;
 exec_f	f_print0;
+exec_f	f_printf;
 exec_f	f_prune;
 exec_f	f_regex;
 exec_f	f_size;
diff -ruN find.orig/function.c find/function.c
--- find.orig/function.c	2006-05-27 11:27:41.000000000 -0700
+++ find/function.c	2008-09-05 03:01:36.000000000 -0700
@@ -1272,6 +1272,86 @@
 /* c_print0 is the same as c_print */
 
 /*
+ * -printf functions --
+ *
+ *	Always true, manipulates output based on printf()-like
+ *	formatting characters.
+ */
+int
+f_printf(PLAN *plan, FTSENT *entry)
+{
+	char *scan;
+	char *outptr;
+	char *outidx;
+
+	if ((outptr = calloc(MAXPATHLEN, 1)) == NULL)
+		err(1, NULL);
+
+	outidx = outptr;
+
+	for (scan = plan->c_data; *scan; scan++) {
+		if (*scan == '%') {
+			if (scan[1] == 0) {
+				errx(1, "missing format character");
+			}
+			else if (scan[1] == '%') {
+				*outidx++ = '%';
+			}
+			else if (scan[1] == 'f') {
+				strcpy(outidx, entry->fts_name);
+				outidx += entry->fts_namelen;
+			}
+			/* XXX - needs to behave like GNU find %h */
+			/*
+			else if (scan[1] == 'h') {
+				strcpy(outidx, entry->fts_path);
+				outidx += entry->fts_pathlen;
+			}
+			*/
+			else if (scan[1] == 'p') {
+				strcpy(outidx, entry->fts_path);
+				outidx += entry->fts_pathlen;
+			}
+			scan++;
+		}
+		else if (*scan == '\\') {
+			if (scan[1] == '\\') {
+				*outidx++ = '\\';
+			}
+			else if (scan[1] == 'n') {
+				*outidx++ = '\n';
+			}
+			else if (scan[1] == 't') {
+				*outidx++ = '\t';
+			}
+			scan++;
+		}
+		else {
+			*outidx++ = *scan;
+		}
+	}
+
+	(void)printf(outptr);
+	free(outptr);
+	return 1;
+}
+
+PLAN *
+c_printf(OPTION *option, char ***argvp)
+{
+	char *argstring;
+	PLAN *new;
+
+	argstring = nextarg(option, argvp);
+	ftsoptions &= ~FTS_NOSTAT;
+	isoutput = 1;
+
+	new = palloc(option);
+	new->c_data = argstring;
+	return new;
+}
+
+/*
  * -prune functions --
  *
  *	Prune a portion of the hierarchy.
diff -ruN find.orig/option.c find/option.c
--- find.orig/option.c	2006-04-05 16:06:11.000000000 -0700
+++ find/option.c	2008-09-04 20:48:18.000000000 -0700
@@ -128,6 +128,7 @@
 	{ "-perm",	c_perm,		f_perm,		0 },
 	{ "-print",	c_print,	f_print,	0 },
 	{ "-print0",	c_print,	f_print0,	0 },
+	{ "-printf",	c_printf,	f_printf,	0 },
 	{ "-prune",	c_simple,	f_prune,	0 },
 	{ "-regex",	c_regex,	f_regex,	0 },
 	{ "-size",	c_size,		f_size,		0 },


More information about the freebsd-hackers mailing list