static int libxlMakeChrdevStr(virDomainChrDefPtr def, char **buf) { virDomainChrSourceDef srcdef = def->source; const char *type = virDomainChrTypeToString(srcdef.type); if (!type) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("unknown chrdev type")); return -1; } switch (srcdef.type) { case VIR_DOMAIN_CHR_TYPE_NULL: case VIR_DOMAIN_CHR_TYPE_STDIO: case VIR_DOMAIN_CHR_TYPE_VC: case VIR_DOMAIN_CHR_TYPE_PTY: if (VIR_STRDUP(*buf, type) < 0) return -1; break; case VIR_DOMAIN_CHR_TYPE_FILE: case VIR_DOMAIN_CHR_TYPE_PIPE: if (virAsprintf(buf, "%s:%s", type, srcdef.data.file.path) < 0) return -1; break; case VIR_DOMAIN_CHR_TYPE_DEV: if (VIR_STRDUP(*buf, srcdef.data.file.path) < 0) return -1; break; case VIR_DOMAIN_CHR_TYPE_UDP: { const char *connectHost = srcdef.data.udp.connectHost; const char *bindHost = srcdef.data.udp.bindHost; const char *bindService = srcdef.data.udp.bindService; if (connectHost == NULL) connectHost = ""; if (bindHost == NULL) bindHost = ""; if (bindService == NULL) bindService = "0"; if (virAsprintf(buf, "udp:%s:%s@%s:%s", connectHost, srcdef.data.udp.connectService, bindHost, bindService) < 0) return -1; break; } case VIR_DOMAIN_CHR_TYPE_TCP: { const char *prefix; if (srcdef.data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET) prefix = "telnet"; else prefix = "tcp"; if (virAsprintf(buf, "%s:%s:%s%s", prefix, srcdef.data.tcp.host, srcdef.data.tcp.service, srcdef.data.tcp.listen ? ",server,nowait" : "") < 0) return -1; break; } case VIR_DOMAIN_CHR_TYPE_UNIX: if (virAsprintf(buf, "unix:%s%s", srcdef.data.nix.path, srcdef.data.nix.listen ? ",server,nowait" : "") < 0) return -1; break; default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unsupported chardev '%s'"), type); return -1; } return 0; }
qemuAgentPtr qemuAgentOpen(virDomainObjPtr vm, virDomainChrSourceDefPtr config, qemuAgentCallbacksPtr cb) { qemuAgentPtr mon; if (!cb || !cb->eofNotify) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("EOF notify callback must be supplied")); return NULL; } if (qemuAgentInitialize() < 0) return NULL; if (!(mon = virObjectNew(qemuAgentClass))) return NULL; if (virMutexInit(&mon->lock) < 0) { virReportSystemError(errno, "%s", _("cannot initialize monitor mutex")); VIR_FREE(mon); return NULL; } if (virCondInit(&mon->notify) < 0) { virReportSystemError(errno, "%s", _("cannot initialize monitor condition")); virMutexDestroy(&mon->lock); VIR_FREE(mon); return NULL; } mon->fd = -1; mon->vm = vm; mon->cb = cb; qemuAgentLock(mon); switch (config->type) { case VIR_DOMAIN_CHR_TYPE_UNIX: mon->fd = qemuAgentOpenUnix(config->data.nix.path, vm->pid, &mon->connectPending); break; case VIR_DOMAIN_CHR_TYPE_PTY: mon->fd = qemuAgentOpenPty(config->data.file.path); break; default: virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to handle monitor type: %s"), virDomainChrTypeToString(config->type)); goto cleanup; } if (mon->fd == -1) goto cleanup; if ((mon->watch = virEventAddHandle(mon->fd, VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_READABLE | (mon->connectPending ? VIR_EVENT_HANDLE_WRITABLE : 0), qemuAgentIO, mon, virObjectFreeCallback)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("unable to register monitor events")); goto cleanup; } virObjectRef(mon); VIR_DEBUG("New mon %p fd =%d watch=%d", mon, mon->fd, mon->watch); qemuAgentUnlock(mon); return mon; cleanup: /* We don't want the 'destroy' callback invoked during * cleanup from construction failure, because that can * give a double-unref on virDomainObjPtr in the caller, * so kill the callbacks now. */ mon->cb = NULL; qemuAgentUnlock(mon); qemuAgentClose(mon); return NULL; }