]> git.tuebingen.mpg.de Git - dss.git/blob - signal.c
Make the dss log facility C89 conform.
[dss.git] / signal.c
1 /*
2  * Copyright (C) 2004-2010 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6 /** \file signal.c Signal handling functions. */
7
8 #include <string.h>
9 #include <errno.h>
10 #include <signal.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <dirent.h>
14 #include <assert.h>
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <signal.h>
18 #include <stdlib.h>
19 #include <sys/select.h>
20
21
22 #include "gcc-compat.h"
23 #include "error.h"
24 #include "log.h"
25 #include "string.h"
26 #include "fd.h"
27 #include "signal.h"
28
29 static int signal_pipe[2];
30
31 /**
32  * Initialize the signal subsystem.
33  *
34  * This function creates a pipe, the signal pipe, to deliver pending signals to
35  * the application (Bernstein's trick). It should be called during the
36  * application's startup part, followed by subsequent calls to
37  * install_sighandler() for each signal that should be caught.
38  *
39  * signal_init() installs a generic signal handler which is used for all
40  * signals simultaneously. When a signal arrives, this generic signal handler
41  * writes the corresponding signal number to the signal pipe so that the
42  * application can test for pending signals simply by checking the signal pipe
43  * for reading, e.g. by using the select(2) system call.
44  *
45  * \return This function either succeeds or calls exit(2) to terminate
46  * the current process. On success, the file descriptor of the signal pipe is
47  * returned.
48  */
49 int signal_init(void)
50 {
51         int ret;
52         if (pipe(signal_pipe) < 0) {
53                 ret = -ERRNO_TO_DSS_ERROR(errno);
54                 goto err_out;
55         }
56         ret = mark_fd_nonblocking(signal_pipe[0]);
57         if (ret < 0)
58                 goto err_out;
59         ret = mark_fd_nonblocking(signal_pipe[1]);
60         if (ret < 0)
61                 goto err_out;
62         return signal_pipe[0];
63 err_out:
64         DSS_EMERG_LOG(("%s\n", dss_strerror(-ret)));
65         exit(EXIT_FAILURE);
66 }
67
68 /*
69  * just write one integer to signal pipe
70  */
71 static void generic_signal_handler(int s)
72 {
73         write(signal_pipe[1], &s, sizeof(int));
74 }
75
76 /**
77  * Reap one child.
78  *
79  * \param pid In case a child died, its pid is returned here.
80  *
81  * Call waitpid() and print a log message containing the pid and the cause of
82  * the child's death.
83  *
84  * \return A (negative) error code on errors, zero, if no child died, one
85  * otherwise. If and only if the function returns one, the content of \a pid is
86  * meaningful.
87  *
88  * \sa waitpid(2)
89  */
90 int reap_child(pid_t *pid, int *status)
91 {
92         *pid = waitpid(-1, status, WNOHANG);
93
94         if (!*pid)
95                 return 0;
96         if (*pid < 0)
97                 return -ERRNO_TO_DSS_ERROR(errno);
98         if (WIFEXITED(*status))
99                 DSS_DEBUG_LOG(("child %i exited. Exit status: %i\n", (int)*pid,
100                         WEXITSTATUS(*status)));
101         else if (WIFSIGNALED(*status))
102                 DSS_DEBUG_LOG(("child %i was killed by signal %i\n", (int)*pid,
103                         WTERMSIG(*status)));
104         else
105                 DSS_WARNING_LOG(("child %i terminated abormally\n", (int)*pid));
106         return 1;
107 }
108
109 /**
110  * Wrapper around signal(2)
111  *
112  * \param sig The number of the signal to catch.
113  *
114  * This installs the generic signal handler for the given signal.
115  *
116  * \return This function returns 1 on success and \p -E_SIGNAL_SIG_ERR on errors.
117  * \sa signal(2)
118  */
119 int install_sighandler(int sig)
120 {
121         DSS_DEBUG_LOG(("catching signal %d\n", sig));
122         if (signal(sig, &generic_signal_handler) != SIG_ERR)
123                 return 1;
124         return -E_SIGNAL_SIG_ERR;
125 }
126
127 /**
128  * Return number of next pending signal.
129  *
130  * This should be called if the fd for the signal pipe is ready for reading.
131  *
132  * \return On success, the number of the received signal is returned.
133  * If the read was interrupted by another signal the function returns 0.
134  * Otherwise a negative error code is returned.
135  */
136 int next_signal(void)
137 {
138         int s, err;
139         ssize_t r;
140
141         r = read(signal_pipe[0], &s, sizeof(s));
142         if (r == sizeof(s)) {
143                 DSS_DEBUG_LOG(("next signal: %d\n", s));
144                 return s;
145         }
146         err = errno;
147         assert(r < 0);
148         if (err == EAGAIN)
149                 return 0;
150         DSS_ERROR_LOG(("failed to read from signal pipe\n"));
151         return -ERRNO_TO_DSS_ERROR(err);
152 }
153
154 /**
155  * Close the signal pipe.
156  */
157 void signal_shutdown(void)
158 {
159         close(signal_pipe[1]);
160 }