typedefstruct _virConnectDrivervirConnectDriver; struct _virConnectDriver { /* Whether driver permits a server in the URI */ bool localOnly; /* Whether driver needs a server in the URI */ bool remoteOnly; /* Whether driver can be used in embedded mode */ bool embeddable; /* * NULL terminated list of supported URI schemes. * - Single element { NULL } list indicates no supported schemes * - NULL list indicates wildcard supporting all schemes */ constchar **uriSchemes; virHypervisorDriver *hypervisorDriver; virInterfaceDriver *interfaceDriver; virNetworkDriver *networkDriver; virNodeDeviceDriver *nodeDeviceDriver; virNWFilterDriver *nwfilterDriver; virSecretDriver *secretDriver; virStorageDriver *storageDriver; };
/** * virRegisterConnectDriver: * @driver: pointer to a driver block * @setSharedDrivers: populate shared drivers * * Register a virtualization driver, optionally filling in * any empty pointers for shared secondary drivers * * Returns the driver priority or -1 in case of error. */ int virRegisterConnectDriver(virConnectDriver *driver, bool setSharedDrivers) { VIR_DEBUG("driver=%p name=%s", driver, driver ? NULLSTR(driver->hypervisorDriver->name) : "(null)");
virCheckNonNullArgReturn(driver, -1); if (virConnectDriverTabCount >= MAX_DRIVERS) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Too many drivers, cannot register %1$s"), driver->hypervisorDriver->name); return-1; }
VIR_DEBUG("registering %s as driver %d", driver->hypervisorDriver->name, virConnectDriverTabCount);
if (setSharedDrivers) { if (driver->interfaceDriver == NULL) driver->interfaceDriver = virSharedInterfaceDriver; if (driver->networkDriver == NULL) driver->networkDriver = virSharedNetworkDriver; if (driver->nodeDeviceDriver == NULL) driver->nodeDeviceDriver = virSharedNodeDeviceDriver; if (driver->nwfilterDriver == NULL) driver->nwfilterDriver = virSharedNWFilterDriver; if (driver->secretDriver == NULL) driver->secretDriver = virSharedSecretDriver; if (driver->storageDriver == NULL) driver->storageDriver = virSharedStorageDriver; }
//#0 virConnectOpenInternal (name=0x0, auth=0x7ffff7e38920 <virConnectAuthDefault>, flags=0) at ../src/libvirt.c:897 //#1 0x00007ffff7cb3f6e in virConnectOpenAuth (name=name@entry=0x0, auth=0x7ffff7e38920 <virConnectAuthDefault>, flags=flags@entry=0) at ../src/libvirt.c:1283 //#2 0x00005555555924f0 in virshConnect (ctl=ctl@entry=0x7fffffffdb90, uri=0x0, readonly=false) at ../tools/virsh.c:127 //#3 0x00005555555927c3 in virshReconnect (ctl=ctl@entry=0x7fffffffdb90, name=name@entry=0x0, readonly=<optimized out>, readonly@entry=false, force=force@entry=false) at ../tools/virsh.c:208 //#4 0x00005555555929b4 in virshConnectionHandler (ctl=0x7fffffffdb90) at ../tools/virsh.c:309 //#5 0x00005555555e146a in vshCommandRun (ctl=ctl@entry=0x7fffffffdb90, cmd=0x555555673060) at ../tools/vsh.c:1358 //#6 0x0000555555591f70 in main (argc=argc@entry=2, argv=argv@entry=0x7fffffffdf58) at ../tools/virsh.c:889 //#7 0x00007ffff7429d90 in __libc_start_call_main (main=main@entry=0x555555591410 <main>, argc=argc@entry=2, argv=argv@entry=0x7fffffffdf58) at ../sysdeps/nptl/libc_start_call_main.h:58 //#8 0x00007ffff7429e40 in __libc_start_main_impl (main=0x555555591410 <main>, argc=2, argv=0x7fffffffdf58, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf48) at ../csu/libc-start.c:392 //#9 0x0000555555592145 in _start ()
//#0 virConnectOpenInternal (name=0x73f3b8004660 "", auth=0x0, flags=0) at ../src/libvirt.c:897 //#1 0x000073f3cbcb3f6e in virConnectOpenAuth (name=name@entry=0x73f3b8004660 "", auth=auth@entry=0x0, flags=flags@entry=0) at ../src/libvirt.c:1283 //#2 0x00005e62526a1fec in remoteOpenConn (uri=0x73f3b8004660 "", readonly=false, preserveIdentity=<optimized out>, conn=0x5e6252fc44d0) at ../src/remote/remote_daemon_dispatch.c:1821 //#3 0x00005e62526a4330 in remoteDispatchConnectOpen (server=<optimized out>, msg=<optimized out>, args=<optimized out>, rerr=0x73f3c6dff9e0, client=0x5e6252fc15a0) at ../src/remote/remote_daemon_dispatch.c:2091 //#4 remoteDispatchConnectOpenHelper (server=<optimized out>, client=0x5e6252fc15a0, msg=<optimized out>, rerr=0x73f3c6dff9e0, args=<optimized out>, ret=<optimized out>) at src/remote/remote_daemon_dispatch_stubs.h:3291 //#5 0x000073f3cbc0053c in virNetServerProgramDispatchCall (msg=0x5e6252fc3230, client=0x5e6252fc15a0, server=0x5e6252fad880, prog=0x5e6252fb7010) at ../src/rpc/virnetserverprogram.c:423 //#6 virNetServerProgramDispatch (prog=0x5e6252fb7010, server=server@entry=0x5e6252fad880, client=0x5e6252fc15a0, msg=0x5e6252fc3230) at ../src/rpc/virnetserverprogram.c:299 //#7 0x000073f3cbc06538 in virNetServerProcessMsg (msg=<optimized out>, prog=<optimized out>, client=<optimized out>, srv=0x5e6252fad880) at ../src/rpc/virnetserver.c:135 //#8 virNetServerHandleJob (jobOpaque=0x5e6252f931f0, opaque=0x5e6252fad880) at ../src/rpc/virnetserver.c:155 //#9 0x000073f3cbb3e9f3 in virThreadPoolWorker (opaque=<optimized out>) at ../src/util/virthreadpool.c:164 //#10 0x000073f3cbb3dfe9 in virThreadHelper (data=<optimized out>) at ../src/util/virthread.c:256 //#11 0x000073f3cb294ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442 //#12 0x000073f3cb326850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81 static virConnectPtr virConnectOpenInternal(constchar *name, virConnectAuthPtr auth, unsignedint flags) { size_t i; int res; g_autoptr(virConnect) ret = NULL; g_autoptr(virConf) conf = NULL; g_autofree char *uristr = NULL; bool embed = false;
ret = virGetConnect(); if (ret == NULL) returnNULL;
if (virConfLoadConfig(&conf, "libvirt.conf") < 0) returnNULL;
if (name && name[0] == '\0') name = NULL; ... /* * If no URI is passed, then check for an environment string if not * available probe the compiled in drivers to find a default hypervisor * if detectable. */ if (name) { uristr = g_strdup(name); } else { if (virConnectGetDefaultURI(conf, &uristr) < 0) returnNULL;
if (uristr == NULL) { VIR_DEBUG("Trying to probe for default URI"); for (i = 0; i < virConnectDriverTabCount && uristr == NULL; i++) { if (virConnectDriverTab[i]->hypervisorDriver->connectURIProbe) { if (virConnectDriverTab[i]->hypervisorDriver->connectURIProbe(&uristr) < 0) returnNULL; VIR_DEBUG("%s driver URI probe returned '%s'", virConnectDriverTab[i]->hypervisorDriver->name, NULLSTR(uristr)); } } } }
if (alias) { g_free(uristr); uristr = g_steal_pointer(&alias); }
if (!(ret->uri = virURIParse(uristr))) returnNULL;
/* Avoid need for drivers to worry about NULLs, as * no one needs to distinguish "" vs NULL */ if (ret->uri->path == NULL) ret->uri->path = g_strdup("");
VIR_DEBUG("Split \"%s\" to URI components:\n" " scheme %s\n" " server %s\n" " user %s\n" " port %d\n" " path %s", uristr, NULLSTR(ret->uri->scheme), NULLSTR(ret->uri->server), NULLSTR(ret->uri->user), ret->uri->port, ret->uri->path);
if (ret->uri->scheme == NULL) { virReportError(VIR_ERR_NO_CONNECT, _("URI '%1$s' does not include a driver name"), name); returnNULL; }
if (virConnectCheckURIMissingSlash(uristr, ret->uri) < 0) { returnNULL; }
if (STREQ(ret->uri->path, "/embed")) { constchar *root = NULL; g_autofree char *regMethod = NULL; VIR_DEBUG("URI path requests %s driver embedded mode", ret->uri->scheme); if (strspn(ret->uri->scheme, "abcdefghijklmnopqrstuvwxyz") != strlen(ret->uri->scheme)) { virReportError(VIR_ERR_NO_CONNECT, _("URI scheme '%1$s' for embedded driver is not valid"), ret->uri->scheme); returnNULL; }
root = virURIGetParam(ret->uri, "root"); if (!root) returnNULL;
if (!g_path_is_absolute(root)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("root path must be absolute")); returnNULL; }
for (i = 0; i < virConnectDriverTabCount; i++) { /* We're going to probe the remote driver next. So we have already * probed all other client-side-only driver before, but none of them * accepted the URI. * If the scheme corresponds to a known but disabled client-side-only * driver then report a useful error, instead of a cryptic one about * not being able to connect to libvirtd or not being able to find * certificates. */ if (STREQ(virConnectDriverTab[i]->hypervisorDriver->name, "remote") && ret->uri != NULL && ( #ifndef WITH_ESX STRCASEEQ(ret->uri->scheme, "vpx") || STRCASEEQ(ret->uri->scheme, "esx") || STRCASEEQ(ret->uri->scheme, "gsx") || #endif #ifndef WITH_HYPERV STRCASEEQ(ret->uri->scheme, "hyperv") || #endif #ifndef WITH_VZ STRCASEEQ(ret->uri->scheme, "parallels") || #endif false)) { virReportErrorHelper(VIR_FROM_NONE, VIR_ERR_CONFIG_UNSUPPORTED, __FILE__, __FUNCTION__, __LINE__, _("libvirt was built without the '%1$s' driver"), ret->uri->scheme); returnNULL; }
VIR_DEBUG("trying driver %zu (%s) ...", i, virConnectDriverTab[i]->hypervisorDriver->name);
if (virConnectDriverTab[i]->localOnly && ret->uri && ret->uri->server) { VIR_DEBUG("Server present, skipping local only driver"); continue; }
/* Filter drivers based on declared URI schemes */ if (virConnectDriverTab[i]->uriSchemes) { bool matchScheme = false; size_t s; if (!ret->uri) { VIR_DEBUG("No URI, skipping driver with URI whitelist"); continue; } if (embed && !virConnectDriverTab[i]->embeddable) { VIR_DEBUG("Ignoring non-embeddable driver %s", virConnectDriverTab[i]->hypervisorDriver->name); continue; }
VIR_DEBUG("Checking for supported URI schemes"); for (s = 0; virConnectDriverTab[i]->uriSchemes[s] != NULL; s++) { if (STREQ(ret->uri->scheme, virConnectDriverTab[i]->uriSchemes[s])) { VIR_DEBUG("Matched URI scheme '%s'", ret->uri->scheme); matchScheme = true; break; } } if (!matchScheme) { VIR_DEBUG("No matching URI scheme"); continue; } } else { if (embed) { VIR_DEBUG("Skipping wildcard for embedded URI"); continue; } else { VIR_DEBUG("Matching any URI scheme for '%s'", ret->uri ? ret->uri->scheme : ""); } }
if (embed && !virConnectDriverTab[i]->embeddable) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Driver %1$s cannot be used in embedded mode"), virConnectDriverTab[i]->hypervisorDriver->name); returnNULL; } /* before starting the new connection, check if the driver only works * with a server, and so return an error if the server is missing */ if (virConnectDriverTab[i]->remoteOnly && ret->uri && !ret->uri->server) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("URI is missing the server part")); returnNULL; }
if (!ret->driver) { /* If we reach here, then all drivers declined the connection. */ virReportError(VIR_ERR_NO_CONNECT, "%s", NULLSTR(name)); returnNULL; }
/** * vshCommandStringParse: * @ctl virsh control structure * @cmdstr: string to parse * @partial: store partially parsed command here * * Parse given string @cmdstr as a command and store it under * @ctl->cmd. For readline completion, if @partial is not NULL on * the input then errors in parsing are ignored (because user is * still in progress of writing the command string) and partially * parsed command is stored at *@partial (caller has to free it * afterwards). */ bool vshCommandStringParse(vshControl *ctl, char *cmdstr, vshCmd **partial) { vshCommandParser parser = { 0 };
if (cmdstr == NULL || *cmdstr == '\0') returnfalse;
while (1) { /* previous iteration might have already gotten a value. Store it as the * token in this iteration */ g_autofree char *tkdata = g_steal_pointer(&optionvalue);
/* If we have a value already or the option to fill is a boolean we * don't want to fetch a new token */ if (!(tkdata || (opt && opt->def->type == VSH_OT_BOOL))) { vshCommandToken tk;
switch (tk) { case VSH_TK_ARG: /* will be handled below */ break;
case VSH_TK_ERROR: goto out;
case VSH_TK_END: case VSH_TK_SUBCMD_END: /* The last argument name expects a value, but it's missing */ if (opt) { if (partial) { /* for completion to work we need to also store the * last token into the last 'opt' */ vshCmdOptAssign(ctl, cmd, opt, tkdata, report); } else { if (opt->def->type == VSH_OT_INT) vshError(ctl, _("expected syntax: --%1$s <number>"), opt->def->name); else vshError(ctl, _("expected syntax: --%1$s <string>"), opt->def->name);
goto out; } }
/* command parsed -- allocate new struct for the command */ if (cmd) { /* if we encountered --help, replace parsed command with 'help <cmdname>' */ if (cmd->helpOptionSeen) { vshCmd *helpcmd = vshCmdNewHelp(cmd->def->name);
vshCommandFree(cmd); cmd = helpcmd; }
if (!partial && vshCommandCheckOpts(ctl, cmd) < 0) goto out;
if (!cmds) cmds = cmd; if (cmds_last) cmds_last->next = cmd; cmds_last = g_steal_pointer(&cmd); }
/* everything parsed */ if (tk == VSH_TK_END) { ret = true; goto out; }
/* after processing the command we need to start over again to * fetch another token */ state = VSH_CMD_PARSER_STATE_START; continue; } }
/* at this point we know that @tkdata is an argument */ switch (state) { case VSH_CMD_PARSER_STATE_START: if (*tkdata == '#') { state = VSH_CMD_PARSER_STATE_COMMENT; } else { state = VSH_CMD_PARSER_STATE_COMMAND;
if (!(cmd = vshCmdNew(ctl, tkdata, !partial))) goto out; }
break;
case VSH_CMD_PARSER_STATE_COMMENT: /* continue eating tokens until end of line or end of input */ state = VSH_CMD_PARSER_STATE_COMMENT; break;
case VSH_CMD_PARSER_STATE_COMMAND: { /* parsing individual options for the command. There are following options: * --option * --option value * --option=value * --aliasoptionwithvalue (value is part of the alias definition) * value * -- (terminate accepting '--option', fill only positional args) */ constchar *optionname = tkdata + 2; char *sep;
if (!STRPREFIX(tkdata, "--")) { if (vshCmdOptAssignPositional(ctl, cmd, tkdata, report) < 0) goto out; break; }
if (STREQ(tkdata, "--")) { state = VSH_CMD_PARSER_STATE_POSITIONAL_ONLY; break; }
if ((sep = strchr(optionname, '='))) { *(sep++) = '\0';
/* 'optionvalue' has lifetime until next iteration */ optionvalue = g_strdup(sep); }
/* lookup the option. Note that vshCmdGetOption also resolves aliases * and thus the value possibly contained in the alias */ if (STREQ(optionname, "help")) { cmd->helpOptionSeen = true; g_clear_pointer(&optionvalue, g_free); } elseif (!(opt = vshCmdGetOption(ctl, cmd, optionname, &optionvalue, report))) { if (STRNEQ(cmd->def->name, "help")) goto out;
/* ignore spurious arguments for 'help' command */ g_clear_pointer(&optionvalue, g_free); state = VSH_CMD_PARSER_STATE_COMMAND; } else { state = VSH_CMD_PARSER_STATE_ASSIGN_OPT; } } break;
case VSH_CMD_PARSER_STATE_ASSIGN_OPT: /* Parameter for a boolean was passed via --boolopt=val */ if (tkdata && opt->def->type == VSH_OT_BOOL) { if (report) vshError(ctl, _("invalid '=' after option --%1$s"), opt->def->name); goto out; }
if (!(c->def = vshCmddefSearch(cmdname))) { if (report) vshError(ctl, _("unknown command: '%1$s'"), cmdname);
returnNULL; }
/* resolve command alias */ if (c->def->alias) { if (!(c->def = vshCmddefSearch(c->def->alias))) { /* dead code: self-test ensures that the alias exists thus no error reported here */ returnNULL; } }
/* Find number of arguments */ for (optdef = c->def->opts; optdef && optdef->name; optdef++) nopts++;
/* populate links to definitions */ for (optdef = c->def->opts; optdef && optdef->name; optdef++) { opt->def = optdef; opt++; }
return g_steal_pointer(&c); }
/* vshCmddefSearch: * @cmdname: name of command to find * * Looks for @cmdname in the global list of command definitions @cmdGroups and * returns pointer to the definition struct if the command exists. */ staticconst vshCmdDef * vshCmddefSearch(constchar *cmdname) { const vshCmdGrp *g; const vshCmdDef *c;
for (g = cmdGroups; g->name; g++) { for (c = g->commands; c->name; c++) { if (STREQ(c->name, cmdname)) return c; } }
VIR_WITH_OBJECT_LOCK_GUARD(srv) { prog = virNetServerGetProgramLocked(srv, msg); /* we can unlock @srv since @prog can only become invalid in case * of disposing @srv, but let's grab a ref first to ensure nothing * disposes of it before we use it. */ virObjectRef(srv); }
if (virThreadPoolGetMaxWorkers(srv->workers) > 0) { virNetServerJob *job;
/** * virNetServerGetProgramLocked: * @srv: server (must be locked by the caller) * @msg: message * * Searches @srv for the right program for a given message @msg. * * Returns a pointer to the server program or NULL if not found. */ static virNetServerProgram * virNetServerGetProgramLocked(virNetServer *srv, virNetMessage *msg) { size_t i; for (i = 0; i < srv->nprograms; i++) { if (virNetServerProgramMatches(srv->programs[i], msg)) return srv->programs[i]; } returnNULL; }
//#0 virConnectOpenInternal (name=0x0, auth=0x7ffff7e38920 <virConnectAuthDefault>, flags=0) at ../src/libvirt.c:897 //#1 0x00007ffff7cb3f6e in virConnectOpenAuth (name=name@entry=0x0, auth=0x7ffff7e38920 <virConnectAuthDefault>, flags=flags@entry=0) at ../src/libvirt.c:1283 //#2 0x00005555555924f0 in virshConnect (ctl=ctl@entry=0x7fffffffdba0, uri=0x0, readonly=false) at ../tools/virsh.c:127 //#3 0x00005555555927c3 in virshReconnect (ctl=ctl@entry=0x7fffffffdba0, name=0x0, readonly=<optimized out>, readonly@entry=false, force=force@entry=true) at ../tools/virsh.c:208 //#4 0x000055555559294e in cmdConnect (ctl=0x7fffffffdba0, cmd=0x555555673060) at ../tools/virsh.c:275 //#5 0x00005555555e147f in vshCommandRun (ctl=ctl@entry=0x7fffffffdba0, cmd=0x555555673060) at ../tools/vsh.c:1359 //#6 0x0000555555591f70 in main (argc=argc@entry=2, argv=argv@entry=0x7fffffffdf68) at ../tools/virsh.c:889 //#7 0x00007ffff7429d90 in __libc_start_call_main (main=main@entry=0x555555591410 <main>, argc=argc@entry=2, argv=argv@entry=0x7fffffffdf68) at ../sysdeps/nptl/libc_start_call_main.h:58 //#8 0x00007ffff7429e40 in __libc_start_main_impl (main=0x555555591410 <main>, argc=2, argv=0x7fffffffdf68, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf58) at ../csu/libc-start.c:392 //#9 0x0000555555592145 in _start () staticbool cmdConnect(vshControl *ctl, const vshCmd *cmd) { bool ro = vshCommandOptBool(cmd, "readonly"); constchar *name = NULL;
if (vshCommandOptString(ctl, cmd, "name", &name) < 0) returnfalse;
if (virshReconnect(ctl, name, ro, true) < 0) returnfalse;
returntrue; }
/* * virshReconnect: * * Reconnect after a disconnect from libvirtd * */ staticint virshReconnect(vshControl *ctl, constchar *name, bool readonly, bool force) { ... priv->conn = virshConnect(ctl, name ? name : ctl->connname, readonly); ... return0; }
/* Main Function which should be used for connecting. * This function properly handles keepalive settings. */ virConnectPtr virshConnect(vshControl *ctl, constchar *uri, bool readonly) { ... do { virErrorPtr err;
/** * virConnectOpenAuth: * @name: (optional) URI of the hypervisor * @auth: Authenticate callback parameters * @flags: bitwise-OR of virConnectFlags * * This function should be called first to get a connection to the * Hypervisor. If necessary, authentication will be performed fetching * credentials via the callback * * See virConnectOpen for notes about environment variables which can * have an effect on opening drivers and freeing the connection resources * * URIs are documented at https://libvirt.org/uri.html * * Returns a pointer to the hypervisor connection or NULL in case of error * * Since: 0.4.0 */ virConnectPtr virConnectOpenAuth(constchar *name, virConnectAuthPtr auth, unsignedint flags) { ... ret = virConnectOpenInternal(name, auth, flags); ... return ret; }
//#0 virNetClientProgramCall (prog=prog@entry=0x55555567f410, client=client@entry=0x55555567b010, serial=serial@entry=0, proc=proc@entry=66, noutfds=noutfds@entry=0, outfds=outfds@entry=0x0, ninfds=0x0, infds=0x0, args_filter=0x7ffff767de90 <xdr_void>, args=0x0, ret_filter=0x7ffff7c3f7f0 <xdr_remote_auth_list_ret>, ret=0x7fffffffd8f0) at ../src/rpc/virnetclientprogram.c:271 //#1 0x00007ffff7c5350d in callFull (conn=<optimized out>, ret=0x7fffffffd8f0 "", ret_filter=0x7ffff7c3f7f0 <xdr_remote_auth_list_ret>, args=0x0, args_filter=0x7ffff767de90 <xdr_void>, proc_nr=66, fdoutlen=0x0, fdout=0x0, fdinlen=0, fdin=0x0, flags=flags@entry=0, priv=0x5555556785f0, priv@entry=0x42) at ../src/remote/remote_driver.c:6054 //#2 call (priv=priv@entry=0x5555556785f0, flags=flags@entry=0, proc_nr=proc_nr@entry=66, args_filter=0x7ffff767de90 <xdr_void>, args=args@entry=0x0, ret_filter=0x7ffff7c3f7f0 <xdr_remote_auth_list_ret>, ret=0x7fffffffd8f0 "", conn=<optimized out>) at ../src/remote/remote_driver.c:6076 //#3 0x00007ffff7c63f1e in remoteAuthenticate (conn=0x555555679040, auth=0x7ffff7e38920 <virConnectAuthDefault>, authtype=0x0, priv=0x5555556785f0) at ../src/remote/remote_driver.c:3193 //#4 doRemoteOpen (flags=<optimized out>, conf=0x0, auth=0x7ffff7e38920 <virConnectAuthDefault>, transport=REMOTE_DRIVER_TRANSPORT_UNIX, driver_str=0x0, priv=0x5555556785f0, conn=0x555555679040) at ../src/remote/remote_driver.c:1170 //#5 remoteConnectOpen (conn=0x555555679040, auth=0x7ffff7e38920 <virConnectAuthDefault>, conf=0x0, flags=<optimized out>) at ../src/remote/remote_driver.c:1313 //#6 0x00007ffff7cb338e in virConnectOpenInternal (name=<optimized out>, auth=0x7ffff7e38920 <virConnectAuthDefault>, flags=0) at ../src/libvirt.c:1140 //#7 0x00007ffff7cb3f6e in virConnectOpenAuth (name=name@entry=0x0, auth=0x7ffff7e38920 <virConnectAuthDefault>, flags=flags@entry=0) at ../src/libvirt.c:1283 //#8 0x00005555555924f0 in virshConnect (ctl=ctl@entry=0x7fffffffdba0, uri=0x0, readonly=false) at ../tools/virsh.c:127 //#9 0x00005555555927c3 in virshReconnect (ctl=ctl@entry=0x7fffffffdba0, name=0x0, readonly=<optimized out>, readonly@entry=false, force=force@entry=true) at ../tools/virsh.c:208 //#10 0x000055555559294e in cmdConnect (ctl=0x7fffffffdba0, cmd=0x555555673060) at ../tools/virsh.c:275 //#11 0x00005555555e147f in vshCommandRun (ctl=ctl@entry=0x7fffffffdba0, cmd=0x555555673060) at ../tools/vsh.c:1359 //#12 0x0000555555591f70 in main (argc=argc@entry=2, argv=argv@entry=0x7fffffffdf68) at ../tools/virsh.c:889 //#13 0x00007ffff7429d90 in __libc_start_call_main (main=main@entry=0x555555591410 <main>, argc=argc@entry=2, argv=argv@entry=0x7fffffffdf68) at ../sysdeps/nptl/libc_start_call_main.h:58 //#14 0x00007ffff7429e40 in __libc_start_main_impl (main=0x555555591410 <main>, argc=2, argv=0x7fffffffdf68, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf58) at ../csu/libc-start.c:392 //#15 0x0000555555592145 in _start () static virDrvOpenStatus remoteConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, virConf *conf, unsignedint flags) { g_autofree structprivate_data *priv =NULL; int ret = VIR_DRV_OPEN_ERROR; unsignedint rflags = 0; g_autofree char *driver = NULL; remoteDriverTransport transport;
if (conn->uri) { if (remoteSplitURIScheme(conn->uri, &driver, &transport) < 0) return VIR_DRV_OPEN_ERROR; } else { /* No URI, then must be probing so use UNIX socket */ transport = REMOTE_DRIVER_TRANSPORT_UNIX; }
if (inside_daemon) { if (!conn->uri) return VIR_DRV_OPEN_DECLINED;
/* Handle deferring to local drivers if we are dealing with a default * local URI. (Unknown local socket paths may be proxied to a remote * host so they are treated as remote too). * * Deferring to a local driver is needed if: * - the driver is registered in the current daemon * - if we are running monolithic libvirtd, in which case we consider * even un-registered drivers as local */ if (!conn->uri->server && !virURICheckUnixSocket(conn->uri)) { if (virHasDriverForURIScheme(driver)) return VIR_DRV_OPEN_DECLINED;
if (monolithic_daemon) return VIR_DRV_OPEN_DECLINED; } }
if (!(priv = remoteAllocPrivateData())) return VIR_DRV_OPEN_ERROR;
remoteGetURIDaemonInfo(conn->uri, transport, &rflags); if (flags & VIR_CONNECT_RO) rflags |= REMOTE_DRIVER_OPEN_RO;
ret = doRemoteOpen(conn, priv, driver, transport, auth, conf, rflags); remoteDriverUnlock(priv);
/* * Serial a set of arguments into a method call message, * send that to the server and wait for reply */ staticint callFull(virConnectPtr conn G_GNUC_UNUSED, struct private_data *priv, unsignedint flags, int *fdin, size_t fdinlen, int **fdout, size_t *fdoutlen, int proc_nr, xdrproc_t args_filter, char *args, xdrproc_t ret_filter, char *ret) { ... prog = priv->remoteProgram;
/* Unlock, so that if we get any async events/stream data * while processing the RPC, we don't deadlock when our * callbacks for those are invoked */ remoteDriverUnlock(priv); rv = virNetClientProgramCall(prog, client, counter, proc_nr, fdinlen, fdin, fdoutlen, fdout, args_filter, args, ret_filter, ret); remoteDriverLock(priv); priv->localUses--;
return rv; }
intvirNetClientProgramCall(virNetClientProgram *prog, virNetClient *client, unsigned serial, int proc, size_t noutfds, int *outfds, size_t *ninfds, int **infds, xdrproc_t args_filter, void *args, xdrproc_t ret_filter, void *ret) { virNetMessage *msg; size_t i;
if (infds) *infds = NULL; if (ninfds) *ninfds = 0;
if (!(msg = virNetMessageNew(false))) return-1;
msg->header.prog = prog->program; msg->header.vers = prog->version; msg->header.status = VIR_NET_OK; msg->header.type = noutfds ? VIR_NET_CALL_WITH_FDS : VIR_NET_CALL; msg->header.serial = serial; msg->header.proc = proc; msg->fds = g_new0(int, noutfds); msg->nfds = noutfds; for (i = 0; i < msg->nfds; i++) msg->fds[i] = -1; for (i = 0; i < msg->nfds; i++) { if ((msg->fds[i] = dup(outfds[i])) < 0) { virReportSystemError(errno, _("Cannot duplicate FD %1$d"), outfds[i]); goto error; } if (virSetInherit(msg->fds[i], false) < 0) { virReportSystemError(errno, _("Cannot set close-on-exec %1$d"), msg->fds[i]); goto error; } }
if (virNetMessageEncodeHeader(msg) < 0) goto error;
if (msg->nfds && virNetMessageEncodeNumFDs(msg) < 0) goto error;
if (virNetMessageEncodePayload(msg, args_filter, args) < 0) goto error;
if (virNetClientSendWithReply(client, msg) < 0) goto error;
/* None of these 3 should ever happen here, because * virNetClientSend should have validated the reply, * but it doesn't hurt to check again. */ if (msg->header.type != VIR_NET_REPLY && msg->header.type != VIR_NET_REPLY_WITH_FDS) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected message type %1$d"), msg->header.type); goto error; } if (msg->header.proc != proc) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected message proc %1$d != %2$d"), msg->header.proc, proc); goto error; } if (msg->header.serial != serial) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected message serial %1$d != %2$d"), msg->header.serial, serial); goto error; }
switch (msg->header.status) { case VIR_NET_OK: if (infds && ninfds) { *ninfds = msg->nfds; *infds = g_new0(int, *ninfds);
for (i = 0; i < *ninfds; i++) (*infds)[i] = -1; for (i = 0; i < *ninfds; i++) { if (((*infds)[i] = dup(msg->fds[i])) < 0) { virReportSystemError(errno, _("Cannot duplicate FD %1$d"), msg->fds[i]); goto error; } if (virSetInherit((*infds)[i], false) < 0) { virReportSystemError(errno, _("Cannot set close-on-exec %1$d"), (*infds)[i]); goto error; } }
} if (virNetMessageDecodePayload(msg, ret_filter, ret) < 0) goto error; break;
case VIR_NET_ERROR: virNetClientProgramDispatchError(prog, msg); goto error;
case VIR_NET_CONTINUE: default: virReportError(VIR_ERR_RPC, _("Unexpected message status %1$d"), msg->header.status); goto error; }
//#0 0x0000763d1be003a0 in virNetServerProgramDispatchCall (msg=<optimized out>, client=<optimized out>, server=<optimized out>, prog=<optimized out>) at ../src/rpc/virnetserverprogram.c:373 //#1 virNetServerProgramDispatch (prog=0x591cd6811010, server=server@entry=0x591cd6807880, client=0x591cd681b380, msg=0x591cd6821700) at ../src/rpc/virnetserverprogram.c:299 //#2 0x0000763d1be06538 in virNetServerProcessMsg (msg=<optimized out>, prog=<optimized out>, client=<optimized out>, srv=0x591cd6807880) at ../src/rpc/virnetserver.c:135 //#3 virNetServerHandleJob (jobOpaque=0x591cd67efbd0, opaque=0x591cd6807880) at ../src/rpc/virnetserver.c:155 //#4 0x0000763d1bd3e9f3 in virThreadPoolWorker (opaque=<optimized out>) at ../src/util/virthreadpool.c:164 //#5 0x0000763d1bd3dfe9 in virThreadHelper (data=<optimized out>) at ../src/util/virthread.c:256 //#6 0x0000763d1b694ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442 //#7 0x0000763d1b726850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
/* * @server: the unlocked server object * @client: the unlocked client object * @msg: the complete incoming method call, with header already decoded * * This method is used to dispatch a message representing an * incoming method call from a client. It decodes the payload * to obtain method call arguments, invokes the method and * then sends a reply packet with the return values * * Returns 0 if the reply was sent, or -1 upon fatal error */ staticint virNetServerProgramDispatchCall(virNetServerProgram *prog, virNetServer *server, virNetServerClient *client, virNetMessage *msg) { g_autofree char *arg = NULL; g_autofree char *ret = NULL; int rv = -1; virNetServerProgramProc *dispatcher = NULL; virNetMessageError rerr = { 0 }; size_t i; g_autoptr(virIdentity) identity = NULL;
if (msg->header.status != VIR_NET_OK) { virReportError(VIR_ERR_RPC, _("Unexpected message status %1$u"), msg->header.status); goto error; }
/* If the client is not authenticated, don't allow any RPC ops * which are except for authentication ones */ if (dispatcher->needAuth && !virNetServerClientIsAuthenticated(client)) { /* Explicitly *NOT* calling remoteDispatchAuthError() because we want back-compatibility with libvirt clients which don't support the VIR_ERR_AUTH_FAILED error code */ virReportError(VIR_ERR_RPC, "%s", _("authentication required")); goto error; }
arg = g_new0(char, dispatcher->arg_len); ret = g_new0(char, dispatcher->ret_len);
if (virNetMessageDecodePayload(msg, dispatcher->arg_filter, arg) < 0) goto error;
if (!(identity = virNetServerClientGetIdentity(client))) goto error;
if (virIdentitySetCurrent(identity) < 0) goto error;
/* * When the RPC handler is called: * * - Server object is unlocked * - Client object is unlocked * * Without locking, it is safe to use: * * 'args and 'ret' */ rv = (dispatcher->func)(server, client, msg, &rerr, arg, ret);
if (virIdentitySetCurrent(NULL) < 0) goto error;
/* * If rv == 1, this indicates the dispatch func has * populated 'msg' with a list of FDs to return to * the caller. * * Otherwise we must clear out the FDs we got from * the client originally. * */ if (rv != 1) { for (i = 0; i < msg->nfds; i++) VIR_FORCE_CLOSE(msg->fds[i]); VIR_FREE(msg->fds); msg->nfds = 0; }
if (rv < 0) goto error;
/* Return header. We're re-using same message object, so * only need to tweak type/status fields */ /*msg->header.prog = msg->header.prog;*/ /*msg->header.vers = msg->header.vers;*/ /*msg->header.proc = msg->header.proc;*/ msg->header.type = msg->nfds ? VIR_NET_REPLY_WITH_FDS : VIR_NET_REPLY; /*msg->header.serial = msg->header.serial;*/ msg->header.status = VIR_NET_OK;
if (virNetMessageEncodeHeader(msg) < 0) goto error;
if (msg->nfds && virNetMessageEncodeNumFDs(msg) < 0) goto error;
if (virNetMessageEncodePayload(msg, dispatcher->ret_filter, ret) < 0) goto error;
/* If this connection arrived on a readonly socket, force * the connection to be readonly. */ flags = args->flags; if (virNetServerClientGetReadonly(client)) flags |= VIR_CONNECT_RO;
/* * For libvirtd/virtproxyd one connection handles * all drivers */ VIR_DEBUG("Pointing secondary drivers to primary"); priv->interfaceConn = virObjectRef(priv->conn); priv->networkConn = virObjectRef(priv->conn); priv->nodedevConn = virObjectRef(priv->conn); priv->nwfilterConn = virObjectRef(priv->conn); priv->secretConn = virObjectRef(priv->conn); priv->storageConn = virObjectRef(priv->conn);
/* force update the @readonly attribute which was inherited from the * virNetServerService object - this is important for sockets that are RW * by default, but do accept RO flags, e.g. TCP */ virNetServerClientSetReadonly(client, (flags & VIR_CONNECT_RO)); return0; }
/* Need to do a lookup figure out ID of newly started guest, because * bug in design of REMOTE_PROC_DOMAIN_CREATE means we aren't getting * it returned. */ memcpy(args2.uuid, domain->uuid, VIR_UUID_BUFLEN); if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_LOOKUP_BY_UUID, (xdrproc_t) xdr_remote_domain_lookup_by_uuid_args, (char *) &args2, (xdrproc_t) xdr_remote_domain_lookup_by_uuid_ret, (char *) &ret2) == -1) return-1;
virConnectPtr conn = remoteGetHypervisorConn(client); if (!conn) goto cleanup;
if (!(dom = get_nonnull_domain(conn, args->dom))) goto cleanup;
if (virDomainCreate(dom) < 0) goto cleanup;
rv = 0; ... return rv; }
/** * virDomainCreate: * @domain: pointer to a defined domain * * Launch a defined domain. If the call succeeds the domain moves from the * defined to the running domains pools. The domain will be paused only * if restoring from managed state created from a paused domain. For more * control, see virDomainCreateWithFlags(). * * Returns 0 in case of success, -1 in case of error * * Since: 0.1.1 */ int virDomainCreate(virDomainPtr domain) { virConnectPtr conn;
staticvoid qemuMonitorUpdateWatch(qemuMonitor *mon) { qemuMonitorUnregister(mon); if (mon->socket) qemuMonitorRegister(mon); }
/** * qemuMonitorRegister: * @mon: QEMU monitor * * Registers the monitor in the event loop. The caller has to hold the * lock for @mon. */ void qemuMonitorRegister(qemuMonitor *mon) { GIOCondition cond = 0;
if (mon->lastError.code == VIR_ERR_OK) { cond |= G_IO_IN;
evt->thread = g_thread_try_new(thname, virEventThreadWorker, data, &gerr); if (!evt->thread) { virEventThreadDataFree(data); virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to start event thread: %1$s"), gerr->message); return-1; }
g_mutex_lock(&data->lock); while (!data->running) g_cond_wait(&data->cond, &data->lock); g_mutex_unlock(&data->lock);
return0; }
staticvoid * virEventThreadWorker(void *opaque) { virEventThreadData *data = opaque; /* * Do NOT use g_autoptr on this. We need to unref it * before the GMainContext is unrefed */ GSource *running = g_idle_source_new();
//#0 qmp_dispatch (cmds=0x6201acdc5a50 <qmp_commands>, request=0x7850a8007630, allow_oob=false, cur_mon=0x6201acf6ecf0) at ../qapi/qmp-dispatch.c:139 //#1 0x00006201abd3f930 in monitor_qmp_dispatch (mon=0x6201acf6ecf0, req=0x7850a8007630) at ../monitor/qmp.c:168 //#2 0x00006201abd3fe66 in monitor_qmp_dispatcher_co (data=0x0) at ../monitor/qmp.c:335 //#3 0x00006201abe32f87 in coroutine_trampoline (i0=-1393168112, i1=25089) at ../util/coroutine-ucontext.c:175 //#4 0x00007851b845a130 in __start_context () at ../sysdeps/unix/sysv/linux/x86_64/__start_context.S:90 //#5 0x00007fffe3b98b50 in () //#6 0x0000000000000000 in () /* * Runs outside of coroutine context for OOB commands, but in coroutine * context for everything else. */ QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *request, bool allow_oob, Monitor *cur_mon) { /* * Actual context doesn't match the one the command needs. * * Case 1: we are in coroutine context, but command does not * have QCO_COROUTINE. We need to drop out of coroutine * context for executing it. * * Case 2: we are outside coroutine context, but command has * QCO_COROUTINE. Can't actually happen, because we get here * outside coroutine context only when executing a command * out of band, and OOB commands never have QCO_COROUTINE. */ assert(!oob && qemu_in_coroutine() && !(cmd->options & QCO_COROUTINE));
//#0 qmp_query_kvm (errp=0x7fffe3b99208) at ../hw/core/machine-qmp-cmds.c:238 //#1 0x00006201abd9dba4 in qmp_marshal_query_kvm (args=0x7850a8008650, ret=0x7851b7fbbda8, errp=0x7851b7fbbda0) at qapi/qapi-commands-machine.c:584 //#2 0x00006201abe00d45 in do_qmp_dispatch_bh (opaque=0x7851b7fbbe40) at ../qapi/qmp-dispatch.c:128 //#3 0x00006201abe2e5c8 in aio_bh_call (bh=0x6201ad4d3000) at ../util/async.c:171 //#4 0x00006201abe2e6ef in aio_bh_poll (ctx=0x6201acf5f250) at ../util/async.c:218 //#5 0x00006201abe0ee59 in aio_dispatch (ctx=0x6201acf5f250) at ../util/aio-posix.c:423 //#6 0x00006201abe2eb84 in aio_ctx_dispatch (source=0x6201acf5f250, callback=0x0, user_data=0x0) at ../util/async.c:360 //#7 0x00007851b8992d3b in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 //#8 0x00006201abe3020f in glib_pollfds_poll () at ../util/main-loop.c:287 //#9 0x00006201abe3029a in os_host_main_loop_wait (timeout=0) at ../util/main-loop.c:310 //#10 0x00006201abe303c6 in main_loop_wait (nonblocking=0) at ../util/main-loop.c:589 //#11 0x00006201ab932fc7 in qemu_main_loop () at ../system/runstate.c:783 //#12 0x00006201abbf4002 in qemu_default_main () at ../system/main.c:37 //#13 0x00006201abbf4043 in main (argc=64, argv=0x7fffe3b99618) at ../system/main.c:48 //#14 0x00007851b8429d90 in __libc_start_call_main (main=main@entry=0x6201abbf4016 <main>, argc=argc@entry=64, argv=argv@entry=0x7fffe3b99618) at ../sysdeps/nptl/libc_start_call_main.h:58 //#15 0x00007851b8429e40 in __libc_start_main_impl (main=0x6201abbf4016 <main>, argc=64, argv=0x7fffe3b99618, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffe3b99608) at ../csu/libc-start.c:392 //#16 0x00006201ab5ca675 in _start () voidqmp_marshal_query_kvm(QDict *args, QObject **ret, Error **errp) { Error *err = NULL; bool ok = false; Visitor *v; KvmInfo *retval;
v = qobject_input_visitor_new_qmp(QOBJECT(args)); if (!visit_start_struct(v, NULL, NULL, 0, errp)) { goto out; } ok = visit_check_struct(v, errp); visit_end_struct(v, NULL); if (!ok) { goto out; }
if (trace_event_get_state_backends(TRACE_QMP_ENTER_QUERY_KVM)) { g_autoptr(GString) req_json = qobject_to_json(QOBJECT(args));
/* * Runs outside of coroutine context for OOB commands, but in coroutine * context for everything else. */ QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *request, bool allow_oob, Monitor *cur_mon) { ... /* * Actual context doesn't match the one the command needs. * * Case 1: we are in coroutine context, but command does not * have QCO_COROUTINE. We need to drop out of coroutine * context for executing it. * * Case 2: we are outside coroutine context, but command has * QCO_COROUTINE. Can't actually happen, because we get here * outside coroutine context only when executing a command * out of band, and OOB commands never have QCO_COROUTINE. */ assert(!oob && qemu_in_coroutine() && !(cmd->options & QCO_COROUTINE));
static gboolean qemuMonitorIO(GSocket *socket G_GNUC_UNUSED, GIOCondition cond, gpointer opaque) { if (!error && cond & G_IO_IN) { int got = qemuMonitorIORead(mon); if (got < 0) { error = true; if (errno == ECONNRESET) hangup = true; } elseif (got == 0) { mon->goteof = true; } else { /* Ignore hangup/error cond if we read some data, to * give time for that data to be consumed */ cond = 0;
if (qemuMonitorIOProcess(mon) < 0) error = true; } }
/* * Called when the monitor has incoming data to read * Call this function while holding the monitor lock. * * Returns -1 on error, or number of bytes read */ staticint qemuMonitorIORead(qemuMonitor *mon) { size_t avail = mon->bufferLength - mon->bufferOffset; int ret = 0;
/* Read as much as we can get into our buffer, until we block on EAGAIN, or hit EOF */ while (avail > 1) { int got; got = read(mon->fd, mon->buffer + mon->bufferOffset, avail - 1); if (got < 0) { if (errno == EAGAIN) break; virReportSystemError(errno, "%s", _("Unable to read from monitor")); ret = -1; break; } if (got == 0) break;
/* This method processes data that has been received * from the monitor. Looking for async events and * replies/errors. */ staticint qemuMonitorIOProcess(qemuMonitor *mon) { int len; qemuMonitorMessage *msg = NULL;
/* See if there's a message & whether its ready for its reply * ie whether its completed writing all its data */ if (mon->msg && mon->msg->txOffset == mon->msg->txLength) msg = mon->msg;
len = qemuMonitorJSONIOProcess(mon, mon->buffer, mon->bufferOffset, msg); if (len < 0) return-1;
if (len && mon->waitGreeting) mon->waitGreeting = false;
if (len < mon->bufferOffset) { memmove(mon->buffer, mon->buffer + len, mon->bufferOffset - len); mon->bufferOffset -= len; } else { VIR_FREE(mon->buffer); mon->bufferOffset = mon->bufferLength = 0; } /* As the monitor mutex was unlocked in qemuMonitorJSONIOProcess() * while dealing with qemu event, mon->msg could be changed which * means the above 'msg' may be invalid, thus we use 'mon->msg' here */ if (mon->msg && mon->msg->finished) virCondBroadcast(&mon->notify); return len; }
intqemuMonitorJSONIOProcess(qemuMonitor *mon, constchar *data, size_t len, qemuMonitorMessage *msg) { int used = 0; /*VIR_DEBUG("Data %d bytes [%s]", len, data);*/