On 1/10/20 11:34 AM, Daniel P. Berrangé wrote: > The driver URI scheme: > > "$drivername:///embed?root=/some/path" > > enables a new way to use the drivers by embedding them directly in the > calling process. To use this the process must have a thread running the > libvirt event loop. This URI will then cause libvirt to dynamically load > the driver module and call its global initialization function. This > syntax is applicable to any driver, but only those will have been > modified to support a custom root directory and embed URI path will > successfully open. > > The application can now make normal libvirt API calls which are all > serviced in-process with no RPC layer involved. > > It is required to specify an explicit root directory, and locks will be > acquired on this directory to avoid conflicting with another app that > might accidentally pick the same directory. > > Use of '/' is not explicitly forbidden, but note that the file layout > used underneath the embedded driver root does not match the file > layout used by system/session mode drivers. So this cannot be used as > a backdoor to interact with, or fake, the system/session mode drivers. > > Libvirt will create arbitrary files underneath this root directory. The > root directory can be kept untouched across connection open attempts if > the application needs persistence. The application is responsible for > purging everything underneath this root directory when finally no longer > required. > > Even when a virt driver is used in embedded mode, it is still possible > for it to in turn use functionality that calls out to other secondary > drivers in libvirtd. For example an embedded instance of QEMU can open > the network, secret or storage drivers in the system libvirtd. > > That said, the application would typically want to at least open an > embedded secret driver ("secret:///embed?root=/some/path"). Note that > multiple different embedded drivers can use the same root prefix and > co-operate just as they would inside a normal libvirtd daemon. > > A key thing to note is that for this to work, the application that links > to libvirt *MUST* be built with -Wl,--export-dynamic to ensure that > symbols from libvirt.so are exported & thus available to the dynamically > loaded driver module. If libvirt.so itself was dynamically loaded then > RTLD_GLOBAL must be passed to dlopen(). > > Reviewed-by: Michal Privoznik <mprivozn@xxxxxxxxxx> > Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> > --- > src/driver-state.h | 1 + > src/driver.h | 2 ++ > src/libvirt.c | 72 ++++++++++++++++++++++++++++++++++++++++++++-- > 3 files changed, 73 insertions(+), 2 deletions(-) > > diff --git a/src/libvirt.c b/src/libvirt.c > index 4de87cdecd..5599d5ff31 100644 > --- a/src/libvirt.c > +++ b/src/libvirt.c > @@ -934,6 +939,52 @@ virConnectOpenInternal(const char *name, > ret->uri) < 0) { > goto failed; > } > + > + if (STREQ(ret->uri->path, "/embed")) { > + const char *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 '%s' for embedded driver is not valid"), > + ret->uri->scheme); > + goto failed; > + } > + > + for (i = 0; i < ret->uri->paramsCount; i++) { > + virURIParamPtr var = &ret->uri->params[i]; > + if (STREQ(var->name, "root")) > + root = var->value; > + } > + > + if (!root) { > + virReportError(VIR_ERR_INVALID_ARG, "%s", > + _("root parameter required for embedded driver")); > + goto failed; > + } Or use virURIGetParam() you've introduced two patches ago. > + > + if (virEventRequireImpl() < 0) > + goto failed; > + > + regMethod = g_strdup_printf("%sRegister", ret->uri->scheme); > + > + if (virDriverLoadModule(ret->uri->scheme, regMethod, false) < 0) > + goto failed; > + > + if (virAccessManagerGetDefault() == NULL) { If this is true, then an error is reported. Should we reset the error then? > + virAccessManagerPtr acl = virAccessManagerNew("none"); > + if (!acl) > + goto failed; > + virAccessManagerSetDefault(acl); > + } > + > + if (virStateInitialize(geteuid() == 0, true, root, NULL, NULL) < 0) > + goto failed; > + > + embed = true; > + } > } else { > VIR_DEBUG("no name, allowing driver auto-select"); > } Michal