/* * POSIX library for Lua 5.1, 5.2 & 5.3. * (c) Gary V. Vaughan , 2013-2015 * (c) Reuben Thomas 2010-2013 * (c) Natanael Copa 2008-2010 * Clean up and bug fixes by Leo Razoumov 2006-10-11 * Luiz Henrique de Figueiredo 07 Apr 2006 23:17:49 * Based on original by Claudio Terra for Lua 3.x. * With contributions by Roberto Ierusalimschy. * With documentation from Steve Donovan 2012 */ /*** Software Signal Facilities. Constants and functions for propagating signals among processes. Note that `posix.signal.signal` is implemented with sigaction(2) for consistent semantics across platforms. @module posix.signal */ #include #include #include "_helpers.c" /*** Send a signal to the given process. @function kill @int pid process to act on @int[opt=`SIGTERM` sig signal to send @treturn[1] int `0`, if successful @return[2] nil @treturn[2] string error message @treturn[2] int errnum @see kill(2) */ static int Pkill(lua_State *L) { pid_t pid = checkint(L, 1); int sig = optint(L, 2, SIGTERM); checknargs(L, 2); return pushresult(L, kill(pid, sig), NULL); } /*** Send a signal to the given process group. @function killpg @int pgrp group id to act on, or `0` for the sending process`s group @int[opt=`SIGTERM`] sig signal to send @treturn[1] int `0`, if successful @return[2] nil @treturn[2] string error message @treturn[2] int errnum @see killpg(2) */ static int Pkillpg(lua_State *L) { int pgrp = checkint(L, 1); int sig = optint(L, 2, SIGTERM); checknargs(L, 2); return pushresult(L, killpg(pgrp, sig), NULL); } /*** Raise a signal on this process. @function raise @int sig signal to send @treturn[1] int `0`, if successful @return[2] nil @treturn[2] string error message @treturn[2] int errnum @see raise(3) */ static int Praise(lua_State *L) { int sig = checkint(L, 1); checknargs(L, 1); lua_pop(L, 1); return pushintresult(raise(sig)); } static lua_State *signalL; #define SIGNAL_QUEUE_MAX 25 static volatile sig_atomic_t signal_pending, defer_signal; static volatile sig_atomic_t signal_count = 0; static volatile sig_atomic_t signals[SIGNAL_QUEUE_MAX]; #define sigmacros_map \ MENTRY( _DFL ) \ MENTRY( _IGN ) static const char *const Ssigmacros[] = { #define MENTRY(_s) LPOSIX_STR_1(LPOSIX_SPLICE(_SIG, _s)), sigmacros_map #undef MENTRY NULL }; static void (*Fsigmacros[])(int) = { #define MENTRY(_s) LPOSIX_SPLICE(SIG, _s), sigmacros_map #undef MENTRY NULL }; static void sig_handle (lua_State *L, lua_Debug *LPOSIX_UNUSED (ar)) { /* Block all signals until we have run the Lua signal handler */ sigset_t mask, oldmask; sigfillset(&mask); sigprocmask(SIG_SETMASK, &mask, &oldmask); lua_sethook(L, NULL, 0, 0); /* Get signal handlers table */ lua_pushlightuserdata(L, &signalL); lua_rawget(L, LUA_REGISTRYINDEX); /* Empty the signal queue */ while (signal_count--) { sig_atomic_t signalno = signals[signal_count]; /* Get handler */ lua_pushinteger(L, signalno); lua_gettable(L, -2); /* Call handler with signal number */ lua_pushinteger(L, signalno); if (lua_pcall(L, 1, 0, 0) != 0) fprintf(stderr,"error in signal handler %ld: %s\n", (long)signalno, lua_tostring(L,-1)); } signal_count = 0; /* reset global to initial state */ /* Having run the Lua signal handler, restore original signal mask */ sigprocmask(SIG_SETMASK, &oldmask, NULL); } static void sig_postpone (int i) { if (defer_signal) { signal_pending = i; return; } if (signal_count == SIGNAL_QUEUE_MAX) return; defer_signal++; /* Queue signals */ signals[signal_count] = i; signal_count ++; lua_sethook(signalL, sig_handle, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); defer_signal--; /* re-raise any pending signals */ if (defer_signal == 0 && signal_pending != 0) raise (signal_pending); } static int sig_handler_wrap (lua_State *L) { int sig = luaL_checkinteger(L, lua_upvalueindex(1)); void (*handler)(int) = lua_touserdata(L, lua_upvalueindex(2)); handler(sig); return 0; } /*** Install a signal handler for this signal number. Although this is the same API as signal(2), it uses sigaction for guaranteed semantics. @function signal @see signal.lua @int signum @tparam[opt=SIG_DFL] function handler function, or `SIG_IGN` or `SIG_DFL` constants @param[opt] flags the `sa_flags` element of `struct sigaction` @treturn function previous handler function @see sigaction(2) */ static int Psignal (lua_State *L) { struct sigaction sa, oldsa; int sig = checkint(L, 1), ret; void (*handler)(int) = sig_postpone; checknargs(L, 3); /* Check handler is OK */ switch (lua_type(L, 2)) { case LUA_TNIL: case LUA_TSTRING: handler = Fsigmacros[luaL_checkoption(L, 2, "SIG_DFL", Ssigmacros)]; break; case LUA_TFUNCTION: if (lua_tocfunction(L, 2) == sig_handler_wrap) { lua_getupvalue(L, 2, 1); handler = lua_touserdata(L, -1); lua_pop(L, 1); } break; default: argtypeerror(L, 2, "function, string or nil"); break; } /* Set up C signal handler, getting old handler */ sa.sa_handler = handler; sa.sa_flags = optint(L, 3, 0); sigfillset(&sa.sa_mask); ret = sigaction(sig, &sa, &oldsa); if (ret == -1) return 0; /* Set Lua handler if necessary */ if (handler == sig_postpone) { lua_pushlightuserdata(L, &signalL); /* We could use an upvalue, but we need this for sig_handle anyway. */ lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_rawset(L, -3); lua_pop(L, 1); } /* Push old handler as result */ if (oldsa.sa_handler == sig_postpone) { lua_pushlightuserdata(L, &signalL); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, 1); lua_rawget(L, -2); } else if (oldsa.sa_handler == SIG_DFL) lua_pushstring(L, "SIG_DFL"); else if (oldsa.sa_handler == SIG_IGN) lua_pushstring(L, "SIG_IGN"); else { lua_pushinteger(L, sig); lua_pushlightuserdata(L, oldsa.sa_handler); lua_pushcclosure(L, sig_handler_wrap, 2); } return 1; } static const luaL_Reg posix_signal_fns[] = { LPOSIX_FUNC( Pkill ), LPOSIX_FUNC( Pkillpg ), LPOSIX_FUNC( Praise ), LPOSIX_FUNC( Psignal ), {NULL, NULL} }; /*** Constants. @section constants */ /*** Signal constants. Any constants not available in the underlying system will be `nil` valued. @table posix.signal @int SIGABRT abort () @int SIGALRM alarm clock @int SIGBUS bus error @int SIGCHLD to parent on child stop or exit @int SIGCONT continue a stopped process @int SIGFPE floating point error @int SIGHUP hangup @int SIGILL illegal instruction @int SIGINT interrupt @int SIGKILL kill @int SIGPIPE write on pipe with no reader @int SIGQUIT quit @int SIGSEGV segmentation violation @int SIGSTOP stop @int SIGTERM terminate @int SIGTSTP stop signal from tty @int SIGTTIN to readers process group on background tty read @int SIGTTOU to readers process group on background tty output @int SIGUSR1 user defined @int SIGUSR2 user defined @int SIGSYS bad argument to system call @int SIGTRAP trace trap @int SIGURG urgent condition on i/o channel @int SIGVTALRM virtual time alarm @int SIGXCPU exceeded cpu time limit @int SIGXFSZ exceeded file size limit @int SA_NOCLDSTOP do not generate a SIGCHLD on child stop @int SA_NOCLDWAIT don't keep zombies child processes @int SA_RESETHAND reset to SIG_DFL when taking a signal @int SA_NODEFER don't mask the signal we're delivering @usage -- Print signal constants supported on this host. for name, value in pairs (require "posix.signal") do if type (value) == "number" then print (name, value) end end */ LUALIB_API int luaopen_posix_signal(lua_State *L) { luaL_register(L, "posix.signal", posix_signal_fns); lua_pushliteral(L, "posix.signal for " LUA_VERSION " / " PACKAGE_STRING); lua_setfield(L, -2, "version"); /* Signals table stored in registry for Psignal and sig_handle */ lua_pushlightuserdata(L, &signalL); lua_newtable(L); lua_rawset(L, LUA_REGISTRYINDEX); signalL = L; /* For sig_postpone */ /* Signals */ #ifdef SIGABRT LPOSIX_CONST( SIGABRT ); #endif #ifdef SIGALRM LPOSIX_CONST( SIGALRM ); #endif #ifdef SIGBUS LPOSIX_CONST( SIGBUS ); #endif #ifdef SIGCHLD LPOSIX_CONST( SIGCHLD ); #endif #ifdef SIGCONT LPOSIX_CONST( SIGCONT ); #endif #ifdef SIGFPE LPOSIX_CONST( SIGFPE ); #endif #ifdef SIGHUP LPOSIX_CONST( SIGHUP ); #endif #ifdef SIGILL LPOSIX_CONST( SIGILL ); #endif #ifdef SIGINT LPOSIX_CONST( SIGINT ); #endif #ifdef SIGKILL LPOSIX_CONST( SIGKILL ); #endif #ifdef SIGPIPE LPOSIX_CONST( SIGPIPE ); #endif #ifdef SIGQUIT LPOSIX_CONST( SIGQUIT ); #endif #ifdef SIGSEGV LPOSIX_CONST( SIGSEGV ); #endif #ifdef SIGSTOP LPOSIX_CONST( SIGSTOP ); #endif #ifdef SIGTERM LPOSIX_CONST( SIGTERM ); #endif #ifdef SIGTSTP LPOSIX_CONST( SIGTSTP ); #endif #ifdef SIGTTIN LPOSIX_CONST( SIGTTIN ); #endif #ifdef SIGTTOU LPOSIX_CONST( SIGTTOU ); #endif #ifdef SIGUSR1 LPOSIX_CONST( SIGUSR1 ); #endif #ifdef SIGUSR2 LPOSIX_CONST( SIGUSR2 ); #endif #ifdef SIGSYS LPOSIX_CONST( SIGSYS ); #endif #ifdef SIGTRAP LPOSIX_CONST( SIGTRAP ); #endif #ifdef SIGURG LPOSIX_CONST( SIGURG ); #endif #ifdef SIGVTALRM LPOSIX_CONST( SIGVTALRM ); #endif #ifdef SIGXCPU LPOSIX_CONST( SIGXCPU ); #endif #ifdef SIGXFSZ LPOSIX_CONST( SIGXFSZ ); #endif /* String constants */ lua_pushliteral(L, "SIG_DFL"); lua_setfield(L, -2, "SIG_DFL"); lua_pushliteral(L, "SIG_IGN"); lua_setfield(L, -2, "SIG_IGN"); /* Signal flags */ #ifdef SA_NOCLDSTOP LPOSIX_CONST( SA_NOCLDSTOP ); #endif #ifdef SA_NOCLDWAIT LPOSIX_CONST( SA_NOCLDWAIT ); #endif #ifdef SA_RESETHAND LPOSIX_CONST( SA_RESETHAND ); #endif #ifdef SA_NODEFER LPOSIX_CONST( SA_NODEFER ); #endif return 1; }