1 /* $NetBSD: clogd.c,v 1.1.1.1 2009/12/02 00:27:06 haad Exp $ */
2
3 /*
4 * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
5 *
6 * This copyrighted material is made available to anyone wishing to use,
7 * modify, copy, or redistribute it subject to the terms and conditions
8 * of the GNU General Public License v.2.
9 *
10 * You should have received a copy of the GNU General Public License
11 * along with this program; if not, write to the Free Software Foundation,
12 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
13 */
14
15 #include "configure.h"
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <sched.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <sys/stat.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <linux/types.h>
30 #include <sys/socket.h>
31 #include <linux/netlink.h>
32 #include <linux/dm-ioctl.h>
33
34 #include "dm-log-userspace.h"
35 #include "functions.h"
36 #include "local.h"
37 #include "cluster.h"
38 #include "common.h"
39 #include "logging.h"
40 #include "link_mon.h"
41
42 static int exit_now = 0;
43 static sigset_t signal_mask;
44 static int signal_received;
45
46 static void process_signals(void);
47 static void daemonize(void);
48 static void init_all(void);
49 static void cleanup_all(void);
50
main(int argc,char * argv[])51 int main(int argc, char *argv[])
52 {
53 daemonize();
54
55 init_all();
56
57 /* Parent can now exit, we're ready to handle requests */
58 kill(getppid(), SIGTERM);
59
60 LOG_PRINT("Starting cmirrord:");
61 LOG_PRINT(" Built: "__DATE__" "__TIME__"\n");
62 LOG_DBG(" Compiled with debugging.");
63
64 while (!exit_now) {
65 links_monitor();
66
67 links_issue_callbacks();
68
69 process_signals();
70 }
71 exit(EXIT_SUCCESS);
72 }
73
74 /*
75 * parent_exit_handler: exit the parent
76 * @sig: the signal
77 *
78 */
parent_exit_handler(int sig)79 static void parent_exit_handler(int sig)
80 {
81 exit_now = 1;
82 }
83
84 /*
85 * create_lockfile - create and lock a lock file
86 * @lockfile: location of lock file
87 *
88 * Returns: 0 on success, -1 otherwise
89 */
create_lockfile(char * lockfile)90 static int create_lockfile(char *lockfile)
91 {
92 int fd;
93 struct flock lock;
94 char buffer[50];
95
96 if((fd = open(lockfile, O_CREAT | O_WRONLY,
97 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0)
98 return -errno;
99
100 lock.l_type = F_WRLCK;
101 lock.l_start = 0;
102 lock.l_whence = SEEK_SET;
103 lock.l_len = 0;
104
105 if (fcntl(fd, F_SETLK, &lock) < 0) {
106 close(fd);
107 return -errno;
108 }
109
110 if (ftruncate(fd, 0) < 0) {
111 close(fd);
112 return -errno;
113 }
114
115 sprintf(buffer, "%d\n", getpid());
116
117 if(write(fd, buffer, strlen(buffer)) < strlen(buffer)){
118 close(fd);
119 unlink(lockfile);
120 return -errno;
121 }
122
123 return 0;
124 }
125
sig_handler(int sig)126 static void sig_handler(int sig)
127 {
128 sigaddset(&signal_mask, sig);
129 ++signal_received;
130 }
131
process_signal(int sig)132 static void process_signal(int sig){
133 int r = 0;
134
135 switch(sig) {
136 case SIGINT:
137 case SIGQUIT:
138 case SIGTERM:
139 case SIGHUP:
140 r += log_status();
141 break;
142 case SIGUSR1:
143 case SIGUSR2:
144 log_debug();
145 /*local_debug();*/
146 cluster_debug();
147 return;
148 default:
149 LOG_PRINT("Unknown signal received... ignoring");
150 return;
151 }
152
153 if (!r) {
154 LOG_DBG("No current cluster logs... safe to exit.");
155 cleanup_all();
156 exit(EXIT_SUCCESS);
157 }
158
159 LOG_ERROR("Cluster logs exist. Refusing to exit.");
160 }
161
process_signals(void)162 static void process_signals(void)
163 {
164 int x;
165
166 if (!signal_received)
167 return;
168
169 signal_received = 0;
170
171 for (x = 1; x < _NSIG; x++) {
172 if (sigismember(&signal_mask, x)) {
173 sigdelset(&signal_mask, x);
174 process_signal(x);
175 }
176 }
177 }
178
179 /*
180 * daemonize
181 *
182 * Performs the steps necessary to become a daemon.
183 */
daemonize(void)184 static void daemonize(void)
185 {
186 int pid;
187 int status;
188
189 signal(SIGTERM, &parent_exit_handler);
190
191 pid = fork();
192
193 if (pid < 0) {
194 LOG_ERROR("Unable to fork()");
195 exit(EXIT_FAILURE);
196 }
197
198 if (pid) {
199 /* Parent waits here for child to get going */
200 while (!waitpid(pid, &status, WNOHANG) && !exit_now);
201 if (exit_now)
202 exit(EXIT_SUCCESS);
203
204 switch (WEXITSTATUS(status)) {
205 case EXIT_LOCKFILE:
206 LOG_ERROR("Failed to create lockfile");
207 LOG_ERROR("Process already running?");
208 break;
209 case EXIT_KERNEL_SOCKET:
210 LOG_ERROR("Unable to create netlink socket");
211 break;
212 case EXIT_KERNEL_BIND:
213 LOG_ERROR("Unable to bind to netlink socket");
214 break;
215 case EXIT_KERNEL_SETSOCKOPT:
216 LOG_ERROR("Unable to setsockopt on netlink socket");
217 break;
218 case EXIT_CLUSTER_CKPT_INIT:
219 LOG_ERROR("Unable to initialize checkpoint service");
220 LOG_ERROR("Has the cluster infrastructure been started?");
221 break;
222 case EXIT_FAILURE:
223 LOG_ERROR("Failed to start: Generic error");
224 break;
225 default:
226 LOG_ERROR("Failed to start: Unknown error");
227 break;
228 }
229 exit(EXIT_FAILURE);
230 }
231
232 setsid();
233 chdir("/");
234 umask(0);
235
236 close(0); close(1); close(2);
237 open("/dev/null", O_RDONLY); /* reopen stdin */
238 open("/dev/null", O_WRONLY); /* reopen stdout */
239 open("/dev/null", O_WRONLY); /* reopen stderr */
240
241 LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
242
243 if (create_lockfile(CMIRRORD_PIDFILE))
244 exit(EXIT_LOCKFILE);
245
246 signal(SIGINT, &sig_handler);
247 signal(SIGQUIT, &sig_handler);
248 signal(SIGTERM, &sig_handler);
249 signal(SIGHUP, &sig_handler);
250 signal(SIGPIPE, SIG_IGN);
251 signal(SIGUSR1, &sig_handler);
252 signal(SIGUSR2, &sig_handler);
253 sigemptyset(&signal_mask);
254 signal_received = 0;
255 }
256
257 /*
258 * init_all
259 *
260 * Initialize modules. Exit on failure.
261 */
init_all(void)262 static void init_all(void)
263 {
264 int r;
265
266 if ((r = init_local()) ||
267 (r = init_cluster())) {
268 exit(r);
269 }
270 }
271
272 /*
273 * cleanup_all
274 *
275 * Clean up before exiting
276 */
cleanup_all(void)277 static void cleanup_all(void)
278 {
279 cleanup_local();
280 cleanup_cluster();
281 }
282