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