openvz_conf.c 28.2 KB
Newer Older
1 2 3
/*
 * openvz_conf.c: config functions for managing OpenVZ VEs
 *
4
 * Copyright (C) 2010-2012, 2014 Red Hat, Inc.
5 6
 * Copyright (C) 2006, 2007 Binary Karma
 * Copyright (C) 2006 Shuveb Hussain
7
 * Copyright (C) 2007 Anoop Joe Cyriac
8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library.  If not, see
O
Osier Yang 已提交
21
 * <http://www.gnu.org/licenses/>.
22
 *
23
 * Authors:
24 25 26
 * Shuveb Hussain <shuveb@binarykarma.com>
 * Anoop Joe Cyriac <anoop@binarykarma.com>
 *
27 28
 */

29
#include <config.h>
J
Jim Meyering 已提交
30

31 32 33 34 35 36 37
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
38 39 40
#include <sys/stat.h>
#include <limits.h>
#include <errno.h>
D
Daniel P. Berrange 已提交
41
#include <string.h>
42
#include <sys/wait.h>
43

44
#include "virerror.h"
45
#include "openvz_conf.h"
46
#include "openvz_util.h"
47
#include "viruuid.h"
48
#include "virbuffer.h"
49
#include "viralloc.h"
E
Eric Blake 已提交
50
#include "virfile.h"
51
#include "vircommand.h"
52
#include "virstring.h"
53
#include "virhostcpu.h"
54

55 56
#define VIR_FROM_THIS VIR_FROM_OPENVZ

57
static char *openvzLocateConfDir(void);
58
static int openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len);
59
static int openvzAssignUUIDs(void);
60 61 62
static int openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext);

openvzLocateConfFileFunc openvzLocateConfFile = openvzLocateConfFileDefault;
63

64
int
65
strtoI(const char *str)
66 67 68
{
    int val;

69
    if (virStrToLong_i(str, NULL, 10, &val) < 0)
E
Eric Blake 已提交
70
        return 0;
71

72 73 74
    return val;
}

75 76

static int
77
openvzExtractVersionInfo(const char *cmdstr, int *retversion)
78
{
79
    int ret = -1;
80
    unsigned long version;
81
    char *help = NULL;
82
    char *tmp;
83
    virCommandPtr cmd = virCommandNewArgList(cmdstr, "--help", NULL);
84 85 86 87

    if (retversion)
        *retversion = 0;

88 89
    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &help);
90

91 92
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;
93

94 95 96 97
    tmp = help;

    /* expected format: vzctl version <major>.<minor>.<micro> */
    if ((tmp = STRSKIP(tmp, "vzctl version ")) == NULL)
98
        goto cleanup;
99

I
Ilja Livenson 已提交
100
    if (virParseVersionString(tmp, &version, true) < 0)
101
        goto cleanup;
102 103 104 105 106 107

    if (retversion)
        *retversion = version;

    ret = 0;

108
 cleanup:
109
    virCommandFree(cmd);
110 111 112 113 114
    VIR_FREE(help);

    return ret;
}

115
int openvzExtractVersion(struct openvz_driver *driver)
116 117 118 119 120
{
    if (driver->version > 0)
        return 0;

    if (openvzExtractVersionInfo(VZCTL, &driver->version) < 0) {
121 122
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not extract vzctl version"));
123 124 125 126 127 128 129
        return -1;
    }

    return 0;
}


130 131 132 133 134 135
/* Parse config values of the form barrier:limit into barrier and limit */
static int
openvzParseBarrierLimit(const char* value,
                        unsigned long long *barrier,
                        unsigned long long *limit)
{
136 137
    char **tmp = NULL;
    size_t ntmp = 0;
P
Pavel Hrdina 已提交
138
    int ret = -1;
139

140
    if (!(tmp = virStringSplitCount(value, ":", 0, &ntmp)))
141 142
        goto error;

143
    if (ntmp != 2)
144
        goto error;
145 146

    if (barrier && virStrToLong_ull(tmp[0], NULL, 10, barrier) < 0)
147
        goto error;
148 149 150 151

    if (limit && virStrToLong_ull(tmp[1], NULL, 10, limit) < 0)
        goto error;

P
Pavel Hrdina 已提交
152
    ret = 0;
153
 error:
154
    virStringListFreeCount(tmp, ntmp);
P
Pavel Hrdina 已提交
155
    return ret;
156 157 158
}


159 160 161 162 163
virCapsPtr openvzCapsInit(void)
{
    virCapsPtr caps;
    virCapsGuestPtr guest;

164
    if ((caps = virCapabilitiesNew(virArchFromHost(),
165
                                   false, false)) == NULL)
166 167
        goto no_memory;

M
Martin Kletzander 已提交
168
    if (virCapabilitiesInitNUMA(caps) < 0)
169 170
        goto no_memory;

171 172 173
    if (virCapabilitiesInitCaches(caps) < 0)
        goto no_memory;

174
    if ((guest = virCapabilitiesAddGuest(caps,
175
                                         VIR_DOMAIN_OSTYPE_EXE,
176
                                         caps->host.arch,
177 178 179 180 181 182 183
                                         NULL,
                                         NULL,
                                         0,
                                         NULL)) == NULL)
        goto no_memory;

    if (virCapabilitiesAddGuestDomain(guest,
184
                                      VIR_DOMAIN_VIRT_OPENVZ,
185 186 187 188 189 190
                                      NULL,
                                      NULL,
                                      0,
                                      NULL) == NULL)
        goto no_memory;

191
    return caps;
192

193
 no_memory:
194
    virObjectUnref(caps);
195 196 197 198
    return NULL;
}


199
int
200
openvzReadNetworkConf(virDomainDefPtr def,
201 202
                      int veid)
{
203
    int ret;
204
    virDomainNetDefPtr net = NULL;
205
    char *temp = NULL;
206 207 208 209 210
    char *token, *saveptr = NULL;

    /*parse routing network configuration*
     * Sample from config:
     *   IP_ADDRESS="1.1.1.1 1.1.1.2"
N
Nehal J Wani 已提交
211
     * IPs split by space
212
     */
213
    ret = openvzReadVPSConfigParam(veid, "IP_ADDRESS", &temp);
214
    if (ret < 0) {
215 216 217
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'IP_ADDRESS' from config for container %d"),
                       veid);
218 219 220 221
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, " ", &saveptr);
        while (token != NULL) {
222
            if (VIR_ALLOC(net) < 0)
223
                goto error;
224 225

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
226
            if (virDomainNetAppendIPAddress(net, token, AF_UNSPEC, 0) < 0)
227
                goto error;
228

229
            if (VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net) < 0)
230
                goto error;
231

232 233 234 235 236 237
            token = strtok_r(NULL, " ", &saveptr);
        }
    }

    /*parse bridge devices*/
    /*Sample from config:
N
Nehal J Wani 已提交
238 239
     * NETIF="ifname=eth10,mac=00:18:51:C1:05:EE,host_ifname=veth105.10,host_mac=00:18:51:8F:D9:F3"
     *devices split by ';'
240
     */
241
    ret = openvzReadVPSConfigParam(veid, "NETIF", &temp);
242
    if (ret < 0) {
243 244 245
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'NETIF' from config for container %d"),
                       veid);
246 247 248 249 250
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, ";", &saveptr);
        while (token != NULL) {
            /*add new device to list*/
251
            if (VIR_ALLOC(net) < 0)
252
                goto error;
253 254 255

            net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;

256
            char *p = token;
257 258 259 260 261
            char cpy_temp[32];
            int len;

            /*parse string*/
            do {
262
                char *next = strchrnul(p, ',');
263
                if (STRPREFIX(p, "ifname=")) {
264 265 266
                    /* skip in libvirt */
                } else if (STRPREFIX(p, "host_ifname=")) {
                    p += 12;
267 268
                    len = next - p;
                    if (len > 16) {
269 270
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Too long network device name"));
271 272 273
                        goto error;
                    }

274
                    if (VIR_ALLOC_N(net->ifname, len+1) < 0)
275
                        goto error;
276

C
Chris Lalancette 已提交
277
                    if (virStrncpy(net->ifname, p, len, len+1) == NULL) {
278 279
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Network ifname %s too long for destination"), p);
C
Chris Lalancette 已提交
280 281
                        goto error;
                    }
282 283 284 285
                } else if (STRPREFIX(p, "bridge=")) {
                    p += 7;
                    len = next - p;
                    if (len > 16) {
286 287
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Too long bridge device name"));
288 289 290
                        goto error;
                    }

291
                    if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
292
                        goto error;
293

C
Chris Lalancette 已提交
294
                    if (virStrncpy(net->data.bridge.brname, p, len, len+1) == NULL) {
295 296
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Bridge name %s too long for destination"), p);
C
Chris Lalancette 已提交
297 298
                        goto error;
                    }
299 300 301
                } else if (STRPREFIX(p, "mac=")) {
                    p += 4;
                    len = next - p;
302
                    if (len != 17) { /* should be 17 */
303 304
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Wrong length MAC address"));
305 306
                        goto error;
                    }
C
Chris Lalancette 已提交
307
                    if (virStrncpy(cpy_temp, p, len, sizeof(cpy_temp)) == NULL) {
308 309
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("MAC address %s too long for destination"), p);
C
Chris Lalancette 已提交
310 311
                        goto error;
                    }
312
                    if (virMacAddrParse(cpy_temp, &net->mac) < 0) {
313 314
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Wrong MAC address"));
315 316 317 318 319 320
                        goto error;
                    }
                }
                p = ++next;
            } while (p < token + strlen(token));

321
            if (VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net) < 0)
322
                goto error;
323

324 325 326 327
            token = strtok_r(NULL, ";", &saveptr);
        }
    }

328 329
    VIR_FREE(temp);

330
    return 0;
331

332
 error:
333
    VIR_FREE(temp);
334
    virDomainNetDefFree(net);
335
    return -1;
336 337 338
}


339
static int
340
openvzReadFSConf(virDomainDefPtr def,
341 342
                 int veid)
{
343 344
    int ret;
    virDomainFSDefPtr fs = NULL;
345 346
    char *veid_str = NULL;
    char *temp = NULL;
347 348
    const char *param;
    unsigned long long barrier, limit;
349

350
    ret = openvzReadVPSConfigParam(veid, "OSTEMPLATE", &temp);
351
    if (ret < 0) {
352 353 354
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'OSTEMPLATE' from config for container %d"),
                       veid);
355 356
        goto error;
    } else if (ret > 0) {
357
        if (!(fs = virDomainFSDefNew()))
358
            goto error;
359 360

        fs->type = VIR_DOMAIN_FS_TYPE_TEMPLATE;
361
        if (VIR_STRDUP(fs->src->path, temp) < 0)
362
            goto error;
363 364
    } else {
        /* OSTEMPLATE was not found, VE was booted from a private dir directly */
365
        ret = openvzReadVPSConfigParam(veid, "VE_PRIVATE", &temp);
366
        if (ret <= 0) {
367 368 369
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read 'VE_PRIVATE' from config for container %d"),
                           veid);
370 371
            goto error;
        }
372

373
        if (VIR_ALLOC(fs) < 0)
374
            goto error;
375

376
        if (virAsprintf(&veid_str, "%d", veid) < 0)
377
            goto error;
378 379

        fs->type = VIR_DOMAIN_FS_TYPE_MOUNT;
380
        if (!(fs->src->path = virStringReplace(temp, "$VEID", veid_str)))
381
            goto error;
382

383
        VIR_FREE(veid_str);
384 385
    }

386 387
    if (VIR_STRDUP(fs->dst, "/") < 0)
        goto error;
388

389 390 391 392
    param = "DISKSPACE";
    ret = openvzReadVPSConfigParam(veid, param, &temp);
    if (ret > 0) {
        if (openvzParseBarrierLimit(temp, &barrier, &limit)) {
393 394 395
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read '%s' from config for container %d"),
                           param, veid);
396 397 398
            goto error;
        } else {
            /* Ensure that we can multiply by 1024 without overflowing. */
399
            if (barrier > ULLONG_MAX / 1024 ||
400
                limit > ULLONG_MAX / 1024) {
J
Jiri Denemark 已提交
401 402
                virReportError(VIR_ERR_OVERFLOW, "%s",
                               _("Unable to parse quota"));
403 404 405 406 407 408 409
                goto error;
            }
            fs->space_soft_limit = barrier * 1024; /* unit is bytes */
            fs->space_hard_limit = limit * 1024;   /* unit is bytes */
        }
    }

410
    if (VIR_APPEND_ELEMENT(def->fss, def->nfss, fs) < 0)
411
        goto error;
412

413 414
    VIR_FREE(temp);

415
    return 0;
416
 error:
417
    VIR_FREE(temp);
418 419 420 421 422
    virDomainFSDefFree(fs);
    return -1;
}


423 424 425
static int
openvzReadMemConf(virDomainDefPtr def, int veid)
{
426
    int ret = -1;
427 428 429
    char *temp = NULL;
    unsigned long long barrier, limit;
    const char *param;
430
    long kb_per_pages;
431

432 433
    kb_per_pages = openvzKBPerPages();
    if (kb_per_pages < 0)
434 435 436 437 438 439
        goto error;

    /* Memory allocation guarantee */
    param = "VMGUARPAGES";
    ret = openvzReadVPSConfigParam(veid, param, &temp);
    if (ret < 0) {
440 441 442
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read '%s' from config for container %d"),
                       param, veid);
443 444 445 446
        goto error;
    } else if (ret > 0) {
        ret = openvzParseBarrierLimit(temp, &barrier, NULL);
        if (ret < 0) {
447 448 449
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse barrier of '%s' "
                             "from config for container %d"), param, veid);
450 451 452 453 454 455 456 457 458 459 460 461
            goto error;
        }
        if (barrier == LONG_MAX)
            def->mem.min_guarantee = 0ull;
        else
            def->mem.min_guarantee = barrier * kb_per_pages;
    }

    /* Memory hard and soft limits */
    param = "PRIVVMPAGES";
    ret = openvzReadVPSConfigParam(veid, param, &temp);
    if (ret < 0) {
462 463 464
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read '%s' from config for container %d"),
                       param, veid);
465 466 467 468
        goto error;
    } else if (ret > 0) {
        ret = openvzParseBarrierLimit(temp, &barrier, &limit);
        if (ret < 0) {
469 470 471
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse barrier and limit of '%s' "
                             "from config for container %d"), param, veid);
472 473 474
            goto error;
        }
        if (barrier == LONG_MAX)
475
            def->mem.soft_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
476 477 478 479
        else
            def->mem.soft_limit = barrier * kb_per_pages;

        if (limit == LONG_MAX)
480
            def->mem.hard_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
481 482 483 484 485
        else
            def->mem.hard_limit = limit * kb_per_pages;
    }

    ret = 0;
486
 error:
487 488 489 490 491
    VIR_FREE(temp);
    return ret;
}


492 493 494 495 496 497
/* Free all memory associated with a openvz_driver structure */
void
openvzFreeDriver(struct openvz_driver *driver)
{
    if (!driver)
        return;
498

499
    virObjectUnref(driver->xmlopt);
500
    virObjectUnref(driver->domains);
501
    virObjectUnref(driver->caps);
502
    VIR_FREE(driver);
503
}
D
Daniel Veillard 已提交
504 505 506



507 508
int openvzLoadDomains(struct openvz_driver *driver)
{
509
    int veid, ret;
510
    char *status;
511
    char uuidstr[VIR_UUID_STRING_BUFLEN];
512
    virDomainObjPtr dom = NULL;
513
    virDomainDefPtr def = NULL;
514
    char *temp = NULL;
E
Eric Blake 已提交
515 516 517
    char *outbuf = NULL;
    char *line;
    virCommandPtr cmd = NULL;
518
    unsigned int vcpus = 0;
519

520 521
    if (openvzAssignUUIDs() < 0)
        return -1;
522

E
Eric Blake 已提交
523 524 525 526
    cmd = virCommandNewArgList(VZLIST, "-a", "-ovpsid,status", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;
527

528 529
    line = outbuf;
    while (line[0] != '\0') {
530
        unsigned int flags = 0;
531 532 533
        if (virStrToLong_i(line, &status, 10, &veid) < 0 ||
            *status++ != ' ' ||
            (line = strchr(status, '\n')) == NULL) {
534 535
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Failed to parse vzlist output"));
536
            goto cleanup;
537
        }
538
        *line++ = '\0';
539

540
        if (!(def = virDomainDefNew()))
541
            goto cleanup;
542

543
        def->virtType = VIR_DOMAIN_VIRT_OPENVZ;
544

545 546
        if (STREQ(status, "stopped"))
            def->id = -1;
J
Jiri Denemark 已提交
547
        else
548 549
            def->id = veid;
        if (virAsprintf(&def->name, "%i", veid) < 0)
550
            goto cleanup;
551

552
        openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr));
553
        ret = virUUIDParse(uuidstr, def->uuid);
554

555
        if (ret == -1) {
556 557
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("UUID in config file malformed"));
558
            goto cleanup;
559
        }
560

561
        def->os.type = VIR_DOMAIN_OSTYPE_EXE;
562 563
        if (VIR_STRDUP(def->os.init, "/sbin/init") < 0)
            goto cleanup;
564

565
        ret = openvzReadVPSConfigParam(veid, "CPUS", &temp);
566
        if (ret < 0) {
567 568 569
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read config for container %d"),
                           veid);
570
            goto cleanup;
571
        } else if (ret > 0) {
572
            vcpus = strtoI(temp);
573 574
        }

575
        if (ret == 0 || vcpus == 0)
576
            vcpus = virHostCPUGetCount();
577

578
        if (virDomainDefSetVcpusMax(def, vcpus, driver->xmlopt) < 0)
579 580
            goto cleanup;

581 582
        if (virDomainDefSetVcpus(def, vcpus) < 0)
            goto cleanup;
583

584
        /* XXX load rest of VM config data .... */
585

586 587 588
        openvzReadNetworkConf(def, veid);
        openvzReadFSConf(def, veid);
        openvzReadMemConf(def, veid);
589

590
        virUUIDFormat(def->uuid, uuidstr);
591 592 593 594
        flags = VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE;
        if (STRNEQ(status, "stopped"))
            flags |= VIR_DOMAIN_OBJ_LIST_ADD_LIVE;

595 596
        if (!(dom = virDomainObjListAdd(driver->domains,
                                        def,
597
                                        driver->xmlopt,
598 599
                                        flags,
                                        NULL)))
600
            goto cleanup;
601 602 603 604 605 606 607 608 609

        if (STREQ(status, "stopped")) {
            virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF,
                                 VIR_DOMAIN_SHUTOFF_UNKNOWN);
            dom->pid = -1;
        } else {
            virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_UNKNOWN);
            dom->pid = veid;
610
        }
611 612
        /* XXX OpenVZ doesn't appear to have concept of a transient domain */
        dom->persistent = 1;
613

614
        virObjectUnlock(dom);
615
        dom = NULL;
616
        def = NULL;
617
    }
618

E
Eric Blake 已提交
619
    virCommandFree(cmd);
620
    VIR_FREE(temp);
E
Eric Blake 已提交
621
    VIR_FREE(outbuf);
622

623
    return 0;
624

625
 cleanup:
E
Eric Blake 已提交
626
    virCommandFree(cmd);
627
    VIR_FREE(temp);
E
Eric Blake 已提交
628
    VIR_FREE(outbuf);
629
    virDomainDefFree(def);
630
    return -1;
631 632
}

633 634
static int
openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
635
{
636
    char * temp_file = NULL;
637 638 639 640
    int temp_fd = -1;
    FILE *fp;
    char *line = NULL;
    size_t line_size = 0;
641

642
    if (virAsprintf(&temp_file, "%s.tmp", conf_file)<0)
643 644
        return -1;

645 646
    fp = fopen(conf_file, "r");
    if (fp == NULL)
647
        goto error;
648
    temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
649
    if (temp_fd == -1)
650
        goto error;
651

E
Eric Blake 已提交
652
    while (1) {
653
        if (getline(&line, &line_size, fp) <= 0)
654 655
            break;

656
        if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
657 658 659 660 661 662 663 664 665 666 667 668
            if (safewrite(temp_fd, line, strlen(line)) !=
                strlen(line))
                goto error;
        }
    }

    if (safewrite(temp_fd, param, strlen(param)) < 0 ||
        safewrite(temp_fd, "=\"", 2) < 0 ||
        safewrite(temp_fd, value, strlen(value)) < 0 ||
        safewrite(temp_fd, "\"\n", 2) < 0)
        goto error;

669
    if (VIR_FCLOSE(fp) < 0)
670
        goto error;
671
    if (VIR_CLOSE(temp_fd) < 0)
672 673 674 675 676
        goto error;

    if (rename(temp_file, conf_file) < 0)
        goto error;

677 678
    VIR_FREE(line);

679 680
    return 0;

681
 error:
682 683
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
684
    VIR_FORCE_CLOSE(temp_fd);
E
Eric Blake 已提交
685
    if (temp_file)
686 687
        unlink(temp_file);
    VIR_FREE(temp_file);
688 689 690
    return -1;
}

691
int
692 693
openvzWriteVPSConfigParam(int vpsid, const char *param, const char *value)
{
694 695
    char *conf_file;
    int ret;
696

697
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
698 699
        return -1;

700 701 702
    ret = openvzWriteConfigParam(conf_file, param, value);
    VIR_FREE(conf_file);
    return ret;
703 704
}

705 706 707
/*
 * value will be freed before a new value is assigned to it, the caller is
 * responsible for freeing it afterwards.
708 709
 *
 * Returns <0 on error, 0 if not found, 1 if found.
710
 */
711
int
712
openvzReadConfigParam(const char *conf_file, const char *param, char **value)
713
{
714 715 716
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
717 718
    int err = 0;
    char *sf, *token, *saveptr = NULL;
719

720 721
    fp = fopen(conf_file, "r");
    if (fp == NULL)
722 723
        return -1;

724
    VIR_FREE(*value);
725 726 727 728 729 730
    while (1) {
        if (getline(&line, &line_size, fp) < 0) {
            err = !feof(fp);
            break;
        }

J
Ján Tomko 已提交
731
        if (!(sf = STRSKIP(line, param)))
732 733
            continue;

J
Ján Tomko 已提交
734 735
        if (*sf++ != '=')
            continue;
736

737
        saveptr = NULL;
738 739
        if ((token = strtok_r(sf, "\"\t\n", &saveptr)) != NULL) {
            VIR_FREE(*value);
740
            if (VIR_STRDUP(*value, token) < 0) {
741 742
                err = 1;
                break;
743
            }
744 745
            /* keep going - last entry wins */
        }
746
    }
747 748
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
749

750
    return err ? -1 : *value ? 1 : 0;
751 752
}

753
/*
754 755
 * Read parameter from container config
 *
N
Nitesh Konkar 已提交
756
 * value will be freed before a new value is assigned to it, the caller is
757 758 759 760 761 762 763
 * responsible for freeing it afterwards.
 *
 * sample: 133, "OSTEMPLATE", &value
 * return: -1 - error
 *          0 - don't found
 *          1 - OK
 */
764
int
765
openvzReadVPSConfigParam(int vpsid, const char *param, char **value)
766
{
767 768
    char *conf_file;
    int ret;
769

770
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
771 772
        return -1;

773
    ret = openvzReadConfigParam(conf_file, param, value);
774 775
    VIR_FREE(conf_file);
    return ret;
776 777 778 779 780
}

static int
openvz_copyfile(char* from_path, char* to_path)
{
781 782 783 784
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
    int copy_fd;
785 786
    int bytes_read;

787 788
    fp = fopen(from_path, "r");
    if (fp == NULL)
789 790 791
        return -1;
    copy_fd = open(to_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (copy_fd == -1) {
792
        VIR_FORCE_FCLOSE(fp);
793 794 795
        return -1;
    }

E
Eric Blake 已提交
796
    while (1) {
797
        if (getline(&line, &line_size, fp) <= 0)
798 799 800 801 802 803 804
            break;

        bytes_read = strlen(line);
        if (safewrite(copy_fd, line, bytes_read) != bytes_read)
            goto error;
    }

805
    if (VIR_FCLOSE(fp) < 0)
806
        goto error;
807
    if (VIR_CLOSE(copy_fd) < 0)
808 809
        goto error;

810 811
    VIR_FREE(line);

812 813
    return 0;

814
 error:
815 816
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
817
    VIR_FORCE_CLOSE(copy_fd);
818 819 820 821 822 823 824 825 826 827 828
    return -1;
}

/*
* Copy the default config to the VE conf file
* return: -1 - error
*          0 - OK
*/
int
openvzCopyDefaultConfig(int vpsid)
{
829 830 831
    char *confdir = NULL;
    char *default_conf_file = NULL;
    char *configfile_value = NULL;
832
    char *conf_file = NULL;
833 834
    int ret = -1;

835
    if (openvzReadConfigParam(VZ_CONF_FILE, "CONFIGFILE", &configfile_value) < 0)
836 837 838 839 840 841
        goto cleanup;

    confdir = openvzLocateConfDir();
    if (confdir == NULL)
        goto cleanup;

842
    if (virAsprintf(&default_conf_file, "%s/ve-%s.conf-sample", confdir,
843
                    configfile_value) < 0)
844 845
        goto cleanup;

846
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
847 848 849 850 851 852
        goto cleanup;

    if (openvz_copyfile(default_conf_file, conf_file)<0)
        goto cleanup;

    ret = 0;
853
 cleanup:
854 855
    VIR_FREE(confdir);
    VIR_FREE(default_conf_file);
856
    VIR_FREE(configfile_value);
857
    VIR_FREE(conf_file);
858 859 860
    return ret;
}

861
/* Locate config file of container
862 863
 * return -1 - error
 *         0 - OK */
864
static int
865
openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext)
866
{
867
    char *confdir;
868 869 870 871 872 873
    int ret = 0;

    confdir = openvzLocateConfDir();
    if (confdir == NULL)
        return -1;

874
    if (virAsprintf(conffile, "%s/%d.%s", confdir, vpsid,
875
                    ext ? ext : "conf") < 0)
876 877 878 879 880 881
        ret = -1;

    VIR_FREE(confdir);
    return ret;
}

882 883
static char *
openvzLocateConfDir(void)
884 885
{
    const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL};
886
    size_t i = 0;
887
    char *ret = NULL;
888

E
Eric Blake 已提交
889
    while (conf_dir_list[i]) {
890
        if (virFileExists(conf_dir_list[i])) {
891 892 893
            ignore_value(VIR_STRDUP(ret, conf_dir_list[i]));
            goto cleanup;
        }
E
Eric Blake 已提交
894
        i++;
895 896
    }

897
 cleanup:
898
    return ret;
899 900 901
}

/* Richard Steven's classic readline() function */
902
int
903
openvz_readline(int fd, char *ptr, int maxlen)
904 905 906 907
{
    int n, rc;
    char c;

E
Eric Blake 已提交
908
    for (n = 1; n < maxlen; n++) {
909
        if ((rc = read(fd, &c, 1)) == 1) {
910
            *ptr++ = c;
E
Eric Blake 已提交
911
            if (c == '\n')
912
                break;
E
Eric Blake 已提交
913 914
        } else if (rc == 0) {
            if (n == 1)
915 916 917 918 919 920 921 922 923 924 925
                return 0; /* EOF condition */
            else
                break;
        }
        else
            return -1; /* error */
    }
    *ptr = 0;
    return n;
}

926
static int
927
openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
928
{
929
    char *conf_file;
930 931
    char *line = NULL;
    size_t line_size = 0;
932
    char *saveptr = NULL;
933 934
    char *uuidbuf;
    char *iden;
935
    FILE *fp;
936
    int retval = -1;
937

938
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
939
        return -1;
940

941 942
    fp = fopen(conf_file, "r");
    if (fp == NULL)
943
        goto cleanup;
944

E
Eric Blake 已提交
945
    while (1) {
946 947 948 949 950 951 952
        if (getline(&line, &line_size, fp) < 0) {
            if (feof(fp)) { /* EOF, UUID was not found */
                uuidstr[0] = 0;
                break;
            } else {
                goto cleanup;
            }
953 954
        }

955 956 957 958
        iden = strtok_r(line, " ", &saveptr);
        uuidbuf = strtok_r(NULL, "\n", &saveptr);

        if (iden != NULL && uuidbuf != NULL && STREQ(iden, "#UUID:")) {
959
            if (virStrcpy(uuidstr, uuidbuf, len) == NULL) {
960 961
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("invalid uuid %s"), uuidbuf);
962 963
                goto cleanup;
            }
964 965 966
            break;
        }
    }
967
    retval = 0;
968
 cleanup:
969 970
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
971
    VIR_FREE(conf_file);
972

C
Chris Lalancette 已提交
973
    return retval;
974 975 976 977 978
}

/* Do actual checking for UUID presence in conf file,
 * assign if not present.
 */
979 980
int
openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
981
{
982
    char *conf_file;
983
    char uuidstr[VIR_UUID_STRING_BUFLEN];
984
    FILE *fp = NULL;
985
    int ret = -1;
986 987 988

    if (uuid == NULL)
        return -1;
989

990
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
991
        return -1;
992

993
    if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
994
        goto cleanup;
995

J
Jim Meyering 已提交
996
    if (uuidstr[0] == 0) {
997
        fp = fopen(conf_file, "a"); /* append */
998
        if (fp == NULL)
999
            goto cleanup;
1000

1001 1002
        virUUIDFormat(uuid, uuidstr);

1003
        /* Record failure if fprintf or VIR_FCLOSE fails,
1004
           and be careful always to close the stream.  */
1005 1006
        if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0) ||
            (VIR_FCLOSE(fp) == EOF))
1007
            goto cleanup;
1008 1009
    }

1010
    ret = 0;
1011
 cleanup:
1012
    VIR_FORCE_FCLOSE(fp);
1013 1014
    VIR_FREE(conf_file);
    return ret;
1015 1016
}

1017
static int
1018 1019
openvzSetUUID(int vpsid)
{
1020 1021
    unsigned char uuid[VIR_UUID_BUFLEN];

1022
    if (virUUIDGenerate(uuid) < 0) {
1023 1024
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to generate UUID"));
1025 1026
        return -1;
    }
1027 1028 1029 1030

    return openvzSetDefinedUUID(vpsid, uuid);
}

1031 1032 1033 1034 1035 1036 1037
/*
 * Scan VPS config files and see if they have a UUID.
 * If not, assign one. Just append one to the config
 * file as comment so that the OpenVZ tools ignore it.
 *
 */

1038
static int openvzAssignUUIDs(void)
1039 1040 1041 1042
{
    DIR *dp;
    struct dirent *dent;
    char *conf_dir;
1043 1044 1045
    int vpsid;
    char *ext;
    int ret = 0;
1046 1047

    conf_dir = openvzLocateConfDir();
1048 1049
    if (conf_dir == NULL)
        return -1;
1050

J
Ján Tomko 已提交
1051
    if (virDirOpenQuiet(&dp, conf_dir) < 0) {
1052
        VIR_FREE(conf_dir);
1053 1054 1055
        return 0;
    }

E
Eric Blake 已提交
1056
    while ((ret = virDirRead(dp, &dent, conf_dir)) > 0) {
1057 1058 1059
        if (virStrToLong_i(dent->d_name, &ext, 10, &vpsid) < 0 ||
            *ext++ != '.' ||
            STRNEQ(ext, "conf"))
1060
            continue;
E
Eric Blake 已提交
1061
        if (vpsid > 0) /* '0.conf' belongs to the host, ignore it */
1062 1063
            openvzSetUUID(vpsid);
    }
1064

J
Ján Tomko 已提交
1065
    VIR_DIR_CLOSE(dp);
1066
    VIR_FREE(conf_dir);
1067
    return ret;
1068
}
1069 1070 1071 1072 1073 1074 1075


/*
 * Return CTID from name
 *
 */

1076 1077
int openvzGetVEID(const char *name)
{
E
Eric Blake 已提交
1078 1079
    virCommandPtr cmd;
    char *outbuf;
1080
    char *temp;
1081
    int veid;
1082
    bool ok;
1083

E
Eric Blake 已提交
1084 1085 1086 1087 1088
    cmd = virCommandNewArgList(VZLIST, name, "-ovpsid", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0) {
        virCommandFree(cmd);
        VIR_FREE(outbuf);
1089 1090 1091
        return -1;
    }

E
Eric Blake 已提交
1092
    virCommandFree(cmd);
1093
    ok = virStrToLong_i(outbuf, &temp, 10, &veid) == 0 && *temp == '\n';
E
Eric Blake 已提交
1094
    VIR_FREE(outbuf);
1095

1096 1097 1098
    if (ok && veid >= 0)
        return veid;

1099 1100
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("Failed to parse vzlist output"));
1101 1102
    return -1;
}