1 /*
2  * Copyright (C) 2010-2014 Red Hat, Inc.
3  * Copyright IBM Corp. 2008
4  *
5  * lxc_domain.h: LXC domain helpers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library.  If not, see
19  * <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 
24 #include "lxc_domain.h"
25 
26 #include "virlog.h"
27 #include "virerror.h"
28 #include "virstring.h"
29 #include "virfile.h"
30 #include "virtime.h"
31 #include "virsystemd.h"
32 #include "virinitctl.h"
33 #include "domain_driver.h"
34 
35 #define VIR_FROM_THIS VIR_FROM_LXC
36 
37 VIR_ENUM_IMPL(virLXCDomainJob,
38               LXC_JOB_LAST,
39               "none",
40               "query",
41               "destroy",
42               "modify",
43 );
44 
45 VIR_LOG_INIT("lxc.lxc_domain");
46 
47 static int
virLXCDomainObjInitJob(virLXCDomainObjPrivate * priv)48 virLXCDomainObjInitJob(virLXCDomainObjPrivate *priv)
49 {
50     memset(&priv->job, 0, sizeof(priv->job));
51 
52     if (virCondInit(&priv->job.cond) < 0)
53         return -1;
54 
55     return 0;
56 }
57 
58 static void
virLXCDomainObjResetJob(virLXCDomainObjPrivate * priv)59 virLXCDomainObjResetJob(virLXCDomainObjPrivate *priv)
60 {
61     struct virLXCDomainJobObj *job = &priv->job;
62 
63     job->active = LXC_JOB_NONE;
64     job->owner = 0;
65 }
66 
67 static void
virLXCDomainObjFreeJob(virLXCDomainObjPrivate * priv)68 virLXCDomainObjFreeJob(virLXCDomainObjPrivate *priv)
69 {
70     ignore_value(virCondDestroy(&priv->job.cond));
71 }
72 
73 /* Give up waiting for mutex after 30 seconds */
74 #define LXC_JOB_WAIT_TIME (1000ull * 30)
75 
76 /*
77  * obj must be locked before calling, virLXCDriver *must NOT be locked
78  *
79  * This must be called by anything that will change the VM state
80  * in any way
81  *
82  * Upon successful return, the object will have its ref count increased.
83  * Successful calls must be followed by EndJob eventually.
84  */
85 int
virLXCDomainObjBeginJob(virLXCDriver * driver G_GNUC_UNUSED,virDomainObj * obj,enum virLXCDomainJob job)86 virLXCDomainObjBeginJob(virLXCDriver *driver G_GNUC_UNUSED,
87                        virDomainObj *obj,
88                        enum virLXCDomainJob job)
89 {
90     virLXCDomainObjPrivate *priv = obj->privateData;
91     unsigned long long now;
92     unsigned long long then;
93 
94     if (virTimeMillisNow(&now) < 0)
95         return -1;
96     then = now + LXC_JOB_WAIT_TIME;
97 
98     while (priv->job.active) {
99         VIR_DEBUG("Wait normal job condition for starting job: %s",
100                   virLXCDomainJobTypeToString(job));
101         if (virCondWaitUntil(&priv->job.cond, &obj->parent.lock, then) < 0)
102             goto error;
103     }
104 
105     virLXCDomainObjResetJob(priv);
106 
107     VIR_DEBUG("Starting job: %s", virLXCDomainJobTypeToString(job));
108     priv->job.active = job;
109     priv->job.owner = virThreadSelfID();
110 
111     return 0;
112 
113  error:
114     VIR_WARN("Cannot start job (%s) for domain %s;"
115              " current job is (%s) owned by (%d)",
116              virLXCDomainJobTypeToString(job),
117              obj->def->name,
118              virLXCDomainJobTypeToString(priv->job.active),
119              priv->job.owner);
120 
121     if (errno == ETIMEDOUT)
122         virReportError(VIR_ERR_OPERATION_TIMEOUT,
123                        "%s", _("cannot acquire state change lock"));
124     else
125         virReportSystemError(errno,
126                              "%s", _("cannot acquire job mutex"));
127     return -1;
128 }
129 
130 
131 /*
132  * obj must be locked and have a reference before calling
133  *
134  * To be called after completing the work associated with the
135  * earlier virLXCDomainBeginJob() call
136  */
137 void
virLXCDomainObjEndJob(virLXCDriver * driver G_GNUC_UNUSED,virDomainObj * obj)138 virLXCDomainObjEndJob(virLXCDriver *driver G_GNUC_UNUSED,
139                      virDomainObj *obj)
140 {
141     virLXCDomainObjPrivate *priv = obj->privateData;
142     enum virLXCDomainJob job = priv->job.active;
143 
144     VIR_DEBUG("Stopping job: %s",
145               virLXCDomainJobTypeToString(job));
146 
147     virLXCDomainObjResetJob(priv);
148     virCondSignal(&priv->job.cond);
149 }
150 
151 
152 static void *
virLXCDomainObjPrivateAlloc(void * opaque G_GNUC_UNUSED)153 virLXCDomainObjPrivateAlloc(void *opaque G_GNUC_UNUSED)
154 {
155     virLXCDomainObjPrivate *priv = g_new0(virLXCDomainObjPrivate, 1);
156 
157     if (virLXCDomainObjInitJob(priv) < 0) {
158         g_free(priv);
159         return NULL;
160     }
161 
162     return priv;
163 }
164 
165 
166 static void
virLXCDomainObjPrivateFree(void * data)167 virLXCDomainObjPrivateFree(void *data)
168 {
169     virLXCDomainObjPrivate *priv = data;
170 
171     virCgroupFree(priv->cgroup);
172     virLXCDomainObjFreeJob(priv);
173     g_free(priv);
174 }
175 
176 
177 
178 VIR_ENUM_IMPL(virLXCDomainNamespace,
179               VIR_LXC_DOMAIN_NAMESPACE_LAST,
180               "sharenet",
181               "shareipc",
182               "shareuts",
183 );
184 
185 VIR_ENUM_IMPL(virLXCDomainNamespaceSource,
186               VIR_LXC_DOMAIN_NAMESPACE_SOURCE_LAST,
187               "none",
188               "name",
189               "pid",
190               "netns",
191 );
192 
193 static void
lxcDomainDefNamespaceFree(void * nsdata)194 lxcDomainDefNamespaceFree(void *nsdata)
195 {
196     size_t i;
197     lxcDomainDef *lxcDef = nsdata;
198 
199     if (!lxcDef)
200         return;
201 
202     for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++)
203         g_free(lxcDef->ns_val[i]);
204     g_free(nsdata);
205 }
206 
207 static int
lxcDomainDefNamespaceParse(xmlXPathContextPtr ctxt,void ** data)208 lxcDomainDefNamespaceParse(xmlXPathContextPtr ctxt,
209                            void **data)
210 {
211     lxcDomainDef *lxcDef = NULL;
212     g_autofree xmlNodePtr *nodes = NULL;
213     VIR_XPATH_NODE_AUTORESTORE(ctxt)
214     int n;
215     size_t i;
216     int ret = -1;
217 
218     if ((n = virXPathNodeSet("./lxc:namespace/*", ctxt, &nodes)) < 0)
219         return -1;
220 
221     if (n == 0)
222         return 0;
223 
224     lxcDef = g_new0(lxcDomainDef, 1);
225 
226     for (i = 0; i < n; i++) {
227         g_autofree char *tmp = NULL;
228         int feature;
229 
230         if ((feature = virLXCDomainNamespaceTypeFromString(
231                  (const char *)nodes[i]->name)) < 0) {
232             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
233                            _("unsupported Namespace feature: %s"),
234                            nodes[i]->name);
235             goto cleanup;
236         }
237 
238         ctxt->node = nodes[i];
239 
240         if (!(tmp = virXMLPropString(nodes[i], "type"))) {
241             virReportError(VIR_ERR_INTERNAL_ERROR,
242                            "%s", _("No lxc environment type specified"));
243             goto cleanup;
244         }
245         if ((lxcDef->ns_source[feature] =
246              virLXCDomainNamespaceSourceTypeFromString(tmp)) < 0) {
247             virReportError(VIR_ERR_INTERNAL_ERROR,
248                            _("Unknown LXC namespace source '%s'"),
249                            tmp);
250             goto cleanup;
251         }
252 
253         if (!(lxcDef->ns_val[feature] =
254               virXMLPropString(nodes[i], "value"))) {
255             virReportError(VIR_ERR_INTERNAL_ERROR,
256                            "%s", _("No lxc environment type specified"));
257             goto cleanup;
258         }
259     }
260 
261     *data = g_steal_pointer(&lxcDef);
262     ret = 0;
263 
264  cleanup:
265     lxcDomainDefNamespaceFree(lxcDef);
266     return ret;
267 }
268 
269 
270 static int
lxcDomainDefNamespaceFormatXML(virBuffer * buf,void * nsdata)271 lxcDomainDefNamespaceFormatXML(virBuffer *buf,
272                                void *nsdata)
273 {
274     lxcDomainDef *lxcDef = nsdata;
275     size_t i;
276 
277     if (!lxcDef)
278        return 0;
279 
280     virBufferAddLit(buf, "<lxc:namespace>\n");
281     virBufferAdjustIndent(buf, 2);
282 
283     for (i = 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) {
284         if (lxcDef->ns_source[i] == VIR_LXC_DOMAIN_NAMESPACE_SOURCE_NONE)
285             continue;
286 
287         virBufferAsprintf(buf, "<lxc:%s type='%s' value='%s'/>\n",
288                           virLXCDomainNamespaceTypeToString(i),
289                           virLXCDomainNamespaceSourceTypeToString(
290                               lxcDef->ns_source[i]),
291                           lxcDef->ns_val[i]);
292     }
293 
294     virBufferAdjustIndent(buf, -2);
295     virBufferAddLit(buf, "</lxc:namespace>\n");
296     return 0;
297 }
298 
299 
300 virXMLNamespace virLXCDriverDomainXMLNamespace = {
301     .parse = lxcDomainDefNamespaceParse,
302     .free = lxcDomainDefNamespaceFree,
303     .format = lxcDomainDefNamespaceFormatXML,
304     .prefix = "lxc",
305     .uri = "http://libvirt.org/schemas/domain/lxc/1.0",
306 };
307 
308 
309 static int
virLXCDomainObjPrivateXMLFormat(virBuffer * buf,virDomainObj * vm)310 virLXCDomainObjPrivateXMLFormat(virBuffer *buf,
311                                 virDomainObj *vm)
312 {
313     virLXCDomainObjPrivate *priv = vm->privateData;
314 
315     virBufferAsprintf(buf, "<init pid='%lld'/>\n",
316                       (long long)priv->initpid);
317 
318     return 0;
319 }
320 
321 static int
virLXCDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,virDomainObj * vm,virDomainDefParserConfig * config G_GNUC_UNUSED)322 virLXCDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,
323                                virDomainObj *vm,
324                                virDomainDefParserConfig *config G_GNUC_UNUSED)
325 {
326     virLXCDomainObjPrivate *priv = vm->privateData;
327     long long thepid;
328 
329     if (virXPathLongLong("string(./init[1]/@pid)", ctxt, &thepid) < 0) {
330         VIR_WARN("Failed to load init pid from state %s",
331                  virGetLastErrorMessage());
332         priv->initpid = 0;
333     } else {
334         priv->initpid = thepid;
335     }
336 
337     return 0;
338 }
339 
340 virDomainXMLPrivateDataCallbacks virLXCDriverPrivateDataCallbacks = {
341     .alloc = virLXCDomainObjPrivateAlloc,
342     .free = virLXCDomainObjPrivateFree,
343     .format = virLXCDomainObjPrivateXMLFormat,
344     .parse  = virLXCDomainObjPrivateXMLParse,
345 };
346 
347 static int
virLXCDomainDefPostParse(virDomainDef * def,unsigned int parseFlags G_GNUC_UNUSED,void * opaque,void * parseOpaque G_GNUC_UNUSED)348 virLXCDomainDefPostParse(virDomainDef *def,
349                          unsigned int parseFlags G_GNUC_UNUSED,
350                          void *opaque,
351                          void *parseOpaque G_GNUC_UNUSED)
352 {
353     virLXCDriver *driver = opaque;
354     g_autoptr(virCaps) caps = virLXCDriverGetCapabilities(driver, false);
355     if (!caps)
356         return -1;
357     if (!virCapabilitiesDomainSupported(caps, def->os.type,
358                                         def->os.arch,
359                                         def->virtType))
360         return -1;
361 
362     /* check for emulator and create a default one if needed */
363     if (!def->emulator &&
364         !(def->emulator = virDomainDefGetDefaultEmulator(def, caps)))
365         return -1;
366 
367     return 0;
368 }
369 
370 
371 static int
virLXCDomainDeviceDefPostParse(virDomainDeviceDef * dev,const virDomainDef * def G_GNUC_UNUSED,unsigned int parseFlags G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED,void * parseOpaque G_GNUC_UNUSED)372 virLXCDomainDeviceDefPostParse(virDomainDeviceDef *dev,
373                                const virDomainDef *def G_GNUC_UNUSED,
374                                unsigned int parseFlags G_GNUC_UNUSED,
375                                void *opaque G_GNUC_UNUSED,
376                                void *parseOpaque G_GNUC_UNUSED)
377 {
378     if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
379         dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
380         dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
381         dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC;
382 
383     return 0;
384 }
385 
386 
387 virDomainDefParserConfig virLXCDriverDomainDefParserConfig = {
388     .domainPostParseCallback = virLXCDomainDefPostParse,
389     .devicesPostParseCallback = virLXCDomainDeviceDefPostParse,
390 };
391 
392 
393 char *
virLXCDomainGetMachineName(virDomainDef * def,pid_t pid)394 virLXCDomainGetMachineName(virDomainDef *def, pid_t pid)
395 {
396     char *ret = NULL;
397 
398     if (pid) {
399         ret = virSystemdGetMachineNameByPID(pid);
400         if (!ret)
401             virResetLastError();
402     }
403 
404     if (!ret)
405         ret = virDomainDriverGenerateMachineName("lxc", NULL, def->id, def->name, true);
406 
407     return ret;
408 }
409 
410 
411 typedef struct _lxcDomainInitctlCallbackData lxcDomainInitctlCallbackData;
412 struct _lxcDomainInitctlCallbackData {
413     int runlevel;
414     bool *st_valid;
415     struct stat *st;
416 };
417 
418 
419 static int
lxcDomainInitctlCallback(pid_t pid G_GNUC_UNUSED,void * opaque)420 lxcDomainInitctlCallback(pid_t pid G_GNUC_UNUSED,
421                          void *opaque)
422 {
423     lxcDomainInitctlCallbackData *data = opaque;
424     size_t i;
425 
426     for (i = 0; virInitctlFifos[i]; i++) {
427         const char *fifo = virInitctlFifos[i];
428         struct stat cont_sb;
429 
430         if (stat(fifo, &cont_sb) < 0) {
431             if (errno == ENOENT)
432                 continue;
433 
434             virReportSystemError(errno, _("Unable to stat %s"), fifo);
435             return -1;
436         }
437 
438         /* Check if the init fifo is not the very one that's on
439          * the host. We don't want to change the host's runlevel.
440          */
441         if (data->st_valid[i] &&
442             data->st[i].st_dev == cont_sb.st_dev &&
443             data->st[i].st_ino == cont_sb.st_ino)
444             continue;
445 
446         return virInitctlSetRunLevel(fifo, data->runlevel);
447     }
448 
449     /* If no usable fifo was found then declare success. Caller
450      * will try killing the domain with signal. */
451     return 0;
452 }
453 
454 
455 int
virLXCDomainSetRunlevel(virDomainObj * vm,int runlevel)456 virLXCDomainSetRunlevel(virDomainObj *vm,
457                         int runlevel)
458 {
459     virLXCDomainObjPrivate *priv = vm->privateData;
460     lxcDomainInitctlCallbackData data;
461     size_t nfifos = 0;
462     size_t i;
463     int ret = -1;
464 
465     memset(&data, 0, sizeof(data));
466 
467     data.runlevel = runlevel;
468 
469     for (nfifos = 0; virInitctlFifos[nfifos]; nfifos++)
470         ;
471 
472     data.st = g_new0(struct stat, nfifos);
473     data.st_valid = g_new0(bool, nfifos);
474 
475     for (i = 0; virInitctlFifos[i]; i++) {
476         const char *fifo = virInitctlFifos[i];
477 
478         if (stat(fifo, &(data.st[i])) < 0) {
479             if (errno == ENOENT)
480                 continue;
481 
482             virReportSystemError(errno, _("Unable to stat %s"), fifo);
483             goto cleanup;
484         }
485 
486         data.st_valid[i] = true;
487     }
488 
489     ret = virProcessRunInMountNamespace(priv->initpid,
490                                         lxcDomainInitctlCallback,
491                                         &data);
492  cleanup:
493     g_free(data.st);
494     data.st = NULL;
495     g_free(data.st_valid);
496     data.st_valid = NULL;
497     return ret;
498 }
499