Date: Tue, 21 May 2013 14:04:55 -0400 From: Kurt Lidl <lidl@pix.net> To: John Baldwin <jhb@freebsd.org> Cc: freebsd-hackers@freebsd.org, Jilles Tjoelker <jilles@stack.nl> Subject: Re: find -delete broken, or just used improperly? Message-ID: <519BB747.8030107@pix.net> In-Reply-To: <201305211106.39313.jhb@freebsd.org> References: <20130520192316.GA32531@pix.net> <20130520214731.GA43407@stack.nl> <201305211106.39313.jhb@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On 5/21/13 11:06 AM, John Baldwin wrote: > On Monday, May 20, 2013 5:47:31 pm Jilles Tjoelker wrote: >> On Mon, May 20, 2013 at 03:23:16PM -0400, Kurt Lidl wrote: >>> OK, maybe I'm missing something obvious, but... >> >>> find(1) says: >> >>> -delete >>> Delete found files and/or directories. Always returns true. >>> This executes from the current working directory as find recurses >>> down the tree. It will not attempt to delete a filename with a >>> ``/'' character in its pathname relative to ``.'' for security >>> reasons. Depth-first traversal processing is implied by this >>> option. Following symlinks is incompatible with this option. >> >>> However, it fails even when the path is absolute: >> >>> bhyve9# mkdir /tmp/foo >>> bhyve9# find /tmp/foo -empty -delete >>> find: -delete: /tmp/foo: relative path potentially not safe >> >>> Shouldn't this work? >> >> The "relative path" refers to a pathname that contains a slash other >> than at the beginning or end and may therefore refer to somewhere else >> if a directory is concurrently replaced by a symlink. >> >> When -L is not specified and "." can be opened, the fts(3) code >> underlying find(1) is careful to avoid following symlinks or being >> dropped in different locations by moving the directory fts is currently >> traversing. If a problematic concurrent modification is detected, fts >> will not enter the directory or abort. Files found in the search are >> returned via the current working directory and a pathname not containing >> a slash. >> >> For paranoia, find(1) verifies this when -delete is used. However, it is >> too paranoid about the root of the traversal. It is already assumed that >> the initial pathname does not refer to directories or symlinks that >> might be replaced by untrusted users; otherwise, the whole traversal >> would be unsafe. Therefore, it is not necessary to do the check for >> fts_level == FTS_ROOTLEVEL. >> >> The below patch allows deleting the pathname given to find itself: >> >> Index: usr.bin/find/function.c >> =================================================================== >> --- usr.bin/find/function.c (revision 250661) >> +++ usr.bin/find/function.c (working copy) >> @@ -442,7 +442,8 @@ >> errx(1, "-delete: forbidden when symlinks are followed"); >> >> /* Potentially unsafe - do not accept relative paths whatsoever */ >> - if (strchr(entry->fts_accpath, '/') != NULL) >> + if (entry->fts_level > FTS_ROOTLEVEL && >> + strchr(entry->fts_accpath, '/') != NULL) >> errx(1, "-delete: %s: relative path potentially not safe", >> entry->fts_accpath); > > I'm curious, how would you instruct a patched find to avoid deleteing the > /tmp/foo directory (e.g. if you wanted this to be a job that pruned empty > dirs from /tmp/foo but never pruned the directory itself). Would -mindepth 1 > do it? (Just asking. I have also found this message annoying but most of > the jobs I have seen it on probably don't want to delete the root path, > just descendants.) Using "-mindepth 1" does indeed preserve the target directory. Without it, the target directory is removed if all the children files/directories are empty. I've just finished a complete build of a recent stable/9: make buildworld && make buildkernel && cd release && make release With WITHOUT_SHAREDOCS= set in my src.conf, and Jilles' patch to find, and the following patch to Makefile.inc1, it now builds a release properly. bhyve9# hg diff Makefile.inc1 diff -r ca8ef48b4ba6 Makefile.inc1 --- a/Makefile.inc1 Thu May 16 10:21:04 2013 -0400 +++ b/Makefile.inc1 Tue May 21 13:58:13 2013 -0400 @@ -754,7 +754,7 @@ ${IMAKEENV} rm -rf ${INSTALLTMP} .if make(distributeworld) .for dist in ${EXTRA_DISTRIBUTIONS} - find ${DESTDIR}/${DISTDIR}/${dist} -empty -delete + find ${DESTDIR}/${DISTDIR}/${dist} -mindepth 1 -empty -delete .endfor .if defined(NO_ROOT) .for dist in base ${EXTRA_DISTRIBUTIONS} If one doesn't have the "-mindepth 1" in the find command, it will remove the usr/share/doc directory entirely, which will cause a failure later in the 'make release' target code... -Kurt
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?519BB747.8030107>