xref: /aosp_15_r20/external/libfuse/lib/fuse_signals.c (revision 9e5649576b786774a32d7b0252c9cd8c6538fa49)
1*9e564957SAndroid Build Coastguard Worker /*
2*9e564957SAndroid Build Coastguard Worker   FUSE: Filesystem in Userspace
3*9e564957SAndroid Build Coastguard Worker   Copyright (C) 2001-2007  Miklos Szeredi <[email protected]>
4*9e564957SAndroid Build Coastguard Worker 
5*9e564957SAndroid Build Coastguard Worker   Utility functions for setting signal handlers.
6*9e564957SAndroid Build Coastguard Worker 
7*9e564957SAndroid Build Coastguard Worker   This program can be distributed under the terms of the GNU LGPLv2.
8*9e564957SAndroid Build Coastguard Worker   See the file COPYING.LIB
9*9e564957SAndroid Build Coastguard Worker */
10*9e564957SAndroid Build Coastguard Worker 
11*9e564957SAndroid Build Coastguard Worker #include "fuse_config.h"
12*9e564957SAndroid Build Coastguard Worker #include "fuse_lowlevel.h"
13*9e564957SAndroid Build Coastguard Worker #include "fuse_i.h"
14*9e564957SAndroid Build Coastguard Worker 
15*9e564957SAndroid Build Coastguard Worker #include <stdio.h>
16*9e564957SAndroid Build Coastguard Worker #include <string.h>
17*9e564957SAndroid Build Coastguard Worker #include <signal.h>
18*9e564957SAndroid Build Coastguard Worker #include <stdlib.h>
19*9e564957SAndroid Build Coastguard Worker #include <execinfo.h>
20*9e564957SAndroid Build Coastguard Worker 
21*9e564957SAndroid Build Coastguard Worker static struct fuse_session *fuse_instance;
22*9e564957SAndroid Build Coastguard Worker 
dump_stack(void)23*9e564957SAndroid Build Coastguard Worker static void dump_stack(void)
24*9e564957SAndroid Build Coastguard Worker {
25*9e564957SAndroid Build Coastguard Worker #ifdef HAVE_BACKTRACE
26*9e564957SAndroid Build Coastguard Worker 	const size_t backtrace_sz = 1024 * 1024;
27*9e564957SAndroid Build Coastguard Worker 	void* backtrace_buffer[backtrace_sz];
28*9e564957SAndroid Build Coastguard Worker 
29*9e564957SAndroid Build Coastguard Worker 	int err_fd = fileno(stderr);
30*9e564957SAndroid Build Coastguard Worker 
31*9e564957SAndroid Build Coastguard Worker 	int trace_len = backtrace(backtrace_buffer, backtrace_sz);
32*9e564957SAndroid Build Coastguard Worker 	backtrace_symbols_fd(backtrace_buffer, trace_len, err_fd);
33*9e564957SAndroid Build Coastguard Worker #endif
34*9e564957SAndroid Build Coastguard Worker }
35*9e564957SAndroid Build Coastguard Worker 
exit_handler(int sig)36*9e564957SAndroid Build Coastguard Worker static void exit_handler(int sig)
37*9e564957SAndroid Build Coastguard Worker {
38*9e564957SAndroid Build Coastguard Worker 	if (fuse_instance) {
39*9e564957SAndroid Build Coastguard Worker 		fuse_session_exit(fuse_instance);
40*9e564957SAndroid Build Coastguard Worker 		if(sig <= 0) {
41*9e564957SAndroid Build Coastguard Worker 			fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n");
42*9e564957SAndroid Build Coastguard Worker 			dump_stack();
43*9e564957SAndroid Build Coastguard Worker 			abort();
44*9e564957SAndroid Build Coastguard Worker 		}
45*9e564957SAndroid Build Coastguard Worker 		fuse_instance->error = sig;
46*9e564957SAndroid Build Coastguard Worker 	}
47*9e564957SAndroid Build Coastguard Worker }
48*9e564957SAndroid Build Coastguard Worker 
do_nothing(int sig)49*9e564957SAndroid Build Coastguard Worker static void do_nothing(int sig)
50*9e564957SAndroid Build Coastguard Worker {
51*9e564957SAndroid Build Coastguard Worker 	(void) sig;
52*9e564957SAndroid Build Coastguard Worker }
53*9e564957SAndroid Build Coastguard Worker 
set_one_signal_handler(int sig,void (* handler)(int),int remove)54*9e564957SAndroid Build Coastguard Worker static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
55*9e564957SAndroid Build Coastguard Worker {
56*9e564957SAndroid Build Coastguard Worker 	struct sigaction sa;
57*9e564957SAndroid Build Coastguard Worker 	struct sigaction old_sa;
58*9e564957SAndroid Build Coastguard Worker 
59*9e564957SAndroid Build Coastguard Worker 	memset(&sa, 0, sizeof(struct sigaction));
60*9e564957SAndroid Build Coastguard Worker 	sa.sa_handler = remove ? SIG_DFL : handler;
61*9e564957SAndroid Build Coastguard Worker 	sigemptyset(&(sa.sa_mask));
62*9e564957SAndroid Build Coastguard Worker 	sa.sa_flags = 0;
63*9e564957SAndroid Build Coastguard Worker 
64*9e564957SAndroid Build Coastguard Worker 	if (sigaction(sig, NULL, &old_sa) == -1) {
65*9e564957SAndroid Build Coastguard Worker 		perror("fuse: cannot get old signal handler");
66*9e564957SAndroid Build Coastguard Worker 		return -1;
67*9e564957SAndroid Build Coastguard Worker 	}
68*9e564957SAndroid Build Coastguard Worker 
69*9e564957SAndroid Build Coastguard Worker 	if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
70*9e564957SAndroid Build Coastguard Worker 	    sigaction(sig, &sa, NULL) == -1) {
71*9e564957SAndroid Build Coastguard Worker 		perror("fuse: cannot set signal handler");
72*9e564957SAndroid Build Coastguard Worker 		return -1;
73*9e564957SAndroid Build Coastguard Worker 	}
74*9e564957SAndroid Build Coastguard Worker 	return 0;
75*9e564957SAndroid Build Coastguard Worker }
76*9e564957SAndroid Build Coastguard Worker 
fuse_set_signal_handlers(struct fuse_session * se)77*9e564957SAndroid Build Coastguard Worker int fuse_set_signal_handlers(struct fuse_session *se)
78*9e564957SAndroid Build Coastguard Worker {
79*9e564957SAndroid Build Coastguard Worker 	/* If we used SIG_IGN instead of the do_nothing function,
80*9e564957SAndroid Build Coastguard Worker 	   then we would be unable to tell if we set SIG_IGN (and
81*9e564957SAndroid Build Coastguard Worker 	   thus should reset to SIG_DFL in fuse_remove_signal_handlers)
82*9e564957SAndroid Build Coastguard Worker 	   or if it was already set to SIG_IGN (and should be left
83*9e564957SAndroid Build Coastguard Worker 	   untouched. */
84*9e564957SAndroid Build Coastguard Worker 	if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
85*9e564957SAndroid Build Coastguard Worker 	    set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
86*9e564957SAndroid Build Coastguard Worker 	    set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
87*9e564957SAndroid Build Coastguard Worker 	    set_one_signal_handler(SIGPIPE, do_nothing, 0) == -1)
88*9e564957SAndroid Build Coastguard Worker 		return -1;
89*9e564957SAndroid Build Coastguard Worker 
90*9e564957SAndroid Build Coastguard Worker 	fuse_instance = se;
91*9e564957SAndroid Build Coastguard Worker 	return 0;
92*9e564957SAndroid Build Coastguard Worker }
93*9e564957SAndroid Build Coastguard Worker 
fuse_remove_signal_handlers(struct fuse_session * se)94*9e564957SAndroid Build Coastguard Worker void fuse_remove_signal_handlers(struct fuse_session *se)
95*9e564957SAndroid Build Coastguard Worker {
96*9e564957SAndroid Build Coastguard Worker 	if (fuse_instance != se)
97*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR,
98*9e564957SAndroid Build Coastguard Worker 			"fuse: fuse_remove_signal_handlers: unknown session\n");
99*9e564957SAndroid Build Coastguard Worker 	else
100*9e564957SAndroid Build Coastguard Worker 		fuse_instance = NULL;
101*9e564957SAndroid Build Coastguard Worker 
102*9e564957SAndroid Build Coastguard Worker 	set_one_signal_handler(SIGHUP, exit_handler, 1);
103*9e564957SAndroid Build Coastguard Worker 	set_one_signal_handler(SIGINT, exit_handler, 1);
104*9e564957SAndroid Build Coastguard Worker 	set_one_signal_handler(SIGTERM, exit_handler, 1);
105*9e564957SAndroid Build Coastguard Worker 	set_one_signal_handler(SIGPIPE, do_nothing, 1);
106*9e564957SAndroid Build Coastguard Worker }
107