Index: function.c =================================================================== --- function.c (revision 232950) +++ function.c (working copy) @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -595,7 +596,7 @@ int f_exec(PLAN *plan, FTSENT *entry) { - int cnt; + int cnt, path_fd; pid_t pid; int status; char *file; @@ -644,9 +645,31 @@ /* NOTREACHED */ case 0: /* change dir back from where we started */ - if (!(plan->flags & F_EXECDIR) && fchdir(dotfd)) { - warn("chdir"); + if (!(plan->flags & F_EXECDIR) && \ + !(tree->fts_options & FTS_NOCHDIR) && \ + fchdir(dotfd)) { _exit(1); + /* + * if no entry, we are finishing. without F_NOCHDIR this would + * happen to be in pwd, so don't chdir. We use tree->fts_options + * instead of ftsoptions, as FTS_LOGICAL sets FTS_NOCHDIR on + * fts_open(3) + */ + } else if (entry != NULL && entry->fts_level > 0 && \ + (plan->flags & F_EXECDIR) && \ + (tree->fts_options & FTS_NOCHDIR)) { + /* + * "Truncate" by NUL at name boundary, we cannot use + * entry->fts_parent here as it is not reliably set + * unless we have called fts_children(3), which we have + * not. + */ + entry->fts_path[entry->fts_pathlen - entry->fts_namelen] = '\0'; + if ((path_fd = open(entry->fts_path, O_RDONLY, 0)) < 0 \ + || fchdir(path_fd) || close(path_fd)) { + warn("chdir"); + _exit(1); + } } execvp(plan->e_argv[0], plan->e_argv); warn("%s", plan->e_argv[0]); Index: find.c =================================================================== --- find.c (revision 232950) +++ find.c (working copy) @@ -179,7 +179,7 @@ tree = fts_open(paths, ftsoptions, (issort ? find_compare : NULL)); if (tree == NULL) - err(1, "ftsopen"); + err(1, "fts_open"); for (rval = 0; (entry = fts_read(tree)) != NULL;) { if (maxdepth != -1 && entry->fts_level >= maxdepth) { Index: main.c =================================================================== --- main.c (revision 232950) +++ main.c (working copy) @@ -63,7 +63,7 @@ time_t now; /* time find was run */ int dotfd; /* starting directory */ -int ftsoptions; /* options for the ftsopen(3) call */ +int ftsoptions; /* options for the fts_open(3) call */ int isdeprecated; /* using deprecated syntax */ int isdepth; /* do directories on post-order visit */ int isoutput; /* user specified output operator */ @@ -150,8 +150,10 @@ usage(); *p = NULL; - if ((dotfd = open(".", O_RDONLY, 0)) < 0) - err(1, "."); + if ((dotfd = open(".", O_RDONLY, 0)) < 0) { + warn("."); + ftsoptions |= FTS_NOCHDIR; + } exit(find_execute(find_formplan(argv), start)); }