]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/monitor.c
Merge the liblxc API work by Serge Hallyn.
[mirror_lxc.git] / src / lxc / monitor.c
index 98195c8e861153b0053a9b39fccbb806dd90c6a5..2eb03978f98eb89696d2b3398fe3462d44ca1652 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/param.h>
-#include <sys/inotify.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
 #include <net/if.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
 
 #include "error.h"
-#include <lxc/lxc.h>
+#include "af_unix.h"
+
+#include <lxc/log.h>
+#include <lxc/state.h>
+#include <lxc/monitor.h>
+
+lxc_log_define(lxc_monitor, lxc);
 
 #ifndef UNIX_PATH_MAX
 #define UNIX_PATH_MAX 108
 #endif
 
-#ifndef SOL_NETLINK
-#define SOL_NETLINK 270
-#endif
-
-/* assuming this multicast group is not used by anyone else :/
- * otherwise a new genetlink family should be defined to own
- * its multicast groups */
-#define MONITOR_MCGROUP RTNLGRP_MAX
-
-int lxc_monitor(const char *name, int output_fd)
-{
-       char path[MAXPATHLEN];
-       int err = -1, nfd, wfd, state;
-
-       nfd = inotify_init();
-       if (nfd < 0) {
-               lxc_log_syserror("failed to initialize inotify");
-               return -1;
-       }
-
-       snprintf(path, MAXPATHLEN, LXCPATH "/%s/state", name);
-
-       wfd = inotify_add_watch(nfd, path, IN_DELETE_SELF|IN_CLOSE_WRITE);
-       if (wfd < 0) {
-               lxc_log_syserror("failed to add a watch on %s", path);
-               goto out;
-       }
-
-       for(;;) {
-               struct inotify_event evt;
-
-               if (read(nfd, &evt, sizeof(evt)) < 0) {
-                       lxc_log_syserror("failed to read inotify event");
-                       goto out;
-               }
-
-               if (evt.mask & IN_CLOSE_WRITE) {
-
-                       state = lxc_getstate(name);
-                       if (state < 0) {
-                               lxc_log_error("failed to get the state for %s",
-                                             name);
-                               goto out;
-                       }
-
-                       if (write(output_fd, &state, sizeof(state)) < 0) {
-                               lxc_log_syserror("failed to send state to %d", 
-                                                output_fd);
-                               goto out;
-                       }
-                       continue;
-               }
-
-               if (evt.mask & IN_DELETE_SELF) {
-                       close(output_fd);
-                       err = 0;
-                       goto out;
-               }
-
-               lxc_log_error("unknown evt for inotity (%d)", evt.mask);
-               goto out;
-       }
-
-out:
-       inotify_rm_watch(nfd, wfd);
-       close(nfd);
-       return err;
-}
-
 static void lxc_monitor_send(struct lxc_msg *msg)
 {
        int fd;
-       struct sockaddr_nl addr;
-
-       fd = socket(PF_NETLINK, SOCK_RAW, 0);
-       if (fd < 0) {
-               lxc_log_syserror("failed to create notification socket");
-               return;
-       }
+       struct sockaddr_un addr = { .sun_family = AF_UNIX };
+       char *offset = &addr.sun_path[1];
 
-       memset(&addr, 0, sizeof(addr));
+       strcpy(offset, "lxc-monitor");
 
-       addr.nl_family = AF_NETLINK;
-       addr.nl_pid = 0;
-       addr.nl_groups = MONITOR_MCGROUP;
+       fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+       if (fd < 0)
+               return;
 
        sendto(fd, msg, sizeof(*msg), 0,
               (const struct sockaddr *)&addr, sizeof(addr));
@@ -140,30 +70,27 @@ void lxc_monitor_send_state(const char *name, lxc_state_t state)
        struct lxc_msg msg = { .type = lxc_msg_state,
                               .value = state };
        strncpy(msg.name, name, sizeof(msg.name));
+       msg.name[sizeof(msg.name) - 1] = 0;
 
        lxc_monitor_send(&msg);
 }
 
 int lxc_monitor_open(void)
 {
+       struct sockaddr_un addr = { .sun_family = AF_UNIX };
+       char *offset = &addr.sun_path[1];
        int fd;
-       struct sockaddr_nl addr;
 
-       fd = socket(PF_NETLINK, SOCK_RAW, 0);
+       strcpy(offset, "lxc-monitor");
+
+       fd = socket(PF_UNIX, SOCK_DGRAM, 0);
        if (fd < 0) {
-               lxc_log_syserror("failed to create notification socket");
-               return -LXC_ERROR_INTERNAL;
+               ERROR("socket : %s", strerror(errno));
+               return -1;
        }
 
-       memset(&addr, 0, sizeof(addr));
-
-       addr.nl_family = AF_NETLINK;
-       addr.nl_pid = 0;
-       addr.nl_groups = MONITOR_MCGROUP;
-
-       if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr))) {
-               lxc_log_syserror("failed to bind to multicast group '%d'",
-                       addr.nl_groups);
+       if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
+               ERROR("bind : %s", strerror(errno));
                close(fd);
                return -1;
        }
@@ -171,22 +98,44 @@ int lxc_monitor_open(void)
        return fd;
 }
 
-int lxc_monitor_read(int fd, struct lxc_msg *msg)
+/* timeout of 0 means return immediately;  -1 means wait forever */
+int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout)
 {
-       struct sockaddr_nl from;
+       struct sockaddr_un from;
        socklen_t len = sizeof(from);
        int ret;
+       fd_set rfds;
+       struct timeval tv;
 
-       ret = recvfrom(fd, msg, sizeof(*msg), 0, 
+       if (timeout != -1) {
+               FD_ZERO(&rfds);
+               FD_SET(fd, &rfds);
+
+               tv.tv_sec = timeout;
+               tv.tv_usec = 0;
+
+               ret = select(fd+1, &rfds, NULL, NULL, &tv);
+               if (ret == -1)
+                       return -1;
+               else if (!ret)
+                       return -2;  // timed out
+       }
+
+       ret = recvfrom(fd, msg, sizeof(*msg), 0,
                       (struct sockaddr *)&from, &len);
        if (ret < 0) {
-               lxc_log_syserror("failed to received state");
-               return -LXC_ERROR_INTERNAL;
+               SYSERROR("failed to receive state");
+               return -1;
        }
 
        return ret;
 }
 
+int lxc_monitor_read(int fd, struct lxc_msg *msg)
+{
+       return lxc_monitor_read_timeout(fd, msg, -1);
+}
+
 int lxc_monitor_close(int fd)
 {
        return close(fd);