From 4d2317dafb3c3aac56f9f604262d82fd1b396a19 Mon Sep 17 00:00:00 2001 From: Andrew Gregory Date: Mon, 30 Nov 2015 12:36:30 -0500 Subject: move signal handlers to sighandler.[ch] Signals are special because they run asynchronously, making them non-trivial to handle correctly. Move the handlers a separate file to offset them from the normal code and make them easier to separate into individual functions without further cluttering pacman.c Signed-off-by: Andrew Gregory Signed-off-by: Allan McRae --- src/pacman/sighandler.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/pacman/sighandler.c (limited to 'src/pacman/sighandler.c') diff --git a/src/pacman/sighandler.c b/src/pacman/sighandler.c new file mode 100644 index 00000000..d488ecec --- /dev/null +++ b/src/pacman/sighandler.c @@ -0,0 +1,92 @@ +/* + * sighandler.c + * + * Copyright (c) 2015 Pacman Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include + +#include "conf.h" +#include "sighandler.h" +#include "util.h" + +/** Write function that correctly handles EINTR. + */ +static ssize_t xwrite(int fd, const void *buf, size_t count) +{ + ssize_t ret; + do { + ret = write(fd, buf, count); + } while(ret == -1 && errno == EINTR); + return ret; +} + +/** Catches thrown signals. Performs necessary cleanup to ensure database is + * in a consistent state. + * @param signum the thrown signal + */ +static void handler(int signum) +{ + if(signum == SIGSEGV) { + const char msg[] = "\nerror: segmentation fault\n" + "Please submit a full bug report with --debug if appropriate.\n"; + xwrite(STDERR_FILENO, msg, ARRAYSIZE(msg) - 1); + exit(signum); + } else if(signum == SIGINT || signum == SIGHUP) { + if(signum == SIGINT) { + const char msg[] = "\nInterrupt signal received\n"; + xwrite(STDERR_FILENO, msg, ARRAYSIZE(msg) - 1); + } else { + const char msg[] = "\nHangup signal received\n"; + xwrite(STDERR_FILENO, msg, ARRAYSIZE(msg) - 1); + } + if(alpm_trans_interrupt(config->handle) == 0) { + /* a transaction is being interrupted, don't exit pacman yet. */ + return; + } + } else if(signum == SIGWINCH) { + columns_cache_reset(); + return; + } + /* SIGINT/SIGHUP: no committing transaction, release it now and then exit pacman */ + alpm_unlock(config->handle); + /* output a newline to be sure we clear any line we may be on */ + xwrite(STDOUT_FILENO, "\n", 1); + _Exit(128 + signum); +} + +void install_signal_handlers(void) +{ + struct sigaction new_action; + const int signals[] = { SIGHUP, SIGINT, SIGSEGV, SIGWINCH }; + size_t i; + /* Set signal handlers */ + /* Set up the structure to specify the new action. */ + new_action.sa_handler = handler; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = SA_RESTART; + + /* assign our handler to any signals we care about */ + for(i = 0; i < ARRAYSIZE(signals); i++) { + sigaction(signals[i], &new_action, NULL); + } +} + +/* vim: set noet: */ -- cgit v1.2.3