diff options
Diffstat (limited to 'daemons/cmirrord/clogd.c')
-rw-r--r-- | daemons/cmirrord/clogd.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/daemons/cmirrord/clogd.c b/daemons/cmirrord/clogd.c new file mode 100644 index 00000000..bfb74fad --- /dev/null +++ b/daemons/cmirrord/clogd.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <sched.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> +#include <linux/types.h> +#include <sys/socket.h> +#include <linux/netlink.h> +#include <linux/dm-ioctl.h> + +#include "dm-log-userspace.h" +#include "functions.h" +#include "local.h" +#include "cluster.h" +#include "common.h" +#include "logging.h" +#include "link_mon.h" + +static int exit_now = 0; +static sigset_t signal_mask; +static int signal_received; + +static void process_signals(void); +static void daemonize(void); +static void init_all(void); +static void cleanup_all(void); + +int main(int argc, char *argv[]) +{ + daemonize(); + + init_all(); + + /* Parent can now exit, we're ready to handle requests */ + kill(getppid(), SIGTERM); + + LOG_PRINT("Starting cmirrord:"); + LOG_PRINT(" Built: "__DATE__" "__TIME__"\n"); + LOG_DBG(" Compiled with debugging."); + + while (!exit_now) { + links_monitor(); + + links_issue_callbacks(); + + process_signals(); + } + exit(EXIT_SUCCESS); +} + +/* + * parent_exit_handler: exit the parent + * @sig: the signal + * + */ +static void parent_exit_handler(int sig) +{ + exit_now = 1; +} + +/* + * create_lockfile - create and lock a lock file + * @lockfile: location of lock file + * + * Returns: 0 on success, -1 otherwise + */ +static int create_lockfile(char *lockfile) +{ + int fd; + struct flock lock; + char buffer[50]; + + if((fd = open(lockfile, O_CREAT | O_WRONLY, + (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) + return -errno; + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + if (fcntl(fd, F_SETLK, &lock) < 0) { + close(fd); + return -errno; + } + + if (ftruncate(fd, 0) < 0) { + close(fd); + return -errno; + } + + sprintf(buffer, "%d\n", getpid()); + + if(write(fd, buffer, strlen(buffer)) < strlen(buffer)){ + close(fd); + unlink(lockfile); + return -errno; + } + + return 0; +} + +static void sig_handler(int sig) +{ + sigaddset(&signal_mask, sig); + ++signal_received; +} + +static void process_signal(int sig){ + int r = 0; + + switch(sig) { + case SIGINT: + case SIGQUIT: + case SIGTERM: + case SIGHUP: + r += log_status(); + break; + case SIGUSR1: + case SIGUSR2: + log_debug(); + /*local_debug();*/ + cluster_debug(); + return; + default: + LOG_PRINT("Unknown signal received... ignoring"); + return; + } + + if (!r) { + LOG_DBG("No current cluster logs... safe to exit."); + cleanup_all(); + exit(EXIT_SUCCESS); + } + + LOG_ERROR("Cluster logs exist. Refusing to exit."); +} + +static void process_signals(void) +{ + int x; + + if (!signal_received) + return; + + signal_received = 0; + + for (x = 1; x < _NSIG; x++) { + if (sigismember(&signal_mask, x)) { + sigdelset(&signal_mask, x); + process_signal(x); + } + } +} + +/* + * daemonize + * + * Performs the steps necessary to become a daemon. + */ +static void daemonize(void) +{ + int pid; + int status; + + signal(SIGTERM, &parent_exit_handler); + + pid = fork(); + + if (pid < 0) { + LOG_ERROR("Unable to fork()"); + exit(EXIT_FAILURE); + } + + if (pid) { + /* Parent waits here for child to get going */ + while (!waitpid(pid, &status, WNOHANG) && !exit_now); + if (exit_now) + exit(EXIT_SUCCESS); + + switch (WEXITSTATUS(status)) { + case EXIT_LOCKFILE: + LOG_ERROR("Failed to create lockfile"); + LOG_ERROR("Process already running?"); + break; + case EXIT_KERNEL_SOCKET: + LOG_ERROR("Unable to create netlink socket"); + break; + case EXIT_KERNEL_BIND: + LOG_ERROR("Unable to bind to netlink socket"); + break; + case EXIT_KERNEL_SETSOCKOPT: + LOG_ERROR("Unable to setsockopt on netlink socket"); + break; + case EXIT_CLUSTER_CKPT_INIT: + LOG_ERROR("Unable to initialize checkpoint service"); + LOG_ERROR("Has the cluster infrastructure been started?"); + break; + case EXIT_FAILURE: + LOG_ERROR("Failed to start: Generic error"); + break; + default: + LOG_ERROR("Failed to start: Unknown error"); + break; + } + exit(EXIT_FAILURE); + } + + setsid(); + chdir("/"); + umask(0); + + close(0); close(1); close(2); + open("/dev/null", O_RDONLY); /* reopen stdin */ + open("/dev/null", O_WRONLY); /* reopen stdout */ + open("/dev/null", O_WRONLY); /* reopen stderr */ + + LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON); + + if (create_lockfile(CMIRRORD_PIDFILE)) + exit(EXIT_LOCKFILE); + + signal(SIGINT, &sig_handler); + signal(SIGQUIT, &sig_handler); + signal(SIGTERM, &sig_handler); + signal(SIGHUP, &sig_handler); + signal(SIGPIPE, SIG_IGN); + signal(SIGUSR1, &sig_handler); + signal(SIGUSR2, &sig_handler); + sigemptyset(&signal_mask); + signal_received = 0; +} + +/* + * init_all + * + * Initialize modules. Exit on failure. + */ +static void init_all(void) +{ + int r; + + if ((r = init_local()) || + (r = init_cluster())) { + exit(r); + } +} + +/* + * cleanup_all + * + * Clean up before exiting + */ +static void cleanup_all(void) +{ + cleanup_local(); + cleanup_cluster(); +} |