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