src/lxc/lxc-init
src/lxc/lxc-kill
src/lxc/lxc-monitor
+src/lxc/lxc-monitord
src/lxc/lxc-netstat
src/lxc/lxc-ps
src/lxc/lxc-restart
&commonoptions;
- <refsect1>
- <title>Bugs</title>
-
- <para>
- Only one <command>lxc-monitor</command> can run at a time. Other
- invocations will fail with the following error:
- </para>
- <para>
- lxc-monitor: bind : Address already in use
- </para>
-
- </refsect1>
<refsect1>
<title>Examples</title>
<variablelist>
lxc-start \
lxc-execute \
lxc-monitor \
+ lxc-monitord \
lxc-wait \
lxc-console \
lxc-freeze \
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
goto out_mainloop_open;
}
- err = lxc_mainloop(&descr);
+ err = lxc_mainloop(&descr, -1);
if (err) {
ERROR("mainloop returned an error");
goto out_mainloop_open;
out:
/* Restore previous terminal parameter */
tcsetattr(0, TCSAFLUSH, &oldtios);
-
+
/* Return to line it is */
printf("\n");
return -1;
}
+ lxc_monitord_spawn(my_args.lxcpath);
+
fd = lxc_monitor_open(my_args.lxcpath);
if (fd < 0)
return -1;
--- /dev/null
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2012 Oracle.
+ *
+ * Authors:
+ * Dwight Engen <dwight.engen@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>
+
+#define CLIENTFDS_CHUNK 64
+
+lxc_log_define(lxc_monitord, lxc);
+
+static struct lxc_monitor mon;
+
+static void lxc_monitord_cleanup(void);
+
+/*
+ * Defines the structure to store the monitor information
+ * @lxcpath : the path being monitored
+ * @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_size : number of file descriptors clientfds can hold
+ * @clientfds_cnt : the count of valid fds in clientfds
+ * @descr : the lxc_mainloop state
+ */
+struct lxc_monitor {
+ const char *lxcpath;
+ int fifofd;
+ int listenfd;
+ int *clientfds;
+ int clientfds_size;
+ int clientfds_cnt;
+ struct lxc_epoll_descr descr;
+};
+
+static int lxc_monitord_fifo_create(struct lxc_monitor *mon)
+{
+ char fifo_path[PATH_MAX];
+ int ret;
+
+ ret = snprintf(fifo_path, sizeof(fifo_path), "%s/monitor-fifo", mon->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("monitor fifo %s exists, already running?", fifo_path);
+ return -1;
+ }
+
+ mon->fifofd = open(fifo_path, O_RDWR);
+ if (mon->fifofd < 0) {
+ unlink(fifo_path);
+ ERROR("failed to open monitor fifo");
+ return -1;
+ }
+ return 0;
+}
+
+static int lxc_monitord_fifo_delete(struct lxc_monitor *mon)
+{
+ char fifo_path[PATH_MAX];
+ int ret;
+
+ ret = snprintf(fifo_path, sizeof(fifo_path), "%s/monitor-fifo", mon->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;
+
+ if (lxc_mainloop_del_handler(&mon->descr, fd))
+ CRIT("fd:%d not found in mainloop", fd);
+ close(fd);
+
+ for (i = 0; i < mon->clientfds_cnt; i++) {
+ if (mon->clientfds[i] == fd)
+ break;
+ }
+ if (i >= mon->clientfds_cnt) {
+ CRIT("fd:%d not found in clients array", fd);
+ lxc_monitord_cleanup();
+ exit(EXIT_FAILURE);
+ }
+
+ memmove(&mon->clientfds[i], &mon->clientfds[i+1],
+ (mon->clientfds_cnt - i - 1) * sizeof(mon->clientfds[0]));
+ 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;
+ struct ucred cred;
+ socklen_t credsz = sizeof(cred);
+
+ 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;
+ }
+
+ if (getsockopt(clientfd, SOL_SOCKET, SO_PEERCRED, &cred, &credsz))
+ {
+ ERROR("failed to get credentials on socket");
+ goto err1;
+ }
+ if (cred.uid && cred.uid != geteuid()) {
+ WARN("monitor denied for uid:%d", cred.uid);
+ ret = -EACCES;
+ goto err1;
+ }
+
+ if (mon->clientfds_cnt + 1 > mon->clientfds_size) {
+ int *clientfds;
+ DEBUG("realloc space for %d clientfds",
+ mon->clientfds_size + CLIENTFDS_CHUNK);
+ clientfds = realloc(mon->clientfds,
+ (mon->clientfds_size + CLIENTFDS_CHUNK) *
+ sizeof(mon->clientfds[0]));
+ if (clientfds == NULL) {
+ ERROR("failed to realloc memory for clientfds");
+ goto err1;
+ }
+ mon->clientfds = clientfds;
+ mon->clientfds_size += CLIENTFDS_CHUNK;
+ }
+
+ 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 client fd:%d clients:%d", clientfd, mon->clientfds_cnt);
+ goto out;
+
+err1:
+ close(clientfd);
+out:
+ return ret;
+}
+
+static int lxc_monitord_sock_create(struct lxc_monitor *mon)
+{
+ struct sockaddr_un addr;
+ int fd;
+
+ if (lxc_monitor_sock_name(mon->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(struct lxc_monitor *mon)
+{
+ struct sockaddr_un addr;
+
+ if (lxc_monitor_sock_name(mon->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)
+{
+ int ret;
+
+ ret = lxc_monitord_fifo_create(mon);
+ if (ret < 0)
+ return ret;
+
+ ret = lxc_monitord_sock_create(mon);
+ return ret;
+}
+
+static void lxc_monitord_delete(struct lxc_monitor *mon)
+{
+ int i;
+
+ lxc_mainloop_del_handler(&mon->descr, mon->listenfd);
+ close(mon->listenfd);
+ lxc_monitord_sock_delete(mon);
+
+ lxc_mainloop_del_handler(&mon->descr, mon->fifofd);
+ close(mon->fifofd);
+ lxc_monitord_fifo_delete(mon);
+
+ 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++) {
+ DEBUG("writing client fd:%d", mon->clientfds[i]);
+ ret = write(mon->clientfds[i], &msglxc, sizeof(msglxc));
+ if (ret < 0) {
+ ERROR("write failed to client sock:%d %d %s",
+ mon->clientfds[i], errno, strerror(errno));
+ }
+ }
+
+ 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_cleanup(void)
+{
+ lxc_monitord_delete(&mon);
+}
+
+static void lxc_monitord_sig_handler(int sig)
+{
+ INFO("caught signal %d", sig);
+ lxc_monitord_cleanup();
+ exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret,pipefd;
+ char *lxcpath = argv[1];
+ char logpath[PATH_MAX];
+ sigset_t mask;
+
+ if (argc != 3) {
+ fprintf(stderr,
+ "Usage: lxc-monitord lxcpath sync-pipe-fd\n\n"
+ "NOTE: lxc-monitord is intended for use by lxc internally\n"
+ " and does not need to be run by hand\n\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = snprintf(logpath, sizeof(logpath), "%s/lxc-monitord.log",
+ lxcpath);
+ if (ret < 0 || ret >= sizeof(logpath))
+ return EXIT_FAILURE;
+
+ ret = lxc_log_init(NULL, logpath, "NOTICE", "lxc-monitord", 0);
+ if (ret)
+ return ret;
+
+ pipefd = atoi(argv[2]);
+
+ if (sigfillset(&mask) ||
+ sigdelset(&mask, SIGILL) ||
+ sigdelset(&mask, SIGSEGV) ||
+ sigdelset(&mask, SIGBUS) ||
+ sigdelset(&mask, SIGTERM) ||
+ sigprocmask(SIG_BLOCK, &mask, NULL)) {
+ SYSERROR("failed to set signal mask");
+ return -1;
+ }
+
+ signal(SIGILL, lxc_monitord_sig_handler);
+ signal(SIGSEGV, lxc_monitord_sig_handler);
+ signal(SIGBUS, lxc_monitord_sig_handler);
+ signal(SIGTERM, lxc_monitord_sig_handler);
+
+ ret = EXIT_FAILURE;
+ memset(&mon, 0, sizeof(mon));
+ mon.lxcpath = lxcpath;
+ if (lxc_mainloop_open(&mon.descr)) {
+ ERROR("failed to create mainloop");
+ goto out;
+ }
+
+ if (lxc_monitord_create(&mon)) {
+ goto out;
+ }
+
+ /* sync with parent, we're ignoring the return from write
+ * because regardless if it works or not, the following
+ * close will sync us with the parent process. the
+ * if-empty-statement construct is to quiet the
+ * warn-unused-result warning.
+ */
+ if (write(pipefd, "S", 1)) ;
+ close(pipefd);
+
+ if (lxc_monitord_mainloop_add(&mon)) {
+ ERROR("failed to add mainloop handlers");
+ goto out;
+ }
+
+ NOTICE("monitoring lxcpath %s", mon.lxcpath);
+ for(;;) {
+ ret = lxc_mainloop(&mon.descr, 1000 * 30);
+ if (mon.clientfds_cnt <= 0)
+ {
+ NOTICE("no clients for 30 seconds, exiting");
+ break;
+ }
+ }
+
+ lxc_mainloop_close(&mon.descr);
+ lxc_monitord_cleanup();
+ ret = EXIT_SUCCESS;
+ NOTICE("monitor exiting");
+out:
+ return ret;
+}
#include <sys/wait.h>
#include <errno.h>
#include <lxc/utils.h>
+#include <lxc/monitor.h>
lxc_log_define(lxc_container, lxc);
if (daemonize) {
if (!lxc_container_get(c))
return false;
+ lxc_monitord_spawn(c->config_path);
pid_t pid = fork();
if (pid < 0) {
lxc_container_put(c);
}
/* container is already created if we have a config and rootfs.path is accessible */
- if (lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) == 0)
+ if (lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) == 0)
goto out;
/* we're going to fork. but since we'll wait for our child, we
return false;
/* container is already destroyed if we don't have a config and rootfs.path is not accessible */
- if (!lxcapi_is_defined(c) && (!c->lxc_conf || !c->lxc_conf->rootfs.path || access(c->lxc_conf->rootfs.path, F_OK) != 0))
+ if (!lxcapi_is_defined(c) && (!c->lxc_conf || !c->lxc_conf->rootfs.path || access(c->lxc_conf->rootfs.path, F_OK) != 0))
return false;
pid = fork();
#define MAX_EVENTS 10
-int lxc_mainloop(struct lxc_epoll_descr *descr)
+int lxc_mainloop(struct lxc_epoll_descr *descr, int timeout_ms)
{
int i, nfds;
struct mainloop_handler *handler;
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;
return 0;
}
+ if (nfds == 0 && timeout_ms != 0)
+ return 0;
+
if (lxc_list_empty(&descr->handlers))
return 0;
}
* 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 {
typedef int (*lxc_mainloop_callback_t)(int fd, void *data,
struct lxc_epoll_descr *descr);
-extern int lxc_mainloop(struct lxc_epoll_descr *descr);
+extern int lxc_mainloop(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,
extern int lxc_mainloop_open(struct lxc_epoll_descr *descr);
extern int lxc_mainloop_close(struct lxc_epoll_descr *descr);
+
+#endif
*
* Authors:
* Daniel Lezcano <daniel.lezcano at free.fr>
+ * Dwight Engen <dwight.engen@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 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>
#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>
#include <lxc/log.h>
#include <lxc/state.h>
#include <lxc/monitor.h>
+#include <lxc/utils.h>
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;
-
- /*
- * 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");
+ int fd,ret;
+ char fifo_path[PATH_MAX];
+
+ BUILD_BUG_ON(sizeof(*msg) > PIPE_BUF); /* write not guaranteed atomic */
+ ret = snprintf(fifo_path, sizeof(fifo_path), "%s/monitor-fifo", 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) {
+ /* it is normal for this open to fail when there is no monitor
+ * running, so we don't log it
+ */
return;
+ }
- sendto(fd, msg, sizeof(*msg), 0,
- (const struct sockaddr *)&addr, sizeof(addr));
+ ret = write(fd, msg, sizeof(*msg));
+ if (ret != sizeof(*msg)) {
+ SYSERROR("failed to write monitor fifo %s", fifo_path);
+ return;
+ }
close(fd);
}
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;
-
- /*
- * addr.sun_path is only 108 bytes.
- * should we take a hash of lxcpath? a subset of it?
+ return close(fd);
+}
+
+int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr) {
+ size_t len;
+ int 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()? we need
+ * to make sure it is unique.
*/
- 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;
+}
- fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+int lxc_monitor_open(const char *lxcpath)
+{
+ struct sockaddr_un addr;
+ int fd,ret;
+ int retry,backoff_ms[] = {10, 50, 100};
+
+ 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;
+ for (retry = 0; retry < sizeof(backoff_ms)/sizeof(backoff_ms[0]); retry++) {
+ ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret == 0 || errno != ECONNREFUSED)
+ break;
+ ERROR("connect : backing off %d", backoff_ms[retry]);
+ usleep(backoff_ms[retry] * 1000);
}
+ if (ret < 0) {
+ 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;
+ int ret;
if (timeout != -1) {
FD_ZERO(&rfds);
return -2; // timed out
}
- ret = recvfrom(fd, msg, sizeof(*msg), 0,
- (struct sockaddr *)&from, &len);
- if (ret < 0) {
- SYSERROR("failed to receive state");
+ ret = recv(fd, msglxc, sizeof(*msglxc), 0);
+ if (ret <= 0) {
+ SYSERROR("client failed to recv (monitord died?) %s",
+ strerror(errno));
return -1;
}
-
return ret;
}
return lxc_monitor_read_timeout(fd, msg, -1);
}
-int lxc_monitor_close(int fd)
+
+
+/* used to spawn a monitord either on startup of a daemon 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[11];
+
+ 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 < 0) {
+ SYSERROR("failed to fork");
+ exit(EXIT_FAILURE);
+ }
+ if (pid2) {
+ char c;
+ /* wait for daemon to create socket */
+ close(pipefd[1]);
+ /* sync with child, we're ignoring the return from read
+ * because regardless if it works or not, either way we've
+ * synced with the child process. the if-empty-statement
+ * construct is to quiet the warn-unused-result warning.
+ */
+ if (read(pipefd[0], &c, 1)) ;
+ close(pipefd[0]);
+ exit(EXIT_SUCCESS);
+ }
+
+ umask(0);
+ if (setsid() < 0) {
+ SYSERROR("failed to setsid");
+ exit(EXIT_FAILURE);
+ }
+ close(0);
+ close(1);
+ close(2);
+ open("/dev/null", O_RDONLY);
+ open("/dev/null", O_RDWR);
+ open("/dev/null", O_RDWR);
+ close(pipefd[0]);
+ sprintf(pipefd_str, "%d", pipefd[1]);
+ execvp(args[0], args);
+ exit(EXIT_FAILURE);
}
#define __monitor_h
#include <sys/param.h>
+#include <sys/un.h>
+
+#include <lxc/conf.h>
typedef enum {
lxc_msg_state,
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
#endif
}
- return lxc_mainloop(&descr);
+ return lxc_mainloop(&descr, -1);
out_mainloop_open:
lxc_mainloop_close(&descr);
/* 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;
*/
extern const char *default_lxc_path(void);
+/**
+ * BUILD_BUG_ON - break compile if a condition is true.
+ * @condition: the condition which the compiler should know is false.
+ *
+ * If you have some code which relies on certain constants being equal, or
+ * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
+ * detect if someone changes it.
+ *
+ * The implementation uses gcc's reluctance to create a negative array, but
+ * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
+ * to inline functions). So as a fallback we use the optimizer; if it can't
+ * prove the condition is false, it will cause a link error on the undefined
+ * "__build_bug_on_failed". This error message can be harder to track down
+ * though, hence the two different methods.
+ */
+#ifndef __OPTIMIZE__
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#else
+extern int __build_bug_on_failed;
+#define BUILD_BUG_ON(condition) \
+ do { \
+ ((void)sizeof(char[1 - 2*!!(condition)])); \
+ if (condition) __build_bug_on_failed = 1; \
+ } while(0)
+#endif
+
#endif