mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
280 lines
5.2 KiB
C
280 lines
5.2 KiB
C
/*
|
|
* 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 "configure.h"
|
|
|
|
#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();
|
|
}
|