1 /*
2 * sighandler.c
3 *
4 * Copyright (c) 2015-2018 Pacman Development Team <pacman-dev@archlinux.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <errno.h>
21 #include <signal.h>
22 #include <unistd.h>
23
24 #include <alpm.h>
25
26 #include "conf.h"
27 #include "sighandler.h"
28 #include "util.h"
29
30 /** Write function that correctly handles EINTR.
31 */
xwrite(int fd,const void * buf,size_t count)32 static ssize_t xwrite(int fd, const void *buf, size_t count)
33 {
34 ssize_t ret;
35 do {
36 ret = write(fd, buf, count);
37 } while(ret == -1 && errno == EINTR);
38 return ret;
39 }
40
41 /** Catches thrown signals. Performs necessary cleanup to ensure database is
42 * in a consistent state.
43 * @param signum the thrown signal
44 */
soft_interrupt_handler(int signum)45 static void soft_interrupt_handler(int signum)
46 {
47 if(signum == SIGINT) {
48 const char msg[] = "\nInterrupt signal received\n";
49 xwrite(STDERR_FILENO, msg, ARRAYSIZE(msg) - 1);
50 } else {
51 const char msg[] = "\nHangup signal received\n";
52 xwrite(STDERR_FILENO, msg, ARRAYSIZE(msg) - 1);
53 }
54 if(alpm_trans_interrupt(config->handle) == 0) {
55 /* a transaction is being interrupted, don't exit pacman yet. */
56 return;
57 }
58 alpm_unlock(config->handle);
59 /* output a newline to be sure we clear any line we may be on */
60 xwrite(STDOUT_FILENO, "\n", 1);
61 _Exit(128 + signum);
62 }
63
install_soft_interrupt_handler(void)64 void install_soft_interrupt_handler(void)
65 {
66 struct sigaction new_action;
67 new_action.sa_handler = soft_interrupt_handler;
68 new_action.sa_flags = SA_RESTART;
69 sigemptyset(&new_action.sa_mask);
70 sigaddset(&new_action.sa_mask, SIGINT);
71 sigaddset(&new_action.sa_mask, SIGHUP);
72
73 sigaction(SIGINT, &new_action, NULL);
74 sigaction(SIGHUP, &new_action, NULL);
75 }
76
remove_soft_interrupt_handler(void)77 void remove_soft_interrupt_handler(void)
78 {
79 struct sigaction new_action;
80 sigemptyset(&new_action.sa_mask);
81 new_action.sa_handler = SIG_DFL;
82 new_action.sa_flags = 0;
83 sigaction(SIGINT, &new_action, NULL);
84 sigaction(SIGHUP, &new_action, NULL);
85 }
86
segv_handler(int signum)87 static void segv_handler(int signum)
88 {
89 const char msg[] = "\nerror: segmentation fault\n"
90 "Please submit a full bug report with --debug if appropriate.\n";
91 xwrite(STDERR_FILENO, msg, sizeof(msg) - 1);
92 _Exit(signum);
93 }
94
install_segv_handler(void)95 void install_segv_handler(void)
96 {
97 struct sigaction new_action;
98 new_action.sa_handler = segv_handler;
99 sigemptyset(&new_action.sa_mask);
100 new_action.sa_flags = SA_RESTART;
101 sigaction(SIGSEGV, &new_action, NULL);
102 }
103
winch_handler(int signum)104 static void winch_handler(int signum)
105 {
106 (void)signum; /* suppress unused variable warnings */
107 columns_cache_reset();
108 }
109
install_winch_handler(void)110 void install_winch_handler(void)
111 {
112 struct sigaction new_action;
113 new_action.sa_handler = winch_handler;
114 sigemptyset(&new_action.sa_mask);
115 new_action.sa_flags = SA_RESTART;
116 sigaction(SIGWINCH, &new_action, NULL);
117 }
118