1 /*
2 * driver.c: Helpers for loading drivers
3 *
4 * Copyright (C) 2006-2011 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22
23 #include <config.h>
24
25 #include <unistd.h>
26
27 #include "driver.h"
28 #include "viralloc.h"
29 #include "virfile.h"
30 #include "virlog.h"
31 #include "virmodule.h"
32 #include "virobject.h"
33 #include "virstring.h"
34 #include "virthread.h"
35 #include "virutil.h"
36 #include "viridentity.h"
37 #include "datatypes.h"
38 #include "configmake.h"
39
40 VIR_LOG_INIT("driver");
41
42 #define VIR_FROM_THIS VIR_FROM_NONE
43
44 /* XXX re-implement this for other OS, or use libtools helper lib ? */
45 #define DEFAULT_DRIVER_DIR LIBDIR "/libvirt/connection-driver"
46
47
48
49 int
virDriverLoadModule(const char * name,const char * regfunc,bool required)50 virDriverLoadModule(const char *name,
51 const char *regfunc,
52 bool required)
53 {
54 g_autofree char *modfile = NULL;
55
56 VIR_DEBUG("Module load %s", name);
57
58 if (!(modfile = virFileFindResourceFull(name,
59 "libvirt_driver_",
60 VIR_FILE_MODULE_EXT,
61 abs_top_builddir "/src",
62 DEFAULT_DRIVER_DIR,
63 "LIBVIRT_DRIVER_DIR")))
64 return -1;
65
66 return virModuleLoad(modfile, regfunc, required);
67 }
68
69
70 /* XXX unload modules, but we can't until we can unregister libvirt drivers */
71
72 /**
73 * virDriverShouldAutostart:
74 * @dir: driver's run state directory (usually /var/run/libvirt/$driver)
75 * @autostart: whether driver should initiate autostart
76 *
77 * Automatic starting of libvirt's objects (e.g. domains, networks, storage
78 * pools, etc.) doesn't play nice with using '--timeout' on daemon's command
79 * line because the objects are attempted to autostart on every start of
80 * corresponding driver/daemon. To resolve this problem, a file is created in
81 * driver's private directory (which doesn't survive host's reboot) and thus
82 * autostart is attempted only once.
83 */
84 int
virDriverShouldAutostart(const char * dir,bool * autostart)85 virDriverShouldAutostart(const char *dir,
86 bool *autostart)
87 {
88 g_autofree char *path = NULL;
89
90 *autostart = false;
91
92 path = g_strdup_printf("%s/autostarted", dir);
93
94 if (virFileExists(path)) {
95 VIR_DEBUG("Autostart file %s exists, skipping autostart", path);
96 return 0;
97 }
98
99 VIR_DEBUG("Autostart file %s does not exist, do autostart", path);
100 *autostart = true;
101
102 if (virFileTouch(path, 0600) < 0)
103 return -1;
104
105 return 0;
106 }
107
108
109 virThreadLocal connectInterface;
110 virThreadLocal connectNetwork;
111 virThreadLocal connectNWFilter;
112 virThreadLocal connectNodeDev;
113 virThreadLocal connectSecret;
114 virThreadLocal connectStorage;
115
116 static int
virConnectCacheOnceInit(void)117 virConnectCacheOnceInit(void)
118 {
119 if (virThreadLocalInit(&connectInterface, NULL) < 0 ||
120 virThreadLocalInit(&connectNetwork, NULL) < 0 ||
121 virThreadLocalInit(&connectNWFilter, NULL) < 0 ||
122 virThreadLocalInit(&connectNodeDev, NULL) < 0 ||
123 virThreadLocalInit(&connectSecret, NULL) < 0 ||
124 virThreadLocalInit(&connectStorage, NULL) < 0) {
125 virReportSystemError(errno, "%s",
126 _("Unable to initialize thread local variable"));
127 return -1;
128 }
129
130 return 0;
131 }
132
133 VIR_ONCE_GLOBAL_INIT(virConnectCache);
134
135 static virConnectPtr
virGetConnectGeneric(virThreadLocal * threadPtr,const char * name)136 virGetConnectGeneric(virThreadLocal *threadPtr, const char *name)
137 {
138 virConnectPtr conn;
139 virErrorPtr orig_err;
140
141 if (virConnectCacheInitialize() < 0)
142 return NULL;
143
144 conn = virThreadLocalGet(threadPtr);
145
146 if (conn) {
147 VIR_DEBUG("Return cached %s connection %p", name, conn);
148 virObjectRef(conn);
149 } else {
150 g_autofree char *uri = NULL;
151 const char *uriPath = geteuid() == 0 ? "/system" : "/session";
152
153 uri = g_strdup_printf("%s://%s", name, uriPath);
154
155 conn = virConnectOpen(uri);
156 VIR_DEBUG("Opened new %s connection %p", name, conn);
157 if (!conn)
158 return NULL;
159
160 if (conn->driver->connectSetIdentity != NULL) {
161 g_autoptr(virIdentity) ident = NULL;
162 virTypedParameterPtr identparams = NULL;
163 int nidentparams = 0;
164
165 VIR_DEBUG("Attempting to delegate current identity");
166 if (!(ident = virIdentityGetCurrent()))
167 goto error;
168
169 if (virIdentityGetParameters(ident, &identparams, &nidentparams) < 0)
170 goto error;
171
172 if (virConnectSetIdentity(conn, identparams, nidentparams, 0) < 0)
173 goto error;
174 }
175 }
176 return conn;
177
178 error:
179 virErrorPreserveLast(&orig_err);
180 virConnectClose(conn);
181 virErrorRestore(&orig_err);
182 return NULL;
183 }
184
185
virGetConnectInterface(void)186 virConnectPtr virGetConnectInterface(void)
187 {
188 return virGetConnectGeneric(&connectInterface, "interface");
189 }
190
virGetConnectNetwork(void)191 virConnectPtr virGetConnectNetwork(void)
192 {
193 return virGetConnectGeneric(&connectNetwork, "network");
194 }
195
virGetConnectNWFilter(void)196 virConnectPtr virGetConnectNWFilter(void)
197 {
198 return virGetConnectGeneric(&connectNWFilter, "nwfilter");
199 }
200
virGetConnectNodeDev(void)201 virConnectPtr virGetConnectNodeDev(void)
202 {
203 return virGetConnectGeneric(&connectNodeDev, "nodedev");
204 }
205
virGetConnectSecret(void)206 virConnectPtr virGetConnectSecret(void)
207 {
208 return virGetConnectGeneric(&connectSecret, "secret");
209 }
210
virGetConnectStorage(void)211 virConnectPtr virGetConnectStorage(void)
212 {
213 return virGetConnectGeneric(&connectStorage, "storage");
214 }
215
216
217 int
virSetConnectInterface(virConnectPtr conn)218 virSetConnectInterface(virConnectPtr conn)
219 {
220 if (virConnectCacheInitialize() < 0)
221 return -1;
222
223 VIR_DEBUG("Override interface connection with %p", conn);
224 return virThreadLocalSet(&connectInterface, conn);
225 }
226
227
228 int
virSetConnectNetwork(virConnectPtr conn)229 virSetConnectNetwork(virConnectPtr conn)
230 {
231 if (virConnectCacheInitialize() < 0)
232 return -1;
233
234 VIR_DEBUG("Override network connection with %p", conn);
235 return virThreadLocalSet(&connectNetwork, conn);
236 }
237
238
239 int
virSetConnectNWFilter(virConnectPtr conn)240 virSetConnectNWFilter(virConnectPtr conn)
241 {
242 if (virConnectCacheInitialize() < 0)
243 return -1;
244
245 VIR_DEBUG("Override nwfilter connection with %p", conn);
246 return virThreadLocalSet(&connectNWFilter, conn);
247 }
248
249
250 int
virSetConnectNodeDev(virConnectPtr conn)251 virSetConnectNodeDev(virConnectPtr conn)
252 {
253 if (virConnectCacheInitialize() < 0)
254 return -1;
255
256 VIR_DEBUG("Override nodedev connection with %p", conn);
257 return virThreadLocalSet(&connectNodeDev, conn);
258 }
259
260
261 int
virSetConnectSecret(virConnectPtr conn)262 virSetConnectSecret(virConnectPtr conn)
263 {
264 if (virConnectCacheInitialize() < 0)
265 return -1;
266
267 VIR_DEBUG("Override secret connection with %p", conn);
268 return virThreadLocalSet(&connectSecret, conn);
269 }
270
271
272 int
virSetConnectStorage(virConnectPtr conn)273 virSetConnectStorage(virConnectPtr conn)
274 {
275 if (virConnectCacheInitialize() < 0)
276 return -1;
277
278 VIR_DEBUG("Override storage connection with %p", conn);
279 return virThreadLocalSet(&connectStorage, conn);
280 }
281
282 bool
virConnectValidateURIPath(const char * uriPath,const char * entityName,bool privileged)283 virConnectValidateURIPath(const char *uriPath,
284 const char *entityName,
285 bool privileged)
286 {
287 if (privileged) {
288 /* TODO: qemu and vbox drivers allow '/session'
289 * connections as root. This is not ideal, but changing
290 * these drivers to refuse privileged '/session'
291 * connections, like everyone else is already doing, can
292 * break existing applications. Until we decide what to do,
293 * for now we can handle them as exception in this validate
294 * function.
295 */
296 bool compatSessionRoot = (STREQ(entityName, "qemu") ||
297 STREQ(entityName, "vbox")) &&
298 STREQ(uriPath, "/session");
299
300 if (STRNEQ(uriPath, "/system") && !compatSessionRoot) {
301 virReportError(VIR_ERR_INTERNAL_ERROR,
302 _("unexpected %s URI path '%s', try "
303 "%s:///system"),
304 entityName, uriPath, entityName);
305 return false;
306 }
307 } else {
308 if (STRNEQ(uriPath, "/session")) {
309 virReportError(VIR_ERR_INTERNAL_ERROR,
310 _("unexpected %s URI path '%s', try "
311 "%s:///session"),
312 entityName, uriPath, entityName);
313 return false;
314 }
315 }
316
317 return true;
318 }
319