added sys::dup() and sys::openfd().

added the optional second parameter to sys::close(). it accepts sys::C_KEEPFD.
This commit is contained in:
hyung-hwan 2019-08-26 02:47:02 +00:00
parent 8bfac9fff4
commit 4e6015ed36
6 changed files with 239 additions and 22 deletions

2
qse/configure vendored
View File

@ -18198,7 +18198,7 @@ _ACEOF
fi
done
for ac_func in pipe2 accept4 sendmsg recvmsg writev readv
for ac_func in dup2 dup3 pipe2 accept4 sendmsg recvmsg writev readv
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

View File

@ -130,7 +130,7 @@ AC_CHECK_FUNCS([sysconf prctl fdopendir setrlimit getrlimit getpgid getpgrp])
AC_CHECK_FUNCS([backtrace backtrace_symbols])
AC_CHECK_FUNCS([fork vfork posix_spawn gettid nanosleep select])
AC_CHECK_FUNCS([makecontext swapcontext getcontext setcontext])
AC_CHECK_FUNCS([pipe2 accept4 sendmsg recvmsg writev readv])
AC_CHECK_FUNCS([dup2 dup3 pipe2 accept4 sendmsg recvmsg writev readv])
OLDLIBS="$LIBS"
LIBS="$LIBM $LIBS"

View File

@ -1371,6 +1371,7 @@ The *dir* module provides an interface to read file names in a specified directo
- sys::chmod
- sys::close
- sys::closedir
- sys::dup
- sys::errmsg
- sys::fork
- sys::getegid
@ -1387,6 +1388,7 @@ The *dir* module provides an interface to read file names in a specified directo
- sys::mktime
- sys::open
- sys::opendir
- sys::openfd
- sys::pipe
- sys::read
- sys::readdir
@ -1406,6 +1408,16 @@ BEGIN {
}
~~~~~
~~~~~{.awk}
BEGIN {
a = sys::openfd(1);
sys::write (a, B"let me write something here\n");
sys::close (a, sys::C_KEEPFD); ## set C_KEEPFD to release 1 without closing it.
##sys::close (a);
print "done\n";
}
~~~~~
~~~~~{.awk}
BEGIN {
if (sys::pipe(p0, p1, sys::O_CLOEXEC | sys::O_NONBLOCK) <= -1)
@ -1458,6 +1470,27 @@ BEGIN {
}
~~~~~
~~~~~{.awk}
BEGIN {
a = sys::open("/etc/inittab", sys::O_RDONLY);
x = sys::open("/etc/fstab", sys::O_RDONLY);
b = sys::dup(a);
sys::close(a);
while (sys::read(b, abc, 100) > 0) printf (B"%s", abc);
print "-------------------------------";
c = sys::dup(x, b, sys::O_CLOEXEC);
## assertion: b == c
sys::close (x);
while (sys::read(c, abc, 100) > 0) printf (B"%s", abc);
sys::close (c);
}
~~~~~
~~~~~{.awk}
BEGIN {
d = sys::opendir("/etc", sys::DIR_SORT);

View File

@ -124,6 +124,12 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the `dup2' function. */
#undef HAVE_DUP2
/* Define to 1 if you have the `dup3' function. */
#undef HAVE_DUP3
/* Define to 1 if you have the `ENGINE_cleanup' function. */
#undef HAVE_ENGINE_CLEANUP

View File

@ -68,6 +68,8 @@
#define DEFAULT_MODE (0777)
#define CLOSE_KEEPFD (1 << 0)
enum sys_rc_t
{
RC_ERROR = -1,
@ -369,13 +371,22 @@ static int fnc_close (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
sys_list_t* sys_list;
sys_node_t* sys_node;
int rx = RC_ERROR;
qse_awk_int_t cflags;
sys_list = rtx_to_sys_list(rtx, fi);
sys_node = get_sys_list_node_with_arg(rtx, sys_list, qse_awk_rtx_getarg(rtx, 0));
if (qse_awk_rtx_getnargs(rtx) >= 2 && (qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg(rtx, 1), &cflags) <= -1 || cflags < 0)) cflags = 0;
if (sys_node && sys_node->ctx.type == SYS_NODE_DATA_FD)
{
/* even if free_sys_node can handle other types, sys::close() is allowed to
/* although free_sys_node can handle other types, sys::close() is allowed to
* close nodes of the SYS_NODE_DATA_FD type only */
if (cflags & CLOSE_KEEPFD) /* this flag applies to file descriptors only */
{
sys_node->ctx.u.fd = -1; /* you may leak the original file descriptor. */
}
free_sys_node (rtx, sys_list, sys_node);
rx = 0;
}
@ -400,8 +411,8 @@ static int fnc_close (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
static int fnc_open (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
sys_list_t* sys_list;
sys_node_t* sys_node = QSE_NULL;
qse_awk_int_t rx = RC_ERROR, flags = 0, mode = DEFAULT_MODE;
qse_awk_int_t rx = RC_ERROR, oflags = 0, mode = DEFAULT_MODE;
int fd;
qse_mchar_t* pstr;
qse_size_t plen;
@ -409,30 +420,33 @@ static int fnc_open (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
sys_list = rtx_to_sys_list(rtx, fi);
if (qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg(rtx, 1), &flags) <= -1 || flags < 0) flags = O_RDONLY;
if (qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg(rtx, 1), &oflags) <= -1 || oflags < 0) oflags = O_RDONLY;
if (qse_awk_rtx_getnargs(rtx) >= 3 && (qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg(rtx, 2), &mode) <= -1 || mode < 0)) mode = DEFAULT_MODE;
#if defined(O_LARGEFILE)
flags |= O_LARGEFILE;
oflags |= O_LARGEFILE;
#endif
a0 = qse_awk_rtx_getarg(rtx, 0);
pstr = qse_awk_rtx_getvalmbs(rtx, a0, &plen);
if (!pstr) goto fail;
fd = open(pstr, flags, mode);
fd = open(pstr, oflags, mode);
qse_awk_rtx_freevalmbs (rtx, a0, pstr);
if (fd >= 0)
{
sys_node = new_sys_node_fd(rtx, sys_list, fd);
if (sys_node)
sys_node_t* new_node;
new_node = new_sys_node_fd(rtx, sys_list, fd);
if (new_node)
{
rx = sys_node->id;
rx = new_node->id;
}
else
{
close (fd);
fail:
rx = awkerr_to_rc(qse_awk_rtx_geterrnum(rtx));
set_errmsg_on_sys_list (rtx, sys_list, QSE_NULL);
}
}
@ -447,6 +461,56 @@ static int fnc_open (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
return 0;
}
/*
a = sys::openfd(1);
sys::write (a, B"let me write something here\n");
sys::close (a, sys::C_KEEPFD); ## set C_KEEPFD to release 1 without closing it.
##sys::close (a);
print "done\n";
*/
static int fnc_openfd (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
/* wrap a raw system file descriptor into the internal management node */
sys_list_t* sys_list;
qse_awk_int_t rx = RC_ERROR;
qse_awk_int_t fd;
sys_list = rtx_to_sys_list(rtx, fi);
if (qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg(rtx, 0), &fd) <= -1)
{
rx = awkerr_to_rc(qse_awk_rtx_geterrnum(rtx));
set_errmsg_on_sys_list (rtx, sys_list, QSE_NULL);
}
else if (fd >= 0)
{
sys_node_t* sys_node;
sys_node = new_sys_node_fd(rtx, sys_list, fd);
if (sys_node)
{
rx = sys_node->id;
}
else
{
rx = awkerr_to_rc(qse_awk_rtx_geterrnum(rtx));
set_errmsg_on_sys_list (rtx, sys_list, QSE_NULL);
}
}
else
{
rx = RC_EINVAL;
set_errmsg_on_sys_list (rtx, sys_list, rc_to_errstr(rx));
}
QSE_ASSERT (QSE_AWK_IN_QUICKINT_RANGE(rx));
qse_awk_rtx_setretval (rtx, qse_awk_rtx_makeintval(rtx, rx));
return 0;
}
static int fnc_read (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
sys_list_t* sys_list;
@ -553,6 +617,114 @@ static int fnc_write (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
/* ------------------------------------------------------------------------ */
/*
a = sys::open("/etc/inittab", sys::O_RDONLY);
x = sys::open("/etc/fstab", sys::O_RDONLY);
b = sys::dup(a);
sys::close(a);
while (sys::read(b, abc, 100) > 0) printf (B"%s", abc);
print "-------------------------------";
c = sys::dup(x, b, sys::O_CLOEXEC);
## assertion: b == c
sys::close (x);
while (sys::read(c, abc, 100) > 0) printf (B"%s", abc);
sys::close (c);
*/
static int fnc_dup (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
sys_list_t* sys_list;
sys_node_t* sys_node, * sys_node2 = QSE_NULL;
qse_awk_int_t rx = RC_ERROR;
qse_awk_int_t oflags = 0;
sys_list = rtx_to_sys_list(rtx, fi);
sys_node = get_sys_list_node_with_arg(rtx, sys_list, qse_awk_rtx_getarg(rtx, 0));
if (qse_awk_rtx_getnargs(rtx) >= 2)
{
sys_node2 = get_sys_list_node_with_arg(rtx, sys_list, qse_awk_rtx_getarg(rtx, 1));
if (!sys_node2 || sys_node2->ctx.type != SYS_NODE_DATA_FD) goto fail_einval;
if (qse_awk_rtx_getnargs(rtx) >= 3 && (qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg(rtx, 2), &oflags) <= -1 || oflags < 0)) oflags = 0;
}
if (sys_node && sys_node->ctx.type == SYS_NODE_DATA_FD)
{
int fd;
if (sys_node2)
{
#if defined(HAVE_DUP3)
fd = dup3(sys_node->ctx.u.fd, sys_node2->ctx.u.fd, oflags);
#else
fd = dup2(sys_node->ctx.u.fd);
#endif
if (fd >= 0)
{
#if defined(HAVE_DUP3)
/* nothing extra for dup3 */
#else
if (oflags)
{
int nflags = 0;
if (oflags & O_CLOEXEC) nflags |= FD_CLOEXEC;
/*if (oflags & O_NONBLOCK) nflags |= FD_NONBLOCK; dup3() doesn't seem to support NONBLOCK. */
if (nflags) fcntl (fd, F_SETFD, nflags);
}
#endif
sys_node2->ctx.u.fd = fd; /* dup2 or dup3 closes the descriptor implicitly */
rx = sys_node2->id;
}
else
{
rx = syserr_to_rc(errno);
set_errmsg_on_sys_list_with_syserr (rtx, sys_list);
}
}
else
{
fd = dup(sys_node->ctx.u.fd);
if (fd >= 0)
{
sys_node_t* new_node;
new_node = new_sys_node_fd(rtx, sys_list, fd);
if (new_node)
{
rx = new_node->id;
}
else
{
close (fd);
rx = awkerr_to_rc(qse_awk_rtx_geterrnum(rtx));
set_errmsg_on_sys_list (rtx, sys_list, QSE_NULL);
}
}
else
{
rx = syserr_to_rc(errno);
set_errmsg_on_sys_list_with_syserr (rtx, sys_list);
}
}
}
else
{
fail_einval:
rx = RC_EINVAL;
set_errmsg_on_sys_list (rtx, sys_list, rc_to_errstr(rx));
}
qse_awk_rtx_setretval (rtx, qse_awk_rtx_makeintval(rtx, rx));
return 0;
}
/* ------------------------------------------------------------------------ */
/*
##if (sys::pipe(p0, p1) <= -1)
if (sys::pipe(p0, p1, sys::O_NONBLOCK | sys::O_CLOEXEC) <= -1)
@ -685,6 +857,8 @@ static int fnc_pipe (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
qse_awk_rtx_setretval (rtx, qse_awk_rtx_makeintval(rtx, rx));
return 0;
}
/* ------------------------------------------------------------------------ */
/*
@ -752,7 +926,7 @@ static int fnc_closedir (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
sys_node = get_sys_list_node_with_arg(rtx, sys_list, qse_awk_rtx_getarg(rtx, 0));
if (sys_node && sys_node->ctx.type == SYS_NODE_DATA_DIR)
{
/* even if free_sys_node can handle other types, sys::closedir() is allowed to
/* although free_sys_node() can handle other types, sys::closedir() is allowed to
* close nodes of the SYS_NODE_DATA_DIR type only */
free_sys_node (rtx, sys_list, sys_node);
rx = 0;
@ -2277,9 +2451,10 @@ static fnctab_t fnctab[] =
{ QSE_T("WIFSIGNALED"), { { 1, 1, QSE_NULL }, fnc_wifsignaled, 0 } },
{ QSE_T("WTERMSIG"), { { 1, 1, QSE_NULL }, fnc_wtermsig, 0 } },
{ QSE_T("chmod"), { { 2, 2, QSE_NULL }, fnc_chmod, 0 } },
{ QSE_T("close"), { { 1, 1, QSE_NULL }, fnc_close, 0 } },
{ QSE_T("close"), { { 1, 2, QSE_NULL }, fnc_close, 0 } },
{ QSE_T("closedir"), { { 1, 1, QSE_NULL }, fnc_closedir, 0 } },
{ QSE_T("closelog"), { { 0, 0, QSE_NULL }, fnc_closelog, 0 } },
{ QSE_T("dup"), { { 1, 3, QSE_NULL }, fnc_dup, 0 } },
{ QSE_T("errmsg"), { { 0, 0, QSE_NULL }, fnc_errmsg, 0 } },
{ QSE_T("fork"), { { 0, 0, QSE_NULL }, fnc_fork, 0 } },
{ QSE_T("getegid"), { { 0, 0, QSE_NULL }, fnc_getegid, 0 } },
@ -2298,6 +2473,7 @@ static fnctab_t fnctab[] =
{ QSE_T("mktime"), { { 0, 1, QSE_NULL }, fnc_mktime, 0 } },
{ QSE_T("open"), { { 2, 3, QSE_NULL }, fnc_open, 0 } },
{ QSE_T("opendir"), { { 1, 2, QSE_NULL }, fnc_opendir, 0 } },
{ QSE_T("openfd"), { { 1, 1, QSE_NULL }, fnc_openfd, 0 } },
{ QSE_T("openlog"), { { 3, 3, QSE_NULL }, fnc_openlog, 0 } },
{ QSE_T("pipe"), { { 2, 3, QSE_T("rrv") }, fnc_pipe, 0 } },
{ QSE_T("read"), { { 2, 3, QSE_T("vrv") }, fnc_read, 0 } },
@ -2341,6 +2517,8 @@ static fnctab_t fnctab[] =
static inttab_t inttab[] =
{
/* keep this table sorted for binary search in query(). */
{ QSE_T("C_KEEPFD"), { CLOSE_KEEPFD } },
{ QSE_T("DIR_SORT"), { QSE_DIR_SORT } },
#if defined(ENABLE_SYSLOG)

View File

@ -242,25 +242,25 @@ typedef qse_awk_val_t* (*binop_func_t) (qse_awk_rtx_t* rtx, qse_awk_val_t* left,
typedef qse_awk_val_t* (*eval_expr_t) (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde);
QSE_INLINE qse_size_t qse_awk_rtx_getnargs (qse_awk_rtx_t* run)
QSE_INLINE qse_size_t qse_awk_rtx_getnargs (qse_awk_rtx_t* rtx)
{
return (qse_size_t) RTX_STACK_NARGS (run);
return (qse_size_t) RTX_STACK_NARGS(rtx);
}
QSE_INLINE qse_awk_val_t* qse_awk_rtx_getarg (qse_awk_rtx_t* run, qse_size_t idx)
QSE_INLINE qse_awk_val_t* qse_awk_rtx_getarg (qse_awk_rtx_t* rtx, qse_size_t idx)
{
return RTX_STACK_ARG (run, idx);
return RTX_STACK_ARG(rtx, idx);
}
QSE_INLINE qse_awk_val_t* qse_awk_rtx_getgbl (qse_awk_rtx_t* run, int id)
QSE_INLINE qse_awk_val_t* qse_awk_rtx_getgbl (qse_awk_rtx_t* rtx, int id)
{
QSE_ASSERT (id >= 0 && id < (int)QSE_ARR_SIZE(run->awk->parse.gbls));
return RTX_STACK_GBL (run, id);
QSE_ASSERT (id >= 0 && id < (int)QSE_ARR_SIZE(rtx->awk->parse.gbls));
return RTX_STACK_GBL(rtx, id);
}
const qse_cstr_t* qse_awk_rtx_getsubsep (qse_awk_rtx_t* run)
const qse_cstr_t* qse_awk_rtx_getsubsep (qse_awk_rtx_t* rtx)
{
return &run->gbl.subsep;
return &rtx->gbl.subsep;
}
/* internal function to set a value to a global variable.