diff --git a/agents/virt/config/Makefile.am b/agents/virt/config/Makefile.am index 86d8df41..19d97427 100644 --- a/agents/virt/config/Makefile.am +++ b/agents/virt/config/Makefile.am @@ -1,41 +1,44 @@ ############################################################################### ############################################################################### ## ## Copyright (C) 2009-2019 Red Hat, Inc. ## ## 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. ## ############################################################################### ############################################################################### MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = config.l config.y fence_virt.conf noinst_LIBRARIES = libsimpleconfig.a libsimpleconfig_a_SOURCES = \ simpleconfig.c nodist_libsimpleconfig_a_SOURCES = \ y.tab.c \ config.c libsimpleconfig_a_CFLAGS = $(VIRT_AM_CFLAGS) $(AM_CFLAGS) -Wno-unused noinst_HEADERS = config-stack.h sysconf_DATA = fence_virt.conf # local rules y.tab.c: config.y $(YACC) -d $^ config.c: y.tab.c config.l $(LEX) -oconfig.c $(srcdir)/config.l +install-exec-hook: + chmod 600 $(DESTDIR)$(sysconfdir)/fence_virt.conf + clean-local: rm -f config.tab.c config.tab.h config.c y.tab.c y.tab.h diff --git a/agents/virt/include/simpleconfig.h b/agents/virt/include/simpleconfig.h index 83d54377..6aba85f0 100644 --- a/agents/virt/include/simpleconfig.h +++ b/agents/virt/include/simpleconfig.h @@ -1,54 +1,56 @@ #ifndef _SIMPLECONFIG_H #define _SIMPLECONFIG_H typedef int (*config_get_t)(void *config, const char *key, char *value, size_t valuesz); typedef int (*config_set_t)(void *config, const char *key, const char *value); typedef int (*config_parse_t)(const char *filename, void **config); typedef int (*config_free_t)(void *config); typedef void (*config_dump_t)(void *config, FILE *fp); /* * We use an abstract object here so we do not have to link loadable * modules against the configuration library. */ typedef struct { config_get_t get; config_set_t set; config_parse_t parse; config_free_t free; config_dump_t dump; void *info; } config_object_t; /* * These macros may be called from within a loadable module */ #define sc_get(obj, key, value, valuesz) \ obj->get(obj->info, key, value, valuesz) #define sc_set(obj, key, value) \ obj->set(obj->info, key, value) #define sc_parse(obj, filename) \ obj->parse(filename, &obj->info) #define sc_free(obj) \ obj->free(obj->info) #define sc_dump(obj, fp) \ obj->dump(obj->info, fp) /* * Do not call the below functions from loadable modules. Doing so * requires linking the configuration library in to the modules, which * is what we want to avoid. */ /* Returns a copy of our simple config object */ config_object_t *sc_init(void); /* Frees a previously-allocated copy of our simple config object */ void sc_release(config_object_t *c); +int check_file_permissions(const char *fname); + int do_configure(config_object_t *config, const char *filename); #endif diff --git a/agents/virt/server/config.c b/agents/virt/server/config.c index fd817d07..fa9af979 100644 --- a/agents/virt/server/config.c +++ b/agents/virt/server/config.c @@ -1,668 +1,698 @@ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include +#include #include "simpleconfig.h" #include "static_map.h" #include "mcast.h" #include "xvm.h" #include "server_plugin.h" #include "simple_auth.h" static int yesno(const char *prompt, int dfl) { char result[10]; printf("%s [%c/%c]? ", prompt, dfl?'Y':'y', dfl?'n':'N'); fflush(stdout); memset(result, 0, sizeof(result)); if (fgets(result, 9, stdin) == NULL) return dfl; if (result[0] == 'y' || result[0] == 'Y') return 1; if (result[0] == 'n' || result[0] == 'N') return 0; return dfl; } static int text_input(const char *prompt, const char *dfl, char *input, size_t len) { const char *tmpdfl = dfl; const char *nulldfl = ""; if (dfl == NULL) { tmpdfl = nulldfl; } printf("%s [%s]: ", prompt, tmpdfl); fflush(stdout); memset(input, 0, len); if (fgets(input, len, stdin) == NULL) { strncpy(input, tmpdfl, len); return 0; } if (input[strlen(input)-1] == '\n') input[strlen(input)-1] = 0; if (strlen(input) == 0) { strncpy(input, tmpdfl, len); return 0; } return 0; } static int plugin_path_configure(config_object_t *config) { char val[4096]; char inp[4096]; int done = 0; if (sc_get(config, "fence_virtd/@module_path", val, sizeof(val))) { #ifdef MODULE_PATH snprintf(val, sizeof(val), MODULE_PATH); #else printf("Failed to determine module search path.\n"); #endif } do { text_input("Module search path", val, inp, sizeof(inp)); printf("\n"); done = plugin_search(inp); if (done > 0) { plugin_dump(); done = 1; } else { done = 0; printf("No modules found in %s!\n", inp); if (yesno("Use this value anyway", 0) == 1) done = 1; } } while (!done); sc_set(config, "fence_virtd/@module_path", inp); return 0; } static int backend_config_libvirt(config_object_t *config) { char val[4096]; char inp[4096]; printf("\n"); printf("The libvirt backend module is designed for single desktops or\n" "servers. Do not use in environments where virtual machines\n" "may be migrated between hosts.\n\n"); /* Default backend plugin */ if (sc_get(config, "backends/libvirt/@uri", val, sizeof(val))) { strncpy(val, DEFAULT_HYPERVISOR_URI, sizeof(val)); } text_input("Libvirt URI", val, inp, sizeof(inp)); sc_set(config, "backends/libvirt/@uri", inp); return 0; } static int backend_config_cpg(config_object_t *config) { char val[4096]; char inp[4096]; int done = 0; printf("\n"); printf("The CPG backend module is designed for use in clusters\n" "running corosync and libvirt. It utilizes the CPG API to \n" "route fencing requests, finally utilizing libvirt to perform\n" "fencing actions.\n\n"); if (sc_get(config, "backends/cpg/@uri", val, sizeof(val))) { strncpy(val, DEFAULT_HYPERVISOR_URI, sizeof(val)); } text_input("Libvirt URI", val, inp, sizeof(inp)); sc_set(config, "backends/cpg/@uri", inp); printf("\n"); printf("The name mode is how the cpg plugin stores and \n" "references virtual machines. Since virtual machine names\n" "are not guaranteed to be unique cluster-wide, use of UUIDs\n" "is strongly recommended. However, for compatibility with \n" "fence_xvmd, the use of 'name' mode is also supported.\n\n"); if (sc_get(config, "backends/cpg/@name_mode", val, sizeof(val))) { strncpy(val, "uuid", sizeof(val)); } do { text_input("VM naming/tracking mode (name or uuid)", val, inp, sizeof(inp)); if (!strcasecmp(inp, "uuid")) { done = 1; } else if (!strcasecmp(inp, "name")) { done = 0; printf("This can be dangerous if you do not take care to" "ensure that\n" "virtual machine names are unique " "cluster-wide.\n"); if (yesno("Use name mode anyway", 1) == 1) done = 1; } } while (!done); sc_set(config, "backends/cpg/@name_mode", inp); return 0; } static int listener_config_multicast(config_object_t *config) { char val[4096]; char inp[4096]; const char *family = "ipv4"; struct in_addr sin; struct in6_addr sin6; int done = 0; printf("\n"); printf("The multicast listener module is designed for use environments\n" "where the guests and hosts may communicate over a network using\n" "multicast.\n\n"); /* MULTICAST IP ADDRESS/FAMILY */ printf("The multicast address is the address that a client will use to\n" "send fencing requests to fence_virtd.\n\n"); if (sc_get(config, "listeners/multicast/@address", val, sizeof(val)-1)) { strncpy(val, IPV4_MCAST_DEFAULT, sizeof(val)); } done = 0; do { text_input("Multicast IP Address", val, inp, sizeof(inp)); if (inet_pton(AF_INET, inp, &sin) == 1) { printf("\nUsing ipv4 as family.\n\n"); family = "ipv4"; done = 1; } else if (inet_pton(AF_INET6, inp, &sin6) == 1) { printf("\nUsing ipv6 as family.\n\n"); family = "ipv6"; done = 1; } else printf("'%s' is not a valid IP address!\n", inp); } while (!done); sc_set(config, "listeners/multicast/@family", family); sc_set(config, "listeners/multicast/@address", inp); /* MULTICAST IP PORT */ if (sc_get(config, "listeners/multicast/@port", val, sizeof(val)-1)) { snprintf(val, sizeof(val), "%d", DEFAULT_MCAST_PORT); } done = 0; do { char *p; int ret; text_input("Multicast IP Port", val, inp, sizeof(inp)); ret = strtol(inp, &p, 0); if (*p != '\0' || ret <= 0 || ret >= 65536) { printf("Port value '%s' is out of range\n", val); continue; } else done = 1; } while (!done); sc_set(config, "listeners/multicast/@port", inp); /* MULTICAST INTERFACE */ printf("\nSetting a preferred interface causes fence_virtd to listen only\n" "on that interface. Normally, it listens on all interfaces.\n" "In environments where the virtual machines are using the host\n" "machine as a gateway, this *must* be set (typically to virbr0).\n" "Set to 'none' for no interface.\n\n" ); if (sc_get(config, "listeners/multicast/@interface", val, sizeof(val)-1)) { strncpy(val, "none", sizeof(val)); } done = 0; do { text_input("Interface", val, inp, sizeof(inp)); if (!strcasecmp(inp, "none")) { break; } if (strlen(inp) > 0) { int ret; ret = if_nametoindex(inp); if (ret < 0) { printf("Invalid interface: %s\n", inp); if (yesno("Use anyway", 1) == 1) done = 1; } else done = 1; } else printf("No interface given\n"); } while (!done); if (!strcasecmp(inp, "none")) { sc_set(config, "listeners/multicast/@interface", NULL); } else { sc_set(config, "listeners/multicast/@interface", inp); } /* KEY FILE */ printf("\nThe key file is the shared key information which is used to\n" "authenticate fencing requests. The contents of this file must\n" "be distributed to each physical host and virtual machine within\n" "a cluster.\n\n"); if (sc_get(config, "listeners/multicast/@key_file", val, sizeof(val)-1)) { strncpy(val, DEFAULT_KEY_FILE, sizeof(val)); } done = 0; do { text_input("Key File", val, inp, sizeof(inp)); if (!strcasecmp(inp, "none")) { break; } if (strlen(inp) > 0) { if (inp[0] != '/') { printf("Invalid key file: %s\n", inp); if (yesno("Use anyway", 1) == 1) done = 1; } else done = 1; } else printf("No key file given\n"); } while (!done); if (!strcasecmp(inp, "none")) { sc_set(config, "listeners/multicast/@key_file", NULL); } else { sc_set(config, "listeners/multicast/@key_file", inp); } return 0; } static int listener_config_tcp(config_object_t *config) { char val[4096]; char inp[4096]; const char *family = "ipv4"; struct in_addr sin; struct in6_addr sin6; int done = 0; printf("\n"); printf("The TCP listener module is designed for use in environments\n" "where the guests and hosts communicate over viosproxy.\n\n"); /* IP ADDRESS/FAMILY */ printf("The IP address is the address that a client will use to\n" "send fencing requests to fence_virtd.\n\n"); if (sc_get(config, "listeners/tcp/@address", val, sizeof(val)-1)) { strncpy(val, IPV4_MCAST_DEFAULT, sizeof(val)); } done = 0; do { text_input("TCP Listen IP Address", val, inp, sizeof(inp)); if (inet_pton(AF_INET, inp, &sin) == 1) { printf("\nUsing ipv4 as family.\n\n"); family = "ipv4"; done = 1; } else if (inet_pton(AF_INET6, inp, &sin6) == 1) { printf("\nUsing ipv6 as family.\n\n"); family = "ipv6"; done = 1; } else { printf("'%s' is not a valid IP address!\n", inp); continue; } } while (!done); sc_set(config, "listeners/tcp/@family", family); sc_set(config, "listeners/tcp/@address", inp); /* MULTICAST IP PORT */ if (sc_get(config, "listeners/tcp/@port", val, sizeof(val)-1)) { snprintf(val, sizeof(val), "%d", DEFAULT_MCAST_PORT); } done = 0; do { char *p; int ret; text_input("TCP Listen Port", val, inp, sizeof(inp)); ret = strtol(inp, &p, 0); if (*p != '\0' || ret <= 0 || ret >= 65536) { printf("Port value '%s' is out of range\n", val); continue; } done = 1; } while (!done); sc_set(config, "listeners/tcp/@port", inp); /* KEY FILE */ printf("\nThe key file is the shared key information which is used to\n" "authenticate fencing requests. The contents of this file must\n" "be distributed to each physical host and virtual machine within\n" "a cluster.\n\n"); if (sc_get(config, "listeners/tcp/@key_file", val, sizeof(val)-1)) { strncpy(val, DEFAULT_KEY_FILE, sizeof(val)); } done = 0; do { text_input("Key File", val, inp, sizeof(inp)); if (!strcasecmp(inp, "none")) { break; } if (strlen(inp) > 0) { if (inp[0] != '/') { printf("Invalid key file: %s\n", inp); if (yesno("Use anyway", 1) == 1) done = 1; } else done = 1; } else printf("No key file given\n"); } while (!done); if (!strcasecmp(inp, "none")) { sc_set(config, "listeners/tcp/@key_file", NULL); } else { sc_set(config, "listeners/tcp/@key_file", inp); } return 0; } static int listener_config_serial(config_object_t *config) { char val[4096]; char inp[4096]; int done; printf("\n"); printf("The serial plugin allows fence_virtd to communicate with\n" "guests using serial or guest-forwarding VMChannel instead\n" "of using TCP/IP networking.\n\n"); printf("Special configuration of virtual machines is required. See\n" "fence_virt.conf(5) for more details.\n\n"); if (sc_get(config, "listeners/serial/@uri", val, sizeof(val)-1)) { strncpy(val, DEFAULT_HYPERVISOR_URI, sizeof(val)); } text_input("Libvirt URI", val, inp, sizeof(inp)); printf("\nSetting a socket path prevents fence_virtd from taking\n" "hold of all Unix domain sockets created when the guest\n" "is started. A value like /var/run/cluster/fence might\n" "be a good value. Don't forget to create the directory!\n\n"); if (sc_get(config, "listeners/serial/@path", val, sizeof(val)-1)) { strncpy(val, "none", sizeof(val)); } text_input("Socket directory", val, inp, sizeof(inp)); if (!strcasecmp(inp, "none")) { sc_set(config, "listeners/serial/@path", NULL); } else { sc_set(config, "listeners/serial/@path", inp); } printf("\nThe serial plugin allows two types of guest to host\n" "configurations. One is via a serial port; the other is\n" "utilizing the newer VMChannel.\n\n"); if (sc_get(config, "listeners/serial/@mode", val, sizeof(val)-1)) { strncpy(val, "serial", sizeof(val)); } if (!strcasecmp(inp, "none")) { sc_set(config, "listeners/serial/@path", NULL); } else { sc_set(config, "listeners/serial/@path", inp); } done = 0; do { text_input("Mode (serial or vmchannel)", val, inp, sizeof(inp)); if (strcasecmp(inp, "serial") && strcasecmp(inp, "vmchannel")) { printf("Invalid mode: %s\n", inp); if (yesno("Use anyway", 1) == 1) done = 1; } else done = 1; } while (!done); sc_set(config, "listeners/serial/@mode", inp); return 0; } static int backend_configure(config_object_t *config) { char val[4096]; char inp[4096]; int done; printf("\n"); printf("Backend modules are responsible for routing requests to\n" "the appropriate hypervisor or management layer.\n\n"); /* Default backend plugin */ if (sc_get(config, "fence_virtd/@backend", val, sizeof(val))) { strncpy(val, "libvirt", sizeof(val)); } done = 0; do { text_input("Backend module", val, inp, sizeof(inp)); if (plugin_find_backend(inp) == NULL) { printf("No backend module named %s found!\n", inp); if (yesno("Use this value anyway", 0) == 1) done = 1; } else done = 1; } while (!done); sc_set(config, "fence_virtd/@backend", inp); if (!strcmp(inp, "libvirt")) { backend_config_libvirt(config); } else if (!strcmp(inp, "cpg")) { backend_config_cpg(config); } return 0; } static int listener_configure(config_object_t *config) { char val[4096]; char inp[4096]; int done; printf("\n"); printf("Listener modules are responsible for accepting requests\n" "from fencing clients.\n\n"); /* Default backend plugin */ if (sc_get(config, "fence_virtd/@listener", val, sizeof(val))) { strncpy(val, "multicast", sizeof(val)); } done = 0; do { text_input("Listener module", val, inp, sizeof(inp)); if (plugin_find_listener(inp) == NULL) { printf("No listener module named %s found!\n", inp); if (yesno("Use this value anyway", 0) == 1) done = 1; } else done = 1; } while (!done); sc_set(config, "fence_virtd/@listener", inp); if (!strcmp(inp, "multicast")) listener_config_multicast(config); else if (!strcmp(inp, "tcp")) listener_config_tcp(config); else if (!strcmp(inp, "serial")) listener_config_serial(config); else printf("Unable to configure unknown listner module '%s'\n", inp); return 0; } +int +check_file_permissions(const char *fname) +{ + struct stat st; + mode_t file_perms = 0600; + int ret; + + ret = stat(fname, &st); + if (ret != 0) { + printf("stat failed on file '%s': %s\n", + fname, strerror(errno)); + return 1; + } + + if ((st.st_mode & 0777) != file_perms) { + printf("Insecure permissions on file " + "'%s': changing from 0%o to 0%o.\n", fname, + (unsigned int)(st.st_mode & 0777), + (unsigned int)file_perms); + if (chmod(fname, file_perms) != 0) { + printf("Unable to change permissions for file '%s'", + fname); + return 1; + } + } + + return 0; +} + int do_configure(config_object_t *config, const char *config_file) { FILE *fp = NULL; char message[80]; char tmp_filename[4096]; int tmp_fd = -1; mode_t old_umask; if (sc_parse(config, config_file) != 0) { printf("Parsing of %s failed.\n", config_file); if (yesno("Start from scratch", 0) == 0) { return 1; } } plugin_path_configure(config); listener_configure(config); backend_configure(config); printf("\nConfiguration complete.\n\n"); printf("=== Begin Configuration ===\n"); sc_dump(config, stdout); printf("=== End Configuration ===\n"); snprintf(message, sizeof(message), "Replace %s with the above", config_file); if (yesno(message, 0) == 0) { return 1; } snprintf(tmp_filename, sizeof(tmp_filename), "%s.XXXXXX", config_file); old_umask = umask(077); tmp_fd = mkstemp(tmp_filename); umask(old_umask); if (tmp_fd < 0) { perror("fopen"); printf("Failed to write configuration file!\n"); return 1; } fp = fdopen(tmp_fd, "w+"); if (fp == NULL) goto out_fail; sc_dump(config, fp); if (rename(tmp_filename, config_file) < 0) { perror("rename"); goto out_fail; } fclose(fp); close(tmp_fd); return 0; out_fail: if (fp) fclose(fp); if (tmp_fd >= 0) close(tmp_fd); if (strlen(tmp_filename)) unlink(tmp_filename); printf("Failed to write configuration file!\n"); return 1; } diff --git a/agents/virt/server/main.c b/agents/virt/server/main.c index e4656961..fe578998 100644 --- a/agents/virt/server/main.c +++ b/agents/virt/server/main.c @@ -1,265 +1,281 @@ #include "config.h" #include #include #include #include #include #include #include #include #include #include /* Local includes */ #include "simpleconfig.h" #include "static_map.h" +#include "xvm.h" #include "server_plugin.h" +#include "simple_auth.h" #include "debug.h" /* configure.c */ int daemon_init(const char *prog, const char *pid_file, int nofork); int daemon_cleanup(void); static void usage(void) { printf("Usage: fence_virtd [options]\n"); printf(" -F Do not daemonize.\n"); printf(" -f Use as configuration file.\n"); printf(" -d Set debugging level to .\n"); printf(" -c Configuration mode.\n"); printf(" -l List plugins.\n"); printf(" -w Wait for initialization.\n"); printf(" -p Use to record the active process id.\n"); } static int run = 1; static void exit_handler(int sig) { run = 0; } int main(int argc, char **argv) { char val[4096]; char listener_name[80]; char backend_name[80]; const char *config_file = SYSCONFDIR "/fence_virt.conf"; char *pid_file = NULL; config_object_t *config = NULL; map_object_t *map = NULL; const listener_plugin_t *lp; const backend_plugin_t *p; listener_context_t listener_ctx = NULL; backend_context_t backend_ctx = NULL; int debug_set = 0, foreground = 0, wait_for_init = 0; int opt, configure = 0; config = sc_init(); map = map_init(); if (!config || !map) { perror("malloc"); return -1; } while ((opt = getopt(argc, argv, "Ff:d:cwlhp:")) != EOF) { switch(opt) { case 'F': printf("Background mode disabled\n"); foreground = 1; break; case 'f': printf("Using %s\n", optarg); config_file = optarg; break; case 'p': printf("Using %s\n", optarg); pid_file = optarg; break; case 'd': debug_set = atoi(optarg); break; case 'c': configure = 1; break; case 'w': wait_for_init = 1; break; case 'l': plugin_dump(); return 0; case 'h': case '?': usage(); return 0; default: return -1; } } if (configure) { return do_configure(config, config_file); } if (sc_parse(config, config_file) != 0) { printf("Failed to parse %s\n", config_file); return -1; } if (debug_set) { snprintf(val, sizeof(val), "%d", debug_set); sc_set(config, "fence_virtd/@debug", val); } else { if (sc_get(config, "fence_virtd/@debug", val, sizeof(val))==0) debug_set = atoi(val); } dset(debug_set); if (!foreground) { if (sc_get(config, "fence_virtd/@foreground", val, sizeof(val)) == 0) foreground = atoi(val); } if (!wait_for_init) { if (sc_get(config, "fence_virtd/@wait_for_init", val, sizeof(val)) == 0) wait_for_init = atoi(val); if (!wait_for_init) { /* XXX compat */ if (sc_get(config, "fence_virtd/@wait_for_backend", val, sizeof(val)) == 0) wait_for_init = atoi(val); } } if (dget() > 3) sc_dump(config, stdout); if (sc_get(config, "fence_virtd/@backend", backend_name, sizeof(backend_name))) { printf("Failed to determine backend.\n"); printf("%s\n", val); return -1; } dbg_printf(1, "Backend plugin: %s\n", backend_name); if (sc_get(config, "fence_virtd/@listener", listener_name, sizeof(listener_name))) { printf("Failed to determine backend.\n"); printf("%s\n", val); return -1; } dbg_printf(1, "Listener plugin: %s\n", listener_name); if (sc_get(config, "fence_virtd/@module_path", val, sizeof(val))) { #ifdef MODULE_PATH snprintf(val, sizeof(val), MODULE_PATH); #else printf("Failed to determine module path.\n"); return -1; #endif } dbg_printf(1, "Searching %s for plugins...\n", val); opt = plugin_search(val); if (opt > 0) { dbg_printf(1, "%d plugins found\n", opt); } else { printf("No plugins found\n"); return 1; } if (dget() > 3) plugin_dump(); lp = plugin_find_listener(listener_name); if (!lp) { printf("Could not find listener \"%s\"\n", listener_name); return 1; } p = plugin_find_backend(backend_name); if (!p) { printf("Could not find backend \"%s\"\n", backend_name); return 1; } if (pid_file == NULL) { pid_file = malloc(PATH_MAX); memset(pid_file, 0, PATH_MAX); snprintf(pid_file, PATH_MAX, "/var/run/%s.pid", basename(argv[0])); } + if (check_file_permissions(config_file) != 0) + return -1; + + sprintf(val, "listeners/%s/@key_file", listener_name); + if (sc_get(config, val, + val, sizeof(val)-1) == 0) { + dbg_printf(1, "Got %s for key_file\n", val); + } else { + snprintf(val, sizeof(val), "%s", DEFAULT_KEY_FILE); + } + + if (check_file_permissions(val) != 0) + return -1; + openlog(basename(argv[0]), LOG_NDELAY | LOG_PID, LOG_DAEMON); daemon_init(basename(argv[0]), pid_file, foreground); signal(SIGINT, exit_handler); signal(SIGTERM, exit_handler); signal(SIGQUIT, exit_handler); syslog(LOG_NOTICE, "fence_virtd starting. Listener: %s Backend: %s", listener_name, backend_name); while (p->init(&backend_ctx, config) < 0) { if (!wait_for_init || !run) { if (foreground) { printf("Backend plugin %s failed to initialize\n", backend_name); } syslog(LOG_ERR, "Backend plugin %s failed to initialize\n", backend_name); return 1; } sleep(5); } if (map_load(map, config) < 0) { syslog(LOG_WARNING, "Failed to load static maps\n"); } /* only client we have now is mcast (fence_xvm behavior) */ while (lp->init(&listener_ctx, p->callbacks, config, map, backend_ctx) != 0) { if (!wait_for_init || !run) { if (foreground) { printf("Listener plugin %s failed to initialize\n", listener_name); } syslog(LOG_ERR, "Listener plugin %s failed to initialize\n", listener_name); return 1; } sleep(5); } while (run && lp->dispatch(listener_ctx, NULL) >= 0); syslog(LOG_NOTICE, "fence_virtd shutting down"); map_release(map); sc_release(config); lp->cleanup(listener_ctx); p->cleanup(backend_ctx); plugin_unload(); daemon_cleanup(); return 0; }