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