[lxc-devel] [RFC PATCH] allow multiple monitor clients
S.Çağlar Onur
caglar at 10ur.org
Thu Apr 18 18:22:08 UTC 2013
Hey Dwight,
This sounds great, I'll give it a try ASAP. In the meantime ,if you want to
test it yourself, you can grab go bindings from github via "go get
github.com/caglar10ur/lxc" but please keep in your mind that you need my
other two patches to start/stop work reliably [1]/[2].
https://github.com/caglar10ur/lxc/tree/master/examples directory contains
concurrent versions of create/start/stop/shutdown to test.
[1]
https://github.com/caglar10ur/lxc-upstream/commit/db60b9c38083e8ed553f3cbdd96ad410bd5eb7ed.patch
[2]
https://github.com/caglar10ur/lxc-upstream/commit/97d4daf4cc5016bcb01c72e5cf9fe3189e9df4f5.patch
Cheers,
On Thu, Apr 18, 2013 at 2:09 PM, Dwight Engen <dwight.engen at oracle.com>wrote:
> After the recent discussions on the lxc monitor, I took a closer look at
> it. It seems like Serge was resigned to having some sort of daemon as
> having multicast unix domain supported by the kernel is not going to
> happen any time soon, and doing it over loopback has some
> complications too.
>
> Initially I thought it would be nice to just have lxc-start "be the
> daemon" as Stéphane had suggested. I tried this out, putting the fds
> for the consumer clients (lxc-monitors) in lxc_mainloop , but this is
> problematic for the scenario where lxc-monitor runs first and we miss
> some startup states.
>
> So here is what I'm proposing: when lxc-monitor starts, it attempts to
> start lxc-monitord. lxc-monitord creates a fifo and a socket on lxcpath.
>
> Producers (containers) wishing to send messages open the fifo and
> write their lxc_msg's on it. The reason I used a fifo is so that we get
> permission checks on the opening of it. Right now it is created 0600.
> This fixes the problem we have today where anyone can open the unix
> socket and send state changes in.
>
> Consumers (lxc-monitor) connect to the unix socket and each gets a copy
> of the messages. lxc-monitord can do a PEERCRED to ensure the client
> should be able to get these messages, this is one benefit to using unix
> domain. I don't think it would be difficult to write a lxc-monitor
> like client that would bridge the messages onto d-bus.
>
> When lxc-monitord hasn't had a client for 30 seconds it will exit.
>
> Attached is a proof of concept patch for your comments. It works for
> the common cases that I've tried but I know it needs some cleanup and
> testing if we like the approach. The monitor.c part is hard to read
> because that file is mostly rewritten.
>
> I need to test S.Çağlar Onur's scenario of parallel startup with his
> test script. We need to decide if we want to monitor per lxcpath or per
> container, today it is per path and I think that being able to do
> lxc-monitor * would be very useful.
>
> --
>
> Signed-off-by: Dwight Engen <dwight.engen at oracle.com>
> ---
> src/lxc/Makefile.am | 2 +
> src/lxc/af_unix.c | 5 +-
> src/lxc/lxc_monitor.c | 2 +
> src/lxc/lxc_monitord.c | 334
> +++++++++++++++++++++++++++++++++++++++++++++++++
> src/lxc/mainloop.c | 11 +-
> src/lxc/mainloop.h | 7 ++
> src/lxc/monitor.c | 180 ++++++++++++++++----------
> src/lxc/monitor.h | 11 +-
> src/lxc/start.c | 7 +-
> 9 files changed, 484 insertions(+), 75 deletions(-)
> create mode 100644 src/lxc/lxc_monitord.c
>
> diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
> index ebeca466..1fa0fa8 100644
> --- a/src/lxc/Makefile.am
> +++ b/src/lxc/Makefile.am
> @@ -150,6 +150,7 @@ bin_PROGRAMS = \
> lxc-start \
> lxc-execute \
> lxc-monitor \
> + lxc-monitord \
> lxc-wait \
> lxc-console \
> lxc-freeze \
> @@ -181,6 +182,7 @@ lxc_freeze_SOURCES = lxc_freeze.c
> lxc_info_SOURCES = lxc_info.c
> lxc_init_SOURCES = lxc_init.c
> lxc_monitor_SOURCES = lxc_monitor.c
> +lxc_monitord_SOURCES = lxc_monitord.c
> lxc_restart_SOURCES = lxc_restart.c
> lxc_start_SOURCES = lxc_start.c
> lxc_stop_SOURCES = lxc_stop.c
> diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c
> index eff13d4..ceef340 100644
> --- a/src/lxc/af_unix.c
> +++ b/src/lxc/af_unix.c
> @@ -52,6 +52,7 @@ int lxc_af_unix_open(const char *path, int type, int
> flags)
>
> addr.sun_family = AF_UNIX;
> /* copy entire buffer in case of abstract socket */
> + /* FIXME: this is unsafe if path is too long... */
> memcpy(addr.sun_path, path,
> path[0]?strlen(path):sizeof(addr.sun_path));
>
> @@ -61,7 +62,7 @@ int lxc_af_unix_open(const char *path, int type, int
> flags)
> errno = tmp;
> return -1;
> }
> -
> +
> if (type == SOCK_STREAM && listen(fd, 100)) {
> int tmp = errno;
> close(fd);
> @@ -76,7 +77,7 @@ int lxc_af_unix_close(int fd)
> {
> struct sockaddr_un addr;
> socklen_t addrlen = sizeof(addr);
> -
> +
> if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) &&
> addr.sun_path[0])
> unlink(addr.sun_path);
> diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c
> index 8c15869..0ca829f 100644
> --- a/src/lxc/lxc_monitor.c
> +++ b/src/lxc/lxc_monitor.c
> @@ -87,6 +87,8 @@ int main(int argc, char *argv[])
> return -1;
> }
>
> + lxc_monitord_spawn(my_args.lxcpath);
> +
> fd = lxc_monitor_open(my_args.lxcpath);
> if (fd < 0)
> return -1;
> diff --git a/src/lxc/lxc_monitord.c b/src/lxc/lxc_monitord.c
> new file mode 100644
> index 0000000..3e9c708
> --- /dev/null
> +++ b/src/lxc/lxc_monitord.c
> @@ -0,0 +1,334 @@
> +/*
> + * lxc: linux Container library
> + *
> + * Copyright © 2012 Oracle.
> + *
> + * Authors:
> + * Dwight Engen <dwight.engen at oracle.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <signal.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <fcntl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/param.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <netinet/in.h>
> +#include <net/if.h>
> +
> +#include <lxc/af_unix.h>
> +#include <lxc/log.h>
> +#include <lxc/mainloop.h>
> +#include <lxc/monitor.h>
> +#include <lxc/utils.h>
> +
> +lxc_log_define(lxc_monitord, lxc);
> +
> +/*
> + * Defines the structure to store the monitor information
> + * @fifofd : the file descriptor for publishers (containers) to
> write state
> + * @listenfd : the file descriptor for subscribers (lxc-monitors) to
> connect
> + * @clientfds : accepted client file descriptors
> + * @clientfds_cnt: the count of valid fds in clientfds
> + */
> +struct lxc_monitor {
> + int fifofd;
> + int listenfd;
> + int clientfds[1024];
> + int clientfds_cnt;
> + struct lxc_epoll_descr descr;
> +};
> +
> +static int lxc_monitord_fifo_create(struct lxc_monitor *mon, const char
> *lxcpath)
> +{
> + char fifo_path[PATH_MAX];
> + int ret;
> +
> + ret = snprintf(fifo_path, sizeof(fifo_path), "%s/monitor",
> lxcpath);
> + if (ret < 0 || ret >= sizeof(fifo_path)) {
> + ERROR("lxcpath too long to monitor fifo");
> + return -1;
> + }
> +
> + ret = mknod(fifo_path, S_IFIFO|S_IRUSR|S_IWUSR, 0);
> + if (ret < 0) {
> + INFO("existing monitor fifo at %s, monitor already
> running?", fifo_path);
> + return -1;
> + }
> + mon->fifofd = open(fifo_path, O_RDWR);
> + if (mon->fifofd < 0) {
> + ERROR("failed to open monitor fifo");
> + return -1;
> + }
> + return 0;
> +}
> +
> +static int lxc_monitord_fifo_delete(const char *lxcpath)
> +{
> + char fifo_path[PATH_MAX];
> + int ret;
> +
> + ret = snprintf(fifo_path, sizeof(fifo_path), "%s/monitor",
> lxcpath);
> + if (ret < 0 || ret >= sizeof(fifo_path)) {
> + ERROR("lxcpath too long to monitor fifo");
> + return -1;
> + }
> + unlink(fifo_path);
> + return 0;
> +}
> +
> +static void lxc_monitord_sockfd_remove(struct lxc_monitor *mon, int fd) {
> + int i;
> +
> + lxc_mainloop_del_handler(&mon->descr, fd);
> + close(fd);
> +
> + for (i = 0; i < mon->clientfds_cnt; i++) {
> + if (mon->clientfds[i] == fd)
> + break;
> + }
> + if (i >= mon->clientfds_cnt) {
> + CRIT("fd not found");
> + exit(EXIT_FAILURE);
> + }
> + DEBUG("MON: removing client fd:%d memmoving %p %p %lu bytes", fd,
> + &mon->clientfds[mon->clientfds_cnt],
> + &mon->clientfds[i],
> + (&mon->clientfds[mon->clientfds_cnt-1] -
> &mon->clientfds[i]) * sizeof(int));
> + memmove(&mon->clientfds[i], &mon->clientfds[i+1],
> + (&mon->clientfds[mon->clientfds_cnt-1] -
> &mon->clientfds[i]) * sizeof(int));
> + mon->clientfds_cnt--;
> +}
> +
> +static int lxc_monitord_sock_handler(int fd, void *data,
> + struct lxc_epoll_descr *descr)
> +{
> + struct lxc_monitor *mon = data;
> + lxc_monitord_sockfd_remove(mon, fd);
> + return 0;
> +}
> +
> +static int lxc_monitord_sock_accept(int fd, void *data,
> + struct lxc_epoll_descr *descr)
> +{
> + int ret,clientfd;
> + struct lxc_monitor *mon = data;
> +
> + ret = -1;
> + clientfd = accept(fd, NULL, 0);
> + if (clientfd < 0) {
> + SYSERROR("failed to accept connection");
> + goto out;
> + }
> +
> + if (fcntl(clientfd, F_SETFD, FD_CLOEXEC)) {
> + SYSERROR("failed to set close-on-exec on incoming
> connection");
> + goto err1;
> + }
> +
> + /* FIXME: check the connected clients credentials here, drop if we
> don't
> + * like them.
> + int on = 1;
> + if (setsockopt(clientfd, SOL_SOCKET, SO_PASSCRED, &on,
> sizeof(on))) {
> + ERROR("failed to enable credential on socket");
> + goto err1;
> + }
> + */
> +
> + ret = lxc_mainloop_add_handler(&mon->descr, clientfd,
> + lxc_monitord_sock_handler, mon);
> + if (ret) {
> + ERROR("failed to add socket handler");
> + goto err1;
> + }
> + mon->clientfds[mon->clientfds_cnt++] = clientfd;
> + INFO("accepted new client fd:%d clientfds_cnt:%d", clientfd,
> mon->clientfds_cnt);
> + goto out;
> +
> +err1:
> + close(clientfd);
> +out:
> + return ret;
> +}
> +
> +static int lxc_monitord_sock_create(struct lxc_monitor *mon, const char
> *lxcpath)
> +{
> + struct sockaddr_un addr;
> + int fd;
> +
> + if (lxc_monitor_sock_name(lxcpath, &addr) < 0)
> + return -1;
> +
> + fd = lxc_af_unix_open(addr.sun_path, SOCK_STREAM, O_TRUNC);
> + if (fd < 0) {
> + ERROR("failed to open unix socket : %s", strerror(errno));
> + return -1;
> + }
> +
> + mon->listenfd = fd;
> + return 0;
> +}
> +
> +static int lxc_monitord_sock_delete(const char *lxcpath)
> +{
> + struct sockaddr_un addr;
> +
> + if (lxc_monitor_sock_name(lxcpath, &addr) < 0)
> + return -1;
> + if (addr.sun_path[0])
> + unlink(addr.sun_path);
> + return 0;
> +}
> +
> +static int lxc_monitord_create(struct lxc_monitor *mon, const char
> *lxcpath)
> +{
> + int ret;
> +
> + ret = lxc_monitord_fifo_create(mon, lxcpath);
> + if (ret < 0)
> + return ret;
> +
> + ret = lxc_monitord_sock_create(mon, lxcpath);
> + return ret;
> +}
> +
> +static void lxc_monitord_delete(struct lxc_monitor *mon, const char
> *lxcpath)
> +{
> + int i;
> +
> + lxc_mainloop_del_handler(&mon->descr, mon->listenfd);
> + close(mon->listenfd);
> + lxc_monitord_sock_delete(lxcpath);
> +
> + lxc_mainloop_del_handler(&mon->descr, mon->fifofd);
> + close(mon->fifofd);
> + lxc_monitord_fifo_delete(lxcpath);
> +
> + for (i = 0; i < mon->clientfds_cnt; i++) {
> + lxc_mainloop_del_handler(&mon->descr, mon->clientfds[i]);
> + close(mon->clientfds[i]);
> + }
> + mon->clientfds_cnt = 0;
> +}
> +
> +static int lxc_monitord_fifo_handler(int fd, void *data,
> + struct lxc_epoll_descr *descr)
> +{
> + int ret,i;
> + struct lxc_msg msglxc;
> + struct lxc_monitor *mon = data;
> +
> + ret = read(fd, &msglxc, sizeof(msglxc));
> + if (ret != sizeof(msglxc)) {
> + SYSERROR("read fifo failed : %s", strerror(errno));
> + return 1;
> + }
> +
> + for (i = 0; i < mon->clientfds_cnt; i++) {
> + ret = write(mon->clientfds[i], &msglxc, sizeof(msglxc));
> + if (ret < 0) {
> + ERROR("write failed to client sock, removing");
> + lxc_monitord_sockfd_remove(mon, i);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int lxc_monitord_mainloop_add(struct lxc_monitor *mon)
> +{
> + int ret;
> +
> + ret = lxc_mainloop_add_handler(&mon->descr, mon->fifofd,
> + lxc_monitord_fifo_handler, mon);
> + if (ret < 0) {
> + ERROR("failed to add to mainloop monitor handler for
> fifo");
> + return -1;
> + }
> +
> + ret = lxc_mainloop_add_handler(&mon->descr, mon->listenfd,
> + lxc_monitord_sock_accept, mon);
> + if (ret < 0) {
> + ERROR("failed to add to mainloop monitor handler for
> listen socket");
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static void lxc_monitord_sig_handler(int sig)
> +{
> + INFO("caught signal %d", sig);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + struct lxc_monitor mon;
> + int ret,pipefd;
> + char *lxcpath = argv[1];
> + char logpath[PATH_MAX];
> +
> + signal(SIGTERM, lxc_monitord_sig_handler);
> + snprintf(logpath, sizeof(logpath), "%s/lxc-monitord.log", lxcpath);
> + ret = lxc_log_init(NULL, logpath, "INFO", "lxc-monitord", 0);
> + if (ret)
> + return ret;
> +
> + pipefd = atoi(argv[2]);
> +
> + ret = EXIT_FAILURE;
> + memset(&mon, 0, sizeof(mon));
> + if (lxc_mainloop_open(&mon.descr)) {
> + ERROR("failed to create mainloop");
> + goto out;
> + }
> +
> + if (lxc_monitord_create(&mon, lxcpath)) {
> + goto out;
> + }
> +
> + /* sync with parent */
> + write(pipefd, "S", 1);
> + close(pipefd);
> +
> + if (lxc_monitord_mainloop_add(&mon)) {
> + ERROR("failed to add mainloop handlers");
> + goto out;
> + }
> +
> + NOTICE("monitoring lxcpath %s", lxcpath);
> + for(;;) {
> + ret = lxc_mainloop_timeout(&mon.descr, 1000 * 30);
> + if (mon.clientfds_cnt <= 0)
> + {
> + NOTICE("no clients for 30 seconds, exiting");
> + break;
> + }
> + }
> +
> + lxc_monitord_delete(&mon, lxcpath);
> + lxc_mainloop_close(&mon.descr);
> +out:
> + return ret;
> +}
> diff --git a/src/lxc/mainloop.c b/src/lxc/mainloop.c
> index 975215d..4805dcd 100644
> --- a/src/lxc/mainloop.c
> +++ b/src/lxc/mainloop.c
> @@ -38,7 +38,7 @@ struct mainloop_handler {
>
> #define MAX_EVENTS 10
>
> -int lxc_mainloop(struct lxc_epoll_descr *descr)
> +int lxc_mainloop_timeout(struct lxc_epoll_descr *descr, int timeout_ms)
> {
> int i, nfds;
> struct mainloop_handler *handler;
> @@ -46,7 +46,7 @@ int lxc_mainloop(struct lxc_epoll_descr *descr)
>
> for (;;) {
>
> - nfds = epoll_wait(descr->epfd, events, MAX_EVENTS, -1);
> + nfds = epoll_wait(descr->epfd, events, MAX_EVENTS,
> timeout_ms);
> if (nfds < 0) {
> if (errno == EINTR)
> continue;
> @@ -64,11 +64,18 @@ int lxc_mainloop(struct lxc_epoll_descr *descr)
> return 0;
> }
>
> + if (nfds == 0 && timeout_ms != 0)
> + return 0;
> +
> if (lxc_list_empty(&descr->handlers))
> return 0;
> }
> }
>
> +int lxc_mainloop(struct lxc_epoll_descr *descr) {
> + return lxc_mainloop_timeout(descr, -1);
> +}
> +
> int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
> lxc_mainloop_callback_t callback, void *data)
> {
> diff --git a/src/lxc/mainloop.h b/src/lxc/mainloop.h
> index 6b16242..c79c4fd 100644
> --- a/src/lxc/mainloop.h
> +++ b/src/lxc/mainloop.h
> @@ -21,6 +21,9 @@
> * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> */
>
> +#ifndef _mainloop_h
> +#define _mainloop_h
> +
> #include "list.h"
>
> struct lxc_epoll_descr {
> @@ -33,6 +36,8 @@ typedef int (*lxc_mainloop_callback_t)(int fd, void
> *data,
>
> extern int lxc_mainloop(struct lxc_epoll_descr *descr);
>
> +extern int lxc_mainloop_timeout(struct lxc_epoll_descr *descr, int
> timeout_ms);
> +
> extern int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
> lxc_mainloop_callback_t callback,
> void *data);
> @@ -42,3 +47,5 @@ extern int lxc_mainloop_del_handler(struct
> lxc_epoll_descr *descr, int fd);
> extern int lxc_mainloop_open(struct lxc_epoll_descr *descr);
>
> extern int lxc_mainloop_close(struct lxc_epoll_descr *descr);
> +
> +#endif
> diff --git a/src/lxc/monitor.c b/src/lxc/monitor.c
> index afdaf67..0438fbc 100644
> --- a/src/lxc/monitor.c
> +++ b/src/lxc/monitor.c
> @@ -20,6 +20,7 @@
> * License along with this library; if not, write to the Free Software
> * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> */
> +
> #include <stdio.h>
> #include <errno.h>
> #include <unistd.h>
> @@ -30,7 +31,7 @@
> #include <sys/stat.h>
> #include <sys/param.h>
> #include <sys/socket.h>
> -#include <sys/un.h>
> +#include <sys/wait.h>
> #include <netinet/in.h>
> #include <net/if.h>
>
> @@ -43,35 +44,24 @@
>
> lxc_log_define(lxc_monitor, lxc);
>
> -#ifndef UNIX_PATH_MAX
> -#define UNIX_PATH_MAX 108
> -#endif
> -
> -static void lxc_monitor_send(struct lxc_msg *msg, const char *lxcpath)
> +/* routines used by monitor publishers (containers) */
> +static void lxc_monitor_fifo_send(struct lxc_msg *msg, const char
> *lxcpath)
> {
> - int fd;
> - struct sockaddr_un addr = { .sun_family = AF_UNIX };
> - char *offset = &addr.sun_path[1];
> - size_t ret, len;
> + int fd,ret;
> + char fifo_path[PATH_MAX];
>
> - /*
> - * addr.sun_path is only 108 bytes.
> - * should we take a hash of lxcpath? a subset of it?
> - */
> - len = sizeof(addr.sun_path) - 1;
> - ret = snprintf(offset, len, "%s/lxc-monitor", lxcpath);
> - if (ret < 0 || ret >= len) {
> - ERROR("lxcpath too long to open monitor");
> + //FIXME: BuildAssert(sizeof(*msg) < PIPE_BUF), "write not
> guaranteed atomic");
> + ret = snprintf(fifo_path, sizeof(fifo_path), "%s/monitor",
> lxcpath);
> + if (ret < 0 || ret >= sizeof(fifo_path)) {
> + ERROR("lxcpath too long to open monitor fifo");
> return;
> }
> -
> - fd = socket(PF_UNIX, SOCK_DGRAM, 0);
> - if (fd < 0)
> + fd = open(fifo_path, O_WRONLY);
> + if (fd < 0) {
> + ERROR("failed to open monitor fifo %s", fifo_path);
> return;
> -
> - sendto(fd, msg, sizeof(*msg), 0,
> - (const struct sockaddr *)&addr, sizeof(addr));
> -
> + }
> + ret = write(fd, msg, sizeof(*msg));
> close(fd);
> }
>
> @@ -82,72 +72,74 @@ void lxc_monitor_send_state(const char *name,
> lxc_state_t state, const char *lxc
> strncpy(msg.name, name, sizeof(msg.name));
> msg.name[sizeof(msg.name) - 1] = 0;
>
> - lxc_monitor_send(&msg, lxcpath);
> + lxc_monitor_fifo_send(&msg, lxcpath);
> }
>
> -int lxc_monitor_open(const char *lxcpath)
> +
> +/* routines used by monitor subscribers (lxc-monitor) */
> +int lxc_monitor_close(int fd)
> {
> - struct sockaddr_un addr = { .sun_family = AF_UNIX };
> - char *offset = &addr.sun_path[1];
> - int fd;
> - size_t ret, len;
> + return close(fd);
> +}
>
> - /*
> - * addr.sun_path is only 108 bytes.
> - * should we take a hash of lxcpath? a subset of it?
> +int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr) {
> + size_t len,ret;
> + char *sockname = &addr->sun_path[0]; // 1 for abstract
> +
> + /* addr.sun_path is only 108 bytes.
> + * should we take a hash of lxcpath? a subset of it? ftok()? none
> + * are guaranteed.
> */
> - len = sizeof(addr.sun_path) - 1;
> - ret = snprintf(offset, len, "%s/lxc-monitor", lxcpath);
> + memset(addr, 0, sizeof(*addr));
> + addr->sun_family = AF_UNIX;
> + len = sizeof(addr->sun_path) - 1;
> + ret = snprintf(sockname, len, "%s/monitor-sock", lxcpath);
> if (ret < 0 || ret >= len) {
> - ERROR("lxcpath too long to open monitor");
> + ERROR("lxcpath too long for unix socket");
> return -1;
> }
> + return 0;
> +}
> +
> +int lxc_monitor_open(const char *lxcpath)
> +{
> + struct sockaddr_un addr;
> + size_t ret;
> + int fd;
>
> - fd = socket(PF_UNIX, SOCK_DGRAM, 0);
> + if (lxc_monitor_sock_name(lxcpath, &addr) < 0)
> + return -1;
> +
> + fd = socket(PF_UNIX, SOCK_STREAM, 0);
> if (fd < 0) {
> ERROR("socket : %s", strerror(errno));
> return -1;
> }
>
> - if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
> - ERROR("bind : %s", strerror(errno));
> - close(fd);
> - return -1;
> + ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
> + if (ret < 0) {
> + /* try to spawn a lxc-monitord here instead ? */
> + ERROR("connect : %s", strerror(errno));
> + goto err1;
> }
> -
> return fd;
> +err1:
> + close(fd);
> + return ret;
> }
>
> -/* timeout of 0 means return immediately; -1 means wait forever */
> -int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout)
> +int lxc_monitor_read_timeout(int fd, struct lxc_msg *msglxc, int timeout)
> {
> struct sockaddr_un from;
> socklen_t len = sizeof(from);
> int ret;
> - fd_set rfds;
> - struct timeval tv;
>
> - 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,
> + ret = recvfrom(fd, msglxc, sizeof(*msglxc), 0,
> (struct sockaddr *)&from, &len);
> - if (ret < 0) {
> - SYSERROR("failed to receive state");
> + if (ret <= 0) {
> + SYSERROR("client failed to receive lxc_msg (monitord
> died?)");
> return -1;
> }
> -
> return ret;
> }
>
> @@ -156,7 +148,61 @@ int lxc_monitor_read(int fd, struct lxc_msg *msg)
> return lxc_monitor_read_timeout(fd, msg, -1);
> }
>
> -int lxc_monitor_close(int fd)
> +
> +
> +/* used to spawn a monitord either on startup of a container, or when
> + * lxc-monitor starts
> + */
> +int lxc_monitord_spawn(const char *lxcpath)
> {
> - return close(fd);
> + pid_t pid1,pid2;
> + int pipefd[2];
> + char pipefd_str[10];
> +
> + char * const args[] = {
> + "/usr/bin/lxc-monitord",
> + (char *)lxcpath,
> + pipefd_str,
> + NULL,
> + };
> +
> + /* double fork to avoid zombies when monitord exits */
> + pid1 = fork();
> + if (pid1 < 0) {
> + SYSERROR("failed to fork");
> + return -1;
> + }
> +
> + if (pid1) {
> + waitpid(pid1, NULL, 0);
> + return 0;
> + }
> +
> + if (pipe(pipefd) < 0) {
> + SYSERROR("failed to create pipe");
> + exit(EXIT_FAILURE);
> + }
> +
> + pid2 = fork();
> + if (pid2) {
> + char c;
> + /* wait for daemon to create socket */
> + close(pipefd[1]);
> + read(pipefd[0], &c, 1);
> + close(pipefd[0]);
> + exit(EXIT_SUCCESS);
> + }
> +
> + umask(0);
> + if (setsid() < 0) {
> + SYSERROR("failed to setsid");
> + exit(EXIT_FAILURE);
> + }
> + freopen("/dev/null", "r", stdin);
> + freopen("/dev/null", "w", stdout);
> + freopen("/dev/null", "w", stderr);
> + close(pipefd[0]);
> + sprintf(pipefd_str, "%d", pipefd[1]);
> + execvp(args[0], args);
> + exit(EXIT_FAILURE);
> }
> diff --git a/src/lxc/monitor.h b/src/lxc/monitor.h
> index 8bef4c7..faa606c 100644
> --- a/src/lxc/monitor.h
> +++ b/src/lxc/monitor.h
> @@ -24,6 +24,10 @@
> #define __monitor_h
>
> #include <sys/param.h>
> +#include <sys/un.h>
> +
> +#include <lxc/conf.h>
> +#include <lxc/mainloop.h>
>
> typedef enum {
> lxc_msg_state,
> @@ -32,11 +36,14 @@ typedef enum {
>
> struct lxc_msg {
> lxc_msg_type_t type;
> - char name[MAXPATHLEN];
> + char name[NAME_MAX+1];
> int value;
> };
>
> -void lxc_monitor_send_state(const char *name, lxc_state_t state,
> +extern int lxc_monitor_open(const char *lxcpath);
> +extern int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un
> *addr);
> +extern void lxc_monitor_send_state(const char *name, lxc_state_t state,
> const char *lxcpath);
> +extern int lxc_monitord_spawn(const char *lxcpath);
>
> #endif
> diff --git a/src/lxc/start.c b/src/lxc/start.c
> index aefccd6..9451fb7 100644
> --- a/src/lxc/start.c
> +++ b/src/lxc/start.c
> @@ -429,6 +429,9 @@ struct lxc_handler *lxc_init(const char *name, struct
> lxc_conf *conf, const char
> if (lxc_command_init(name, handler, lxcpath))
> goto out_free_name;
>
> + if (lxc_monitord_spawn(lxcpath))
> + goto out_close_maincmd_fd;
> +
> if (lxc_read_seccomp_config(conf) != 0) {
> ERROR("failed loading seccomp policy");
> goto out_close_maincmd_fd;
> @@ -437,7 +440,7 @@ struct lxc_handler *lxc_init(const char *name, struct
> lxc_conf *conf, const char
> /* Begin the set the state to STARTING*/
> if (lxc_set_state(name, handler, STARTING)) {
> ERROR("failed to set state '%s'", lxc_state2str(STARTING));
> - goto out_free_name;
> + goto out_close_maincmd_fd;
> }
>
> /* Start of environment variable setup for hooks */
> @@ -808,7 +811,7 @@ int lxc_spawn(struct lxc_handler *handler)
> /* TODO - pass lxc.cgroup.dir (or user's pam cgroup) in for first
> argument */
> if ((handler->cgroup = lxc_cgroup_path_create(NULL, name)) == NULL)
> goto out_delete_net;
> -
> +
> if (lxc_cgroup_enter(handler->cgroup, handler->pid) < 0)
> goto out_delete_net;
>
> --
> 1.8.1.4
>
>
>
>
> ------------------------------------------------------------------------------
> Precog is a next-generation analytics platform capable of advanced
> analytics on semi-structured data. The platform includes APIs for building
> apps and a phenomenal toolset for data science. Developers can use
> our toolset for easy data analysis & visualization. Get a free account!
> http://www2.precog.com/precogplatform/slashdotnewsletter
> _______________________________________________
> Lxc-devel mailing list
> Lxc-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel
>
--
S.Çağlar Onur <caglar at 10ur.org>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20130418/3cb37a3a/attachment.html>
More information about the lxc-devel
mailing list