import source from lvm2 2.02.79
[external/device-mapper.git] / daemons / cmirrord / clogd.c
1 /*
2  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
3  *
4  * This copyrighted material is made available to anyone wishing to use,
5  * modify, copy, or redistribute it subject to the terms and conditions
6  * of the GNU General Public License v.2.
7  *
8  * You should have received a copy of the GNU General Public License
9  * along with this program; if not, write to the Free Software Foundation,
10  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
11  */
12 #include "logging.h"
13 #include "common.h"
14 #include "functions.h"
15 #include "link_mon.h"
16 #include "local.h"
17
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <sys/socket.h>
21 #include <sys/stat.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24
25 static volatile sig_atomic_t exit_now = 0;
26 /* FIXME Review signal handling.  Should be volatile sig_atomic_t */
27 static sigset_t signal_mask;
28 static volatile sig_atomic_t signal_received;
29
30 static void process_signals(void);
31 static void daemonize(void);
32 static void init_all(void);
33 static void cleanup_all(void);
34
35 int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
36 {
37         daemonize();
38
39         init_all();
40
41         /* Parent can now exit, we're ready to handle requests */
42         kill(getppid(), SIGTERM);
43
44         LOG_PRINT("Starting cmirrord:");
45         LOG_PRINT(" Built: "__DATE__" "__TIME__"\n");
46         LOG_DBG(" Compiled with debugging.");
47
48         while (!exit_now) {
49                 links_monitor();
50
51                 links_issue_callbacks();
52
53                 process_signals();
54         }
55         exit(EXIT_SUCCESS);
56 }
57
58 /*
59  * parent_exit_handler: exit the parent
60  * @sig: the signal
61  *
62  */
63 static void parent_exit_handler(int sig __attribute__((unused)))
64 {
65         exit_now = 1;
66 }
67
68 static void sig_handler(int sig)
69 {
70         /* FIXME Races - don't touch signal_mask here. */
71         sigaddset(&signal_mask, sig);
72         signal_received = 1;
73 }
74
75 static void process_signal(int sig){
76         int r = 0;
77
78         switch(sig) {
79         case SIGINT:
80         case SIGQUIT:
81         case SIGTERM:
82         case SIGHUP:
83                 r += log_status();
84                 break;
85         case SIGUSR1:
86         case SIGUSR2:
87                 log_debug();
88                 /*local_debug();*/
89                 cluster_debug();
90                 return;
91         default:
92                 LOG_PRINT("Unknown signal received... ignoring");
93                 return;
94         }
95
96         if (!r) {
97                 LOG_DBG("No current cluster logs... safe to exit.");
98                 cleanup_all();
99                 exit(EXIT_SUCCESS);
100         }
101
102         LOG_ERROR("Cluster logs exist.  Refusing to exit.");
103 }
104
105 static void process_signals(void)
106 {
107         int x;
108
109         if (!signal_received)
110                 return;
111
112         signal_received = 0;
113
114         for (x = 1; x < _NSIG; x++) {
115                 if (sigismember(&signal_mask, x)) {
116                         sigdelset(&signal_mask, x);
117                         process_signal(x);
118                 }
119         }
120 }
121
122 static void remove_lockfile(void)
123 {
124         unlink(CMIRRORD_PIDFILE);
125 }
126
127 /*
128  * daemonize
129  *
130  * Performs the steps necessary to become a daemon.
131  */
132 static void daemonize(void)
133 {
134         int pid;
135         int status;
136
137         signal(SIGTERM, &parent_exit_handler);
138
139         pid = fork();
140
141         if (pid < 0) {
142                 LOG_ERROR("Unable to fork()");
143                 exit(EXIT_FAILURE);
144         }
145
146         if (pid) {
147                 /* Parent waits here for child to get going */
148                 while (!waitpid(pid, &status, WNOHANG) && !exit_now);
149                 if (exit_now)
150                         exit(EXIT_SUCCESS);
151
152                 switch (WEXITSTATUS(status)) {
153                 case EXIT_LOCKFILE:
154                         LOG_ERROR("Failed to create lockfile");
155                         LOG_ERROR("Process already running?");
156                         break;
157                 case EXIT_KERNEL_SOCKET:
158                         LOG_ERROR("Unable to create netlink socket");
159                         break;
160                 case EXIT_KERNEL_BIND:
161                         LOG_ERROR("Unable to bind to netlink socket");
162                         break;
163                 case EXIT_KERNEL_SETSOCKOPT:
164                         LOG_ERROR("Unable to setsockopt on netlink socket");
165                         break;
166                 case EXIT_CLUSTER_CKPT_INIT:
167                         LOG_ERROR("Unable to initialize checkpoint service");
168                         LOG_ERROR("Has the cluster infrastructure been started?");
169                         break;
170                 case EXIT_FAILURE:
171                         LOG_ERROR("Failed to start: Generic error");
172                         break;
173                 default:
174                         LOG_ERROR("Failed to start: Unknown error");
175                         break;
176                 }
177                 exit(EXIT_FAILURE);
178         }
179
180         setsid();
181         chdir("/");
182         umask(0);
183
184         close(0); close(1); close(2);
185         open("/dev/null", O_RDONLY); /* reopen stdin */
186         open("/dev/null", O_WRONLY); /* reopen stdout */
187         open("/dev/null", O_WRONLY); /* reopen stderr */
188
189         LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
190
191         (void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG);
192         if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0)
193                 exit(EXIT_LOCKFILE);
194         (void) dm_prepare_selinux_context(NULL, 0);
195
196         atexit(remove_lockfile);
197
198         /* FIXME Replace with sigaction. (deprecated) */
199         signal(SIGINT, &sig_handler);
200         signal(SIGQUIT, &sig_handler);
201         signal(SIGTERM, &sig_handler);
202         signal(SIGHUP, &sig_handler);
203         signal(SIGPIPE, SIG_IGN);
204         signal(SIGUSR1, &sig_handler);
205         signal(SIGUSR2, &sig_handler);
206         sigemptyset(&signal_mask);
207         signal_received = 0;
208 }
209
210 /*
211  * init_all
212  *
213  * Initialize modules.  Exit on failure.
214  */
215 static void init_all(void)
216 {
217         int r;
218
219         if ((r = init_local()) ||
220             (r = init_cluster())) {
221                 exit(r);
222         }
223 }
224
225 /*
226  * cleanup_all
227  *
228  * Clean up before exiting
229  */
230 static void cleanup_all(void)
231 {
232         cleanup_local();
233         cleanup_cluster();
234 }