#include <config.h>
-#ifdef WITH_LXC
-
#include <sys/epoll.h>
#include <sys/wait.h>
#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
#include <unistd.h>
#include <paths.h>
#include <fcntl.h>
#include <signal.h>
+#include <getopt.h>
#include "internal.h"
#include "util.h"
#include "lxc_conf.h"
#include "lxc_container.h"
-#include "lxc_controller.h"
#include "veth.h"
#include "memory.h"
#include "util.h"
#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
+int debugFlag = 0;
+
+static char*lxcMonitorPath(virDomainDefPtr def)
+{
+ char *sockpath;
+ if (asprintf(&sockpath, "%s/%s.sock",
+ LXC_STATE_DIR, def->name) < 0) {
+ lxcError(NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+ return sockpath;
+}
+
+static int lxcMonitorServer(const char *sockpath)
+{
+ int fd;
+ struct sockaddr_un addr;
+
+ if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+ lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("failed to create server socket %s: %s"),
+ sockpath, strerror(errno));
+ goto error;
+ }
+
+ unlink(sockpath);
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
+
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("failed to bind server socket %s: %s"),
+ sockpath, strerror(errno));
+ goto error;
+ }
+ if (listen(fd, 30 /* backlog */ ) < 0) {
+ lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("failed to listen server socket %s: %s"),
+ sockpath, strerror(errno));
+ goto error;
+ }
+
+ return fd;
+
+error:
+ if (fd != -1)
+ close(fd);
+ return -1;
+}
/**
* lxcFdForward:
static int
-lxcControllerRun(const char *stateDir,
- virDomainDefPtr def,
+lxcControllerRun(virDomainDefPtr def,
unsigned int nveths,
char **veths,
int monitor,
if (containerPty != -1)
close(containerPty);
- kill(container, SIGTERM);
- waitpid(container, NULL, 0);
- lxcControllerCleanupInterfaces(nveths, veths);
- virFileDeletePid(stateDir, def->name);
+ if (container > 1) {
+ kill(container, SIGTERM);
+ waitpid(container, NULL, 0);
+ }
return rc;
}
-int lxcControllerStart(const char *stateDir,
- virDomainDefPtr def,
- unsigned int nveths,
- char **veths,
- int monitor,
- int appPty,
- int logfd)
+int main(int argc, char *argv[])
{
pid_t pid;
- int rc;
- int status, null;
- int open_max, i;
+ int rc = 1;
int client;
- struct sigaction sig_action;
+ char *name = NULL;
+ int nveths = 0;
+ char **veths = NULL;
+ int monitor = -1;
+ int appPty = -1;
+ int bg = 0;
+ virCapsPtr caps = NULL;
+ virDomainDefPtr def = NULL;
+ int nnets = 0;
+ virDomainNetDefPtr nets = NULL;
+ char *configFile = NULL;
+ char *sockpath = NULL;
+ const struct option const options[] = {
+ { "background", 0, NULL, 'b' },
+ { "name", 1, NULL, 'n' },
+ { "veth", 1, NULL, 'v' },
+ { "console", 1, NULL, 'c' },
+ { "help", 0, NULL, 'h' },
+ { 0, 0, 0, 0 },
+ };
- if ((pid = fork()) < 0)
- return -1;
+ while (1) {
+ int c;
- if (pid > 0) {
- /* Original caller waits for first child to exit */
- while (1) {
- rc = waitpid(pid, &status, 0);
- if (rc < 0) {
- if (errno == EINTR)
- continue;
- return -1;
+ c = getopt_long(argc, argv, "dn:v:m:c:h",
+ options, NULL);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'b':
+ bg = 1;
+ break;
+
+ case 'n':
+ if ((name = strdup(optarg)) == NULL) {
+ fprintf(stderr, "%s", strerror(errno));
+ goto cleanup;
}
- if (rc != pid) {
- fprintf(stderr,
- _("Unexpected pid %d != %d from waitpid\n"),
- rc, pid);
- return -1;
+ break;
+
+ case 'v':
+ if (VIR_REALLOC_N(veths, nveths+1) < 0) {
+ fprintf(stderr, "cannot allocate veths %s", strerror(errno));
+ goto cleanup;
}
- if (WIFEXITED(status) &&
- WEXITSTATUS(status) == 0)
- return 0;
- else {
- fprintf(stderr,
- _("Unexpected status %d from pid %d\n"),
- status, pid);
- return -1;
+ if ((veths[nveths++] = strdup(optarg)) == NULL) {
+ fprintf(stderr, "cannot allocate veth name %s", strerror(errno));
+ goto cleanup;
}
+ break;
+
+ case 'c':
+ if (virStrToLong_i(optarg, NULL, 10, &appPty) < 0) {
+ fprintf(stderr, "malformed --console argument '%s'", optarg);
+ goto cleanup;
+ }
+ break;
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "\n");
+ fprintf(stderr, "syntax: %s [OPTIONS]\n", argv[0]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Options\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -b, --background\n");
+ fprintf(stderr, " -n NAME, --name NAME\n");
+ fprintf(stderr, " -c FD, --console FD\n");
+ fprintf(stderr, " -v VETH, --veth VETH\n");
+ fprintf(stderr, " -h, --help\n");
+ fprintf(stderr, "\n");
+ goto cleanup;
}
}
- /* First child is running here */
- /* Clobber all libvirtd's signal handlers so they
- * don't affect us
- */
- sig_action.sa_handler = SIG_DFL;
- sig_action.sa_flags = 0;
- sigemptyset(&sig_action.sa_mask);
+ if (name == NULL) {
+ fprintf(stderr, "%s: missing --name argument for configuration\n", argv[0]);
+ goto cleanup;
+ }
+
+ if (appPty < 0) {
+ fprintf(stderr, "%s: missing --console argument for container PTY\n", argv[0]);
+ goto cleanup;
+ }
+
+ if (getuid() && 0) {
+ fprintf(stderr, "%s: must be run as the 'root' user\n", argv[0]);
+ goto cleanup;
+ }
- sigaction(SIGHUP, &sig_action, NULL);
- sigaction(SIGINT, &sig_action, NULL);
- sigaction(SIGQUIT, &sig_action, NULL);
- sigaction(SIGTERM, &sig_action, NULL);
- sigaction(SIGCHLD, &sig_action, NULL);
+ if ((caps = lxcCapsInit()) == NULL)
+ goto cleanup;
- sig_action.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &sig_action, NULL);
+ if ((configFile = virDomainConfigFile(NULL,
+ LXC_STATE_DIR,
+ name)) == NULL)
+ goto cleanup;
+ if ((def = virDomainDefParseFile(NULL, caps, configFile)) == NULL)
+ goto cleanup;
- /* Don't hold onto any cwd we inherit from libvirtd either */
- if (chdir("/") < 0) {
- fprintf(stderr, _("Unable to change to root dir: %s\n"),
- strerror(errno));
- _exit(-1);
+ nets = def->nets;
+ while (nets) {
+ nnets++;
+ nets = nets->next;
}
-
- if (setsid() < 0) {
- fprintf(stderr, _("Unable to become session leader: %s\n"),
- strerror(errno));
- _exit(-1);
+ if (nnets != nveths) {
+ fprintf(stderr, "%s: expecting %d veths, but got %d\n",
+ argv[0], nnets, nveths);
+ goto cleanup;
}
- if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0) {
- fprintf(stderr, _("Unable to open %s: %s\n"),
- _PATH_DEVNULL, strerror(errno));
- _exit(-1);
- }
+ if ((sockpath = lxcMonitorPath(def)) == NULL)
+ goto cleanup;
- open_max = sysconf (_SC_OPEN_MAX);
- for (i = 0; i < open_max; i++)
- if (i != appPty &&
- i != monitor &&
- i != logfd &&
- i != null)
- close(i);
-
- if (dup2(null, STDIN_FILENO) < 0 ||
- dup2(logfd, STDOUT_FILENO) < 0 ||
- dup2(logfd, STDERR_FILENO) < 0) {
- fprintf(stderr, _("Unable to redirect stdio: %s\n"),
- strerror(errno));
- _exit(-1);
- }
+ if ((monitor = lxcMonitorServer(sockpath)) < 0)
+ goto cleanup;
- close(null);
- close(logfd);
+ if (bg) {
+ if ((pid = fork()) < 0)
+ goto cleanup;
- /* Now fork the real controller process */
- if ((pid = fork()) < 0) {
- fprintf(stderr, _("Unable to fork controller: %s\n"),
- strerror(errno));
- _exit(-1);
- }
+ if (pid > 0) {
+ if ((rc = virFileWritePid(LXC_STATE_DIR, name, pid)) != 0) {
+ fprintf(stderr, _("Unable to write pid file: %s\n"),
+ strerror(rc));
+ _exit(1);
+ }
- if (pid > 0) {
- if ((rc = virFileWritePid(stateDir, def->name, pid)) != 0) {
- fprintf(stderr, _("Unable to write pid file: %s\n"),
- strerror(rc));
- _exit(-1);
+ /* First child now exits, allowing original caller
+ * (ie libvirtd's LXC driver to complete their
+ * waitpid & continue */
+ _exit(0);
}
- /* First child now exits, allowing originall caller to
- * complete their waitpid & continue */
- _exit(0);
- }
- /* This is real controller running finally... */
+ /* Don't hold onto any cwd we inherit from libvirtd either */
+ if (chdir("/") < 0) {
+ fprintf(stderr, _("Unable to change to root dir: %s\n"),
+ strerror(errno));
+ goto cleanup;
+ }
+
+ if (setsid() < 0) {
+ fprintf(stderr, _("Unable to become session leader: %s\n"),
+ strerror(errno));
+ goto cleanup;
+ }
+ }
/* Accept initial client which is the libvirtd daemon */
- if ((client = accept(monitor, NULL, 0))) {
+ if ((client = accept(monitor, NULL, 0)) < 0) {
fprintf(stderr, _("Failed connection from LXC driver: %s\n"),
strerror(errno));
- _exit(-1);
+ goto cleanup;
}
- /* Controlling libvirtd LXC driver now knows
- what our PID is, and is able to cleanup after
- us from now on */
- _exit(lxcControllerRun(stateDir, def, nveths, veths, monitor, client, appPty));
-}
+ rc = lxcControllerRun(def, nveths, veths, monitor, client, appPty);
-#endif
+cleanup:
+ virFileDeletePid(LXC_STATE_DIR, def->name);
+ lxcControllerCleanupInterfaces(nveths, veths);
+ unlink(sockpath);
+ VIR_FREE(sockpath);
+
+ return rc;
+}
+
#include "lxc_conf.h"
#include "lxc_container.h"
#include "lxc_driver.h"
-#include "lxc_controller.h"
#include "memory.h"
#include "util.h"
#include "bridge.h"
close(vm->monitor);
virFileDeletePid(driver->stateDir, vm->def->name);
+ virDomainDeleteConfig(conn, driver->stateDir, NULL, vm);
vm->state = VIR_DOMAIN_SHUTOFF;
vm->pid = -1;
return rc;
}
-static int lxcMonitorServer(virConnectPtr conn,
- lxc_driver_t * driver,
- virDomainObjPtr vm)
-{
- char *sockpath = NULL;
- int fd;
- struct sockaddr_un addr;
-
- if (asprintf(&sockpath, "%s/%s.sock",
- driver->stateDir, vm->def->name) < 0) {
- lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL);
- return -1;
- }
-
- if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- _("failed to create server socket: %s"),
- strerror(errno));
- goto error;
- }
-
- unlink(sockpath);
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
-
- if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- _("failed to bind server socket: %s"),
- strerror(errno));
- goto error;
- }
- if (listen(fd, 30 /* backlog */ ) < 0) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- _("failed to listen server socket: %s"),
- strerror(errno));
- goto error;
- return (-1);
- }
-
- VIR_FREE(sockpath);
- return fd;
-
-error:
- VIR_FREE(sockpath);
- if (fd != -1)
- close(fd);
- return -1;
-}
static int lxcMonitorClient(virConnectPtr conn,
lxc_driver_t * driver,
if (signum == 0)
signum = SIGINT;
+ if (vm->pid <= 0) {
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("invalid PID %d for container"), vm->pid);
+ return -1;
+ }
+
if (kill(vm->pid, signum) < 0) {
if (errno != ESRCH) {
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
}
+static int lxcControllerStart(virConnectPtr conn,
+ virDomainObjPtr vm,
+ int nveths,
+ char **veths,
+ int appPty,
+ int logfd)
+{
+ int i;
+ int rc;
+ int ret = -1;
+ int largc = 0, larga = 0;
+ const char **largv = NULL;
+ pid_t child;
+ int status;
+
+#define ADD_ARG_SPACE \
+ do { \
+ if (largc == larga) { \
+ larga += 10; \
+ if (VIR_REALLOC_N(largv, larga) < 0) \
+ goto no_memory; \
+ } \
+ } while (0)
+
+#define ADD_ARG(thisarg) \
+ do { \
+ ADD_ARG_SPACE; \
+ largv[largc++] = thisarg; \
+ } while (0)
+
+#define ADD_ARG_LIT(thisarg) \
+ do { \
+ ADD_ARG_SPACE; \
+ if ((largv[largc++] = strdup(thisarg)) == NULL) \
+ goto no_memory; \
+ } while (0)
+
+ ADD_ARG_LIT(vm->def->emulator);
+ ADD_ARG_LIT("--name");
+ ADD_ARG_LIT(vm->def->name);
+ ADD_ARG_LIT("--console");
+ ADD_ARG_LIT("0"); /* Passing console master PTY as FD 0 */
+ ADD_ARG_LIT("--background");
+
+ for (i = 0 ; i < nveths ; i++) {
+ ADD_ARG_LIT("--veth");
+ ADD_ARG_LIT(veths[i]);
+ }
+
+ ADD_ARG(NULL);
+
+ vm->stdin_fd = appPty; /* Passing console master PTY as FD 0 */
+ vm->stdout_fd = vm->stderr_fd = logfd;
+
+ if (virExec(conn, largv, NULL, &child,
+ vm->stdin_fd, &vm->stdout_fd, &vm->stderr_fd,
+ VIR_EXEC_NONE) < 0)
+ goto cleanup;
+
+ /* We now wait for the process to exit - the controller
+ * will fork() itself into the background - waiting for
+ * it to exit thus guarentees it has written its pidfile
+ */
+ while ((rc = waitpid(child, &status, 0) == -1) && errno == EINTR);
+ if (rc == -1) {
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("cannot wait for '%s': %s"),
+ largv[0], strerror(errno));
+ goto cleanup;
+ }
+
+ if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("container '%s' unexpectedly shutdown during startup"),
+ largv[0]);
+ goto cleanup;
+ }
+
+#undef ADD_ARG
+#undef ADD_ARG_LIT
+#undef ADD_ARG_SPACE
+
+ ret = 0;
+
+cleanup:
+ for (i = 0 ; i < largc ; i++)
+ VIR_FREE(largv[i]);
+
+ return ret;
+
+no_memory:
+ lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL);
+ goto cleanup;
+}
+
+
/**
* lxcVmStart:
* @conn: pointer to connection
{
int rc = -1;
unsigned int i;
- int monitor;
int parentTty;
char *parentTtyPath = NULL;
char *logfile = NULL;
return -1;
}
- if ((monitor = lxcMonitorServer(conn, driver, vm)) < 0)
- goto cleanup;
-
/* open parent tty */
if (virFileOpenTty(&parentTty, &parentTtyPath, 1) < 0) {
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0)
goto cleanup;
+ /* Persist the live configuration now we have veth & tty info */
+ if (virDomainSaveConfig(conn, driver->stateDir, vm->def) < 0) {
+ rc = -1;
+ goto cleanup;
+ }
+
if ((logfd = open(logfile, O_WRONLY | O_TRUNC | O_CREAT,
S_IRUSR|S_IWUSR)) < 0) {
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
goto cleanup;
}
- if (lxcControllerStart(driver->stateDir,
- vm->def, nveths, veths,
- monitor, parentTty, logfd) < 0)
+ if (lxcControllerStart(conn,
+ vm,
+ nveths, veths,
+ parentTty, logfd) < 0)
goto cleanup;
- /* Close the server side of the monitor, now owned
- * by the controller process */
- close(monitor);
- monitor = -1;
/* Connect to the controller as a client *first* because
* this will block until the child has written their
vethDelete(veths[i]);
VIR_FREE(veths[i]);
}
- if (monitor != -1)
- close(monitor);
if (rc != 0 && vm->monitor != -1) {
close(vm->monitor);
vm->monitor = -1;
vm = lxc_driver->domains;
while (vm) {
+ char *config = NULL;
+ virDomainDefPtr tmp;
int rc;
if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0) {
vm = vm->next;
continue;
}
+ if ((config = virDomainConfigFile(NULL,
+ lxc_driver->stateDir,
+ vm->def->name)) == NULL)
+ continue;
+
+ /* Try and load the live config */
+ tmp = virDomainDefParseFile(NULL, lxc_driver->caps, config);
+ VIR_FREE(config);
+ if (tmp) {
+ vm->newDef = vm->def;
+ vm->def = tmp;
+ }
+
if (vm->pid != 0) {
vm->def->id = vm->pid;
vm->state = VIR_DOMAIN_RUNNING;