1 /*
2 * openvz_conf.c: config functions for managing OpenVZ VEs
3 *
4 * Copyright (C) 2010-2012, 2014 Red Hat, Inc.
5 * Copyright (C) 2006, 2007 Binary Karma
6 * Copyright (C) 2006 Shuveb Hussain
7 * Copyright (C) 2007 Anoop Joe Cyriac
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library. If not, see
21 * <http://www.gnu.org/licenses/>.
22 */
23
24 #include <config.h>
25
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <time.h>
31 #include <sys/stat.h>
32
33 #include "virerror.h"
34 #include "openvz_conf.h"
35 #include "openvz_util.h"
36 #include "viruuid.h"
37 #include "virbuffer.h"
38 #include "viralloc.h"
39 #include "virfile.h"
40 #include "vircommand.h"
41 #include "virstring.h"
42 #include "virhostcpu.h"
43 #include "virutil.h"
44
45 #define VIR_FROM_THIS VIR_FROM_OPENVZ
46
47 static char *openvzLocateConfDir(void);
48 static int openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len);
49 static int openvzAssignUUIDs(void);
50 static int openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext);
51
52 openvzLocateConfFileFunc openvzLocateConfFile = openvzLocateConfFileDefault;
53
54 int
strtoI(const char * str)55 strtoI(const char *str)
56 {
57 int val;
58
59 if (virStrToLong_i(str, NULL, 10, &val) < 0)
60 return 0;
61
62 return val;
63 }
64
65
66 static int
openvzExtractVersionInfo(const char * cmdstr,int * retversion)67 openvzExtractVersionInfo(const char *cmdstr, int *retversion)
68 {
69 int ret = -1;
70 unsigned long version;
71 char *help = NULL;
72 char *tmp;
73 virCommand *cmd = virCommandNewArgList(cmdstr, "--help", NULL);
74
75 if (retversion)
76 *retversion = 0;
77
78 virCommandAddEnvString(cmd, "LC_ALL=C");
79 virCommandSetOutputBuffer(cmd, &help);
80
81 if (virCommandRun(cmd, NULL) < 0)
82 goto cleanup;
83
84 tmp = help;
85
86 /* expected format: vzctl version <major>.<minor>.<micro> */
87 if ((tmp = STRSKIP(tmp, "vzctl version ")) == NULL)
88 goto cleanup;
89
90 if (virParseVersionString(tmp, &version, true) < 0)
91 goto cleanup;
92
93 if (retversion)
94 *retversion = version;
95
96 ret = 0;
97
98 cleanup:
99 virCommandFree(cmd);
100 VIR_FREE(help);
101
102 return ret;
103 }
104
openvzExtractVersion(struct openvz_driver * driver)105 int openvzExtractVersion(struct openvz_driver *driver)
106 {
107 if (driver->version > 0)
108 return 0;
109
110 if (openvzExtractVersionInfo(VZCTL, &driver->version) < 0) {
111 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
112 _("Could not extract vzctl version"));
113 return -1;
114 }
115
116 return 0;
117 }
118
119
120 /* Parse config values of the form barrier:limit into barrier and limit */
121 static int
openvzParseBarrierLimit(const char * value,unsigned long long * barrier,unsigned long long * limit)122 openvzParseBarrierLimit(const char* value,
123 unsigned long long *barrier,
124 unsigned long long *limit)
125 {
126 g_auto(GStrv) tmp = NULL;
127
128 if (!(tmp = g_strsplit(value, ":", 0)))
129 return -1;
130
131 if (g_strv_length(tmp) != 2)
132 return -1;
133
134 if (barrier && virStrToLong_ull(tmp[0], NULL, 10, barrier) < 0)
135 return -1;
136
137 if (limit && virStrToLong_ull(tmp[1], NULL, 10, limit) < 0)
138 return -1;
139
140 return 0;
141 }
142
143
openvzCapsInit(void)144 virCaps *openvzCapsInit(void)
145 {
146 g_autoptr(virCaps) caps = NULL;
147 virCapsGuest *guest;
148
149 if ((caps = virCapabilitiesNew(virArchFromHost(),
150 false, false)) == NULL)
151 return NULL;
152
153 if (!(caps->host.numa = virCapabilitiesHostNUMANewHost()))
154 return NULL;
155
156 if (virCapabilitiesInitCaches(caps) < 0)
157 return NULL;
158
159 guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_EXE,
160 caps->host.arch, NULL, NULL, 0, NULL);
161
162 virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_OPENVZ,
163 NULL, NULL, 0, NULL);
164
165 return g_steal_pointer(&caps);
166 }
167
168
169 int
openvzReadNetworkConf(virDomainDef * def,int veid)170 openvzReadNetworkConf(virDomainDef *def,
171 int veid)
172 {
173 int ret;
174 virDomainNetDef *net = NULL;
175 char *temp = NULL;
176 char *token, *saveptr = NULL;
177
178 /*parse routing network configuration*
179 * Sample from config:
180 * IP_ADDRESS="1.1.1.1 1.1.1.2"
181 * IPs split by space
182 */
183 ret = openvzReadVPSConfigParam(veid, "IP_ADDRESS", &temp);
184 if (ret < 0) {
185 virReportError(VIR_ERR_INTERNAL_ERROR,
186 _("Could not read 'IP_ADDRESS' from config for container %d"),
187 veid);
188 goto error;
189 } else if (ret > 0) {
190 token = strtok_r(temp, " ", &saveptr);
191 while (token != NULL) {
192 net = g_new0(virDomainNetDef, 1);
193
194 net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
195 if (virDomainNetAppendIPAddress(net, token, AF_UNSPEC, 0) < 0)
196 goto error;
197
198 VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net);
199
200 token = strtok_r(NULL, " ", &saveptr);
201 }
202 }
203
204 /*parse bridge devices*/
205 /*Sample from config:
206 * NETIF="ifname=eth10,mac=00:18:51:C1:05:EE,host_ifname=veth105.10,host_mac=00:18:51:8F:D9:F3"
207 *devices split by ';'
208 */
209 ret = openvzReadVPSConfigParam(veid, "NETIF", &temp);
210 if (ret < 0) {
211 virReportError(VIR_ERR_INTERNAL_ERROR,
212 _("Could not read 'NETIF' from config for container %d"),
213 veid);
214 goto error;
215 } else if (ret > 0) {
216 g_auto(GStrv) devices = g_strsplit(temp, ";", 0);
217 GStrv device;
218
219 for (device = devices; device && *device; device++) {
220 g_auto(GStrv) keyvals = g_strsplit(*device, ",", 0);
221 GStrv keyval;
222
223 net = g_new0(virDomainNetDef, 1);
224 net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
225
226 for (keyval = keyvals; keyval && *keyval; keyval++) {
227 char *val = strchr(*keyval, '=');
228
229 if (!val)
230 continue;
231
232 val++;
233
234 if (STRPREFIX(*keyval, "ifname=")) {
235 /* skip in libvirt */
236 } else if (STRPREFIX(*keyval, "host_ifname=")) {
237 if (strlen(val) > 16) {
238 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
239 _("Too long network device name"));
240 goto error;
241 }
242
243 net->ifname = g_strdup(val);
244 } else if (STRPREFIX(*keyval, "bridge=")) {
245 if (strlen(val) > 16) {
246 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
247 _("Too long bridge device name"));
248 goto error;
249 }
250
251 net->data.bridge.brname = g_strdup(val);
252 } else if (STRPREFIX(*keyval, "mac=")) {
253 if (strlen(val) != 17) { /* should be 17 */
254 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
255 _("Wrong length MAC address"));
256 goto error;
257 }
258 if (virMacAddrParse(val, &net->mac) < 0) {
259 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
260 _("Wrong MAC address"));
261 goto error;
262 }
263 }
264 }
265
266 VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net);
267 }
268 }
269
270 VIR_FREE(temp);
271
272 return 0;
273
274 error:
275 VIR_FREE(temp);
276 virDomainNetDefFree(net);
277 return -1;
278 }
279
280
281 static int
openvzReadFSConf(virDomainDef * def,int veid)282 openvzReadFSConf(virDomainDef *def,
283 int veid)
284 {
285 int ret;
286 virDomainFSDef *fs = NULL;
287 g_autofree char *veid_str = NULL;
288 char *temp = NULL;
289 const char *param;
290 unsigned long long barrier, limit;
291
292 ret = openvzReadVPSConfigParam(veid, "OSTEMPLATE", &temp);
293 if (ret < 0) {
294 virReportError(VIR_ERR_INTERNAL_ERROR,
295 _("Could not read 'OSTEMPLATE' from config for container %d"),
296 veid);
297 goto error;
298 } else if (ret > 0) {
299 if (!(fs = virDomainFSDefNew(NULL)))
300 goto error;
301
302 fs->type = VIR_DOMAIN_FS_TYPE_TEMPLATE;
303 fs->src->path = g_strdup(temp);
304 } else {
305 /* OSTEMPLATE was not found, VE was booted from a private dir directly */
306 ret = openvzReadVPSConfigParam(veid, "VE_PRIVATE", &temp);
307 if (ret <= 0) {
308 virReportError(VIR_ERR_INTERNAL_ERROR,
309 _("Could not read 'VE_PRIVATE' from config for container %d"),
310 veid);
311 goto error;
312 }
313
314 if (!(fs = virDomainFSDefNew(NULL)))
315 goto error;
316
317 veid_str = g_strdup_printf("%d", veid);
318
319 fs->type = VIR_DOMAIN_FS_TYPE_MOUNT;
320 if (!(fs->src->path = virStringReplace(temp, "$VEID", veid_str)))
321 goto error;
322 }
323
324 fs->dst = g_strdup("/");
325
326 param = "DISKSPACE";
327 ret = openvzReadVPSConfigParam(veid, param, &temp);
328 if (ret > 0) {
329 if (openvzParseBarrierLimit(temp, &barrier, &limit)) {
330 virReportError(VIR_ERR_INTERNAL_ERROR,
331 _("Could not read '%s' from config for container %d"),
332 param, veid);
333 goto error;
334 } else {
335 /* Ensure that we can multiply by 1024 without overflowing. */
336 if (barrier > ULLONG_MAX / 1024 ||
337 limit > ULLONG_MAX / 1024) {
338 virReportError(VIR_ERR_OVERFLOW, "%s",
339 _("Unable to parse quota"));
340 goto error;
341 }
342 fs->space_soft_limit = barrier * 1024; /* unit is bytes */
343 fs->space_hard_limit = limit * 1024; /* unit is bytes */
344 }
345 }
346
347 VIR_APPEND_ELEMENT(def->fss, def->nfss, fs);
348
349 VIR_FREE(temp);
350
351 return 0;
352 error:
353 VIR_FREE(temp);
354 virDomainFSDefFree(fs);
355 return -1;
356 }
357
358
359 static int
openvzReadMemConf(virDomainDef * def,int veid)360 openvzReadMemConf(virDomainDef *def, int veid)
361 {
362 int ret = -1;
363 char *temp = NULL;
364 unsigned long long barrier, limit;
365 const char *param;
366 long kb_per_pages;
367
368 kb_per_pages = openvzKBPerPages();
369 if (kb_per_pages < 0)
370 goto error;
371
372 /* Memory allocation guarantee */
373 param = "VMGUARPAGES";
374 ret = openvzReadVPSConfigParam(veid, param, &temp);
375 if (ret < 0) {
376 virReportError(VIR_ERR_INTERNAL_ERROR,
377 _("Could not read '%s' from config for container %d"),
378 param, veid);
379 goto error;
380 } else if (ret > 0) {
381 ret = openvzParseBarrierLimit(temp, &barrier, NULL);
382 if (ret < 0) {
383 virReportError(VIR_ERR_INTERNAL_ERROR,
384 _("Could not parse barrier of '%s' "
385 "from config for container %d"), param, veid);
386 goto error;
387 }
388 if (barrier == LONG_MAX)
389 def->mem.min_guarantee = 0ull;
390 else
391 def->mem.min_guarantee = barrier * kb_per_pages;
392 }
393
394 /* Memory hard and soft limits */
395 param = "PRIVVMPAGES";
396 ret = openvzReadVPSConfigParam(veid, param, &temp);
397 if (ret < 0) {
398 virReportError(VIR_ERR_INTERNAL_ERROR,
399 _("Could not read '%s' from config for container %d"),
400 param, veid);
401 goto error;
402 } else if (ret > 0) {
403 ret = openvzParseBarrierLimit(temp, &barrier, &limit);
404 if (ret < 0) {
405 virReportError(VIR_ERR_INTERNAL_ERROR,
406 _("Could not parse barrier and limit of '%s' "
407 "from config for container %d"), param, veid);
408 goto error;
409 }
410 if (barrier == LONG_MAX)
411 def->mem.soft_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
412 else
413 def->mem.soft_limit = barrier * kb_per_pages;
414
415 if (limit == LONG_MAX)
416 def->mem.hard_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
417 else
418 def->mem.hard_limit = limit * kb_per_pages;
419 }
420
421 ret = 0;
422 error:
423 VIR_FREE(temp);
424 return ret;
425 }
426
427
428 /* Free all memory associated with a openvz_driver structure */
429 void
openvzFreeDriver(struct openvz_driver * driver)430 openvzFreeDriver(struct openvz_driver *driver)
431 {
432 if (!driver)
433 return;
434
435 virObjectUnref(driver->xmlopt);
436 virObjectUnref(driver->domains);
437 virObjectUnref(driver->caps);
438 g_free(driver);
439 }
440
441
442
openvzLoadDomains(struct openvz_driver * driver)443 int openvzLoadDomains(struct openvz_driver *driver)
444 {
445 int veid, ret;
446 char *status;
447 char uuidstr[VIR_UUID_STRING_BUFLEN];
448 virDomainObj *dom = NULL;
449 virDomainDef *def = NULL;
450 char *temp = NULL;
451 char *outbuf = NULL;
452 char *line;
453 virCommand *cmd = NULL;
454 unsigned int vcpus = 0;
455
456 if (openvzAssignUUIDs() < 0)
457 return -1;
458
459 cmd = virCommandNewArgList(VZLIST, "-a", "-ovpsid,status", "-H", NULL);
460 virCommandSetOutputBuffer(cmd, &outbuf);
461 if (virCommandRun(cmd, NULL) < 0)
462 goto cleanup;
463
464 line = outbuf;
465 while (line[0] != '\0') {
466 unsigned int flags = 0;
467 if (virStrToLong_i(line, &status, 10, &veid) < 0 ||
468 *status++ != ' ' ||
469 (line = strchr(status, '\n')) == NULL) {
470 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
471 _("Failed to parse vzlist output"));
472 goto cleanup;
473 }
474 *line++ = '\0';
475
476 if (!(def = virDomainDefNew(driver->xmlopt)))
477 goto cleanup;
478
479 def->virtType = VIR_DOMAIN_VIRT_OPENVZ;
480
481 if (STREQ(status, "stopped"))
482 def->id = -1;
483 else
484 def->id = veid;
485 def->name = g_strdup_printf("%i", veid);
486
487 openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr));
488 ret = virUUIDParse(uuidstr, def->uuid);
489
490 if (ret == -1) {
491 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
492 _("UUID in config file malformed"));
493 goto cleanup;
494 }
495
496 def->os.type = VIR_DOMAIN_OSTYPE_EXE;
497 def->os.init = g_strdup("/sbin/init");
498
499 ret = openvzReadVPSConfigParam(veid, "CPUS", &temp);
500 if (ret < 0) {
501 virReportError(VIR_ERR_INTERNAL_ERROR,
502 _("Could not read config for container %d"),
503 veid);
504 goto cleanup;
505 } else if (ret > 0) {
506 vcpus = strtoI(temp);
507 }
508
509 if (ret == 0 || vcpus == 0)
510 vcpus = virHostCPUGetCount();
511
512 if (virDomainDefSetVcpusMax(def, vcpus, driver->xmlopt) < 0)
513 goto cleanup;
514
515 if (virDomainDefSetVcpus(def, vcpus) < 0)
516 goto cleanup;
517
518 /* XXX load rest of VM config data .... */
519
520 openvzReadNetworkConf(def, veid);
521 openvzReadFSConf(def, veid);
522 openvzReadMemConf(def, veid);
523
524 virUUIDFormat(def->uuid, uuidstr);
525 flags = VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE;
526 if (STRNEQ(status, "stopped"))
527 flags |= VIR_DOMAIN_OBJ_LIST_ADD_LIVE;
528
529 if (!(dom = virDomainObjListAdd(driver->domains,
530 &def,
531 driver->xmlopt,
532 flags,
533 NULL)))
534 goto cleanup;
535
536 if (STREQ(status, "stopped")) {
537 virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF,
538 VIR_DOMAIN_SHUTOFF_UNKNOWN);
539 dom->pid = -1;
540 } else {
541 virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
542 VIR_DOMAIN_RUNNING_UNKNOWN);
543 dom->pid = veid;
544 }
545 /* XXX OpenVZ doesn't appear to have concept of a transient domain */
546 dom->persistent = 1;
547
548 virDomainObjEndAPI(&dom);
549 dom = NULL;
550 }
551
552 virCommandFree(cmd);
553 VIR_FREE(temp);
554 VIR_FREE(outbuf);
555
556 return 0;
557
558 cleanup:
559 virCommandFree(cmd);
560 VIR_FREE(temp);
561 VIR_FREE(outbuf);
562 virDomainDefFree(def);
563 return -1;
564 }
565
566 static int
openvzWriteConfigParam(const char * conf_file,const char * param,const char * value)567 openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
568 {
569 g_autofree char *temp_file = NULL;
570 int temp_fd = -1;
571 FILE *fp;
572 char *line = NULL;
573 size_t line_size = 0;
574
575 temp_file = g_strdup_printf("%s.tmp", conf_file);
576
577 fp = fopen(conf_file, "r");
578 if (fp == NULL)
579 goto error;
580 temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
581 if (temp_fd == -1)
582 goto error;
583
584 while (1) {
585 if (getline(&line, &line_size, fp) <= 0)
586 break;
587
588 if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
589 if (safewrite(temp_fd, line, strlen(line)) !=
590 strlen(line))
591 goto error;
592 }
593 }
594
595 if (safewrite(temp_fd, param, strlen(param)) < 0 ||
596 safewrite(temp_fd, "=\"", 2) < 0 ||
597 safewrite(temp_fd, value, strlen(value)) < 0 ||
598 safewrite(temp_fd, "\"\n", 2) < 0)
599 goto error;
600
601 if (VIR_FCLOSE(fp) < 0)
602 goto error;
603 if (VIR_CLOSE(temp_fd) < 0)
604 goto error;
605
606 if (rename(temp_file, conf_file) < 0)
607 goto error;
608
609 VIR_FREE(line);
610
611 return 0;
612
613 error:
614 VIR_FREE(line);
615 VIR_FORCE_FCLOSE(fp);
616 VIR_FORCE_CLOSE(temp_fd);
617 if (temp_file)
618 unlink(temp_file);
619 return -1;
620 }
621
622 int
openvzWriteVPSConfigParam(int vpsid,const char * param,const char * value)623 openvzWriteVPSConfigParam(int vpsid, const char *param, const char *value)
624 {
625 char *conf_file;
626 int ret;
627
628 if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
629 return -1;
630
631 ret = openvzWriteConfigParam(conf_file, param, value);
632 VIR_FREE(conf_file);
633 return ret;
634 }
635
636 /*
637 * value will be freed before a new value is assigned to it, the caller is
638 * responsible for freeing it afterwards.
639 *
640 * Returns <0 on error, 0 if not found, 1 if found.
641 */
642 int
openvzReadConfigParam(const char * conf_file,const char * param,char ** value)643 openvzReadConfigParam(const char *conf_file, const char *param, char **value)
644 {
645 char *line = NULL;
646 size_t line_size = 0;
647 FILE *fp;
648 int err = 0;
649 char *sf, *token, *saveptr = NULL;
650
651 fp = fopen(conf_file, "r");
652 if (fp == NULL)
653 return -1;
654
655 VIR_FREE(*value);
656 while (1) {
657 if (getline(&line, &line_size, fp) < 0) {
658 err = !feof(fp);
659 break;
660 }
661
662 if (!(sf = STRSKIP(line, param)))
663 continue;
664
665 if (*sf++ != '=')
666 continue;
667
668 saveptr = NULL;
669 if ((token = strtok_r(sf, "\"\t\n", &saveptr)) != NULL) {
670 VIR_FREE(*value);
671 *value = g_strdup(token);
672 /* keep going - last entry wins */
673 }
674 }
675 VIR_FREE(line);
676 VIR_FORCE_FCLOSE(fp);
677
678 return err ? -1 : *value ? 1 : 0;
679 }
680
681 /*
682 * Read parameter from container config
683 *
684 * value will be freed before a new value is assigned to it, the caller is
685 * responsible for freeing it afterwards.
686 *
687 * sample: 133, "OSTEMPLATE", &value
688 * return: -1 - error
689 * 0 - don't found
690 * 1 - OK
691 */
692 int
openvzReadVPSConfigParam(int vpsid,const char * param,char ** value)693 openvzReadVPSConfigParam(int vpsid, const char *param, char **value)
694 {
695 char *conf_file;
696 int ret;
697
698 if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
699 return -1;
700
701 ret = openvzReadConfigParam(conf_file, param, value);
702 VIR_FREE(conf_file);
703 return ret;
704 }
705
706 static int
openvz_copyfile(char * from_path,char * to_path)707 openvz_copyfile(char* from_path, char* to_path)
708 {
709 char *line = NULL;
710 size_t line_size = 0;
711 FILE *fp;
712 int copy_fd;
713 int bytes_read;
714
715 fp = fopen(from_path, "r");
716 if (fp == NULL)
717 return -1;
718 copy_fd = open(to_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
719 if (copy_fd == -1) {
720 VIR_FORCE_FCLOSE(fp);
721 return -1;
722 }
723
724 while (1) {
725 if (getline(&line, &line_size, fp) <= 0)
726 break;
727
728 bytes_read = strlen(line);
729 if (safewrite(copy_fd, line, bytes_read) != bytes_read)
730 goto error;
731 }
732
733 if (VIR_FCLOSE(fp) < 0)
734 goto error;
735 if (VIR_CLOSE(copy_fd) < 0)
736 goto error;
737
738 VIR_FREE(line);
739
740 return 0;
741
742 error:
743 VIR_FREE(line);
744 VIR_FORCE_FCLOSE(fp);
745 VIR_FORCE_CLOSE(copy_fd);
746 return -1;
747 }
748
749 /*
750 * Copy the default config to the VE conf file
751 * return: -1 - error
752 * 0 - OK
753 */
754 int
openvzCopyDefaultConfig(int vpsid)755 openvzCopyDefaultConfig(int vpsid)
756 {
757 char *confdir = NULL;
758 char *default_conf_file = NULL;
759 char *configfile_value = NULL;
760 char *conf_file = NULL;
761 int ret = -1;
762
763 if (openvzReadConfigParam(VZ_CONF_FILE, "CONFIGFILE", &configfile_value) < 0)
764 goto cleanup;
765
766 confdir = openvzLocateConfDir();
767 if (confdir == NULL)
768 goto cleanup;
769
770 default_conf_file = g_strdup_printf("%s/ve-%s.conf-sample", confdir,
771 configfile_value);
772
773 if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
774 goto cleanup;
775
776 if (openvz_copyfile(default_conf_file, conf_file)<0)
777 goto cleanup;
778
779 ret = 0;
780 cleanup:
781 VIR_FREE(confdir);
782 VIR_FREE(default_conf_file);
783 VIR_FREE(configfile_value);
784 VIR_FREE(conf_file);
785 return ret;
786 }
787
788 /* Locate config file of container
789 * return -1 - error
790 * 0 - OK */
791 static int
openvzLocateConfFileDefault(int vpsid,char ** conffile,const char * ext)792 openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext)
793 {
794 char *confdir;
795 int ret = 0;
796
797 confdir = openvzLocateConfDir();
798 if (confdir == NULL)
799 return -1;
800
801 *conffile = g_strdup_printf("%s/%d.%s", confdir, vpsid, ext ? ext : "conf");
802
803 VIR_FREE(confdir);
804 return ret;
805 }
806
807 static char *
openvzLocateConfDir(void)808 openvzLocateConfDir(void)
809 {
810 const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL};
811 size_t i = 0;
812
813 while (conf_dir_list[i]) {
814 if (virFileExists(conf_dir_list[i]))
815 return g_strdup(conf_dir_list[i]);
816
817 i++;
818 }
819
820 return NULL;
821 }
822
823 /* Richard Steven's classic readline() function */
824 int
openvz_readline(int fd,char * ptr,int maxlen)825 openvz_readline(int fd, char *ptr, int maxlen)
826 {
827 int n, rc;
828 char c;
829
830 for (n = 1; n < maxlen; n++) {
831 if ((rc = read(fd, &c, 1)) == 1) {
832 *ptr++ = c;
833 if (c == '\n')
834 break;
835 } else if (rc == 0) {
836 if (n == 1)
837 return 0; /* EOF condition */
838 else
839 break;
840 }
841 else
842 return -1; /* error */
843 }
844 *ptr = 0;
845 return n;
846 }
847
848 static int
openvzGetVPSUUID(int vpsid,char * uuidstr,size_t len)849 openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
850 {
851 char *conf_file;
852 char *line = NULL;
853 size_t line_size = 0;
854 char *saveptr = NULL;
855 char *uuidbuf;
856 char *iden;
857 FILE *fp;
858 int retval = -1;
859
860 if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
861 return -1;
862
863 fp = fopen(conf_file, "r");
864 if (fp == NULL)
865 goto cleanup;
866
867 while (1) {
868 if (getline(&line, &line_size, fp) < 0) {
869 if (feof(fp)) { /* EOF, UUID was not found */
870 uuidstr[0] = 0;
871 break;
872 } else {
873 goto cleanup;
874 }
875 }
876
877 iden = strtok_r(line, " ", &saveptr);
878 uuidbuf = strtok_r(NULL, "\n", &saveptr);
879
880 if (iden != NULL && uuidbuf != NULL && STREQ(iden, "#UUID:")) {
881 if (virStrcpy(uuidstr, uuidbuf, len) < 0) {
882 virReportError(VIR_ERR_INTERNAL_ERROR,
883 _("invalid uuid %s"), uuidbuf);
884 goto cleanup;
885 }
886 break;
887 }
888 }
889 retval = 0;
890 cleanup:
891 VIR_FREE(line);
892 VIR_FORCE_FCLOSE(fp);
893 VIR_FREE(conf_file);
894
895 return retval;
896 }
897
898 /* Do actual checking for UUID presence in conf file,
899 * assign if not present.
900 */
901 int
openvzSetDefinedUUID(int vpsid,unsigned char * uuid)902 openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
903 {
904 char *conf_file;
905 char uuidstr[VIR_UUID_STRING_BUFLEN];
906 FILE *fp = NULL;
907 int ret = -1;
908
909 if (uuid == NULL)
910 return -1;
911
912 if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
913 return -1;
914
915 if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
916 goto cleanup;
917
918 if (uuidstr[0] == 0) {
919 fp = fopen(conf_file, "a"); /* append */
920 if (fp == NULL)
921 goto cleanup;
922
923 virUUIDFormat(uuid, uuidstr);
924
925 /* Record failure if fprintf or VIR_FCLOSE fails,
926 and be careful always to close the stream. */
927 if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0) ||
928 (VIR_FCLOSE(fp) == EOF))
929 goto cleanup;
930 }
931
932 ret = 0;
933 cleanup:
934 VIR_FORCE_FCLOSE(fp);
935 VIR_FREE(conf_file);
936 return ret;
937 }
938
939 static int
openvzSetUUID(int vpsid)940 openvzSetUUID(int vpsid)
941 {
942 unsigned char uuid[VIR_UUID_BUFLEN];
943
944 if (virUUIDGenerate(uuid) < 0) {
945 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
946 _("Failed to generate UUID"));
947 return -1;
948 }
949
950 return openvzSetDefinedUUID(vpsid, uuid);
951 }
952
953 /*
954 * Scan VPS config files and see if they have a UUID.
955 * If not, assign one. Just append one to the config
956 * file as comment so that the OpenVZ tools ignore it.
957 *
958 */
959
openvzAssignUUIDs(void)960 static int openvzAssignUUIDs(void)
961 {
962 g_autoptr(DIR) dp = NULL;
963 struct dirent *dent;
964 char *conf_dir;
965 int vpsid;
966 char *ext;
967 int ret = 0;
968
969 conf_dir = openvzLocateConfDir();
970 if (conf_dir == NULL)
971 return -1;
972
973 if (virDirOpenQuiet(&dp, conf_dir) < 0) {
974 VIR_FREE(conf_dir);
975 return 0;
976 }
977
978 while ((ret = virDirRead(dp, &dent, conf_dir)) > 0) {
979 if (virStrToLong_i(dent->d_name, &ext, 10, &vpsid) < 0 ||
980 *ext++ != '.' ||
981 STRNEQ(ext, "conf"))
982 continue;
983 if (vpsid > 0) /* '0.conf' belongs to the host, ignore it */
984 openvzSetUUID(vpsid);
985 }
986
987 VIR_FREE(conf_dir);
988 return ret;
989 }
990
991
992 /*
993 * Return CTID from name
994 *
995 */
996
openvzGetVEID(const char * name)997 int openvzGetVEID(const char *name)
998 {
999 virCommand *cmd;
1000 char *outbuf;
1001 char *temp;
1002 int veid;
1003 bool ok;
1004
1005 cmd = virCommandNewArgList(VZLIST, name, "-ovpsid", "-H", NULL);
1006 virCommandSetOutputBuffer(cmd, &outbuf);
1007 if (virCommandRun(cmd, NULL) < 0) {
1008 virCommandFree(cmd);
1009 VIR_FREE(outbuf);
1010 return -1;
1011 }
1012
1013 virCommandFree(cmd);
1014 ok = virStrToLong_i(outbuf, &temp, 10, &veid) == 0 && *temp == '\n';
1015 VIR_FREE(outbuf);
1016
1017 if (ok && veid >= 0)
1018 return veid;
1019
1020 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1021 _("Failed to parse vzlist output"));
1022 return -1;
1023 }
1024
1025
1026 static int
openvzDomainDefPostParse(virDomainDef * def,unsigned int parseFlags G_GNUC_UNUSED,void * opaque,void * parseOpaque G_GNUC_UNUSED)1027 openvzDomainDefPostParse(virDomainDef *def,
1028 unsigned int parseFlags G_GNUC_UNUSED,
1029 void *opaque,
1030 void *parseOpaque G_GNUC_UNUSED)
1031 {
1032 struct openvz_driver *driver = opaque;
1033 if (!virCapabilitiesDomainSupported(driver->caps, def->os.type,
1034 def->os.arch,
1035 def->virtType))
1036 return -1;
1037
1038 /* fill the init path */
1039 if (def->os.type == VIR_DOMAIN_OSTYPE_EXE && !def->os.init)
1040 def->os.init = g_strdup("/sbin/init");
1041
1042 return 0;
1043 }
1044
1045
1046 static int
openvzDomainDeviceDefPostParse(virDomainDeviceDef * dev,const virDomainDef * def G_GNUC_UNUSED,unsigned int parseFlags G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED,void * parseOpaque G_GNUC_UNUSED)1047 openvzDomainDeviceDefPostParse(virDomainDeviceDef *dev,
1048 const virDomainDef *def G_GNUC_UNUSED,
1049 unsigned int parseFlags G_GNUC_UNUSED,
1050 void *opaque G_GNUC_UNUSED,
1051 void *parseOpaque G_GNUC_UNUSED)
1052 {
1053 if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
1054 dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
1055 dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
1056 dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_OPENVZ;
1057
1058 /* forbid capabilities mode hostdev in this kind of hypervisor */
1059 if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
1060 dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
1061 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1062 _("hostdev mode 'capabilities' is not "
1063 "supported in %s"),
1064 virDomainVirtTypeToString(def->virtType));
1065 return -1;
1066 }
1067
1068 if (dev->type == VIR_DOMAIN_DEVICE_VIDEO &&
1069 dev->data.video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT) {
1070 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM)
1071 dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_VGA;
1072 else
1073 dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_PARALLELS;
1074 }
1075
1076 return 0;
1077 }
1078
1079
1080 virDomainDefParserConfig openvzDomainDefParserConfig = {
1081 .domainPostParseCallback = openvzDomainDefPostParse,
1082 .devicesPostParseCallback = openvzDomainDeviceDefPostParse,
1083 .features = VIR_DOMAIN_DEF_FEATURE_NAME_SLASH,
1084 };
1085
openvzXMLOption(struct openvz_driver * driver)1086 virDomainXMLOption *openvzXMLOption(struct openvz_driver *driver)
1087 {
1088 openvzDomainDefParserConfig.priv = driver;
1089 return virDomainXMLOptionNew(&openvzDomainDefParserConfig,
1090 NULL, NULL, NULL, NULL);
1091 }
1092