PageRenderTime 570ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/openvz/openvz_conf.c

https://gitlab.com/unofficial-mirrors/libvirt
C | 1111 lines | 832 code | 188 blank | 91 comment | 215 complexity | 4295d432b108c6eca3e2e4752f4221f0 MD5 | raw file
  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. * Authors:
  24. * Shuveb Hussain <shuveb@binarykarma.com>
  25. * Anoop Joe Cyriac <anoop@binarykarma.com>
  26. *
  27. */
  28. #include <config.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <unistd.h>
  32. #include <fcntl.h>
  33. #include <sys/types.h>
  34. #include <dirent.h>
  35. #include <time.h>
  36. #include <sys/stat.h>
  37. #include <limits.h>
  38. #include <errno.h>
  39. #include <string.h>
  40. #include <sys/wait.h>
  41. #include "virerror.h"
  42. #include "openvz_conf.h"
  43. #include "openvz_util.h"
  44. #include "viruuid.h"
  45. #include "virbuffer.h"
  46. #include "viralloc.h"
  47. #include "nodeinfo.h"
  48. #include "virfile.h"
  49. #include "vircommand.h"
  50. #include "virstring.h"
  51. #define VIR_FROM_THIS VIR_FROM_OPENVZ
  52. static char *openvzLocateConfDir(void);
  53. static int openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len);
  54. static int openvzAssignUUIDs(void);
  55. static int openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext);
  56. openvzLocateConfFileFunc openvzLocateConfFile = openvzLocateConfFileDefault;
  57. int
  58. strtoI(const char *str)
  59. {
  60. int val;
  61. if (virStrToLong_i(str, NULL, 10, &val) < 0)
  62. return 0;
  63. return val;
  64. }
  65. static int
  66. openvzExtractVersionInfo(const char *cmdstr, int *retversion)
  67. {
  68. int ret = -1;
  69. unsigned long version;
  70. char *help = NULL;
  71. char *tmp;
  72. virCommandPtr cmd = virCommandNewArgList(cmdstr, "--help", NULL);
  73. if (retversion)
  74. *retversion = 0;
  75. virCommandAddEnvString(cmd, "LC_ALL=C");
  76. virCommandSetOutputBuffer(cmd, &help);
  77. if (virCommandRun(cmd, NULL) < 0)
  78. goto cleanup;
  79. tmp = help;
  80. /* expected format: vzctl version <major>.<minor>.<micro> */
  81. if ((tmp = STRSKIP(tmp, "vzctl version ")) == NULL)
  82. goto cleanup;
  83. if (virParseVersionString(tmp, &version, true) < 0)
  84. goto cleanup;
  85. if (retversion)
  86. *retversion = version;
  87. ret = 0;
  88. cleanup:
  89. virCommandFree(cmd);
  90. VIR_FREE(help);
  91. return ret;
  92. }
  93. int openvzExtractVersion(struct openvz_driver *driver)
  94. {
  95. if (driver->version > 0)
  96. return 0;
  97. if (openvzExtractVersionInfo(VZCTL, &driver->version) < 0) {
  98. virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  99. _("Could not extract vzctl version"));
  100. return -1;
  101. }
  102. return 0;
  103. }
  104. /* Parse config values of the form barrier:limit into barrier and limit */
  105. static int
  106. openvzParseBarrierLimit(const char* value,
  107. unsigned long long *barrier,
  108. unsigned long long *limit)
  109. {
  110. char **tmp = NULL;
  111. size_t ntmp = 0;
  112. int ret = -1;
  113. if (!(tmp = virStringSplitCount(value, ":", 0, &ntmp)))
  114. goto error;
  115. if (ntmp != 2)
  116. goto error;
  117. if (barrier && virStrToLong_ull(tmp[0], NULL, 10, barrier) < 0)
  118. goto error;
  119. if (limit && virStrToLong_ull(tmp[1], NULL, 10, limit) < 0)
  120. goto error;
  121. ret = 0;
  122. error:
  123. virStringFreeListCount(tmp, ntmp);
  124. return ret;
  125. }
  126. virCapsPtr openvzCapsInit(void)
  127. {
  128. virCapsPtr caps;
  129. virCapsGuestPtr guest;
  130. if ((caps = virCapabilitiesNew(virArchFromHost(),
  131. false, false)) == NULL)
  132. goto no_memory;
  133. if (nodeCapsInitNUMA(caps) < 0)
  134. goto no_memory;
  135. if ((guest = virCapabilitiesAddGuest(caps,
  136. VIR_DOMAIN_OSTYPE_EXE,
  137. caps->host.arch,
  138. NULL,
  139. NULL,
  140. 0,
  141. NULL)) == NULL)
  142. goto no_memory;
  143. if (virCapabilitiesAddGuestDomain(guest,
  144. VIR_DOMAIN_VIRT_OPENVZ,
  145. NULL,
  146. NULL,
  147. 0,
  148. NULL) == NULL)
  149. goto no_memory;
  150. return caps;
  151. no_memory:
  152. virObjectUnref(caps);
  153. return NULL;
  154. }
  155. int
  156. openvzReadNetworkConf(virDomainDefPtr def,
  157. int veid)
  158. {
  159. int ret;
  160. virDomainNetDefPtr net = NULL;
  161. char *temp = NULL;
  162. char *token, *saveptr = NULL;
  163. /*parse routing network configuration*
  164. * Sample from config:
  165. * IP_ADDRESS="1.1.1.1 1.1.1.2"
  166. * IPs split by space
  167. */
  168. ret = openvzReadVPSConfigParam(veid, "IP_ADDRESS", &temp);
  169. if (ret < 0) {
  170. virReportError(VIR_ERR_INTERNAL_ERROR,
  171. _("Could not read 'IP_ADDRESS' from config for container %d"),
  172. veid);
  173. goto error;
  174. } else if (ret > 0) {
  175. token = strtok_r(temp, " ", &saveptr);
  176. while (token != NULL) {
  177. if (VIR_ALLOC(net) < 0)
  178. goto error;
  179. net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
  180. if (virDomainNetAppendIPAddress(net, token, AF_UNSPEC, 0) < 0)
  181. goto error;
  182. if (VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net) < 0)
  183. goto error;
  184. token = strtok_r(NULL, " ", &saveptr);
  185. }
  186. }
  187. /*parse bridge devices*/
  188. /*Sample from config:
  189. * NETIF="ifname=eth10,mac=00:18:51:C1:05:EE,host_ifname=veth105.10,host_mac=00:18:51:8F:D9:F3"
  190. *devices split by ';'
  191. */
  192. ret = openvzReadVPSConfigParam(veid, "NETIF", &temp);
  193. if (ret < 0) {
  194. virReportError(VIR_ERR_INTERNAL_ERROR,
  195. _("Could not read 'NETIF' from config for container %d"),
  196. veid);
  197. goto error;
  198. } else if (ret > 0) {
  199. token = strtok_r(temp, ";", &saveptr);
  200. while (token != NULL) {
  201. /*add new device to list*/
  202. if (VIR_ALLOC(net) < 0)
  203. goto error;
  204. net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
  205. char *p = token;
  206. char cpy_temp[32];
  207. int len;
  208. /*parse string*/
  209. do {
  210. char *next = strchrnul(p, ',');
  211. if (STRPREFIX(p, "ifname=")) {
  212. /* skip in libvirt */
  213. } else if (STRPREFIX(p, "host_ifname=")) {
  214. p += 12;
  215. len = next - p;
  216. if (len > 16) {
  217. virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  218. _("Too long network device name"));
  219. goto error;
  220. }
  221. if (VIR_ALLOC_N(net->ifname, len+1) < 0)
  222. goto error;
  223. if (virStrncpy(net->ifname, p, len, len+1) == NULL) {
  224. virReportError(VIR_ERR_INTERNAL_ERROR,
  225. _("Network ifname %s too long for destination"), p);
  226. goto error;
  227. }
  228. } else if (STRPREFIX(p, "bridge=")) {
  229. p += 7;
  230. len = next - p;
  231. if (len > 16) {
  232. virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  233. _("Too long bridge device name"));
  234. goto error;
  235. }
  236. if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
  237. goto error;
  238. if (virStrncpy(net->data.bridge.brname, p, len, len+1) == NULL) {
  239. virReportError(VIR_ERR_INTERNAL_ERROR,
  240. _("Bridge name %s too long for destination"), p);
  241. goto error;
  242. }
  243. } else if (STRPREFIX(p, "mac=")) {
  244. p += 4;
  245. len = next - p;
  246. if (len != 17) { /* should be 17 */
  247. virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  248. _("Wrong length MAC address"));
  249. goto error;
  250. }
  251. if (virStrncpy(cpy_temp, p, len, sizeof(cpy_temp)) == NULL) {
  252. virReportError(VIR_ERR_INTERNAL_ERROR,
  253. _("MAC address %s too long for destination"), p);
  254. goto error;
  255. }
  256. if (virMacAddrParse(cpy_temp, &net->mac) < 0) {
  257. virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  258. _("Wrong MAC address"));
  259. goto error;
  260. }
  261. }
  262. p = ++next;
  263. } while (p < token + strlen(token));
  264. if (VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net) < 0)
  265. goto error;
  266. token = strtok_r(NULL, ";", &saveptr);
  267. }
  268. }
  269. VIR_FREE(temp);
  270. return 0;
  271. error:
  272. VIR_FREE(temp);
  273. virDomainNetDefFree(net);
  274. return -1;
  275. }
  276. static int
  277. openvzReadFSConf(virDomainDefPtr def,
  278. int veid)
  279. {
  280. int ret;
  281. virDomainFSDefPtr fs = NULL;
  282. char *veid_str = NULL;
  283. char *temp = NULL;
  284. const char *param;
  285. unsigned long long barrier, limit;
  286. ret = openvzReadVPSConfigParam(veid, "OSTEMPLATE", &temp);
  287. if (ret < 0) {
  288. virReportError(VIR_ERR_INTERNAL_ERROR,
  289. _("Could not read 'OSTEMPLATE' from config for container %d"),
  290. veid);
  291. goto error;
  292. } else if (ret > 0) {
  293. if (!(fs = virDomainFSDefNew()))
  294. goto error;
  295. fs->type = VIR_DOMAIN_FS_TYPE_TEMPLATE;
  296. if (VIR_STRDUP(fs->src->path, temp) < 0)
  297. goto error;
  298. } else {
  299. /* OSTEMPLATE was not found, VE was booted from a private dir directly */
  300. ret = openvzReadVPSConfigParam(veid, "VE_PRIVATE", &temp);
  301. if (ret <= 0) {
  302. virReportError(VIR_ERR_INTERNAL_ERROR,
  303. _("Could not read 'VE_PRIVATE' from config for container %d"),
  304. veid);
  305. goto error;
  306. }
  307. if (VIR_ALLOC(fs) < 0)
  308. goto error;
  309. if (virAsprintf(&veid_str, "%d", veid) < 0)
  310. goto error;
  311. fs->type = VIR_DOMAIN_FS_TYPE_MOUNT;
  312. if (!(fs->src->path = virStringReplace(temp, "$VEID", veid_str)))
  313. goto error;
  314. VIR_FREE(veid_str);
  315. }
  316. if (VIR_STRDUP(fs->dst, "/") < 0)
  317. goto error;
  318. param = "DISKSPACE";
  319. ret = openvzReadVPSConfigParam(veid, param, &temp);
  320. if (ret > 0) {
  321. if (openvzParseBarrierLimit(temp, &barrier, &limit)) {
  322. virReportError(VIR_ERR_INTERNAL_ERROR,
  323. _("Could not read '%s' from config for container %d"),
  324. param, veid);
  325. goto error;
  326. } else {
  327. /* Ensure that we can multiply by 1024 without overflowing. */
  328. if (barrier > ULLONG_MAX / 1024 ||
  329. limit > ULLONG_MAX / 1024) {
  330. virReportError(VIR_ERR_OVERFLOW, "%s",
  331. _("Unable to parse quota"));
  332. goto error;
  333. }
  334. fs->space_soft_limit = barrier * 1024; /* unit is bytes */
  335. fs->space_hard_limit = limit * 1024; /* unit is bytes */
  336. }
  337. }
  338. if (VIR_APPEND_ELEMENT(def->fss, def->nfss, fs) < 0)
  339. goto error;
  340. VIR_FREE(temp);
  341. return 0;
  342. error:
  343. VIR_FREE(temp);
  344. virDomainFSDefFree(fs);
  345. return -1;
  346. }
  347. static int
  348. openvzReadMemConf(virDomainDefPtr def, int veid)
  349. {
  350. int ret = -1;
  351. char *temp = NULL;
  352. unsigned long long barrier, limit;
  353. const char *param;
  354. long kb_per_pages;
  355. kb_per_pages = openvzKBPerPages();
  356. if (kb_per_pages < 0)
  357. goto error;
  358. /* Memory allocation guarantee */
  359. param = "VMGUARPAGES";
  360. ret = openvzReadVPSConfigParam(veid, param, &temp);
  361. if (ret < 0) {
  362. virReportError(VIR_ERR_INTERNAL_ERROR,
  363. _("Could not read '%s' from config for container %d"),
  364. param, veid);
  365. goto error;
  366. } else if (ret > 0) {
  367. ret = openvzParseBarrierLimit(temp, &barrier, NULL);
  368. if (ret < 0) {
  369. virReportError(VIR_ERR_INTERNAL_ERROR,
  370. _("Could not parse barrier of '%s' "
  371. "from config for container %d"), param, veid);
  372. goto error;
  373. }
  374. if (barrier == LONG_MAX)
  375. def->mem.min_guarantee = 0ull;
  376. else
  377. def->mem.min_guarantee = barrier * kb_per_pages;
  378. }
  379. /* Memory hard and soft limits */
  380. param = "PRIVVMPAGES";
  381. ret = openvzReadVPSConfigParam(veid, param, &temp);
  382. if (ret < 0) {
  383. virReportError(VIR_ERR_INTERNAL_ERROR,
  384. _("Could not read '%s' from config for container %d"),
  385. param, veid);
  386. goto error;
  387. } else if (ret > 0) {
  388. ret = openvzParseBarrierLimit(temp, &barrier, &limit);
  389. if (ret < 0) {
  390. virReportError(VIR_ERR_INTERNAL_ERROR,
  391. _("Could not parse barrier and limit of '%s' "
  392. "from config for container %d"), param, veid);
  393. goto error;
  394. }
  395. if (barrier == LONG_MAX)
  396. def->mem.soft_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
  397. else
  398. def->mem.soft_limit = barrier * kb_per_pages;
  399. if (limit == LONG_MAX)
  400. def->mem.hard_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
  401. else
  402. def->mem.hard_limit = limit * kb_per_pages;
  403. }
  404. ret = 0;
  405. error:
  406. VIR_FREE(temp);
  407. return ret;
  408. }
  409. /* Free all memory associated with a openvz_driver structure */
  410. void
  411. openvzFreeDriver(struct openvz_driver *driver)
  412. {
  413. if (!driver)
  414. return;
  415. virObjectUnref(driver->xmlopt);
  416. virObjectUnref(driver->domains);
  417. virObjectUnref(driver->caps);
  418. VIR_FREE(driver);
  419. }
  420. int openvzLoadDomains(struct openvz_driver *driver)
  421. {
  422. int veid, ret;
  423. char *status;
  424. char uuidstr[VIR_UUID_STRING_BUFLEN];
  425. virDomainObjPtr dom = NULL;
  426. virDomainDefPtr def = NULL;
  427. char *temp = NULL;
  428. char *outbuf = NULL;
  429. char *line;
  430. virCommandPtr cmd = NULL;
  431. unsigned int vcpus = 0;
  432. if (openvzAssignUUIDs() < 0)
  433. return -1;
  434. cmd = virCommandNewArgList(VZLIST, "-a", "-ovpsid,status", "-H", NULL);
  435. virCommandSetOutputBuffer(cmd, &outbuf);
  436. if (virCommandRun(cmd, NULL) < 0)
  437. goto cleanup;
  438. line = outbuf;
  439. while (line[0] != '\0') {
  440. unsigned int flags = 0;
  441. if (virStrToLong_i(line, &status, 10, &veid) < 0 ||
  442. *status++ != ' ' ||
  443. (line = strchr(status, '\n')) == NULL) {
  444. virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  445. _("Failed to parse vzlist output"));
  446. goto cleanup;
  447. }
  448. *line++ = '\0';
  449. if (!(def = virDomainDefNew()))
  450. goto cleanup;
  451. def->virtType = VIR_DOMAIN_VIRT_OPENVZ;
  452. if (STREQ(status, "stopped"))
  453. def->id = -1;
  454. else
  455. def->id = veid;
  456. if (virAsprintf(&def->name, "%i", veid) < 0)
  457. goto cleanup;
  458. openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr));
  459. ret = virUUIDParse(uuidstr, def->uuid);
  460. if (ret == -1) {
  461. virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  462. _("UUID in config file malformed"));
  463. goto cleanup;
  464. }
  465. def->os.type = VIR_DOMAIN_OSTYPE_EXE;
  466. if (VIR_STRDUP(def->os.init, "/sbin/init") < 0)
  467. goto cleanup;
  468. ret = openvzReadVPSConfigParam(veid, "CPUS", &temp);
  469. if (ret < 0) {
  470. virReportError(VIR_ERR_INTERNAL_ERROR,
  471. _("Could not read config for container %d"),
  472. veid);
  473. goto cleanup;
  474. } else if (ret > 0) {
  475. vcpus = strtoI(temp);
  476. }
  477. if (ret == 0 || vcpus == 0)
  478. vcpus = openvzGetNodeCPUs();
  479. if (virDomainDefSetVcpusMax(def, vcpus, driver->xmlopt) < 0)
  480. goto cleanup;
  481. if (virDomainDefSetVcpus(def, vcpus) < 0)
  482. goto cleanup;
  483. /* XXX load rest of VM config data .... */
  484. openvzReadNetworkConf(def, veid);
  485. openvzReadFSConf(def, veid);
  486. openvzReadMemConf(def, veid);
  487. virUUIDFormat(def->uuid, uuidstr);
  488. flags = VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE;
  489. if (STRNEQ(status, "stopped"))
  490. flags |= VIR_DOMAIN_OBJ_LIST_ADD_LIVE;
  491. if (!(dom = virDomainObjListAdd(driver->domains,
  492. def,
  493. driver->xmlopt,
  494. flags,
  495. NULL)))
  496. goto cleanup;
  497. if (STREQ(status, "stopped")) {
  498. virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF,
  499. VIR_DOMAIN_SHUTOFF_UNKNOWN);
  500. dom->pid = -1;
  501. } else {
  502. virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
  503. VIR_DOMAIN_RUNNING_UNKNOWN);
  504. dom->pid = veid;
  505. }
  506. /* XXX OpenVZ doesn't appear to have concept of a transient domain */
  507. dom->persistent = 1;
  508. virObjectUnlock(dom);
  509. dom = NULL;
  510. def = NULL;
  511. }
  512. virCommandFree(cmd);
  513. VIR_FREE(temp);
  514. VIR_FREE(outbuf);
  515. return 0;
  516. cleanup:
  517. virCommandFree(cmd);
  518. VIR_FREE(temp);
  519. VIR_FREE(outbuf);
  520. virObjectUnref(dom);
  521. virDomainDefFree(def);
  522. return -1;
  523. }
  524. unsigned int
  525. openvzGetNodeCPUs(void)
  526. {
  527. virNodeInfo nodeinfo;
  528. if (nodeGetInfo(&nodeinfo) < 0)
  529. return 0;
  530. return nodeinfo.cpus;
  531. }
  532. static int
  533. openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
  534. {
  535. char * temp_file = NULL;
  536. int temp_fd = -1;
  537. FILE *fp;
  538. char *line = NULL;
  539. size_t line_size = 0;
  540. if (virAsprintf(&temp_file, "%s.tmp", conf_file)<0)
  541. return -1;
  542. fp = fopen(conf_file, "r");
  543. if (fp == NULL)
  544. goto error;
  545. temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  546. if (temp_fd == -1)
  547. goto error;
  548. while (1) {
  549. if (getline(&line, &line_size, fp) <= 0)
  550. break;
  551. if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
  552. if (safewrite(temp_fd, line, strlen(line)) !=
  553. strlen(line))
  554. goto error;
  555. }
  556. }
  557. if (safewrite(temp_fd, param, strlen(param)) < 0 ||
  558. safewrite(temp_fd, "=\"", 2) < 0 ||
  559. safewrite(temp_fd, value, strlen(value)) < 0 ||
  560. safewrite(temp_fd, "\"\n", 2) < 0)
  561. goto error;
  562. if (VIR_FCLOSE(fp) < 0)
  563. goto error;
  564. if (VIR_CLOSE(temp_fd) < 0)
  565. goto error;
  566. if (rename(temp_file, conf_file) < 0)
  567. goto error;
  568. VIR_FREE(line);
  569. return 0;
  570. error:
  571. VIR_FREE(line);
  572. VIR_FORCE_FCLOSE(fp);
  573. VIR_FORCE_CLOSE(temp_fd);
  574. if (temp_file)
  575. unlink(temp_file);
  576. VIR_FREE(temp_file);
  577. return -1;
  578. }
  579. int
  580. openvzWriteVPSConfigParam(int vpsid, const char *param, const char *value)
  581. {
  582. char *conf_file;
  583. int ret;
  584. if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
  585. return -1;
  586. ret = openvzWriteConfigParam(conf_file, param, value);
  587. VIR_FREE(conf_file);
  588. return ret;
  589. }
  590. /*
  591. * value will be freed before a new value is assigned to it, the caller is
  592. * responsible for freeing it afterwards.
  593. *
  594. * Returns <0 on error, 0 if not found, 1 if found.
  595. */
  596. int
  597. openvzReadConfigParam(const char *conf_file, const char *param, char **value)
  598. {
  599. char *line = NULL;
  600. size_t line_size = 0;
  601. FILE *fp;
  602. int err = 0;
  603. char *sf, *token, *saveptr = NULL;
  604. fp = fopen(conf_file, "r");
  605. if (fp == NULL)
  606. return -1;
  607. VIR_FREE(*value);
  608. while (1) {
  609. if (getline(&line, &line_size, fp) < 0) {
  610. err = !feof(fp);
  611. break;
  612. }
  613. if (!(sf = STRSKIP(line, param)))
  614. continue;
  615. if (*sf++ != '=')
  616. continue;
  617. saveptr = NULL;
  618. if ((token = strtok_r(sf, "\"\t\n", &saveptr)) != NULL) {
  619. VIR_FREE(*value);
  620. if (VIR_STRDUP(*value, token) < 0) {
  621. err = 1;
  622. break;
  623. }
  624. /* keep going - last entry wins */
  625. }
  626. }
  627. VIR_FREE(line);
  628. VIR_FORCE_FCLOSE(fp);
  629. return err ? -1 : *value ? 1 : 0;
  630. }
  631. /*
  632. * Read parameter from container config
  633. *
  634. * value will be freed before a new value is assigned to it, the caller is
  635. * responsible for freeing it afterwards.
  636. *
  637. * sample: 133, "OSTEMPLATE", &value
  638. * return: -1 - error
  639. * 0 - don't found
  640. * 1 - OK
  641. */
  642. int
  643. openvzReadVPSConfigParam(int vpsid, const char *param, char **value)
  644. {
  645. char *conf_file;
  646. int ret;
  647. if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
  648. return -1;
  649. ret = openvzReadConfigParam(conf_file, param, value);
  650. VIR_FREE(conf_file);
  651. return ret;
  652. }
  653. static int
  654. openvz_copyfile(char* from_path, char* to_path)
  655. {
  656. char *line = NULL;
  657. size_t line_size = 0;
  658. FILE *fp;
  659. int copy_fd;
  660. int bytes_read;
  661. fp = fopen(from_path, "r");
  662. if (fp == NULL)
  663. return -1;
  664. copy_fd = open(to_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  665. if (copy_fd == -1) {
  666. VIR_FORCE_FCLOSE(fp);
  667. return -1;
  668. }
  669. while (1) {
  670. if (getline(&line, &line_size, fp) <= 0)
  671. break;
  672. bytes_read = strlen(line);
  673. if (safewrite(copy_fd, line, bytes_read) != bytes_read)
  674. goto error;
  675. }
  676. if (VIR_FCLOSE(fp) < 0)
  677. goto error;
  678. if (VIR_CLOSE(copy_fd) < 0)
  679. goto error;
  680. VIR_FREE(line);
  681. return 0;
  682. error:
  683. VIR_FREE(line);
  684. VIR_FORCE_FCLOSE(fp);
  685. VIR_FORCE_CLOSE(copy_fd);
  686. return -1;
  687. }
  688. /*
  689. * Copy the default config to the VE conf file
  690. * return: -1 - error
  691. * 0 - OK
  692. */
  693. int
  694. openvzCopyDefaultConfig(int vpsid)
  695. {
  696. char *confdir = NULL;
  697. char *default_conf_file = NULL;
  698. char *configfile_value = NULL;
  699. char *conf_file = NULL;
  700. int ret = -1;
  701. if (openvzReadConfigParam(VZ_CONF_FILE, "CONFIGFILE", &configfile_value) < 0)
  702. goto cleanup;
  703. confdir = openvzLocateConfDir();
  704. if (confdir == NULL)
  705. goto cleanup;
  706. if (virAsprintf(&default_conf_file, "%s/ve-%s.conf-sample", confdir,
  707. configfile_value) < 0)
  708. goto cleanup;
  709. if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
  710. goto cleanup;
  711. if (openvz_copyfile(default_conf_file, conf_file)<0)
  712. goto cleanup;
  713. ret = 0;
  714. cleanup:
  715. VIR_FREE(confdir);
  716. VIR_FREE(default_conf_file);
  717. VIR_FREE(configfile_value);
  718. VIR_FREE(conf_file);
  719. return ret;
  720. }
  721. /* Locate config file of container
  722. * return -1 - error
  723. * 0 - OK */
  724. static int
  725. openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext)
  726. {
  727. char *confdir;
  728. int ret = 0;
  729. confdir = openvzLocateConfDir();
  730. if (confdir == NULL)
  731. return -1;
  732. if (virAsprintf(conffile, "%s/%d.%s", confdir, vpsid,
  733. ext ? ext : "conf") < 0)
  734. ret = -1;
  735. VIR_FREE(confdir);
  736. return ret;
  737. }
  738. static char *
  739. openvzLocateConfDir(void)
  740. {
  741. const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL};
  742. size_t i = 0;
  743. char *ret = NULL;
  744. while (conf_dir_list[i]) {
  745. if (virFileExists(conf_dir_list[i])) {
  746. ignore_value(VIR_STRDUP(ret, conf_dir_list[i]));
  747. goto cleanup;
  748. }
  749. i++;
  750. }
  751. cleanup:
  752. return ret;
  753. }
  754. /* Richard Steven's classic readline() function */
  755. int
  756. openvz_readline(int fd, char *ptr, int maxlen)
  757. {
  758. int n, rc;
  759. char c;
  760. for (n = 1; n < maxlen; n++) {
  761. if ((rc = read(fd, &c, 1)) == 1) {
  762. *ptr++ = c;
  763. if (c == '\n')
  764. break;
  765. } else if (rc == 0) {
  766. if (n == 1)
  767. return 0; /* EOF condition */
  768. else
  769. break;
  770. }
  771. else
  772. return -1; /* error */
  773. }
  774. *ptr = 0;
  775. return n;
  776. }
  777. static int
  778. openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
  779. {
  780. char *conf_file;
  781. char *line = NULL;
  782. size_t line_size = 0;
  783. char *saveptr = NULL;
  784. char *uuidbuf;
  785. char *iden;
  786. FILE *fp;
  787. int retval = -1;
  788. if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
  789. return -1;
  790. fp = fopen(conf_file, "r");
  791. if (fp == NULL)
  792. goto cleanup;
  793. while (1) {
  794. if (getline(&line, &line_size, fp) < 0) {
  795. if (feof(fp)) { /* EOF, UUID was not found */
  796. uuidstr[0] = 0;
  797. break;
  798. } else {
  799. goto cleanup;
  800. }
  801. }
  802. iden = strtok_r(line, " ", &saveptr);
  803. uuidbuf = strtok_r(NULL, "\n", &saveptr);
  804. if (iden != NULL && uuidbuf != NULL && STREQ(iden, "#UUID:")) {
  805. if (virStrcpy(uuidstr, uuidbuf, len) == NULL) {
  806. virReportError(VIR_ERR_INTERNAL_ERROR,
  807. _("invalid uuid %s"), uuidbuf);
  808. goto cleanup;
  809. }
  810. break;
  811. }
  812. }
  813. retval = 0;
  814. cleanup:
  815. VIR_FREE(line);
  816. VIR_FORCE_FCLOSE(fp);
  817. VIR_FREE(conf_file);
  818. return retval;
  819. }
  820. /* Do actual checking for UUID presence in conf file,
  821. * assign if not present.
  822. */
  823. int
  824. openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
  825. {
  826. char *conf_file;
  827. char uuidstr[VIR_UUID_STRING_BUFLEN];
  828. FILE *fp = NULL;
  829. int ret = -1;
  830. if (uuid == NULL)
  831. return -1;
  832. if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
  833. return -1;
  834. if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
  835. goto cleanup;
  836. if (uuidstr[0] == 0) {
  837. fp = fopen(conf_file, "a"); /* append */
  838. if (fp == NULL)
  839. goto cleanup;
  840. virUUIDFormat(uuid, uuidstr);
  841. /* Record failure if fprintf or VIR_FCLOSE fails,
  842. and be careful always to close the stream. */
  843. if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0) ||
  844. (VIR_FCLOSE(fp) == EOF))
  845. goto cleanup;
  846. }
  847. ret = 0;
  848. cleanup:
  849. VIR_FORCE_FCLOSE(fp);
  850. VIR_FREE(conf_file);
  851. return ret;
  852. }
  853. static int
  854. openvzSetUUID(int vpsid)
  855. {
  856. unsigned char uuid[VIR_UUID_BUFLEN];
  857. if (virUUIDGenerate(uuid)) {
  858. virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  859. _("Failed to generate UUID"));
  860. return -1;
  861. }
  862. return openvzSetDefinedUUID(vpsid, uuid);
  863. }
  864. /*
  865. * Scan VPS config files and see if they have a UUID.
  866. * If not, assign one. Just append one to the config
  867. * file as comment so that the OpenVZ tools ignore it.
  868. *
  869. */
  870. static int openvzAssignUUIDs(void)
  871. {
  872. DIR *dp;
  873. struct dirent *dent;
  874. char *conf_dir;
  875. int vpsid;
  876. char *ext;
  877. int ret = 0;
  878. conf_dir = openvzLocateConfDir();
  879. if (conf_dir == NULL)
  880. return -1;
  881. if (virDirOpenQuiet(&dp, conf_dir) < 0) {
  882. VIR_FREE(conf_dir);
  883. return 0;
  884. }
  885. while ((ret = virDirRead(dp, &dent, conf_dir)) > 0) {
  886. if (virStrToLong_i(dent->d_name, &ext, 10, &vpsid) < 0 ||
  887. *ext++ != '.' ||
  888. STRNEQ(ext, "conf"))
  889. continue;
  890. if (vpsid > 0) /* '0.conf' belongs to the host, ignore it */
  891. openvzSetUUID(vpsid);
  892. }
  893. VIR_DIR_CLOSE(dp);
  894. VIR_FREE(conf_dir);
  895. return ret;
  896. }
  897. /*
  898. * Return CTID from name
  899. *
  900. */
  901. int openvzGetVEID(const char *name)
  902. {
  903. virCommandPtr cmd;
  904. char *outbuf;
  905. char *temp;
  906. int veid;
  907. bool ok;
  908. cmd = virCommandNewArgList(VZLIST, name, "-ovpsid", "-H", NULL);
  909. virCommandSetOutputBuffer(cmd, &outbuf);
  910. if (virCommandRun(cmd, NULL) < 0) {
  911. virCommandFree(cmd);
  912. VIR_FREE(outbuf);
  913. return -1;
  914. }
  915. virCommandFree(cmd);
  916. ok = virStrToLong_i(outbuf, &temp, 10, &veid) == 0 && *temp == '\n';
  917. VIR_FREE(outbuf);
  918. if (ok && veid >= 0)
  919. return veid;
  920. virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
  921. _("Failed to parse vzlist output"));
  922. return -1;
  923. }