I found this problem while looking into Bug#13516 <http://bugs.gnu.org/13515>. Currently, the openat emulator exits the program if savedir fails, but it's nicer if it merely causes openat to fail. If savedir fails, no harm has been done yet -- the program's working directory has not changed, so there's no need to do something as drastic as exit the program.
Here's a proposed patch. It also fixes some more-obscure issues in functions like linkat. I suppose I could pull them out as a separate patch but I'm not sure it's worth the trouble. openat: don't exit program if save_cwd fails * lib/at-func.c (AT_FUNC_NAME): * lib/at-func2.c (at_func2): * lib/openat.c (openat_permissive): If save_cwd fails, simply return a failure rather than exiting the program. No harm has been done yet, since we haven't used chdir. * lib/at-func2.c (at_func2): Simplify, and fix bugs whereby the code would leave the application in the wrong directory (!) in some tricky failure cases. diff --git a/lib/at-func.c b/lib/at-func.c index 03c5678..aa94561 100644 --- a/lib/at-func.c +++ b/lib/at-func.c @@ -108,7 +108,7 @@ AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS) } if (save_cwd (&saved_cwd) != 0) - openat_save_fail (errno); + return FUNC_FAIL; if (0 <= fd && fd == saved_cwd.desc) { /* If saving the working directory collides with the user's diff --git a/lib/at-func2.c b/lib/at-func2.c index bbbddc0..169d886 100644 --- a/lib/at-func2.c +++ b/lib/at-func2.c @@ -180,7 +180,7 @@ at_func2 (int fd1, char const *file1, place, it is time to start changing directories. */ if (save_cwd (&saved_cwd) != 0) - openat_save_fail (errno); + return -1; if (fd1 != AT_FDCWD && fd2 != AT_FDCWD && fd1 != fd2) /* Case 15b. */ { @@ -199,6 +199,7 @@ at_func2 (int fd1, char const *file1, file1_alt = (char *) file1; file2_alt = (char *) file2; + saved_errno = 0; if (fd1 == AT_FDCWD && !IS_ABSOLUTE_FILE_NAME (file1)) /* Case 7. */ { @@ -207,63 +208,41 @@ at_func2 (int fd1, char const *file1, but libraries should not call xalloc_die. */ char *cwd = getcwd (NULL, 0); if (!cwd) + saved_errno = errno; + else { - saved_errno = errno; - free_cwd (&saved_cwd); - errno = saved_errno; - return -1; - } - file1_alt = mfile_name_concat (cwd, file1, NULL); - if (!file1_alt) - { - saved_errno = errno; + file1_alt = mfile_name_concat (cwd, file1, NULL); + if (!file1_alt) + saved_errno = errno; free (cwd); - free_cwd (&saved_cwd); - errno = saved_errno; - return -1; } - free (cwd); /* Reduced to case 3. */ + /* Reduced to case 3. */ } else if (fd2 == AT_FDCWD && !IS_ABSOLUTE_FILE_NAME (file2)) /* Case 13. */ { char *cwd = getcwd (NULL, 0); if (!cwd) + saved_errno = errno; + else { - saved_errno = errno; - free_cwd (&saved_cwd); - errno = saved_errno; - return -1; - } - file2_alt = mfile_name_concat (cwd, file2, NULL); - if (!file2_alt) - { - saved_errno = errno; + file2_alt = mfile_name_concat (cwd, file2, NULL); + if (!file2_alt) + saved_errno = errno; free (cwd); - free_cwd (&saved_cwd); - errno = saved_errno; - return -1; } - free (cwd); /* Reduced to case 12. */ + /* Reduced to case 12. */ } - /* Cases 3, 12, 15a remain. Change to the correct directory. */ - if (fchdir (fd1 == AT_FDCWD ? fd2 : fd1) != 0) + err = -1; + if (! saved_errno) { + /* Cases 3, 12, 15a remain. Change to the correct directory + and perform the user's function. */ + if (fchdir (fd1 == AT_FDCWD ? fd2 : fd1) == 0) + err = func (file1_alt, file2_alt); saved_errno = errno; - free_cwd (&saved_cwd); - if (file1 != file1_alt) - free (file1_alt); - else if (file2 != file2_alt) - free (file2_alt); - errno = saved_errno; - return -1; } - /* Finally safe to perform the user's function, then clean up. */ - - err = func (file1_alt, file2_alt); - saved_errno = (err < 0 ? errno : 0); - if (file1 != file1_alt) free (file1_alt); else if (file2 != file2_alt) @@ -274,8 +253,7 @@ at_func2 (int fd1, char const *file1, free_cwd (&saved_cwd); - if (saved_errno) - errno = saved_errno; + errno = saved_errno; return err; } #undef CALL_FUNC diff --git a/lib/openat.c b/lib/openat.c index fd1ff91..7ea0e58 100644 --- a/lib/openat.c +++ b/lib/openat.c @@ -220,7 +220,7 @@ openat_permissive (int fd, char const *file, int flags, mode_t mode, if (! save_ok) { if (! cwd_errno) - openat_save_fail (errno); + return -1; *cwd_errno = errno; } if (0 <= fd && fd == saved_cwd.desc)