mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +03:00
bf0378593c
There is a rudimentary make file in place so people can build by hand from 'LVM2/daemons/clogd'. It is not hooked into the main build system yet. I am checking this in to provide people better access to the source code. There is still work to be done to make better use of existing code in the LVM repository. (list.h could be removed in favor of existing list implementations, for example. Logging might also be removed in favor of what is already in the tree.) I will probably defer updating WHATS_NEW_DM until this code is linked into the main build system (unless otherwise instructed).
284 lines
5.2 KiB
C
284 lines
5.2 KiB
C
#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-clog-tfr.h>
|
|
#include <linux/dm-ioctl.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);
|
|
static void set_priority(void);
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
daemonize();
|
|
|
|
init_all();
|
|
|
|
/* Parent can now exit, we're ready to handle requests */
|
|
kill(getppid(), SIGTERM);
|
|
|
|
/* set_priority(); -- let's try to do w/o this */
|
|
|
|
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();
|
|
}
|
|
|
|
static void set_priority(void)
|
|
{
|
|
struct sched_param sched_param;
|
|
int res;
|
|
|
|
res = sched_get_priority_max(SCHED_RR);
|
|
if (res != -1) {
|
|
sched_param.sched_priority = res;
|
|
res = sched_setscheduler(0, SCHED_RR, &sched_param);
|
|
}
|
|
|
|
if (res == -1)
|
|
LOG_ERROR("Unable to set SCHED_RR priority.");
|
|
}
|