Blame ext/posix/signal.c

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