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 
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  */
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  */
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 
126 static void sig_handler(int sig)
127 {
128 	sigaddset(&signal_mask, sig);
129 	++signal_received;
130 }
131 
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 
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  */
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  */
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  */
277 static void cleanup_all(void)
278 {
279 	cleanup_local();
280 	cleanup_cluster();
281 }
282