Libvirtd only support hooks when the daemon is started. Hooks cannot be loaded when the daemon is already running. So, to load a hook you need to restart the service everytime. Now, the inotify support enables the option of create a hook and run it even if libvirtd was started. Cc: Carlos Castilho <ccasti@xxxxxxxxxx> Signed-off-by: Julio Faracco <jcfaracco@xxxxxxxxx> --- daemon/libvirtd.c | 1 + src/libvirt_private.syms | 1 + src/util/virhook.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++- src/util/virhook.h | 10 +++ 4 files changed, 175 insertions(+), 2 deletions(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 95c1b1c..56175d1 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1622,6 +1622,7 @@ int main(int argc, char **argv) { 0, "shutdown", NULL, NULL); cleanup: + virHookCleanUp(); virNetlinkEventServiceStopAll(); virObjectUnref(remoteProgram); virObjectUnref(lxcProgram); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6a77e46..c8ad816 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1648,6 +1648,7 @@ virHashValueFree; virHookCall; virHookInitialize; virHookPresent; +virHookCleanUp; # util/virhostdev.h diff --git a/src/util/virhook.c b/src/util/virhook.c index facd74a..d5fc928 100644 --- a/src/util/virhook.c +++ b/src/util/virhook.c @@ -26,6 +26,7 @@ #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> +#include <sys/inotify.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> @@ -45,6 +46,10 @@ VIR_LOG_INIT("util.hook"); #define LIBVIRT_HOOK_DIR SYSCONFDIR "/libvirt/hooks" +#define virHookInstall(driver) virHooksFound |= (1 << driver); + +#define virHookUninstall(driver) virHooksFound ^= (1 << driver); + VIR_ENUM_DECL(virHookDriver) VIR_ENUM_DECL(virHookDaemonOp) VIR_ENUM_DECL(virHookSubop) @@ -109,6 +114,8 @@ VIR_ENUM_IMPL(virHookLibxlOp, VIR_HOOK_LIBXL_OP_LAST, static int virHooksFound = -1; +static virHookInotifyPtr virHooksInotify = NULL; + /** * virHookCheck: * @driver: the driver name "daemon", "qemu", "lxc"... @@ -153,6 +160,121 @@ virHookCheck(int no, const char *driver) return ret; } +/** + * virHookInotifyEvent: + * @fd: inotify file descriptor. + * + * Identifies file events at libvirt's hook directory. + * Install or uninstall hooks on demand. Acording file manipulation. + */ +static void +virHookInotifyEvent(int watch ATTRIBUTE_UNUSED, + int fd, + int events ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + char buf[1024]; + struct inotify_event *e; + int got; + int driver; + char *tmp, *name; + + VIR_DEBUG("inotify event in virHookInotify()"); + +reread: + got = read(fd, buf, sizeof(buf)); + if (got == -1) { + if (errno == EINTR) + goto reread; + return; + } + + tmp = buf; + while (got) { + if (got < sizeof(struct inotify_event)) + return; + + VIR_WARNINGS_NO_CAST_ALIGN + e = (struct inotify_event *)tmp; + VIR_WARNINGS_RESET + + tmp += sizeof(struct inotify_event); + got -= sizeof(struct inotify_event); + + if (got < e->len) + return; + + tmp += e->len; + got -= e->len; + + name = (char *)&(e->name); + + /* Removing hook file. */ + if (e->mask & (IN_DELETE | IN_MOVED_FROM)) { + if ((driver = virHookDriverTypeFromString(name)) < 0) { + VIR_DEBUG("Invalid hook name for %s", name); + return; + } + + virHookUninstall(driver); + } + + /* Creating hook file. */ + if (e->mask & (IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO)) { + if ((driver = virHookDriverTypeFromString(name)) < 0) { + VIR_DEBUG("Invalid hook name for %s", name); + return; + } + + virHookInstall(driver); + } + } +} + +/** + * virHookInotifyInit: + * + * Initialize inotify hooks support. + * Enable hooks installation on demand. + * + * Returns 0 if inotify was successfully installed, -1 in case of failure. + */ +static int +virHookInotifyInit(void) { + + if (VIR_ALLOC(virHooksInotify) < 0) + goto error; + + if ((virHooksInotify->inotifyFD = inotify_init()) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize inotify")); + goto error; + } + + if ((virHooksInotify->inotifyWatch = + inotify_add_watch(virHooksInotify->inotifyFD, + LIBVIRT_HOOK_DIR, + IN_CREATE | IN_MODIFY | IN_DELETE)) < 0) { + virReportSystemError(errno, _("Failed to create inotify watch on %s"), + LIBVIRT_HOOK_DIR); + goto error; + } + + if ((virHooksInotify->inotifyHandler = + virEventAddHandle(virHooksInotify->inotifyFD, + VIR_EVENT_HANDLE_READABLE, + virHookInotifyEvent, NULL, NULL)) < 0) { + VIR_DEBUG("Failed to add inotify handle in virHook."); + goto error; + } + + return 0; + +error: + virHookCleanUp(); + return -1; +} + + /* * virHookInitialize: * @@ -174,10 +296,14 @@ virHookInitialize(void) return -1; if (res == 1) { - virHooksFound |= (1 << i); + virHookInstall(i); ret++; } } + + if (virHookInotifyInit() < 0) + VIR_INFO("Disabling hooks inotify support."); + return ret; } @@ -309,7 +435,12 @@ virHookCall(int driver, if (output) virCommandSetOutputBuffer(cmd, output); - ret = virCommandRun(cmd, NULL); + ret = virHookCheck(driver, virHookDriverTypeToString(driver)); + + if (ret > 0) { + ret = virCommandRun(cmd, NULL); + } + if (ret < 0) { /* Convert INTERNAL_ERROR into known error. */ virReportError(VIR_ERR_HOOK_SCRIPT_FAILED, "%s", @@ -322,3 +453,33 @@ virHookCall(int driver, return ret; } + +/** + * virHookCall: + * + * Release all structures and data used in virhooks. + * + * Returns: 0 if the execution succeeded + */ +int +virHookCleanUp(void) +{ + if (!virHooksInotify) + return -1; + + if ((virHooksInotify->inotifyFD >= 0) && + (virHooksInotify->inotifyWatch >= 0)) + if (inotify_rm_watch(virHooksInotify->inotifyFD, + virHooksInotify->inotifyWatch) < 0) + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Cannot remove inotify watcher.")); + + if (virHooksInotify->inotifyHandler >= 0) + virEventRemoveHandle(virHooksInotify->inotifyHandler); + + VIR_FORCE_CLOSE(virHooksInotify->inotifyFD); + VIR_FREE(virHooksInotify); + + virHooksFound = -1; + + return 0; +} diff --git a/src/util/virhook.h b/src/util/virhook.h index 205249c..47a32c7 100644 --- a/src/util/virhook.h +++ b/src/util/virhook.h @@ -100,6 +100,14 @@ typedef enum { VIR_HOOK_LIBXL_OP_LAST, } virHookLibxlOpType; +struct _virHookInotify { + int inotifyFD; + int inotifyWatch; + int inotifyHandler; +}; + +typedef struct _virHookInotify *virHookInotifyPtr; + int virHookInitialize(void); int virHookPresent(int driver); @@ -107,4 +115,6 @@ int virHookPresent(int driver); int virHookCall(int driver, const char *id, int op, int sub_op, const char *extra, const char *input, char **output); +int virHookCleanUp(void); + #endif /* __VIR_HOOKS_H__ */ -- 2.7.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list