#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 clogd:"); 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_TFR_SOCKET: LOG_ERROR("Unable to create netlink socket"); break; case EXIT_KERNEL_TFR_BIND: LOG_ERROR("Unable to bind to netlink socket"); break; case EXIT_KERNEL_TFR_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("clogd", LOG_PID, LOG_DAEMON); if (create_lockfile("/var/run/clogd.pid")) 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(); }