947 lines
28 KiB
Diff
947 lines
28 KiB
Diff
ChangeLog | 85 ++++++++++++++++++++++++++++++++++++++++++++++
|
||
find/defs.h | 14 ++++----
|
||
find/find.c | 69 +++++--------------------------------
|
||
find/finddata.c | 12 +-----
|
||
find/ftsfind.c | 49 ++-------------------------
|
||
find/parser.c | 35 ++++++------------
|
||
find/pred.c | 92 +++++++++++++++++++++++++++++++++-----------------
|
||
find/util.c | 89 +++++++++++++++++++++++++++++++++++++++---------
|
||
import-gnulib.config | 1 +
|
||
lib/dircallback.c | 35 ++++++++++++++++++-
|
||
lib/dircallback.h | 5 ++-
|
||
lib/listfile.c | 2 +-
|
||
12 files changed, 292 insertions(+), 196 deletions(-)
|
||
|
||
diff --git a/ChangeLog b/ChangeLog
|
||
index 34552d5..f040627 100644
|
||
--- a/ChangeLog
|
||
+++ b/ChangeLog
|
||
@@ -1,5 +1,90 @@
|
||
2010-04-10 James Youngman <jay@gnu.org>
|
||
|
||
+ Exec predicates now store which directory they want to run in.
|
||
+ * lib/dircallback.c (run_in_dirfd): New name for old run_in_dir
|
||
+ function.
|
||
+ (run_in_dir): Like the old function of the same name, but now
|
||
+ takes an argument const struct saved_cwd *.
|
||
+ * lib/dircallback.h: Update declarations of run_in_dirfd and
|
||
+ run_in_dir.
|
||
+ * find/util.c: Include dircallback.h, xalloc.h, save-cwd.h.
|
||
+ (do_complete_pending_execdirs): Remove dir_fd parameter, since the
|
||
+ per-predicate data structures now indicate what directory they
|
||
+ need to be run in. Instead of calling bc_do_exec directly, use a
|
||
+ callback 'exec_cb' that uses run_in_dir (which now takes a
|
||
+ saved_cwd* parameter instead of a file descriptor).
|
||
+ (do_exec): Called by do_complete_pending_execdirs, and simply uses
|
||
+ run_in_dir to call exec_cb, restoring the working directory
|
||
+ afterward.
|
||
+ (record_initial_cwd): New function, initialises the global
|
||
+ variable initial_wd.
|
||
+ (cleanup_initial_cwd): New function, cleans up the global variable
|
||
+ initial_wd.
|
||
+ (cleanup): Call cleanup_initial_cwd.
|
||
+ (get_start_dirfd): Remove.
|
||
+ (is_exec_in_local_dir): New function; true for predicates -execdir
|
||
+ and -okdir.
|
||
+ * find/pred.c: Include save-cwd.h.
|
||
+ (record_exec_dir): New function, sets the value of
|
||
+ execp->wd_for_exec if needed.
|
||
+ (new_impl_pred_exec): Remove the obsolete dir_fd parameter. Call
|
||
+ record_exec_dir.
|
||
+ (pred_exec): Don't pass the dir_fd parameter.
|
||
+ (pred_execdir): Likewise.
|
||
+ (pred_ok): Likewise.
|
||
+ (pred_okdir): Likewise.
|
||
+ (can_access): Call run_in_dirfd rather than run_in_dir (the
|
||
+ function was renamed).
|
||
+ (prep_child_for_exec): Remove dir_fd parameter; don't fchdir to
|
||
+ that. Call restore_cwd instead (passing a saved_cwd* parameter
|
||
+ which replaced dir_fd).
|
||
+ (launch): Remove references to execp->use_current_dir.
|
||
+ (launch): Change references to execp->dir_fd to execp->wd_for_exec.
|
||
+ * find/parser.c: Correct indentiation of declaration of
|
||
+ insert_exec_ok and remove the obsolete dir_fd parameter.
|
||
+ (parse_exec): Don't pass the dir_fd parameter to insert_exec_ok.
|
||
+ (parse_execdir): Likewise.
|
||
+ (parse_ok): Likewise.
|
||
+ (parse_okdir): Likewise.
|
||
+ (insert_exec_ok): Remove obsolete dir_fd paramter. Initialise
|
||
+ execp->wd_for_exec, either to NULL (for -*dir) or to the
|
||
+ initial_wd.
|
||
+ * find/ftsfind.c: Remove get_current_dirfd. Remove
|
||
+ complete_execdirs_cb.
|
||
+ (consider_visiting): Call complete_pending_execdirs directly.
|
||
+ (main): Call record_initial_cwd to record the initial working
|
||
+ directory, early on. Don't initialise starting_dir or
|
||
+ starting_desc, they have been removed.
|
||
+ * find/finddata.c: Include save-cwd.h. Remove starting_dir and
|
||
+ starting_desc. Add new global variable initial_wd. It is a struct
|
||
+ saved_wd* and represents find's initial working directory.
|
||
+ * find/find.c: Include save-cwd.h.
|
||
+ (main): Call record_initial_cwd in order to initialise the
|
||
+ global variable initial_wd Don't set starting_desc and
|
||
+ starting_dir, since those variables have been removed.
|
||
+ (safely_chdir): Don't pass an fd to complete_pending_execdirs.
|
||
+ (chdir_back): Remove the safety check (since we are using fchdir
|
||
+ and in any case no longer have all the data that the existing
|
||
+ wd_sanity_check function wants).
|
||
+ (do_process_top_dir): Don't pass an fd to
|
||
+ complete_pending_execdirs.
|
||
+ (process_dir): Likewise.
|
||
+ * find/defs.h (struct exec_val): Remove use_current_dir and
|
||
+ dir_fd. Replace with wd_for_exec, which is a struct saved_wd*.
|
||
+ (get_start_dirfd): Remove prototype.
|
||
+ (get_current_dirfd): Remove prototype.
|
||
+ (complete_pending_execdirs): No longer takes dir_fd parameter.
|
||
+ (record_initial_cwd): Add prototype.
|
||
+ (is_exec_in_local_dir): Add prototype.
|
||
+ (options): Declare.
|
||
+ (initial_wd): Add declaration. It is a struct saved_wd* and
|
||
+ represents find's initial working directory.
|
||
+ (starting_dir): Remove declaration of global variable.
|
||
+ (starting_desc): Remove declaration of global variable.
|
||
+ * import-gnulib.config (modules): Import module save-cwd.
|
||
+
|
||
+2010-04-10 James Youngman <jay@gnu.org>
|
||
+
|
||
Add a test which checks $CWD for find -execdir {} +/;
|
||
* find/testsuite/find.gnu/execdir-multiple.exp: New test; verifies
|
||
that for -execdir +, all the execs occur with the correct working
|
||
diff --git a/find/defs.h b/find/defs.h
|
||
index 36d428d..b4c1339 100644
|
||
--- a/find/defs.h
|
||
+++ b/find/defs.h
|
||
@@ -196,9 +196,8 @@ struct exec_val
|
||
struct buildcmd_state state;
|
||
char **replace_vec; /* Command arguments (for ";" style) */
|
||
int num_args;
|
||
- boolean use_current_dir; /* If nonzero, don't chdir to start dir */
|
||
boolean close_stdin; /* If true, close stdin in the child. */
|
||
- int dir_fd; /* The directory to do the exec in. */
|
||
+ struct saved_cwd *wd_for_exec;/* What directory to perform the exec in. */
|
||
};
|
||
|
||
/* The format string for a -printf or -fprintf is chopped into one or
|
||
@@ -337,8 +336,6 @@ struct predicate
|
||
|
||
/* find.c, ftsfind.c */
|
||
boolean is_fts_enabled(int *ftsoptions);
|
||
-int get_start_dirfd(void);
|
||
-int get_current_dirfd(void);
|
||
|
||
/* find library function declarations. */
|
||
|
||
@@ -493,8 +490,11 @@ struct predicate *insert_primary_withpred PARAMS((const struct parser_table *ent
|
||
void usage PARAMS((FILE *fp, int status, char *msg));
|
||
extern boolean check_nofollow(void);
|
||
void complete_pending_execs(struct predicate *p);
|
||
-void complete_pending_execdirs(int dir_fd); /* Passing dir_fd is an unpleasant CodeSmell. */
|
||
+void complete_pending_execdirs(void);
|
||
const char *safely_quote_err_filename (int n, char const *arg);
|
||
+void record_initial_cwd (void);
|
||
+boolean is_exec_in_local_dir(const PRED_FUNC pred_func);
|
||
+
|
||
void fatal_file_error(const char *name) ATTRIBUTE_NORETURN;
|
||
void nonfatal_file_error(const char *name);
|
||
|
||
@@ -660,10 +660,10 @@ struct state
|
||
};
|
||
|
||
/* finddata.c */
|
||
+extern struct options options;
|
||
extern struct state state;
|
||
-extern char const *starting_dir;
|
||
-extern int starting_desc;
|
||
extern char *program_name;
|
||
+extern struct saved_cwd *initial_wd;
|
||
|
||
|
||
#endif
|
||
diff --git a/find/find.c b/find/find.c
|
||
index 171988f..badcf3c 100644
|
||
--- a/find/find.c
|
||
+++ b/find/find.c
|
||
@@ -52,6 +52,7 @@
|
||
#include "quotearg.h"
|
||
#include "xgetcwd.h"
|
||
#include "error.h"
|
||
+#include "save-cwd.h"
|
||
|
||
#ifdef HAVE_LOCALE_H
|
||
#include <locale.h>
|
||
@@ -131,6 +132,8 @@ main (int argc, char **argv)
|
||
program_name = argv[0];
|
||
state.exit_status = 0;
|
||
|
||
+ record_initial_cwd ();
|
||
+
|
||
/* Set the option defaults before we do the locale
|
||
* initialisation as check_nofollow() needs to be executed in the
|
||
* POSIX locale.
|
||
@@ -183,23 +186,6 @@ main (int argc, char **argv)
|
||
}
|
||
|
||
|
||
- starting_desc = open (".", O_RDONLY
|
||
-#if defined O_LARGEFILE
|
||
- |O_LARGEFILE
|
||
-#endif
|
||
- );
|
||
- if (0 <= starting_desc && fchdir (starting_desc) != 0)
|
||
- {
|
||
- close (starting_desc);
|
||
- starting_desc = -1;
|
||
- }
|
||
-
|
||
- if (starting_desc < 0)
|
||
- {
|
||
- starting_dir = xgetcwd ();
|
||
- if (! starting_dir)
|
||
- error (1, errno, _("cannot get current directory"));
|
||
- }
|
||
set_stat_placeholders(&starting_stat_buf);
|
||
if ((*options.xstat) (".", &starting_stat_buf) != 0)
|
||
error (1, errno, _("cannot stat current directory"));
|
||
@@ -876,7 +862,7 @@ safely_chdir(const char *dest,
|
||
* processed, do them now because they must be done in the same
|
||
* directory.
|
||
*/
|
||
- complete_pending_execdirs(get_current_dirfd());
|
||
+ complete_pending_execdirs ();
|
||
|
||
#if !defined(O_NOFOLLOW)
|
||
options.open_nofollow_available = false;
|
||
@@ -911,45 +897,10 @@ safely_chdir(const char *dest,
|
||
static void
|
||
chdir_back (void)
|
||
{
|
||
- struct stat stat_buf;
|
||
- boolean dummy;
|
||
-
|
||
- if (starting_desc < 0)
|
||
- {
|
||
- if (options.debug_options & DebugSearch)
|
||
- fprintf(stderr, "chdir_back(): chdir(\"%s\")\n", starting_dir);
|
||
-
|
||
-#ifdef STAT_MOUNTPOINTS
|
||
- /* We will need the mounted device list. Get it now if we don't
|
||
- * already have it.
|
||
- */
|
||
- if (NULL == mounted_devices)
|
||
- init_mounted_dev_list(1);
|
||
-#endif
|
||
-
|
||
- if (chdir (starting_dir) != 0)
|
||
- fatal_file_error(starting_dir);
|
||
-
|
||
- wd_sanity_check(starting_dir,
|
||
- program_name,
|
||
- starting_dir,
|
||
- starting_stat_buf.st_dev,
|
||
- starting_stat_buf.st_ino,
|
||
- &stat_buf, 0, __LINE__,
|
||
- TraversingUp,
|
||
- FATAL_IF_SANITY_CHECK_FAILS,
|
||
- &dummy);
|
||
- }
|
||
- else
|
||
- {
|
||
- if (options.debug_options & DebugSearch)
|
||
- fprintf(stderr, "chdir_back(): chdir(<starting-point>)\n");
|
||
+ if (options.debug_options & DebugSearch)
|
||
+ fprintf (stderr, "chdir_back(): chdir to start point\n");
|
||
|
||
- if (fchdir (starting_desc) != 0)
|
||
- {
|
||
- fatal_file_error(starting_dir);
|
||
- }
|
||
- }
|
||
+ restore_cwd (initial_wd);
|
||
}
|
||
|
||
/* Move to the parent of a given directory and then call a function,
|
||
@@ -1038,7 +989,7 @@ static void do_process_top_dir(char *pathname,
|
||
(void) pstat;
|
||
|
||
process_path (pathname, base, false, ".", mode);
|
||
- complete_pending_execdirs(get_current_dirfd());
|
||
+ complete_pending_execdirs ();
|
||
}
|
||
|
||
static void do_process_predicate(char *pathname,
|
||
@@ -1326,7 +1277,7 @@ process_dir (char *pathname, char *name, int pathlen, const struct stat *statp,
|
||
* yet been processed, do them now because they must be done in
|
||
* the same directory.
|
||
*/
|
||
- complete_pending_execdirs(get_current_dirfd());
|
||
+ complete_pending_execdirs ();
|
||
|
||
if (strcmp (name, "."))
|
||
{
|
||
@@ -1464,7 +1415,7 @@ process_dir (char *pathname, char *name, int pathlen, const struct stat *statp,
|
||
* yet been processed, do them now because they must be done in
|
||
* the same directory.
|
||
*/
|
||
- complete_pending_execdirs(get_current_dirfd());
|
||
+ complete_pending_execdirs ();
|
||
|
||
if (strcmp (name, "."))
|
||
{
|
||
diff --git a/find/finddata.c b/find/finddata.c
|
||
index 373eb38..dcc8261 100644
|
||
--- a/find/finddata.c
|
||
+++ b/find/finddata.c
|
||
@@ -19,6 +19,7 @@
|
||
#include <config.h>
|
||
|
||
#include "defs.h"
|
||
+#include "save-cwd.h"
|
||
|
||
|
||
/* Name this program was run with. */
|
||
@@ -26,13 +27,4 @@ char *program_name;
|
||
|
||
struct options options;
|
||
struct state state;
|
||
-
|
||
-/* The full path of the initial working directory, or "." if
|
||
- STARTING_DESC is nonnegative. */
|
||
-char const *starting_dir = ".";
|
||
-
|
||
-/* A file descriptor open to the initial working directory.
|
||
- Doing it this way allows us to work when the i.w.d. has
|
||
- unreadable parents. */
|
||
-int starting_desc;
|
||
-
|
||
+struct saved_cwd *initial_wd = NULL;
|
||
diff --git a/find/ftsfind.c b/find/ftsfind.c
|
||
index 838b81f..9945abd 100644
|
||
--- a/find/ftsfind.c
|
||
+++ b/find/ftsfind.c
|
||
@@ -98,24 +98,6 @@ static int ftsoptions = FTS_NOSTAT|FTS_TIGHT_CYCLE_CHECK;
|
||
static int prev_depth = INT_MIN; /* fts_level can be < 0 */
|
||
static int curr_fd = -1;
|
||
|
||
-int get_current_dirfd(void)
|
||
-{
|
||
- if (ftsoptions & FTS_CWDFD)
|
||
- {
|
||
- assert (curr_fd != -1);
|
||
- assert ( (AT_FDCWD == curr_fd) || (curr_fd >= 0) );
|
||
-
|
||
- if (AT_FDCWD == curr_fd)
|
||
- return starting_desc;
|
||
- else
|
||
- return curr_fd;
|
||
- }
|
||
- else
|
||
- {
|
||
- return AT_FDCWD;
|
||
- }
|
||
-}
|
||
-
|
||
static void left_dir(void)
|
||
{
|
||
if (ftsoptions & FTS_CWDFD)
|
||
@@ -324,15 +306,6 @@ symlink_loop(const char *name)
|
||
}
|
||
|
||
|
||
-static int
|
||
-complete_execdirs_cb(void *context)
|
||
-{
|
||
- (void) context;
|
||
- /* By the tme this callback is called, the current directory is correct. */
|
||
- complete_pending_execdirs(AT_FDCWD);
|
||
- return 0;
|
||
-}
|
||
-
|
||
static void
|
||
show_outstanding_execdirs(FILE *fp)
|
||
{
|
||
@@ -566,7 +539,7 @@ consider_visiting(FTS *p, FTSENT *ent)
|
||
if (state.execdirs_outstanding)
|
||
{
|
||
show_outstanding_execdirs(stderr);
|
||
- run_in_dir(p->fts_cwd_fd, complete_execdirs_cb, NULL);
|
||
+ complete_pending_execdirs ();
|
||
}
|
||
|
||
if (ent->fts_info == FTS_DP)
|
||
@@ -670,6 +643,8 @@ main (int argc, char **argv)
|
||
state.execdirs_outstanding = false;
|
||
state.cwd_dir_fd = AT_FDCWD;
|
||
|
||
+ record_initial_cwd ();
|
||
+
|
||
/* Set the option defaults before we do the locale initialisation as
|
||
* check_nofollow() needs to be executed in the POSIX locale.
|
||
*/
|
||
@@ -719,24 +694,6 @@ main (int argc, char **argv)
|
||
}
|
||
|
||
|
||
- starting_desc = open (".", O_RDONLY
|
||
-#if defined O_LARGEFILE
|
||
- |O_LARGEFILE
|
||
-#endif
|
||
- );
|
||
- if (0 <= starting_desc && fchdir (starting_desc) != 0)
|
||
- {
|
||
- close (starting_desc);
|
||
- starting_desc = -1;
|
||
- }
|
||
- if (starting_desc < 0)
|
||
- {
|
||
- starting_dir = xgetcwd ();
|
||
- if (! starting_dir)
|
||
- error (1, errno, _("cannot get current directory"));
|
||
- }
|
||
-
|
||
-
|
||
process_all_startpoints(argc-end_of_leading_options, argv+end_of_leading_options);
|
||
|
||
/* If "-exec ... {} +" has been used, there may be some
|
||
diff --git a/find/parser.c b/find/parser.c
|
||
index 6b09eee..612cf71 100644
|
||
--- a/find/parser.c
|
||
+++ b/find/parser.c
|
||
@@ -181,7 +181,6 @@ static struct segment **make_segment PARAMS((struct segment **segment,
|
||
struct predicate *pred));
|
||
static boolean insert_exec_ok PARAMS((const char *action,
|
||
const struct parser_table *entry,
|
||
- int dir_fd,
|
||
char *argv[],
|
||
int *arg_ptr));
|
||
static boolean get_comp_type PARAMS((const char **str,
|
||
@@ -928,13 +927,13 @@ parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||
static boolean
|
||
parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||
{
|
||
- return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
|
||
+ return insert_exec_ok ("-exec", entry, argv, arg_ptr);
|
||
}
|
||
|
||
static boolean
|
||
parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||
{
|
||
- return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
|
||
+ return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
|
||
}
|
||
|
||
static boolean
|
||
@@ -1790,13 +1789,13 @@ parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||
static boolean
|
||
parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||
{
|
||
- return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
|
||
+ return insert_exec_ok ("-ok", entry, argv, arg_ptr);
|
||
}
|
||
|
||
static boolean
|
||
parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||
{
|
||
- return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
|
||
+ return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
|
||
}
|
||
|
||
boolean
|
||
@@ -3161,11 +3160,10 @@ check_path_safety(const char *action, char **argv)
|
||
|
||
/* handles both exec and ok predicate */
|
||
static boolean
|
||
-new_insert_exec_ok (const char *action,
|
||
- const struct parser_table *entry,
|
||
- int dir_fd,
|
||
- char **argv,
|
||
- int *arg_ptr)
|
||
+insert_exec_ok (const char *action,
|
||
+ const struct parser_table *entry,
|
||
+ char **argv,
|
||
+ int *arg_ptr)
|
||
{
|
||
int start, end; /* Indexes in ARGV of start & end of cmd. */
|
||
int i; /* Index into cmd args */
|
||
@@ -3186,6 +3184,7 @@ new_insert_exec_ok (const char *action,
|
||
our_pred->need_type = our_pred->need_stat = false;
|
||
|
||
execp = &our_pred->args.exec_vec;
|
||
+ execp->wd_for_exec = NULL;
|
||
|
||
if ((func != pred_okdir) && (func != pred_ok))
|
||
{
|
||
@@ -3205,13 +3204,14 @@ new_insert_exec_ok (const char *action,
|
||
|
||
if ((func == pred_execdir) || (func == pred_okdir))
|
||
{
|
||
+ execp->wd_for_exec = NULL;
|
||
options.ignore_readdir_race = false;
|
||
check_path_safety(action, argv);
|
||
- execp->use_current_dir = true;
|
||
}
|
||
else
|
||
{
|
||
- execp->use_current_dir = false;
|
||
+ assert (NULL != initial_wd);
|
||
+ execp->wd_for_exec = initial_wd;
|
||
}
|
||
|
||
our_pred->args.exec_vec.multiple = 0;
|
||
@@ -3364,17 +3364,6 @@ new_insert_exec_ok (const char *action,
|
||
|
||
|
||
|
||
-static boolean
|
||
-insert_exec_ok (const char *action,
|
||
- const struct parser_table *entry,
|
||
- int dir_fd,
|
||
- char **argv,
|
||
- int *arg_ptr)
|
||
-{
|
||
- return new_insert_exec_ok(action, entry, dir_fd, argv, arg_ptr);
|
||
-}
|
||
-
|
||
-
|
||
|
||
/* Get a timestamp and comparison type.
|
||
|
||
diff --git a/find/pred.c b/find/pred.c
|
||
index 7c34119..9273bba 100644
|
||
--- a/find/pred.c
|
||
+++ b/find/pred.c
|
||
@@ -47,6 +47,7 @@
|
||
#include "dircallback.h"
|
||
#include "error.h"
|
||
#include "verify.h"
|
||
+#include "save-cwd.h"
|
||
|
||
#include <selinux/selinux.h>
|
||
|
||
@@ -502,8 +503,30 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_
|
||
return (false);
|
||
}
|
||
|
||
+
|
||
static boolean
|
||
-new_impl_pred_exec (int dir_fd, const char *pathname,
|
||
+record_exec_dir (struct exec_val *execp)
|
||
+{
|
||
+ if (!execp->wd_for_exec)
|
||
+ {
|
||
+ /* working directory not already known, so must be a *dir variant,
|
||
+ and this must be the first arg we added. However, this may
|
||
+ be -execdir foo {} \; (i.e. not multiple). */
|
||
+ assert (!execp->state.todo);
|
||
+
|
||
+ /* Record the WD. */
|
||
+ execp->wd_for_exec = xmalloc (sizeof (*execp->wd_for_exec));
|
||
+ execp->wd_for_exec->name = NULL;
|
||
+ execp->wd_for_exec->desc = openat (state.cwd_dir_fd, ".", O_RDONLY);
|
||
+ if (execp->wd_for_exec->desc < 0)
|
||
+ return false;
|
||
+ }
|
||
+ return true;
|
||
+}
|
||
+
|
||
+
|
||
+static boolean
|
||
+new_impl_pred_exec (const char *pathname,
|
||
struct stat *stat_buf,
|
||
struct predicate *pred_ptr,
|
||
const char *prefix, size_t pfxlen)
|
||
@@ -512,7 +535,32 @@ new_impl_pred_exec (int dir_fd, const char *pathname,
|
||
size_t len = strlen(pathname);
|
||
|
||
(void) stat_buf;
|
||
- execp->dir_fd = dir_fd;
|
||
+
|
||
+ if (is_exec_in_local_dir (pred_ptr->pred_func))
|
||
+ {
|
||
+ /* For -execdir/-okdir predicates, the parser did not fill in
|
||
+ the wd_for_exec member of sturct exec_val. So for those
|
||
+ predicates, we do so now.
|
||
+ */
|
||
+ if (!record_exec_dir (execp))
|
||
+ {
|
||
+ error (EXIT_FAILURE, errno,
|
||
+ _("Failed to save working directory in order to "
|
||
+ "run a command on %s"),
|
||
+ safely_quote_err_filename (0, pathname));
|
||
+ /*NOTREACHED*/
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* For the others (-exec, -ok), the parder should
|
||
+ have set wd_for_exec to initial_wd, indicating
|
||
+ that the exec should take place from find's initial
|
||
+ working directory.
|
||
+ */
|
||
+ assert (execp->wd_for_exec == initial_wd);
|
||
+ }
|
||
+
|
||
if (execp->multiple)
|
||
{
|
||
/* Push the argument onto the current list.
|
||
@@ -558,8 +606,7 @@ new_impl_pred_exec (int dir_fd, const char *pathname,
|
||
boolean
|
||
pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||
{
|
||
- return new_impl_pred_exec(get_start_dirfd(),
|
||
- pathname, stat_buf, pred_ptr, NULL, 0);
|
||
+ return new_impl_pred_exec(pathname, stat_buf, pred_ptr, NULL, 0);
|
||
}
|
||
|
||
boolean
|
||
@@ -567,8 +614,7 @@ pred_execdir (const char *pathname, struct stat *stat_buf, struct predicate *pre
|
||
{
|
||
const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
|
||
(void) &pathname;
|
||
- return new_impl_pred_exec (get_current_dirfd(),
|
||
- state.rel_pathname, stat_buf, pred_ptr,
|
||
+ return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
|
||
prefix, (prefix ? 2 : 0));
|
||
}
|
||
|
||
@@ -1460,8 +1506,7 @@ boolean
|
||
pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||
{
|
||
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
|
||
- return new_impl_pred_exec (get_start_dirfd(),
|
||
- pathname, stat_buf, pred_ptr, NULL, 0);
|
||
+ return new_impl_pred_exec (pathname, stat_buf, pred_ptr, NULL, 0);
|
||
else
|
||
return false;
|
||
}
|
||
@@ -1471,8 +1516,7 @@ pred_okdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_
|
||
{
|
||
const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
|
||
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
|
||
- return new_impl_pred_exec (get_current_dirfd(),
|
||
- state.rel_pathname, stat_buf, pred_ptr,
|
||
+ return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
|
||
prefix, (prefix ? 2 : 0));
|
||
else
|
||
return false;
|
||
@@ -1573,7 +1617,7 @@ can_access(int access_type)
|
||
args.filename = state.rel_pathname;
|
||
args.access_type = access_type;
|
||
args.cb_errno = 0;
|
||
- return 0 == run_in_dir(state.cwd_dir_fd, access_callback, &args);
|
||
+ return 0 == run_in_dirfd (state.cwd_dir_fd, access_callback, &args);
|
||
}
|
||
|
||
|
||
@@ -1912,7 +1956,7 @@ pred_context (const char *pathname, struct stat *stat_buf,
|
||
|
||
|
||
static boolean
|
||
-prep_child_for_exec (boolean close_stdin, int dir_fd)
|
||
+prep_child_for_exec (boolean close_stdin, const struct saved_cwd *wd)
|
||
{
|
||
boolean ok = true;
|
||
if (close_stdin)
|
||
@@ -1948,17 +1992,10 @@ prep_child_for_exec (boolean close_stdin, int dir_fd)
|
||
* announcement of a call to stat() anyway, as we're about to exec
|
||
* something.
|
||
*/
|
||
- if (dir_fd != AT_FDCWD)
|
||
+ if (0 != restore_cwd (wd))
|
||
{
|
||
- assert (dir_fd >= 0);
|
||
- if (0 != fchdir(dir_fd))
|
||
- {
|
||
- /* If we cannot execute our command in the correct directory,
|
||
- * we should not execute it at all.
|
||
- */
|
||
- error(0, errno, _("Failed to change directory"));
|
||
- ok = false;
|
||
- }
|
||
+ error (0, errno, _("Failed to change directory"));
|
||
+ ok = false;
|
||
}
|
||
return ok;
|
||
}
|
||
@@ -1974,13 +2011,6 @@ launch (const struct buildcmd_control *ctl,
|
||
static int first_time = 1;
|
||
const struct exec_val *execp = buildstate->usercontext;
|
||
|
||
- if (!execp->use_current_dir)
|
||
- {
|
||
- assert (starting_desc >= 0);
|
||
- assert (execp->dir_fd == starting_desc);
|
||
- }
|
||
-
|
||
-
|
||
/* Null terminate the arg list. */
|
||
bc_push_arg (ctl, buildstate, (char *) NULL, 0, NULL, 0, false);
|
||
|
||
@@ -2001,8 +2031,8 @@ launch (const struct buildcmd_control *ctl,
|
||
if (child_pid == 0)
|
||
{
|
||
/* We are the child. */
|
||
- assert (starting_desc >= 0);
|
||
- if (!prep_child_for_exec(execp->close_stdin, execp->dir_fd))
|
||
+ assert (NULL != execp->wd_for_exec);
|
||
+ if (!prep_child_for_exec (execp->close_stdin, execp->wd_for_exec))
|
||
{
|
||
_exit(1);
|
||
}
|
||
diff --git a/find/util.c b/find/util.c
|
||
index d3cb467..da4fc62 100644
|
||
--- a/find/util.c
|
||
+++ b/find/util.c
|
||
@@ -36,6 +36,9 @@
|
||
#include "error.h"
|
||
#include "verify.h"
|
||
#include "openat.h"
|
||
+#include "dircallback.h"
|
||
+#include "xalloc.h"
|
||
+#include "save-cwd.h"
|
||
|
||
#if ENABLE_NLS
|
||
# include <libintl.h>
|
||
@@ -282,6 +285,26 @@ check_nofollow(void)
|
||
#endif
|
||
|
||
|
||
+static int
|
||
+exec_cb (void *context)
|
||
+{
|
||
+ struct exec_val *execp = context;
|
||
+ launch (&execp->ctl, &execp->state);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void
|
||
+do_exec (struct exec_val *execp)
|
||
+{
|
||
+ run_in_dir (execp->wd_for_exec, exec_cb, execp);
|
||
+ if (execp->wd_for_exec != initial_wd)
|
||
+ {
|
||
+ free_cwd (execp->wd_for_exec);
|
||
+ free (execp->wd_for_exec);
|
||
+ execp->wd_for_exec = NULL;
|
||
+ }
|
||
+}
|
||
+
|
||
|
||
/* Examine the predicate list for instances of -execdir or -okdir
|
||
* which have been terminated with '+' (build argument list) rather
|
||
@@ -289,14 +312,14 @@ check_nofollow(void)
|
||
* have no effect if there are no arguments waiting).
|
||
*/
|
||
static void
|
||
-do_complete_pending_execdirs(struct predicate *p, int dir_fd)
|
||
+do_complete_pending_execdirs(struct predicate *p)
|
||
{
|
||
if (NULL == p)
|
||
return;
|
||
|
||
assert (state.execdirs_outstanding);
|
||
|
||
- do_complete_pending_execdirs(p->pred_left, dir_fd);
|
||
+ do_complete_pending_execdirs(p->pred_left);
|
||
|
||
if (pred_is(p, pred_execdir) || pred_is(p, pred_okdir))
|
||
{
|
||
@@ -311,25 +334,24 @@ do_complete_pending_execdirs(struct predicate *p, int dir_fd)
|
||
if (execp->state.todo)
|
||
{
|
||
/* There are not-yet-executed arguments. */
|
||
- launch (&execp->ctl, &execp->state);
|
||
+ do_exec (execp);
|
||
}
|
||
}
|
||
}
|
||
|
||
- do_complete_pending_execdirs(p->pred_right, dir_fd);
|
||
+ do_complete_pending_execdirs(p->pred_right);
|
||
}
|
||
|
||
void
|
||
-complete_pending_execdirs(int dir_fd)
|
||
+complete_pending_execdirs (void)
|
||
{
|
||
if (state.execdirs_outstanding)
|
||
{
|
||
- do_complete_pending_execdirs(get_eval_tree(), dir_fd);
|
||
+ do_complete_pending_execdirs(get_eval_tree());
|
||
state.execdirs_outstanding = false;
|
||
}
|
||
}
|
||
|
||
-
|
||
|
||
/* Examine the predicate list for instances of -exec which have been
|
||
* terminated with '+' (build argument list) rather than ';' (singles
|
||
@@ -365,6 +387,37 @@ complete_pending_execs(struct predicate *p)
|
||
|
||
complete_pending_execs(p->pred_right);
|
||
}
|
||
+
|
||
+void
|
||
+record_initial_cwd (void)
|
||
+{
|
||
+ initial_wd = xmalloc (sizeof (*initial_wd));
|
||
+ if (0 != save_cwd (initial_wd))
|
||
+ {
|
||
+ error (EXIT_FAILURE, errno,
|
||
+ _("failed to save initial working directory"));
|
||
+ }
|
||
+}
|
||
+
|
||
+static void
|
||
+cleanup_initial_cwd (void)
|
||
+{
|
||
+ if (0 == restore_cwd (initial_wd))
|
||
+ {
|
||
+ free_cwd (initial_wd);
|
||
+ free (initial_wd);
|
||
+ initial_wd = NULL;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* since we may already be in atexit, die with _exit(). */
|
||
+ error (0, errno,
|
||
+ _("failed to restore initial working directory"));
|
||
+ _exit (EXIT_FAILURE);
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
|
||
static void
|
||
traverse_tree(struct predicate *tree,
|
||
@@ -424,9 +477,11 @@ cleanup(void)
|
||
if (eval_tree)
|
||
{
|
||
traverse_tree(eval_tree, complete_pending_execs);
|
||
- complete_pending_execdirs(get_current_dirfd());
|
||
+ complete_pending_execdirs ();
|
||
traverse_tree(eval_tree, flush_and_close_output_files);
|
||
}
|
||
+
|
||
+ cleanup_initial_cwd ();
|
||
}
|
||
|
||
/* Savannah bug #16378 manifests as an assertion failure in pred_type()
|
||
@@ -963,15 +1018,6 @@ set_option_defaults(struct options *p)
|
||
}
|
||
|
||
|
||
-/* get_start_dirfd
|
||
- *
|
||
- * Returns the fd for the directory we started in.
|
||
- */
|
||
-int get_start_dirfd(void)
|
||
-{
|
||
- return starting_desc;
|
||
-}
|
||
-
|
||
/* apply_predicate
|
||
*
|
||
*/
|
||
@@ -997,6 +1043,15 @@ apply_predicate(const char *pathname, struct stat *stat_buf, struct predicate *p
|
||
}
|
||
}
|
||
|
||
+/* is_exec_in_local_dir
|
||
+ *
|
||
+ */
|
||
+bool
|
||
+is_exec_in_local_dir (const PRED_FUNC pred_func)
|
||
+{
|
||
+ return pred_execdir == pred_func || pred_okdir == pred_func;
|
||
+}
|
||
+
|
||
|
||
/* safely_quote_err_filename
|
||
*
|
||
diff --git a/import-gnulib.config b/import-gnulib.config
|
||
index f2e8998..b1f0851 100644
|
||
--- a/import-gnulib.config
|
||
+++ b/import-gnulib.config
|
||
@@ -67,6 +67,7 @@ quotearg
|
||
realloc
|
||
regex
|
||
rpmatch
|
||
+save-cwd
|
||
savedir
|
||
stat-macros
|
||
stat-time
|
||
diff --git a/lib/dircallback.c b/lib/dircallback.c
|
||
index 5dbf3b3..72691ed 100644
|
||
--- a/lib/dircallback.c
|
||
+++ b/lib/dircallback.c
|
||
@@ -54,7 +54,40 @@
|
||
|
||
|
||
int
|
||
-run_in_dir (int dir_fd, int (*callback)(void*), void *usercontext)
|
||
+run_in_dir (const struct saved_cwd *there,
|
||
+ int (*callback)(void*), void *usercontext)
|
||
+{
|
||
+ int err = -1, saved_errno;
|
||
+ struct saved_cwd here;
|
||
+ if (0 == save_cwd (&here))
|
||
+ {
|
||
+ if (0 == restore_cwd (there))
|
||
+ {
|
||
+ err = callback(usercontext);
|
||
+ saved_errno = (err < 0 ? errno : 0);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ openat_restore_fail (errno);
|
||
+ }
|
||
+
|
||
+ if (restore_cwd (&here) != 0)
|
||
+ openat_restore_fail (errno);
|
||
+
|
||
+ free_cwd (&here);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ openat_save_fail (errno);
|
||
+ }
|
||
+ if (saved_errno)
|
||
+ errno = saved_errno;
|
||
+ return err;
|
||
+}
|
||
+
|
||
+
|
||
+int
|
||
+run_in_dirfd (int dir_fd, int (*callback)(void*), void *usercontext)
|
||
{
|
||
if (dir_fd == AT_FDCWD)
|
||
{
|
||
diff --git a/lib/dircallback.h b/lib/dircallback.h
|
||
index 41ea282..3234113 100644
|
||
--- a/lib/dircallback.h
|
||
+++ b/lib/dircallback.h
|
||
@@ -19,6 +19,9 @@
|
||
#if !defined DIRCALLBACK_H
|
||
# define DIRCALLBACK_H
|
||
|
||
-int run_in_dir (int dir_fd, int (*callback)(void*), void *usercontext);
|
||
+struct saved_cwd;
|
||
+
|
||
+int run_in_dirfd (int fd, int (*callback)(void*), void *usercontext);
|
||
+int run_in_dir (struct saved_cwd*, int (*callback)(void*), void *usercontext);
|
||
|
||
#endif
|
||
diff --git a/lib/listfile.c b/lib/listfile.c
|
||
index ca9eae2..b5bee54 100644
|
||
--- a/lib/listfile.c
|
||
+++ b/lib/listfile.c
|
||
@@ -424,7 +424,7 @@ get_link_name_at (const char *name, int dir_fd, char *relname)
|
||
args.result = NULL;
|
||
args.name = name;
|
||
args.relname = relname;
|
||
- if (0 == run_in_dir(dir_fd, get_link_name_cb, &args))
|
||
+ if (0 == run_in_dirfd (dir_fd, get_link_name_cb, &args))
|
||
return args.result;
|
||
else
|
||
return NULL;
|