#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));
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;
}
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);