From 9ee15f2e0aebb3bc6d9c3417017736c955492c2f Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 12 Jun 2009 01:44:44 +0000 Subject: [PATCH] fixed a bug of not closing inherited file handles in qse_pio_open(). --- qse/configure | 104 +++++++++++++++++++++++++++++++++++- qse/configure.ac | 3 +- qse/include/qse/awk/awk.h | 6 +-- qse/include/qse/awk/std.h | 81 ++++++++++++---------------- qse/include/qse/config.h.in | 6 +++ qse/include/qse/sed/sed.h | 6 +-- qse/lib/awk/rio.h | 7 +-- qse/lib/cmn/pio.c | 56 +++++++++++++++++-- qse/lib/cmn/syscall.h | 16 +++++- 9 files changed, 218 insertions(+), 67 deletions(-) diff --git a/qse/configure b/qse/configure index 806166f1..8beefb7c 100755 --- a/qse/configure +++ b/qse/configure @@ -17220,7 +17220,8 @@ done -for ac_header in time.h sys/time.h utime.h sys/syscall.h + +for ac_header in time.h sys/time.h utime.h sys/resource.h sys/syscall.h do as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then @@ -18093,6 +18094,107 @@ fi done +for ac_func in sysconf +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + OLDLIBS="$LIBS" LIBS="$LIBM $LIBS" diff --git a/qse/configure.ac b/qse/configure.ac index 47dc8e6b..24554d39 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -88,7 +88,7 @@ AC_SUBST(LIBM, $LIBM) dnl check header files. AC_HEADER_STDC AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h]) -AC_CHECK_HEADERS([time.h sys/time.h utime.h sys/syscall.h]) +AC_CHECK_HEADERS([time.h sys/time.h utime.h sys/resource.h sys/syscall.h]) dnl check data types AC_CHECK_TYPE([wchar_t], @@ -104,6 +104,7 @@ AC_CHECK_FUNCS([mbsnrtowcs mbsrtowcs wcsnrtombs wcsrtombs]) AC_CHECK_FUNCS([lseek64 stat64 fstat64 ftruncate64]) AC_CHECK_FUNCS([timegm timelocal]) AC_CHECK_FUNCS([utime utimes]) +AC_CHECK_FUNCS([sysconf]) OLDLIBS="$LIBS" LIBS="$LIBM $LIBS" diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index f2b1c8c2..c653ebff 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h 195 2009-06-10 13:18:25Z hyunghwan.chung $ + * $Id: awk.h 196 2009-06-11 07:44:44Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -37,13 +37,13 @@ * stated in the array fnc. If no errors occur, it should print 24. */ -/** @class qse_awk_t +/** @struct qse_awk_t * The qse_awk_t type defines an AWK interpreter. The details are hidden as * it is a complex type susceptible to misuse. */ typedef struct qse_awk_t qse_awk_t; -/** @class qse_awk_rtx_t +/** @struct qse_awk_rtx_t * The qse_awk_rtx_t type defines a runtime context. The details are hidden * as it is a complex type susceptible to misuse. */ diff --git a/qse/include/qse/awk/std.h b/qse/include/qse/awk/std.h index acf7992b..fea5f4e4 100644 --- a/qse/include/qse/awk/std.h +++ b/qse/include/qse/awk/std.h @@ -1,5 +1,5 @@ /* - * $Id: std.h 195 2009-06-10 13:18:25Z hyunghwan.chung $ + * $Id: std.h 196 2009-06-11 07:44:44Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -23,12 +23,13 @@ /** @file * Standard AWK Interpreter + * @todo + * - console name handling an empty string("") and assignment (v=yyyy) + * - StdAwk ARGV and console name handling */ -/****e* AWK/qse_awk_parsestd_type_t - * NAME - * qse_awk_parsestd_type_t - define a source type - * SYNOPSIS +/** + * The qse_awk_parsestd_type_t type defines a source script type */ enum qse_awk_parsestd_type_t { @@ -38,13 +39,9 @@ enum qse_awk_parsestd_type_t QSE_AWK_PARSESTD_STDIO = 3 /* standard input/output */ }; typedef enum qse_awk_parsestd_type_t qse_awk_parsestd_type_t; -/******/ - -/****s* AWK/qse_awk_parsestd_in_t - * NAME - * qse_awk_parsestd_in_t - define source input - * SYNOPSIS +/** + * The qse_awk_parsestd_in_t type defines a source input. */ struct qse_awk_parsestd_in_t { @@ -58,12 +55,9 @@ struct qse_awk_parsestd_in_t } u; }; typedef struct qse_awk_parsestd_in_t qse_awk_parsestd_in_t; -/******/ -/****s* AWK/qse_awk_parsestd_out_t - * NAME - * qse_awk_parsestd_out_t - define source output - * SYNOPSIS +/** + * The qse_awk_parsestd_out_t type defines a source output. */ struct qse_awk_parsestd_out_t { @@ -77,52 +71,46 @@ struct qse_awk_parsestd_out_t } u; }; typedef struct qse_awk_parsestd_out_t qse_awk_parsestd_out_t; -/******/ #ifdef __cplusplus extern "C" { #endif -/****f* AWK/qse_awk_openstd - * NAME - * qse_awk_openstd - create an awk object - * SYNOPSIS +/** + * The qse_awk_openstd() function creates an awk object. */ qse_awk_t* qse_awk_openstd ( - qse_size_t xtnsize + qse_size_t xtnsize /**< size of extension in bytes */ ); -/******/ -/****f* AWK/qse_awk_getxtnstd - * NAME - * qse_awk_getxtnstd - get the pointer to extension space - * SYNOPSIS +/** + * The qse_awk_getxtnstd() gets the pointer to extension space. + * Note that you must not call qse_awk_getxtn() for an awk object + * created with qse_awk_openstd(). */ void* qse_awk_getxtnstd ( qse_awk_t* awk ); -/******/ -/****f* AWK/qse_awk_parsestd - * NAME - * qse_awk_parsestd - parse source code - * EXAMPLE - * The following example parses the literal string 'BEGIN { print 10; }' and - * deparses it out to a buffer 'buf'. - * int n; - * qse_awk_parsestd_in_t in; - * qse_awk_parsestd_out_t out; - * qse_char_t buf[1000]; +/** + * The qse_awk_parsestd() functions parses source script. + * The code below shows how to parse a literal string 'BEGIN { print 10; }' + * and deparses it out to a buffer 'buf'. + * @code + * int n; + * qse_awk_parsestd_in_t in; + * qse_awk_parsestd_out_t out; + * qse_char_t buf[1000]; * - * qse_memset (buf, QSE_T(' '), QSE_COUNTOF(buf)); - * buf[QSE_COUNTOF(buf)-1] = QSE_T('\0'); - * in.type = QSE_AWK_PARSESTD_CP; - * in.u.cp = QSE_T("BEGIN { print 10; }"); - * out.type = QSE_AWK_PARSESTD_CP; - * out.u.cp = buf; + * qse_memset (buf, QSE_T(' '), QSE_COUNTOF(buf)); + * buf[QSE_COUNTOF(buf)-1] = QSE_T('\0'); + * in.type = QSE_AWK_PARSESTD_CP; + * in.u.cp = QSE_T("BEGIN { print 10; }"); + * out.type = QSE_AWK_PARSESTD_CP; + * out.u.cp = buf; * - * n = qse_awk_parsestd (awk, &in, &out); - * SYNOPSIS + * n = qse_awk_parsestd (awk, &in, &out); + * @endcode */ int qse_awk_parsestd ( qse_awk_t* awk, @@ -132,7 +120,6 @@ int qse_awk_parsestd ( /******/ /** - * DESCRIPTION * The qse_awk_rtx_openstd() function creates a standard runtime context. * The caller should keep the contents of icf and ocf valid throughout * the lifetime of the runtime context created. The runtime context diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in index 5fdd3cfa..c87c6091 100644 --- a/qse/include/qse/config.h.in +++ b/qse/include/qse/config.h.in @@ -129,6 +129,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H +/* Define to 1 if you have the `sysconf' function. */ +#undef HAVE_SYSCONF + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H diff --git a/qse/include/qse/sed/sed.h b/qse/include/qse/sed/sed.h index c65e10ff..0fe21d0f 100644 --- a/qse/include/qse/sed/sed.h +++ b/qse/include/qse/sed/sed.h @@ -1,5 +1,5 @@ /* - * $Id: sed.h 195 2009-06-10 13:18:25Z hyunghwan.chung $ + * $Id: sed.h 196 2009-06-11 07:44:44Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -41,7 +41,7 @@ * @todo enhance execution of the l command. */ -/** @class qse_sed_t +/** @struct qse_sed_t * The qse_sed_t type defines a stream editor. The structural details are * hidden as it is a relatively complex data type and fragile to external * changes. To use a stream editor, you typically can: @@ -177,7 +177,7 @@ typedef struct qse_sed_io_arg_t qse_sed_io_arg_t; /** * The qse_sed_io_fun_t type defines an IO handler. An IO handler is called by - * qse_sed_execute(). + * qse_sed_exec(). */ typedef qse_ssize_t (*qse_sed_io_fun_t) ( qse_sed_t* sed, diff --git a/qse/lib/awk/rio.h b/qse/lib/awk/rio.h index 6db571ce..6fd85aeb 100644 --- a/qse/lib/awk/rio.h +++ b/qse/lib/awk/rio.h @@ -1,5 +1,5 @@ /* - * $Id: rio.h 75 2009-02-22 14:10:34Z hyunghwan.chung $ + * $Id: rio.h 196 2009-06-11 07:44:44Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -44,12 +44,7 @@ int qse_awk_rtx_nextio_read ( int qse_awk_rtx_nextio_write ( qse_awk_rtx_t* run, int out_type, const qse_char_t* name); -int qse_awk_rtx_closeio_read ( - qse_awk_rtx_t* run, int in_type, const qse_char_t* name); -int qse_awk_rtx_closeio_write ( - qse_awk_rtx_t* run, int out_type, const qse_char_t* name); int qse_awk_rtx_closeio (qse_awk_rtx_t* run, const qse_char_t* name); - void qse_awk_rtx_cleario (qse_awk_rtx_t* run); #ifdef __cplusplus diff --git a/qse/lib/cmn/pio.c b/qse/lib/cmn/pio.c index b3d03074..26e371fe 100644 --- a/qse/lib/cmn/pio.c +++ b/qse/lib/cmn/pio.c @@ -1,5 +1,5 @@ /* - * $Id: pio.c 193 2009-06-08 13:09:01Z hyunghwan.chung $ + * $Id: pio.c 196 2009-06-11 07:44:44Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -68,6 +68,18 @@ void qse_pio_close (qse_pio_t* pio) QSE_MMGR_FREE (pio->mmgr, pio); } +static int closefile (void* arg, int fd) +{ + qse_pio_hnd_t* handle = (qse_pio_hnd_t*)arg; + if (fd != 0 && fd != 1 && fd != 2 && + fd != handle[0] && fd != handle[1] && fd != handle[2] && + fd != handle[3] && fd != handle[4] && fd != handle[5]) + { + QSE_CLOSE (fd); + } + return 0; +} + qse_pio_t* qse_pio_init ( qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd, int flags) { @@ -172,6 +184,7 @@ qse_pio_t* qse_pio_init ( if (pid == 0) { /* child */ + qse_pio_hnd_t devnull; qse_mchar_t* mcmd; extern char** environ; @@ -182,18 +195,48 @@ qse_pio_t* qse_pio_init ( qse_mchar_t buf[64]; #endif + /* TODO: consider if reading from /proc/self/fd is + * a better idea. */ + + struct rlimit rlim; + int fd; + + if (QSE_GETRLIMIT (RLIMIT_NOFILE, &rlim) == -1 || + rlim.rlim_max == RLIM_INFINITY) + { + #ifdef HAVE_SYSCONF + fd = sysconf (_SC_OPEN_MAX); + if (fd <= 0) + #endif + fd = 1024; + } + else fd = rlim.rlim_max; + + while (--fd > 2) + { + if (fd != handle[0] && + fd != handle[1] && + fd != handle[2] && + fd != handle[3] && + fd != handle[4] && + fd != handle[5]) QSE_CLOSE (fd); + } + if (flags & QSE_PIO_WRITEIN) { /* child should read */ QSE_CLOSE (handle[1]); + handle[1] = QSE_PIO_HND_NIL; if (QSE_DUP2 (handle[0], 0) == -1) goto child_oops; QSE_CLOSE (handle[0]); + handle[0] = QSE_PIO_HND_NIL; } if (flags & QSE_PIO_READOUT) { /* child should write */ QSE_CLOSE (handle[2]); + handle[2] = QSE_PIO_HND_NIL; if (QSE_DUP2 (handle[3], 1) == -1) goto child_oops; if (flags & QSE_PIO_ERRTOOUT) @@ -201,13 +244,15 @@ qse_pio_t* qse_pio_init ( if (QSE_DUP2 (handle[3], 2) == -1) goto child_oops; } - QSE_CLOSE (handle[3]); + QSE_CLOSE (handle[3]); + handle[3] = QSE_PIO_HND_NIL; } if (flags & QSE_PIO_READERR) { /* child should write */ - QSE_CLOSE (handle[4]); + QSE_CLOSE (handle[4]); + handle[4] = QSE_PIO_HND_NIL; if (QSE_DUP2 (handle[5], 2) == -1) goto child_oops; if (flags & QSE_PIO_OUTTOERR) @@ -216,6 +261,7 @@ qse_pio_t* qse_pio_init ( } QSE_CLOSE (handle[5]); + handle[5] = QSE_PIO_HND_NIL; } if ((flags & QSE_PIO_INTONUL) || @@ -440,9 +486,9 @@ oops: void qse_pio_fini (qse_pio_t* pio) { - qse_pio_end (pio, QSE_PIO_IN); - qse_pio_end (pio, QSE_PIO_OUT); qse_pio_end (pio, QSE_PIO_ERR); + qse_pio_end (pio, QSE_PIO_OUT); + qse_pio_end (pio, QSE_PIO_IN); qse_pio_setflags (pio, QSE_PIO_WAIT_NOBLOCK|QSE_PIO_WAIT_NORETRY, -1); qse_pio_wait (pio); diff --git a/qse/lib/cmn/syscall.h b/qse/lib/cmn/syscall.h index f3692289..e2c7c695 100644 --- a/qse/lib/cmn/syscall.h +++ b/qse/lib/cmn/syscall.h @@ -1,5 +1,5 @@ /* - * $Id: syscall.h 193 2009-06-08 13:09:01Z hyunghwan.chung $ + * $Id: syscall.h 196 2009-06-11 07:44:44Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -45,6 +45,9 @@ #ifdef HAVE_UTIME_H # include #endif +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif #if defined(QSE_USE_SYSCALL) && defined(HAVE_SYS_SYSCALL_H) # include @@ -222,5 +225,16 @@ # define QSE_UTIMES(file,t) utimes(file,t) #endif +#ifdef SYS_getrlimit +# define QSE_GETRLIMIT(res,lim) syscall(SYS_getrlimit,res,lim) +#else +# define QSE_GETRLIMIT(res,lim) getrlimit(res,lim) +#endif + +#ifdef SYS_setrlimit +# define QSE_SETRLIMIT(res,lim) syscall(SYS_setrlimit,res,lim) +#else +# define QSE_SETRLIMIT(res,lim) setrlimit(res,lim) +#endif #endif