char **veths,
int monitor,
int client,
- int appPty)
+ int appPty,
+ int handshakefd)
{
int rc = -1;
int control[2] = { -1, -1};
if (lxcControllerClearCapabilities() < 0)
goto cleanup;
+ if (lxcContainerSendContinue(handshakefd) < 0) {
+ virReportSystemError(errno, "%s",
+ _("error sending continue signal to parent"));
+ goto cleanup;
+ }
+ VIR_FORCE_CLOSE(handshakefd);
+
rc = lxcControllerMain(monitor, client, appPty, containerPty, container);
cleanup:
VIR_FORCE_CLOSE(control[1]);
VIR_FREE(containerPtyPath);
VIR_FORCE_CLOSE(containerPty);
+ VIR_FORCE_CLOSE(handshakefd);
if (container > 1) {
int status;
char **veths = NULL;
int monitor = -1;
int appPty = -1;
+ int handshakefd = -1;
int bg = 0;
virCapsPtr caps = NULL;
virDomainDefPtr def = NULL;
{ "name", 1, NULL, 'n' },
{ "veth", 1, NULL, 'v' },
{ "console", 1, NULL, 'c' },
+ { "handshakefd", 1, NULL, 's' },
{ "help", 0, NULL, 'h' },
{ 0, 0, 0, 0 },
};
while (1) {
int c;
- c = getopt_long(argc, argv, "dn:v:m:c:h",
+ c = getopt_long(argc, argv, "dn:v:m:c:s:h",
options, NULL);
if (c == -1)
}
break;
+ case 's':
+ if (virStrToLong_i(optarg, NULL, 10, &handshakefd) < 0) {
+ fprintf(stderr, "malformed --handshakefd argument '%s'",
+ optarg);
+ goto cleanup;
+ }
+ break;
+
case 'h':
case '?':
fprintf(stderr, "\n");
fprintf(stderr, " -n NAME, --name NAME\n");
fprintf(stderr, " -c FD, --console FD\n");
fprintf(stderr, " -v VETH, --veth VETH\n");
+ fprintf(stderr, " -s FD, --handshakefd FD\n");
fprintf(stderr, " -h, --help\n");
fprintf(stderr, "\n");
goto cleanup;
goto cleanup;
}
+ if (handshakefd < 0) {
+ fprintf(stderr, "%s: missing --handshake 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;
goto cleanup;
}
- rc = lxcControllerRun(def, nveths, veths, monitor, client, appPty);
+ rc = lxcControllerRun(def, nveths, veths, monitor, client, appPty,
+ handshakefd);
cleanup:
int nveths,
char **veths,
int appPty,
- int logfile)
+ int logfile,
+ int handshakefd)
{
int i;
char *filterstr;
virCommandAddArgList(cmd, "--name", vm->def->name, "--console", NULL);
virCommandAddArgFormat(cmd, "%d", appPty);
+ virCommandAddArg(cmd, "--handshake");
+ virCommandAddArgFormat(cmd, "%d", handshakefd);
virCommandAddArg(cmd, "--background");
for (i = 0 ; i < nveths ; i++) {
}
virCommandPreserveFD(cmd, appPty);
+ virCommandPreserveFD(cmd, handshakefd);
virCommandSetOutputFD(cmd, &logfile);
virCommandSetErrorFD(cmd, &logfile);
return NULL;
}
+static int
+lxcReadLogOutput(virDomainObjPtr vm,
+ char *logfile,
+ off_t pos,
+ char *buf,
+ size_t buflen)
+{
+ int fd;
+ off_t off;
+ int whence;
+ int got = 0, ret = -1;
+ int retries = 10;
+
+ if ((fd = open(logfile, O_RDONLY)) < 0) {
+ virReportSystemError(errno, _("failed to open logfile %s"),
+ logfile);
+ goto cleanup;
+ }
+
+ if (pos < 0) {
+ off = 0;
+ whence = SEEK_END;
+ } else {
+ off = pos;
+ whence = SEEK_SET;
+ }
+
+ if (lseek(fd, off, whence) < 0) {
+ if (whence == SEEK_END)
+ virReportSystemError(errno,
+ _("unable to seek to end of log for %s"),
+ logfile);
+ else
+ virReportSystemError(errno,
+ _("unable to seek to %lld from start for %s"),
+ (long long)off, logfile);
+ goto cleanup;
+ }
+
+ while (retries) {
+ ssize_t bytes;
+ int isdead = 0;
+
+ if (kill(vm->pid, 0) == -1 && errno == ESRCH)
+ isdead = 1;
+
+ /* Any failures should be detected before we read the log, so we
+ * always have something useful to report on failure. */
+ bytes = saferead(fd, buf+got, buflen-got-1);
+ if (bytes < 0) {
+ virReportSystemError(errno, "%s",
+ _("Failure while reading guest log output"));
+ goto cleanup;
+ }
+
+ got += bytes;
+ buf[got] = '\0';
+
+ if ((got == buflen-1) || isdead) {
+ break;
+ }
+
+ usleep(100*1000);
+ retries--;
+ }
+
+
+ ret = got;
+cleanup:
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+}
/**
* lxcVmStart:
int logfd = -1;
unsigned int nveths = 0;
char **veths = NULL;
+ int handshakefds[2] = { -1, -1 };
off_t pos = -1;
char ebuf[1024];
char *timestamp;
goto cleanup;
}
+ if (pipe(handshakefds) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to create pipe"));
+ goto cleanup;
+ }
+
if (!(cmd = lxcBuildControllerCmd(driver,
vm,
nveths, veths,
- parentTty, logfd)))
+ parentTty, logfd, handshakefds[1])))
goto cleanup;
/* Log timestamp */
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
+ if (VIR_CLOSE(handshakefds[1]) < 0) {
+ virReportSystemError(errno, "%s", _("could not close handshake fd"));
+ goto cleanup;
+ }
+
/* Connect to the controller as a client *first* because
* this will block until the child has written their
* pid file out to disk */
vm->def->id = vm->pid;
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
+ if (lxcContainerWaitForContinue(handshakefds[0]) < 0) {
+ char out[1024];
+
+ if (!(lxcReadLogOutput(vm, logfile, pos, out, 1024) < 0)) {
+ lxcError(VIR_ERR_INTERNAL_ERROR,
+ _("guest failed to start: %s"), out);
+ }
+
+ lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
+ goto cleanup;
+ }
+
if ((priv->monitorWatch = virEventAddHandle(
priv->monitor,
VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
if (rc != 0)
VIR_FORCE_CLOSE(priv->monitor);
VIR_FORCE_CLOSE(parentTty);
+ VIR_FORCE_CLOSE(handshakefds[0]);
+ VIR_FORCE_CLOSE(handshakefds[1]);
VIR_FREE(logfile);
return rc;
}