From 1127409564ed41ac1d0f9494b15abc9ba1280449 Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Wed, 20 Nov 2019 08:43:26 +0000 Subject: [PATCH] eina - add portable close all fd's we don't need function close all fd's starting at a given fd and then leving out an exception list specially passed, if any. useful for fork+exec. this uses it in efl's fork+exec paths. @feat --- src/lib/ecore/ecore_exe_posix.c | 4 ++ src/lib/ecore/efl_exe.c | 5 ++ src/lib/eina/eina_file.c | 84 +++++++++++++++++++++++++++++++++ src/lib/eina/eina_file.h | 17 +++++++ 4 files changed, 110 insertions(+) diff --git a/src/lib/ecore/ecore_exe_posix.c b/src/lib/ecore/ecore_exe_posix.c index 6a0cc3b79e..4a9b7a3338 100644 --- a/src/lib/ecore/ecore_exe_posix.c +++ b/src/lib/ecore/ecore_exe_posix.c @@ -364,6 +364,10 @@ _impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe) E_NO_ERRNO(result, close(statusPipe[0]), ok); E_IF_NO_ERRNO(result, eina_file_close_on_exec(statusPipe[1], EINA_TRUE), ok) /* close on exec shows success */ { + int except[2] = { 0, -1 }; + + except[0] = statusPipe[1]; + eina_file_close_from(3, except); /* Run the actual command. */ _ecore_exe_exec_it(exe_cmd, flags); /* no return */ } diff --git a/src/lib/ecore/efl_exe.c b/src/lib/ecore/efl_exe.c index f6ae3bfdde..8609dbfac5 100644 --- a/src/lib/ecore/efl_exe.c +++ b/src/lib/ecore/efl_exe.c @@ -540,6 +540,11 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd) pd->env = NULL; } + // close all fd's other than the first 3 (0, 1, 2) and exited write fd + int except[2] = { 0, -1 }; + except[0] = pd->fd.exited_write; + eina_file_close_from(3, except); + // actually execute! _exec(cmd, pd->flags, td->flags); // we couldn't exec... uh oh. HAAAAAAAALP! diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c index f4d0e7221c..6277ad6a3e 100644 --- a/src/lib/eina/eina_file.c +++ b/src/lib/eina/eina_file.c @@ -36,6 +36,10 @@ #endif #include +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif + #define PATH_DELIM '/' #include "eina_config.h" @@ -1252,3 +1256,83 @@ eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *st) return 0; } +EAPI void +eina_file_close_from(int fd, int *except_fd) +{ +#if defined(_WIN32) + // XXX: what do to here? anything? +#else +#ifdef HAVE_DIRENT_H + DIR *dir; + + dir = opendir("/proc/sefl/fd"); + if (!dir) dir = opendir("/dev/fd"); + if (dir) + { + struct dirent *dp; + const char *fname; + int *closes = NULL; + int num_closes = 0, i; + + for (;;) + { +skip: + dp = readdir(dir); + if (!dp) break; + fname = dp->d_name; + + if ((fname[0] >= '0') && (fname[0] <= '9')) + { + int num = atoi(fname); + if (num >= fd) + { + if (except_fd) + { + int j; + + for (j = 0; except_fd[j] >= 0; j++) + { + if (except_fd[j] == num) goto skip; + } + } + num_closes++; + int *tmp = realloc(closes, num_closes * sizeof(int)); + if (!tmp) num_closes--; + else + { + closes = tmp; + closes[num_closes - 1] = num; + } + } + } + } + closedir(dir); + for (i = 0; i < num_closes; i++) close(closes[i]); + free(closes); + return; + } +#endif + int i, max = 1024; + +# ifdef HAVE_SYS_RESOURCE_H + struct rlimit lim; + if (getrlimit(RLIMIT_NOFILE, &lim) < 0) return; + max = lim.rlim_max; +# endif + for (i = fd; i < max;) + { + if (except_fd) + { + int j; + + for (j = 0; except_fd[j] >= 0; j++) + { + if (except_fd[j] == i) goto skip2; + } + } + close(i); +skip2: + i++; + } +#endif +} diff --git a/src/lib/eina/eina_file.h b/src/lib/eina/eina_file.h index ade3b4fd79..404dea1ccb 100644 --- a/src/lib/eina/eina_file.h +++ b/src/lib/eina/eina_file.h @@ -347,6 +347,23 @@ EAPI Eina_Iterator *eina_file_stat_ls(const char *dir) EINA_WARN_UNUSED_RESULT E */ EAPI int eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *buf) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2, 3); +/** + * @brief Close all file descriptors that are open at or above the given fd + * @details This closes all open file descriptors that are equal to or of + * higher value than the given inpit fd given. This is intended for + * niche use like closing all open files just before exec()ing a + * new process after calling fork(). The except_fd array can be NULL + * if no fd's are to be skipped, but if some fd's are to skip being + * closed then this will be an array of fd numbers being terminated + * by a fd value of -1. + * + * @param[in] fd The fd value to begin closing at + * @param[in] except_fd An array of fd's not to close terminated by -1 as the last invalid fd + * + * @since 1.24 + */ +EAPI void eina_file_close_from(int fd, int *except_fd); + /** * @brief Generates and creates a uniquely named temporary file from a template name. * The generated file is opened with the open(2) @c O_EXCL flag.