s_a_r_list(): return NULL on errors
[paraslash.git] / signal.c
1 /*
2  * Copyright (C) 2004-2006 Andre Noll <maan@systemlinux.org>
3  *
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  *
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  *
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18 /** \file signal.c signal handling functions */
19
20 #include "para.h"
21 #include "error.h"
22 static int signal_pipe[2];
23
24 /**
25  * initialize the paraslash signal subsystem
26  *
27  * This function creates a pipe, the signal pipe, to deliver pending signals to
28  * the application. It should be called during the application's startup part,
29  * followed by subsequent calls to para_install_sighandler() for each signal
30  * that should be caught.
31  *
32  * para_signal_init() installs a generic signal handler which is used for all
33  * signals simultaneously. When a signal arrives, this generic signal handler
34  * writes the corresponding signal number to the signal pipe so that the
35  * application can test for pending signals simply by checking the signal pipe
36  * for reading, e.g. by using the select(2) system call.
37  *
38  * \return This function either succeeds or calls exit(2) to terminate
39  * the current process. On success, the file descriptor of the signal pipe is
40  * returned.
41  */
42 int para_signal_init(void)
43 {
44         if (!pipe(signal_pipe))
45                 return signal_pipe[0];
46         PARA_EMERG_LOG("%s", "pipe error: Can not setup signal pipe");
47         exit(EXIT_FAILURE);
48 }
49
50 /*
51  * just write one integer to signal pipe
52  */
53 static void generic_signal_handler(int s)
54 {
55         write(signal_pipe[1], &s, sizeof(int));
56         //fprintf(stderr, "got sig %i, write returned %d\n", s, ret);
57 }
58
59 /**
60  * reap one child
61  *
62  * call waitpid() and print a log message containing the pid
63  * and the cause of the child's death.
64  *
65  * \return Like \p waitpid(), this function returns the process ID of the
66  * terminated child; on error, \p -E_WAITPID is returned.
67  * \sa waitpid(2)
68  */
69 pid_t para_reap_child(void)
70 {
71         int status;
72         pid_t pid = waitpid(-1, &status, WNOHANG);
73
74         if (pid <= 0) {
75                 if (pid < 0)
76                         pid = -E_WAITPID;
77                 return 0;
78         }
79         if (WIFEXITED(status))
80                 PARA_DEBUG_LOG("child %i exited. Exit status: %i\n", pid,
81                         WEXITSTATUS(status));
82         else if (WIFSIGNALED(status))
83                 PARA_DEBUG_LOG("child %i was killed by signal %i\n", pid,
84                         WTERMSIG(status));
85         else
86                 PARA_WARNING_LOG("child %i terminated abormally\n", pid);
87         return pid;
88 }
89
90 /**
91  * paraslash's zombie killer
92  *
93  * It just calls \p para_reap_child() until there are no more children left to
94  * reap.
95  */
96 void para_reap_children(void)
97 {
98         while (para_reap_child() > 0)
99                 ; /* nothing */
100 }
101
102 /**
103  * wrapper around signal(2)
104  * \param sig the number of the signal to catch
105  *
106  * This installs the generic signal handler for the given signal.
107  * \return This function returns 1 on success and \p -E_SIGNAL_SIG_ERR on errors.
108  * \sa signal(2)
109  */
110 int para_install_sighandler(int sig)
111 {
112         PARA_DEBUG_LOG("catching signal %d\n", sig);
113         return signal(sig, &generic_signal_handler) == SIG_ERR?  -E_SIGNAL_SIG_ERR : 1;
114 }
115
116 /**
117  * return number of next pending signal
118  *
119  * This should be called if the fd for the signal pipe is ready for reading.
120  *
121  * \return On success, the number of the received signal is returned. \p
122  * -E_SIGNAL_READ is returned if a read error occured while reading the signal
123  * pipe.  If the read was interrupted by another signal the function returns 0.
124  */
125 int para_next_signal(void)
126 {
127         int s;
128         ssize_t r;
129
130         if ((r = read(signal_pipe[0], &s, sizeof(s)) == sizeof(s)) > 0) {
131                 PARA_DEBUG_LOG("next signal: %d\n", s);
132                 return s;
133         }
134         return r < 0 && (errno != EAGAIN)? 0 : -E_SIGNAL_READ;
135 }