end
--- Reset signal handlers back to their default.
--- @return True on success, false on error.
--- @return Error object on failure.
+-- @raise Error on failure.
function e2lib.signal_reset()
local rc, errstring
rc, errstring = le2lib.signal_reset()
if not rc then
- return false, err.new("resetting signal handlers: %s", errstring)
+ error(err.new("resetting signal handlers: %s", errstring))
end
+end
- return true
+--- Install signal handlers that will call interrupt_hook()
+-- @raise Error on failure.
+function e2lib.signal_install()
+ local rc, errstring
+
+ rc, errstring = le2lib.signal_install()
+ if not rc then
+ error(err.new("installing signal handlers: %s", errstring))
+ end
+end
+
+--- Get the first signal triggering shutdown.
+-- Returns empty string if no signal has yet occured.
+-- @return Signal name (eg "Interrupt") or "".
+-- @return Signal number or 0.
+function e2lib.signal_received()
+ return le2lib.signal_received()
end
--- Get current process id.
return le2lib.getpid()
end
---- Set process group ID.
--- @param pid process id
--- @param pgid process group id
--- @raise error on failure.
-function e2lib.setpgid(pid, pgid)
- return le2lib.setpgid(pid, pgid)
-end
-
---- Ignore SIGINT
--- @raise error on failure
-function e2lib.ignore_sigint()
- le2lib.ignore_sigint()
-end
-
--- Send signal to process.
-- @param pid Process ID to signal (number).
-- @param sig Signal number.
end
--- Interrupt handling.
---
--- le2lib sets up a SIGINT handler that calls back into this function.
+-- signal_install() sets up signal handlers that call back into this function.
function e2lib.interrupt_hook()
+ local sigstr, signum = e2lib.signal_received()
trace.install() -- reinstall the trace hook.
- e2lib.abort("*interrupted by user*")
+ e2lib.logf(4, "interrupt_hook() pid=%d, signal=%d, sigstr=%s",
+ e2lib.getpid(), signum, sigstr)
+ e2lib.abort(string.format("*** interrupted by user (%s) ***", sigstr))
end
--- Make sure the environment variables inside the globals table are
trace.install()
trace.default_filter()
- local rc, re = e2lib.signal_reset()
- if not rc then
- e2lib.abort(re)
- end
+ e2lib.signal_reset()
e2lib.closefrom(3)
-- ignore errors, no /proc should not prevent factory from working
-- potentially mixes with the output of the command
e2lib.setlog(4, false)
+ e2lib.signal_reset()
+
fd_child_setup(fdctv)
if workdir then
/*
- * Copyright (C) 2007-2016 emlix GmbH, see file AUTHORS
+ * Copyright (C) 2007-2017 emlix GmbH, see file AUTHORS
*
* This file is part of e2factory, the emlix embedded build system.
* For more information see http://www.e2factory.org
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/prctl.h>
#include <signal.h>
#include <string.h>
#include <poll.h>
return 1;
}
-static int
-do_setpgid(lua_State *L)
-{
- int rc, pid, pgid;
-
- pid = luaL_checkint(L, 1);
- pgid = luaL_checkint(L, 2);
- if (setpgid(pid, pgid) != 0)
- return luaL_error(L, "setpgid: %s", strerror(errno));
-
- return 0;
-}
-
static int
do_unlink(lua_State *lua)
{
return 1;
}
-/* Reset all (possible) signals back to their default settings */
-static int
-signal_reset(lua_State *L)
-{
- int s;
- struct sigaction act;
-
- for (s = 1; s < NSIG; s++) {
- if (sigaction(s, NULL, &act) < 0)
- break; /* end of signals */
-
- switch (s) {
- case SIGINT:
- /* used by e2factory */
- continue;
- case SIGFPE:
- act.sa_handler = SIG_IGN;
- break;
- case SIGKILL:
- case SIGSTOP:
- case SIGCONT:
- continue;
- default:
- act.sa_handler = SIG_DFL;
- }
-
- if (sigaction(s, &act, NULL) < 0) {
- lua_pushboolean(L, 0);
- lua_pushstring(L, strerror(errno));
- return 2;
- }
- }
-
- lua_pushboolean(L, 1);
- return 1;
-}
-
-
/* closes all file descriptors >= fd */
static int
closefrom(lua_State *L)
return 1;
}
-static int
-ignore_sigint(lua_State *L)
-{
- if (signal(SIGINT, SIG_IGN) == SIG_ERR) {
- return luaL_error(L, "signal: %s", strerror(errno));
- }
-
- return 0;
-}
-
static int
do_kill(lua_State *lua)
{
return 4;
}
+/* Reset all (possible) signals to their default settings */
+static int
+signal_reset(lua_State *L)
+{
+ int s;
+ struct sigaction act;
+
+ if (prctl(PR_SET_PDEATHSIG, 0) < 0) {
+ lua_pushboolean(L, 0);
+ lua_pushstring(L, strerror(errno));
+ }
+
+ for (s = 1; s < NSIG; s++) {
+ if (sigaction(s, NULL, &act) < 0)
+ break; /* end of signals */
+
+ switch (s) {
+ case SIGFPE:
+ act.sa_handler = SIG_IGN;
+ break;
+ case SIGKILL:
+ case SIGSTOP:
+ case SIGCONT:
+ continue;
+ default:
+ act.sa_handler = SIG_DFL;
+ }
+ /* No SA_RESTART */
+ act.sa_flags = 0;
+ if (sigaction(s, &act, NULL) < 0) {
+ lua_pushboolean(L, 0);
+ lua_pushstring(L, strerror(errno));
+ return 2;
+ }
+ }
+
+ lua_pushboolean(L, 1);
+ return 1;
+}
+
/*
* Hook that gets called once an interrupt has been requested.
* Calls e2lib.interrupt_hook() to deal with any cleanup that might be required.
*/
static void
-lstop(lua_State *L, lua_Debug *ar) {
+lua_signal_handler(lua_State *L, lua_Debug *ar)
+{
lua_sethook(L, NULL, 0, 0);
/* require e2lib */
lua_call(L, 0, 0);
/* not reached under normal circumstances */
- fprintf(stderr, "e2: interrupt_hook failed, terminating\n");
+ fprintf(stderr, "e2: calling interrupt_hook failed, terminating\n");
exit(1);
}
-static lua_State *globalL;
+/* Lua context for signal handler */
+static lua_State *globalL = NULL;
+/* Are we in shutdown? */
+static volatile sig_atomic_t signal_shutdown = 0;
+/* First signal that triggered shutdown */
+static volatile sig_atomic_t signal_received_first = 0;
/*
* continuing normal execution at the next possible spot.
*/
static void
-laction(int i) {
- /* Ignore further signals because lstop() should
- * terminate the process in an orderly fashion */
- signal(i, SIG_IGN);
- lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+signal_handler(int sig)
+{
+ /*
+ * It's normal for subsequent signals to occur (eg. SIGPIPE)
+ * Ignore signals after they occurred once
+ */
+ struct sigaction sa;
+ sigaction(sig, NULL, &sa);
+ sa.sa_handler = SIG_IGN;
+
+ if (sigaction(sig, &sa, NULL) < 0)
+ fprintf(stderr, "e2: signal_handler: sigaction failed!\n");
+
+ /* Make sure we don't install lua_signal_handler more than once */
+ if (signal_shutdown)
+ return;
+
+ signal_shutdown = 1;
+ signal_received_first = sig;
+ if (globalL) {
+ lua_sethook(globalL, lua_signal_handler,
+ LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+ } else {
+ fprintf(stderr, "e2: signal_handler: missing lua context\n");
+ exit(1);
+ }
+}
+
+/* Install signal handler for all signals of concern */
+static int
+signal_install(lua_State *L)
+{
+ int i;
+ struct sigaction sa;
+ int signals[] = {
+ SIGINT,
+ SIGTERM,
+ SIGPIPE,
+ SIGHUP,
+ 0
+ };
+
+ /* Lua context for use in signal handler */
+ globalL = L;
+
+ sa.sa_handler = signal_handler;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+
+ for (i = 0; signals[i] != 0; i++) {
+ if (sigaction(signals[i], &sa, NULL) < 0) {
+ lua_pushboolean(L, 0);
+ lua_pushstring(L, strerror(errno));
+ return 2;
+ }
+ }
+
+ /* Notify us if the parent dies for whatever reason */
+ if (prctl(PR_SET_PDEATHSIG, SIGINT) < 0) {
+ lua_pushboolean(L, 0);
+ lua_pushstring(L, strerror(errno));
+ }
+
+ lua_pushboolean(L, 1);
+ return 1;
}
+/* Return the first received signal triggering shutdown */
+static int
+signal_received(lua_State *L)
+{
+ char *s = NULL;
+
+ if (signal_received_first) {
+ s = strsignal(signal_received_first);
+ } else {
+ s = "";
+ }
+
+ lua_pushstring(L, s);
+ lua_pushinteger(L, signal_received_first);
+ return 2;
+}
static luaL_Reg lib[] = {
{ "chdir", change_directory },
{ "fork", lua_fork },
{ "getpid", do_getpid },
{ "hardlink", do_hardlink },
- { "ignore_sigint", ignore_sigint },
{ "kill", do_kill },
{ "mkdir", do_mkdir },
{ "mkdtemp", do_mkdtemp },
{ "rename", do_rename },
{ "rmdir", do_rmdir },
{ "setenv", do_setenv },
- { "setpgid", do_setpgid },
{ "signal_reset", signal_reset },
+ { "signal_install", signal_install },
+ { "signal_received", signal_received },
{ "stat", get_file_statistics },
{ "symlink", create_symlink },
{ "umask", set_umask },
};
-int luaopen_le2lib(lua_State *lua)
+int
+luaopen_le2lib(lua_State *lua)
{
luaL_Reg *next;
lua_setfield(lua, -2, next->name);
}
- /* Establish signal handler catching SIGINT for orderly shutdown */
- globalL = lua;
- signal(SIGINT, laction);
-
return 1;
}