From 2183d5451ddd7a0f911738bf63c6a1c8819b5eca Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 5 Aug 2016 13:08:38 -0500 Subject: lvmetad: add helper process and uevent monitor so that lvmetad can keep its cache updated (and autoactivate LVs) by itself without the assistance of externally generated pvscan commands. - the lvm udev rule sets the LVM_DO_PVSCAN label on devs that should be scanned. - the lvmetad uevent monitor watches for devs with the LVM_DO_PVSCAN label. - when an LVM_DO_PVSCAN event is seen, the lvmetad helper is told to run pvscan --cache -aay on that device. TODO: error and failure handling -- if anything fails related to the helper or uevents, lvmetad should simply exit. --- daemons/lvmetad/Makefile.in | 4 +- daemons/lvmetad/lvmetactl.c | 34 +++ daemons/lvmetad/lvmetad-core.c | 59 ++-- daemons/lvmetad/lvmetad-helper.c | 535 +++++++++++++++++++++++++++++++++++++ daemons/lvmetad/lvmetad-internal.h | 89 ++++++ libdaemon/server/daemon-server.c | 14 + libdaemon/server/daemon-server.h | 5 + 7 files changed, 706 insertions(+), 34 deletions(-) create mode 100644 daemons/lvmetad/lvmetad-helper.c create mode 100644 daemons/lvmetad/lvmetad-internal.h diff --git a/daemons/lvmetad/Makefile.in b/daemons/lvmetad/Makefile.in index fa3bdf1da..9e039c93e 100644 --- a/daemons/lvmetad/Makefile.in +++ b/daemons/lvmetad/Makefile.in @@ -15,7 +15,7 @@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ -SOURCES = lvmetad-core.c +SOURCES = lvmetad-core.c lvmetad-helper.c SOURCES2 = testclient.c TARGETS = lvmetad lvmetactl @@ -31,7 +31,7 @@ include $(top_builddir)/make.tmpl INCLUDES += -I$(top_srcdir)/libdaemon/server LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper -LIBS += $(PTHREAD_LIBS) +LIBS += $(PTHREAD_LIBS) -ludev LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) CLDFLAGS += -L$(top_builddir)/libdaemon/server diff --git a/daemons/lvmetad/lvmetactl.c b/daemons/lvmetad/lvmetactl.c index dd2ee1e6d..1e42335cc 100644 --- a/daemons/lvmetad/lvmetactl.c +++ b/daemons/lvmetad/lvmetactl.c @@ -12,6 +12,8 @@ #include "lvmetad-client.h" +#define ARGS_SIZE 128 /* FIXME: get from header */ + daemon_handle h; static void print_reply(daemon_reply reply) @@ -45,6 +47,7 @@ int main(int argc, char **argv) printf("lvmetactl set_global_disable 0|1\n"); printf("lvmetactl set_vg_version \n"); printf("lvmetactl vg_lock_type \n"); + printf("lvmetactl helper_run \n"); return -1; } @@ -237,6 +240,37 @@ int main(int argc, char **argv) NULL); printf("%s\n", reply.buffer.mem); + } else if (!strcmp(cmd, "helper_run")) { + char args[ARGS_SIZE]; + int i; + + memset(args, 0, ARGS_SIZE); + + if (argc < 3) { + printf("helper_run []\n"); + return -1; + } + + if (argc > 3) { + for (i = 3; i < argc; i++) { + if (strlen(argv[i]) + strlen(args) + 2 > ARGS_SIZE) { + printf("args too long\n"); + return -1; + } + strcat(args, argv[i]); + strcat(args, " "); + } + } + + reply = daemon_send_simple(h, "helper_run", + "token = %s", "skip", + "pid = " FMTd64, (int64_t)getpid(), + "cmd = %s", "lvmetactl", + "runpath = %s", argv[2], + "runargs = %s", args[0] ? args : "", + NULL); + printf("%s\n", reply.buffer.mem); + } else { printf("unknown command\n"); goto out_close; diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c index ebaca7872..84c015580 100644 --- a/daemons/lvmetad/lvmetad-core.c +++ b/daemons/lvmetad/lvmetad-core.c @@ -22,6 +22,7 @@ #include "daemon-server.h" #include "daemon-log.h" #include "lvm-version.h" +#include "lvmetad-internal.h" #include "lvmetad-client.h" #include @@ -203,38 +204,10 @@ struct vg_info { #define GLFL_DISABLE_REASON_LVM1 0x00000008 #define GLFL_DISABLE_REASON_DUPLICATES 0x00000010 #define GLFL_DISABLE_REASON_VGRESTORE 0x00000020 - #define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE) #define VGFL_INVALID 0x00000001 -#define CMD_NAME_SIZE 32 - -typedef struct { - daemon_idle *idle; - log_state *log; /* convenience */ - const char *log_config; - - struct dm_hash_table *pvid_to_pvmeta; - struct dm_hash_table *device_to_pvid; /* shares locks with above */ - - struct dm_hash_table *vgid_to_metadata; - struct dm_hash_table *vgid_to_vgname; - struct dm_hash_table *vgid_to_outdated_pvs; - struct dm_hash_table *vgid_to_info; - struct dm_hash_table *vgname_to_vgid; - struct dm_hash_table *pvid_to_vgid; - char token[128]; - char update_cmd[CMD_NAME_SIZE]; - int update_pid; - int update_timeout; - uint64_t update_begin; - uint32_t flags; /* GLFL_ */ - pthread_mutex_t token_lock; - pthread_mutex_t info_lock; - pthread_rwlock_t cache_lock; -} lvmetad_state; - static uint64_t _monotonic_seconds(void) { struct timespec ts; @@ -2655,7 +2628,9 @@ static response dump(lvmetad_state *s) return res; } -static response handler(daemon_state s, client_handle h, request r) +/* called in context of a per-connection thread */ + +static response client_handler(daemon_state s, client_handle h, request r) { response res; lvmetad_state *state = s.private; @@ -2822,7 +2797,8 @@ static response handler(daemon_state s, client_handle h, request r) } if (!strcmp(rq, "set_global_info") || - !strcmp(rq, "get_global_info")) { + !strcmp(rq, "get_global_info") || + !strcmp(rq, "helper_run")) { pthread_mutex_lock(&state->info_lock); info_lock = 1; goto do_rq; @@ -2872,6 +2848,11 @@ static response handler(daemon_state s, client_handle h, request r) else if (!strcmp(rq, "dump")) res = dump(state); + else if (!strcmp(rq, "helper_run")) { + send_helper_request(&s, r); + res = daemon_reply_simple("OK", NULL ); + } + else res = reply_fail("request not implemented"); @@ -2909,6 +2890,9 @@ static int init(daemon_state *s) if (ls->idle) ls->idle->is_idle = 1; + if (ls->enable_udev_monitor) + setup_udev_monitor(s); + return 1; } @@ -2943,6 +2927,8 @@ static void usage(const char *prog, FILE *file) " -V Show version of lvmetad\n" " -h Show this help information\n" " -f Don't fork, run in the foreground\n" + " -u 0|1 Enable udev monitor and running pvscan on new devs\n" + " -a 0|1 Enable LV autoactivation with pvscan\n" " -l Logging message levels (all,fatal,error,warn,info,wire,debug)\n" " -p Set path to the pidfile\n" " -s Set path to the socket to listen on\n" @@ -2958,7 +2944,7 @@ int main(int argc, char *argv[]) daemon_state s = { .daemon_fini = fini, .daemon_init = init, - .handler = handler, + .handler = client_handler, .name = "lvmetad", .pidfile = getenv("LVM_LVMETAD_PIDFILE") ? : LVMETAD_PIDFILE, .private = &ls, @@ -2968,7 +2954,7 @@ int main(int argc, char *argv[]) }; // use getopt_long - while ((opt = getopt(argc, argv, "?fhVl:p:s:t:")) != EOF) { + while ((opt = getopt(argc, argv, "?fhVl:p:s:t:u:a:")) != EOF) { switch (opt) { case 'h': usage(argv[0], stdout); @@ -2997,13 +2983,22 @@ int main(int argc, char *argv[]) if (di.max_timeouts) s.idle = ls.idle = &di; break; + case 'u': + ls.enable_udev_monitor = atoi(optarg); + break; + case 'a': + ls.enable_autoactivate = atoi(optarg); + break; case 'V': printf("lvmetad version: " LVM_VERSION "\n"); exit(1); } } + setup_helper(&s); + daemon_start(s); return 0; } + diff --git a/daemons/lvmetad/lvmetad-helper.c b/daemons/lvmetad/lvmetad-helper.c new file mode 100644 index 000000000..1dbb86440 --- /dev/null +++ b/daemons/lvmetad/lvmetad-helper.c @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * This file is part of LVM2. + * + * 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 Lesser General Public License v.2.1. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _XOPEN_SOURCE 500 /* pthread */ +#define _GNU_SOURCE +#define _REENTRANT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" + +#include "tool.h" + +#include "daemon-io.h" +#include "daemon-server.h" +#include "daemon-log.h" +#include "lvm-version.h" +#include "lvmetad-internal.h" +#include "lvmetad-client.h" + +/* + * lvmetad_main is the main process that: + * . forks threads to handle client (command) connections + * . receives client requests from socket + * . reads/writes cache state + * . receives uevent messages + * . sends lvmetad_helper pvscan requests for uevents + * . sends lvmetad_helper client requests from lvmetactl + * + * lvmetad_helper is the helper process that: + * . receives pvscan requests from lvmetad_main + * . forks/execs pvscan commands for each request + */ + +#define MAX_AV_COUNT 8 + +static int _log_debug_stderr; + +#define log_debug(fmt, args...) \ +do { \ + if (_log_debug_stderr) \ + fprintf(stderr, fmt "\n", ##args); \ +} while (0) + +static void run_path(struct helper_msg *hm) +{ + char arg[HELPER_ARGS_LEN]; + char *args = hm->args; + char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */ + int av_count = 0; + int i, arg_len, args_len; + + for (i = 0; i < MAX_AV_COUNT + 1; i++) + av[i] = NULL; + + av[av_count++] = strdup(hm->path); + + if (!args[0]) + goto run; + + /* this should already be done, but make sure */ + args[HELPER_ARGS_LEN - 1] = '\0'; + + memset(&arg, 0, sizeof(arg)); + arg_len = 0; + args_len = strlen(args); + + for (i = 0; i < args_len; i++) { + if (!args[i]) + break; + + if (av_count == MAX_AV_COUNT) + break; + + if (args[i] == '\\') { + if (i == (args_len - 1)) + break; + i++; + + if (args[i] == '\\') { + arg[arg_len++] = args[i]; + continue; + } + if (isspace(args[i])) { + arg[arg_len++] = args[i]; + continue; + } else { + break; + } + } + + if (isalnum(args[i]) || ispunct(args[i])) { + arg[arg_len++] = args[i]; + } else if (isspace(args[i])) { + if (arg_len) + av[av_count++] = strdup(arg); + + memset(arg, 0, sizeof(arg)); + arg_len = 0; + } else { + break; + } + } + + if ((av_count < MAX_AV_COUNT) && arg_len) { + av[av_count++] = strdup(arg); + } +run: + execvp(av[0], av); +} + +static int read_from_main(int fd, struct helper_msg *hm) +{ + int rv; + retry: + rv = read(fd, hm, sizeof(struct helper_msg)); + if (rv == -1 && errno == EINTR) + goto retry; + + if (rv != sizeof(struct helper_msg)) + return -1; + return 0; +} + +static int send_to_main(int fd, int type) +{ + struct helper_status hs; + int rv; + + memset(&hs, 0, sizeof(hs)); + + hs.type = type; + + rv = write(fd, &hs, sizeof(hs)); + + if (rv == sizeof(hs)) + return 0; + return -1; +} + +#define INACTIVE_TIMEOUT_MS 10000 +#define ACTIVE_TIMEOUT_MS 1000 + +int run_helper(int in_fd, int out_fd, int debug_stderr) +{ + char name[16]; + struct pollfd pollfd; + struct helper_msg hm; + unsigned int fork_count = 0; + unsigned int wait_count = 0; + int timeout = INACTIVE_TIMEOUT_MS; + int rv, pid, status; + + _log_debug_stderr = debug_stderr; + + memset(name, 0, sizeof(name)); + sprintf(name, "%s", "lvmetad_helper"); + prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); + + memset(&pollfd, 0, sizeof(pollfd)); + pollfd.fd = in_fd; + pollfd.events = POLLIN; + + /* Tell the main process we've started. */ + send_to_main(out_fd, HELPER_STARTED); + + while (1) { + rv = poll(&pollfd, 1, timeout); + if (rv == -1 && errno == EINTR) + continue; + + if (rv < 0) + exit(0); + + memset(&hm, 0, sizeof(hm)); + + if (pollfd.revents & POLLIN) { + rv = read_from_main(in_fd, &hm); + if (rv) + continue; + + if (hm.type == HELPER_MSG_RUNPATH) { + pid = fork(); + if (!pid) { + run_path(&hm); + exit(-1); + } + + fork_count++; + + /* + log_debug("helper fork %d count %d %d %s %s", + pid, fork_count, wait_count, + hm.path, hm.args); + */ + } + } + + if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) + exit(0); + + /* collect child exits until no more children exist (ECHILD) + or none are ready (WNOHANG) */ + + while (1) { + rv = waitpid(-1, &status, WNOHANG); + if (rv > 0) { + wait_count++; + + /* + log_debug("helper wait %d count %d %d", + rv, fork_count, wait_count); + */ + continue; + } + + /* no more children to wait for or no children + have exited */ + + if (rv < 0 && errno == ECHILD) + timeout = INACTIVE_TIMEOUT_MS; + else + timeout = ACTIVE_TIMEOUT_MS; + break; + } + } + + return 0; +} + +void close_helper(daemon_state *s) +{ + lvmetad_state *ls = s->private; + + close(ls->helper_pr_fd); + close(ls->helper_pw_fd); + ls->helper_pr_fd = -1; + ls->helper_pw_fd = -1; + s->helper_fd = -1; + s->helper_handler = NULL; +} + +static void _send_helper_msg(daemon_state *s, struct helper_msg *hm) +{ + lvmetad_state *ls = s->private; + int rv; + + retry: + rv = write(ls->helper_pw_fd, hm, sizeof(struct helper_msg)); + if (rv == -1 && errno == EINTR) + goto retry; + + if (rv == -1 && errno == EAGAIN) { + return; + } + + /* helper exited or closed fd, quit using helper */ + if (rv == -1 && errno == EPIPE) { + ERROR(s, "send_helper EPIPE"); + close_helper(s); + return; + } + + if (rv != sizeof(struct helper_msg)) { + /* this shouldn't happen */ + ERROR(s, "send_helper error %d %d", rv, errno); + close_helper(s); + return; + } +} + +/* send a request to helper process */ + +void send_helper_request(daemon_state *s, request r) +{ + struct helper_msg hm = { 0 }; + char *runpath = daemon_request_str(r, "runpath", NULL); + char *runargs = daemon_request_str(r, "runargs", NULL); + + hm.type = HELPER_MSG_RUNPATH; + memcpy(hm.path, runpath, HELPER_PATH_LEN); + if (runargs) + memcpy(hm.args, runargs, HELPER_ARGS_LEN); + + _send_helper_msg(s, &hm); +} + +static void send_helper_pvscan_cache_dev(daemon_state *s, dev_t devt) +{ + lvmetad_state *ls = s->private; + struct helper_msg hm = { 0 }; + + hm.type = HELPER_MSG_RUNPATH; + sprintf(hm.path, "pvscan"); + snprintf(hm.args, HELPER_ARGS_LEN-1, "--cache %s --major %d --minor %d", + ls->enable_autoactivate ? "-aay" : "", + major(devt), minor(devt)); + + _send_helper_msg(s, &hm); +} + +static void send_helper_pvscan_cache_all(daemon_state *s) +{ + lvmetad_state *ls = s->private; + struct helper_msg hm = { 0 }; + + hm.type = HELPER_MSG_RUNPATH; + sprintf(hm.path, "pvscan"); + snprintf(hm.args, HELPER_ARGS_LEN-1, "--cache %s", + ls->enable_autoactivate ? "-aay" : ""); + + _send_helper_msg(s, &hm); +} + +/* + * called in context of main lvmetad process + * handles a message from helper process + */ + +static int helper_handler(daemon_state *s) +{ + lvmetad_state *ls = s->private; + struct helper_status hs; + int rv; + + memset(&hs, 0, sizeof(hs)); + + rv = read(ls->helper_pr_fd, &hs, sizeof(hs)); + if (!rv || rv == -EAGAIN) + return -1; + if (rv < 0) { + ERROR(s, "handle_helper rv %d errno %d", rv, errno); + goto fail; + } + if (rv != sizeof(hs)) { + ERROR(s, "handle_helper recv size %d", rv); + goto fail; + } + + DEBUGLOG(s, "helper message type %d status %d", hs.type, hs.status); + + /* + * Run initial pvscan --cache to populate lvmetad cache. + * + * (Upon receiving HELPER_STARTED we know that the helper + * is ready to handle to running commands.) + * + * The udev monitor is enabled before this, so there should + * be no gap where new devs could be missed. It's possible + * that new devs added during lvmetad startup could be scanned + * by this initial pvscan --cache, and then scanned again + * individually because of the monitor. This possible repetition + * is harmless. + */ + if (hs.type == HELPER_STARTED) + send_helper_pvscan_cache_all(s); + + return 0; + + fail: + ERROR(s, "close helper connection"); + close_helper(s); + return -1; +} + +/* create helper process */ + +int setup_helper(daemon_state *s) +{ + lvmetad_state *ls = s->private; + int pid; + int pw_fd = -1; /* parent write */ + int cr_fd = -1; /* child read */ + int pr_fd = -1; /* parent read */ + int cw_fd = -1; /* child write */ + int pfd[2]; + + /* don't allow the main daemon thread to block */ + if (pipe2(pfd, O_NONBLOCK | O_CLOEXEC)) + return -errno; + + /* only available on rhel7 */ + /* fcntl(pfd[1], F_SETPIPE_SZ, 1024*1024); */ + + cr_fd = pfd[0]; + pw_fd = pfd[1]; + + if (pipe2(pfd, O_NONBLOCK | O_CLOEXEC)) { + close(cr_fd); + close(pw_fd); + return -errno; + } + + pr_fd = pfd[0]; + cw_fd = pfd[1]; + + pid = fork(); + if (pid < 0) { + close(cr_fd); + close(pw_fd); + close(pr_fd); + close(cw_fd); + return -errno; + } + + if (pid) { + close(cr_fd); + close(cw_fd); + ls->helper_pw_fd = pw_fd; + ls->helper_pr_fd = pr_fd; + ls->helper_pid = pid; + s->helper_fd = pr_fd; /* libdaemon uses helper_fd in select */ + s->helper_handler = helper_handler; + return 0; + } else { + close(pr_fd); + close(pw_fd); + run_helper(cr_fd, cw_fd, (s->foreground && strstr(ls->log_config, "debug"))); + exit(0); + } +} + +/* + * called in context of main lvmetad process + * handles a message from udev monitor + * sends a message to lvmetad helper to scan a device + */ + +static int monitor_handler(daemon_state *s) +{ + lvmetad_state *ls = s->private; + struct udev_device *dev; + const char *name; + dev_t devt; + + dev = udev_monitor_receive_device(ls->udev_mon); + if (!dev) + return 0; + + name = udev_device_get_devnode(dev); + devt = udev_device_get_devnum(dev); + + DEBUGLOG(s, "monitor scan %d:%d %s", major(devt), minor(devt), name ?: ""); + send_helper_pvscan_cache_dev(s, devt); + + udev_device_unref(dev); + return 0; +} + +/* create udev monitor */ + +void setup_udev_monitor(daemon_state *s) +{ + lvmetad_state *ls = s->private; + int fd; + int ret; + + /* FIXME: add error handling/cleanup */ + + ls->udevh = udev_new(); + if (!ls->udevh) { + ERROR(s, "Failed to monitor udev: new."); + return; + } + + ls->udev_mon = udev_monitor_new_from_netlink(ls->udevh, "udev"); + if (!ls->udev_mon) { + ERROR(s, "Failed to monitor udev: netlink."); + return; + } + + ret = udev_monitor_filter_add_match_subsystem_devtype(ls->udev_mon, "block", "disk"); + if (ret < 0) { + ERROR(s, "Failed to monitor udev: devtype."); + return; + } + + ret = udev_monitor_filter_add_match_tag(ls->udev_mon, "LVM_DO_PVSCAN"); + if (ret < 0) { + ERROR(s, "Failed to monitor udev: tag."); + return; + } + + ret = udev_monitor_enable_receiving(ls->udev_mon); + if (ret < 0) { + ERROR(s, "Failed to monitor udev: receive."); + return; + } + + /* udev_monitor_set_receive_buffer_size? */ + + fd = udev_monitor_get_fd(ls->udev_mon); + if (fd < 0) { + ERROR(s, "Failed to monitor udev: fd."); + return; + } + + ls->udev_fd = fd; + s->monitor_fd = fd; + s->monitor_handler = monitor_handler; +} + diff --git a/daemons/lvmetad/lvmetad-internal.h b/daemons/lvmetad/lvmetad-internal.h new file mode 100644 index 000000000..8308f9e68 --- /dev/null +++ b/daemons/lvmetad/lvmetad-internal.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * This file is part of LVM2. + * + * 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 Lesser General Public License v.2.1. + */ + +#ifndef _LVM_LVMETAD_INTERNAL_H +#define _LVM_LVMETAD_INTERNAL_H + +#define CMD_NAME_SIZE 32 + +typedef struct { + daemon_idle *idle; + log_state *log; /* convenience */ + const char *log_config; + int enable_udev_monitor; + int enable_autoactivate; + + struct dm_hash_table *pvid_to_pvmeta; + struct dm_hash_table *device_to_pvid; /* shares locks with above */ + + struct dm_hash_table *vgid_to_metadata; + struct dm_hash_table *vgid_to_vgname; + struct dm_hash_table *vgid_to_outdated_pvs; + struct dm_hash_table *vgid_to_info; + struct dm_hash_table *vgname_to_vgid; + struct dm_hash_table *pvid_to_vgid; + char token[128]; + char update_cmd[CMD_NAME_SIZE]; + int update_pid; + int update_timeout; + uint64_t update_begin; + uint32_t flags; /* GLFL_ */ + pthread_mutex_t token_lock; + pthread_mutex_t info_lock; + pthread_rwlock_t cache_lock; + + int helper_pid; + int helper_pw_fd; /* parent write to send message to helper */ + int helper_pr_fd; /* parent read to recv message from helper */ + + struct udev *udevh; + struct udev_monitor *udev_mon; + int udev_fd; +} lvmetad_state; + +/* + * helper process + * recvs 512 byte helper_msg on in_fd + * sends 4 byte helper_status on out_fd + */ + +/* max length of path and args, includes terminate \0 byte */ + +#define HELPER_PATH_LEN 128 +#define HELPER_ARGS_LEN 128 +#define HELPER_MSG_LEN 512 +#define HELPER_MSG_RUNPATH 1 + +struct helper_msg { + uint8_t type; + uint8_t pad1; + uint16_t pad2; + uint32_t flags; + int pid; + int unused; + char path[HELPER_PATH_LEN]; /* 128 */ + char args[HELPER_ARGS_LEN]; /* 128 */ + char pad[240]; +}; + +#define HELPER_STARTED 1 + +struct helper_status { + uint8_t type; + uint8_t status; + uint16_t len; +}; + +void close_helper(daemon_state *s); +void send_helper_request(daemon_state *s, request r); +int setup_helper(daemon_state *s); +void setup_udev_monitor(daemon_state *s); + +#endif diff --git a/libdaemon/server/daemon-server.c b/libdaemon/server/daemon-server.c index 4d6546633..00c23f5f6 100644 --- a/libdaemon/server/daemon-server.c +++ b/libdaemon/server/daemon-server.c @@ -630,12 +630,26 @@ void daemon_start(daemon_state s) _reset_timeout(s); FD_ZERO(&in); FD_SET(s.socket_fd, &in); + + if (s.helper_handler) + FD_SET(s.helper_fd, &in); + if (s.monitor_handler) + FD_SET(s.monitor_fd, &in); + if (select(FD_SETSIZE, &in, NULL, NULL, _get_timeout(s)) < 0 && errno != EINTR) perror("select error"); if (FD_ISSET(s.socket_fd, &in)) { timeout_count = 0; handle_connect(s); } + if (FD_ISSET(s.helper_fd, &in)) { + timeout_count = 0; + s.helper_handler(&s); + } + if (FD_ISSET(s.monitor_fd, &in)) { + timeout_count = 0; + s.monitor_handler(&s); + } _reap(s, 0); diff --git a/libdaemon/server/daemon-server.h b/libdaemon/server/daemon-server.h index 2b9ceac36..ee8ca9c79 100644 --- a/libdaemon/server/daemon-server.h +++ b/libdaemon/server/daemon-server.h @@ -108,10 +108,15 @@ typedef struct daemon_state { int (*daemon_init)(struct daemon_state *st); int (*daemon_fini)(struct daemon_state *st); int (*daemon_main)(struct daemon_state *st); + int (*helper_handler)(struct daemon_state *st); + int (*monitor_handler)(struct daemon_state *st); /* Global runtime info maintained by the framework. */ int socket_fd; + int helper_fd; /* used in select if helper_handler is set */ + int monitor_fd; /* used in select if monitor_handler is set */ + log_state *log; struct thread_state *threads; -- cgit v1.2.1