1 /*
2  * FUSE: Filesystem in Userspace
3  * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
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 "qemu/osdep.h"
12 #include "fuse_i.h"
13 #include "fuse_lowlevel.h"
14 
15 #include <errno.h>
16 #include <signal.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 static struct fuse_session *fuse_instance;
22 
exit_handler(int sig)23 static void exit_handler(int sig)
24 {
25     if (fuse_instance) {
26         fuse_session_exit(fuse_instance);
27         if (sig <= 0) {
28             fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n");
29             abort();
30         }
31         fuse_instance->error = sig;
32     }
33 }
34 
do_nothing(int sig)35 static void do_nothing(int sig)
36 {
37     (void)sig;
38 }
39 
set_one_signal_handler(int sig,void (* handler)(int),int remove)40 static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
41 {
42     struct sigaction sa;
43     struct sigaction old_sa;
44 
45     memset(&sa, 0, sizeof(struct sigaction));
46     sa.sa_handler = remove ? SIG_DFL : handler;
47     sigemptyset(&(sa.sa_mask));
48     sa.sa_flags = 0;
49 
50     if (sigaction(sig, NULL, &old_sa) == -1) {
51         fuse_log(FUSE_LOG_ERR, "fuse: cannot get old signal handler: %s\n",
52                  strerror(errno));
53         return -1;
54     }
55 
56     if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
57         sigaction(sig, &sa, NULL) == -1) {
58         fuse_log(FUSE_LOG_ERR, "fuse: cannot set signal handler: %s\n",
59                  strerror(errno));
60         return -1;
61     }
62     return 0;
63 }
64 
fuse_set_signal_handlers(struct fuse_session * se)65 int fuse_set_signal_handlers(struct fuse_session *se)
66 {
67     /*
68      * If we used SIG_IGN instead of the do_nothing function,
69      * then we would be unable to tell if we set SIG_IGN (and
70      * thus should reset to SIG_DFL in fuse_remove_signal_handlers)
71      * or if it was already set to SIG_IGN (and should be left
72      * untouched.
73      */
74     if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
75         set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
76         set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
77         set_one_signal_handler(SIGPIPE, do_nothing, 0) == -1) {
78         return -1;
79     }
80 
81     fuse_instance = se;
82     return 0;
83 }
84 
fuse_remove_signal_handlers(struct fuse_session * se)85 void fuse_remove_signal_handlers(struct fuse_session *se)
86 {
87     if (fuse_instance != se) {
88         fuse_log(FUSE_LOG_ERR,
89                  "fuse: fuse_remove_signal_handlers: unknown session\n");
90     } else {
91         fuse_instance = NULL;
92     }
93 
94     set_one_signal_handler(SIGHUP, exit_handler, 1);
95     set_one_signal_handler(SIGINT, exit_handler, 1);
96     set_one_signal_handler(SIGTERM, exit_handler, 1);
97     set_one_signal_handler(SIGPIPE, do_nothing, 1);
98 }
99