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