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
This commit is contained in:
Carsten Haitzler 2019-11-20 08:43:26 +00:00
parent dd941fe4f8
commit 1127409564
4 changed files with 110 additions and 0 deletions

View File

@ -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 */
}

View File

@ -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!

View File

@ -36,6 +36,10 @@
#endif
#include <fcntl.h>
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#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
}

View File

@ -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.