openvz_conf.c 29.4 KB
Newer Older
1 2 3
/*
 * openvz_conf.c: config functions for managing OpenVZ VEs
 *
I
Ilja Livenson 已提交
4
 * Copyright (C) 2010-2012 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"
50
#include "nodeinfo.h"
E
Eric Blake 已提交
51
#include "virfile.h"
52
#include "vircommand.h"
53
#include "virstring.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 109
cleanup:
    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 136 137
/* 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)
{
    char *token;
    char *saveptr = NULL;
138
    char *str;
139

140
    if (VIR_STRDUP(str, value) < 0)
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
        goto error;

    token = strtok_r(str, ":", &saveptr);
    if (token == NULL) {
        goto error;
    } else {
        if (barrier != NULL) {
            if (virStrToLong_ull(token, NULL, 10, barrier))
                goto error;
        }
    }
    token = strtok_r(NULL, ":", &saveptr);
    if (token == NULL) {
        goto error;
    } else {
        if (limit != NULL) {
            if (virStrToLong_ull(token, NULL, 10, limit))
                goto error;
        }
    }
    return 0;
error:
    VIR_FREE(str);
    return -1;
}


168 169 170 171 172
virCapsPtr openvzCapsInit(void)
{
    virCapsPtr caps;
    virCapsGuestPtr guest;

173
    if ((caps = virCapabilitiesNew(virArchFromHost(),
174 175 176
                                   0, 0)) == NULL)
        goto no_memory;

177
    if (nodeCapsInitNUMA(caps) < 0)
178 179
        goto no_memory;

180 181
    if ((guest = virCapabilitiesAddGuest(caps,
                                         "exe",
182
                                         caps->host.arch,
183 184 185 186 187 188 189 190 191 192 193 194 195 196
                                         NULL,
                                         NULL,
                                         0,
                                         NULL)) == NULL)
        goto no_memory;

    if (virCapabilitiesAddGuestDomain(guest,
                                      "openvz",
                                      NULL,
                                      NULL,
                                      0,
                                      NULL) == NULL)
        goto no_memory;

197
    return caps;
198

199
no_memory:
200
    virObjectUnref(caps);
201 202 203 204
    return NULL;
}


205
int
206
openvzReadNetworkConf(virDomainDefPtr def,
207
                      int veid) {
208
    int ret;
209
    virDomainNetDefPtr net = NULL;
210
    char *temp = NULL;
211 212 213 214 215 216 217
    char *token, *saveptr = NULL;

    /*parse routing network configuration*
     * Sample from config:
     *   IP_ADDRESS="1.1.1.1 1.1.1.2"
     *   splited IPs by space
     */
218
    ret = openvzReadVPSConfigParam(veid, "IP_ADDRESS", &temp);
219
    if (ret < 0) {
220 221 222
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'IP_ADDRESS' from config for container %d"),
                       veid);
223 224 225 226
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, " ", &saveptr);
        while (token != NULL) {
227
            if (VIR_ALLOC(net) < 0)
228
                goto error;
229 230

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
231 232
            if (VIR_STRDUP(net->data.ethernet.ipaddr, token) < 0)
                goto error;
233

234
            if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
235
                goto error;
236 237 238
            def->nets[def->nnets++] = net;
            net = NULL;

239 240 241 242 243 244 245 246 247
            token = strtok_r(NULL, " ", &saveptr);
        }
    }

    /*parse bridge devices*/
    /*Sample from config:
     *NETIF="ifname=eth10,mac=00:18:51:C1:05:EE,host_ifname=veth105.10,host_mac=00:18:51:8F:D9:F3"
     *devices splited by ';'
     */
248
    ret = openvzReadVPSConfigParam(veid, "NETIF", &temp);
249
    if (ret < 0) {
250 251 252
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'NETIF' from config for container %d"),
                       veid);
253 254 255 256 257
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, ";", &saveptr);
        while (token != NULL) {
            /*add new device to list*/
258
            if (VIR_ALLOC(net) < 0)
259
                goto error;
260 261 262

            net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;

263
            char *p = token;
264 265 266 267 268
            char cpy_temp[32];
            int len;

            /*parse string*/
            do {
269
                char *next = strchrnul(p, ',');
270
                if (STRPREFIX(p, "ifname=")) {
271 272 273
                    /* skip in libvirt */
                } else if (STRPREFIX(p, "host_ifname=")) {
                    p += 12;
274 275
                    len = next - p;
                    if (len > 16) {
276 277
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Too long network device name"));
278 279 280
                        goto error;
                    }

281
                    if (VIR_ALLOC_N(net->ifname, len+1) < 0)
282
                        goto error;
283

C
Chris Lalancette 已提交
284
                    if (virStrncpy(net->ifname, p, len, len+1) == NULL) {
285 286
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Network ifname %s too long for destination"), p);
C
Chris Lalancette 已提交
287 288
                        goto error;
                    }
289 290 291 292
                } else if (STRPREFIX(p, "bridge=")) {
                    p += 7;
                    len = next - p;
                    if (len > 16) {
293 294
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Too long bridge device name"));
295 296 297
                        goto error;
                    }

298
                    if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
299
                        goto error;
300

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

328
            if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
329
                goto error;
330 331 332
            def->nets[def->nnets++] = net;
            net = NULL;

333 334 335 336
            token = strtok_r(NULL, ";", &saveptr);
        }
    }

337 338
    VIR_FREE(temp);

339
    return 0;
340

341
error:
342
    VIR_FREE(temp);
343
    virDomainNetDefFree(net);
344
    return -1;
345 346 347
}


348 349 350 351 352 353 354
/* utility function to replace 'from' by 'to' in 'str' */
static char*
openvz_replace(const char* str,
               const char* from,
               const char* to) {
    const char* offset = NULL;
    const char* str_start = str;
355 356
    int to_len;
    int from_len;
357 358
    virBuffer buf = VIR_BUFFER_INITIALIZER;

359
    if ((!from) || (!to))
360
        return NULL;
361 362
    from_len = strlen(from);
    to_len = strlen(to);
363

E
Eric Blake 已提交
364
    while ((offset = strstr(str_start, from)))
365 366 367 368 369 370
    {
        virBufferAdd(&buf, str_start, offset-str_start);
        virBufferAdd(&buf, to, to_len);
        str_start = offset + from_len;
    }

371
    virBufferAdd(&buf, str_start, -1);
372

373 374 375 376
    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
        return NULL;
    }
377 378 379 380 381

    return virBufferContentAndReset(&buf);
}


382
static int
383
openvzReadFSConf(virDomainDefPtr def,
384 385 386
                 int veid) {
    int ret;
    virDomainFSDefPtr fs = NULL;
387 388
    char *veid_str = NULL;
    char *temp = NULL;
389 390
    const char *param;
    unsigned long long barrier, limit;
391

392
    ret = openvzReadVPSConfigParam(veid, "OSTEMPLATE", &temp);
393
    if (ret < 0) {
394 395 396
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'OSTEMPLATE' from config for container %d"),
                       veid);
397 398 399
        goto error;
    } else if (ret > 0) {
        if (VIR_ALLOC(fs) < 0)
400
            goto error;
401 402

        fs->type = VIR_DOMAIN_FS_TYPE_TEMPLATE;
403 404
        if (VIR_STRDUP(fs->src, temp) < 0)
            goto error;
405 406
    } else {
        /* OSTEMPLATE was not found, VE was booted from a private dir directly */
407
        ret = openvzReadVPSConfigParam(veid, "VE_PRIVATE", &temp);
408
        if (ret <= 0) {
409 410 411
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read 'VE_PRIVATE' from config for container %d"),
                           veid);
412 413
            goto error;
        }
414

415
        if (VIR_ALLOC(fs) < 0)
416
            goto error;
417

418
        if (virAsprintf(&veid_str, "%d", veid) < 0)
419
            goto error;
420 421

        fs->type = VIR_DOMAIN_FS_TYPE_MOUNT;
422 423
        if (!(fs->src = openvz_replace(temp, "$VEID", veid_str)))
            goto no_memory;
424

425
        VIR_FREE(veid_str);
426 427
    }

428 429
    if (VIR_STRDUP(fs->dst, "/") < 0)
        goto error;
430

431 432 433 434
    param = "DISKSPACE";
    ret = openvzReadVPSConfigParam(veid, param, &temp);
    if (ret > 0) {
        if (openvzParseBarrierLimit(temp, &barrier, &limit)) {
435 436 437
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read '%s' from config for container %d"),
                           param, veid);
438 439 440
            goto error;
        } else {
            /* Ensure that we can multiply by 1024 without overflowing. */
441
            if (barrier > ULLONG_MAX / 1024 ||
442
                limit > ULLONG_MAX / 1024) {
443 444
                virReportSystemError(VIR_ERR_OVERFLOW, "%s",
                                     _("Unable to parse quota"));
445 446 447 448 449 450 451
                goto error;
            }
            fs->space_soft_limit = barrier * 1024; /* unit is bytes */
            fs->space_hard_limit = limit * 1024;   /* unit is bytes */
        }
    }

452
    if (VIR_REALLOC_N(def->fss, def->nfss + 1) < 0)
453
        goto error;
454 455 456
    def->fss[def->nfss++] = fs;
    fs = NULL;

457 458
    VIR_FREE(temp);

459 460
    return 0;
no_memory:
461
    virReportOOMError();
462
error:
463
    VIR_FREE(temp);
464 465 466 467 468
    virDomainFSDefFree(fs);
    return -1;
}


469 470 471
static int
openvzReadMemConf(virDomainDefPtr def, int veid)
{
472
    int ret = -1;
473 474 475
    char *temp = NULL;
    unsigned long long barrier, limit;
    const char *param;
476
    long kb_per_pages;
477

478 479
    kb_per_pages = openvzKBPerPages();
    if (kb_per_pages < 0)
480 481 482 483 484 485
        goto error;

    /* Memory allocation guarantee */
    param = "VMGUARPAGES";
    ret = openvzReadVPSConfigParam(veid, param, &temp);
    if (ret < 0) {
486 487 488
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read '%s' from config for container %d"),
                       param, veid);
489 490 491 492
        goto error;
    } else if (ret > 0) {
        ret = openvzParseBarrierLimit(temp, &barrier, NULL);
        if (ret < 0) {
493 494 495
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse barrier of '%s' "
                             "from config for container %d"), param, veid);
496 497 498 499 500 501 502 503 504 505 506 507
            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) {
508 509 510
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read '%s' from config for container %d"),
                       param, veid);
511 512 513 514
        goto error;
    } else if (ret > 0) {
        ret = openvzParseBarrierLimit(temp, &barrier, &limit);
        if (ret < 0) {
515 516 517
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse barrier and limit of '%s' "
                             "from config for container %d"), param, veid);
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
            goto error;
        }
        if (barrier == LONG_MAX)
            def->mem.soft_limit = 0ull;
        else
            def->mem.soft_limit = barrier * kb_per_pages;

        if (limit == LONG_MAX)
            def->mem.hard_limit = 0ull;
        else
            def->mem.hard_limit = limit * kb_per_pages;
    }

    ret = 0;
error:
    VIR_FREE(temp);
    return ret;
}


538 539 540 541 542 543
/* Free all memory associated with a openvz_driver structure */
void
openvzFreeDriver(struct openvz_driver *driver)
{
    if (!driver)
        return;
544

545
    virObjectUnref(driver->xmlopt);
546
    virObjectUnref(driver->domains);
547
    virObjectUnref(driver->caps);
548
    VIR_FREE(driver);
549
}
D
Daniel Veillard 已提交
550 551 552



553
int openvzLoadDomains(struct openvz_driver *driver) {
554
    int veid, ret;
555
    char *status;
556
    char uuidstr[VIR_UUID_STRING_BUFLEN];
557
    virDomainObjPtr dom = NULL;
558
    virDomainDefPtr def = NULL;
559
    char *temp = NULL;
E
Eric Blake 已提交
560 561 562
    char *outbuf = NULL;
    char *line;
    virCommandPtr cmd = NULL;
563

564 565
    if (openvzAssignUUIDs() < 0)
        return -1;
566

E
Eric Blake 已提交
567 568 569 570
    cmd = virCommandNewArgList(VZLIST, "-a", "-ovpsid,status", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;
571

572 573
    line = outbuf;
    while (line[0] != '\0') {
574
        unsigned int flags = 0;
575 576 577
        if (virStrToLong_i(line, &status, 10, &veid) < 0 ||
            *status++ != ' ' ||
            (line = strchr(status, '\n')) == NULL) {
578 579
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Failed to parse vzlist output"));
580
            goto cleanup;
581
        }
582
        *line++ = '\0';
583

584
        if (VIR_ALLOC(def) < 0)
585
            goto cleanup;
586

587
        def->virtType = VIR_DOMAIN_VIRT_OPENVZ;
588

589 590
        if (STREQ(status, "stopped"))
            def->id = -1;
J
Jiri Denemark 已提交
591
        else
592 593
            def->id = veid;
        if (virAsprintf(&def->name, "%i", veid) < 0)
594
            goto cleanup;
595

596
        openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr));
597
        ret = virUUIDParse(uuidstr, def->uuid);
598

599
        if (ret == -1) {
600 601
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("UUID in config file malformed"));
602
            goto cleanup;
603
        }
604

605 606 607 608
        if (VIR_STRDUP(def->os.type, "exe") < 0)
            goto cleanup;
        if (VIR_STRDUP(def->os.init, "/sbin/init") < 0)
            goto cleanup;
609

610
        ret = openvzReadVPSConfigParam(veid, "CPUS", &temp);
611
        if (ret < 0) {
612 613 614
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read config for container %d"),
                           veid);
615
            goto cleanup;
616
        } else if (ret > 0) {
617
            def->maxvcpus = strtoI(temp);
618 619
        }

620 621 622
        if (ret == 0 || def->maxvcpus == 0)
            def->maxvcpus = openvzGetNodeCPUs();
        def->vcpus = def->maxvcpus;
623

624
        /* XXX load rest of VM config data .... */
625

626 627 628
        openvzReadNetworkConf(def, veid);
        openvzReadFSConf(def, veid);
        openvzReadMemConf(def, veid);
629

630
        virUUIDFormat(def->uuid, uuidstr);
631 632 633 634
        flags = VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE;
        if (STRNEQ(status, "stopped"))
            flags |= VIR_DOMAIN_OBJ_LIST_ADD_LIVE;

635 636
        if (!(dom = virDomainObjListAdd(driver->domains,
                                        def,
637
                                        driver->xmlopt,
638 639
                                        flags,
                                        NULL)))
640
            goto cleanup;
641 642 643 644 645 646 647 648 649

        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;
650
        }
651 652
        /* XXX OpenVZ doesn't appear to have concept of a transient domain */
        dom->persistent = 1;
653

654
        virObjectUnlock(dom);
655
        dom = NULL;
656
        def = NULL;
657
    }
658

E
Eric Blake 已提交
659
    virCommandFree(cmd);
660
    VIR_FREE(temp);
E
Eric Blake 已提交
661
    VIR_FREE(outbuf);
662

663
    return 0;
664

665
 cleanup:
E
Eric Blake 已提交
666
    virCommandFree(cmd);
667
    VIR_FREE(temp);
E
Eric Blake 已提交
668
    VIR_FREE(outbuf);
669
    virObjectUnref(dom);
670
    virDomainDefFree(def);
671
    return -1;
672 673
}

674 675 676 677 678
unsigned int
openvzGetNodeCPUs(void)
{
    virNodeInfo nodeinfo;

679
    if (nodeGetInfo(&nodeinfo) < 0)
680 681 682 683
        return 0;

    return nodeinfo.cpus;
}
684

685 686
static int
openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
687
{
688
    char * temp_file = NULL;
689 690 691 692
    int temp_fd = -1;
    FILE *fp;
    char *line = NULL;
    size_t line_size = 0;
693

694
    if (virAsprintf(&temp_file, "%s.tmp", conf_file)<0)
695 696
        return -1;

697 698
    fp = fopen(conf_file, "r");
    if (fp == NULL)
699
        goto error;
700 701
    temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (temp_fd == -1) {
702
        goto error;
703 704
    }

E
Eric Blake 已提交
705
    while (1) {
706
        if (getline(&line, &line_size, fp) <= 0)
707 708
            break;

709
        if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
710 711 712 713 714 715 716 717 718 719 720 721
            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;

722
    if (VIR_FCLOSE(fp) < 0)
723
        goto error;
724
    if (VIR_CLOSE(temp_fd) < 0)
725 726 727 728 729
        goto error;

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

730 731
    VIR_FREE(line);

732 733 734
    return 0;

error:
735 736
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
737
    VIR_FORCE_CLOSE(temp_fd);
E
Eric Blake 已提交
738
    if (temp_file)
739 740
        unlink(temp_file);
    VIR_FREE(temp_file);
741 742 743
    return -1;
}

744
int
745 746
openvzWriteVPSConfigParam(int vpsid, const char *param, const char *value)
{
747 748
    char *conf_file;
    int ret;
749

750
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
751 752
        return -1;

753 754 755
    ret = openvzWriteConfigParam(conf_file, param, value);
    VIR_FREE(conf_file);
    return ret;
756 757
}

758 759 760
/*
 * value will be freed before a new value is assigned to it, the caller is
 * responsible for freeing it afterwards.
761 762
 *
 * Returns <0 on error, 0 if not found, 1 if found.
763
 */
764
int
765
openvzReadConfigParam(const char *conf_file, const char *param, char **value)
766
{
767 768 769
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
770 771
    int err = 0;
    char *sf, *token, *saveptr = NULL;
772

773 774
    fp = fopen(conf_file, "r");
    if (fp == NULL)
775 776
        return -1;

777
    VIR_FREE(*value);
778 779 780 781 782 783
    while (1) {
        if (getline(&line, &line_size, fp) < 0) {
            err = !feof(fp);
            break;
        }

784 785 786 787 788 789
        if (! STREQLEN(line, param, strlen(param)))
            continue;

        sf = line + strlen(param);
        if (*sf++ != '=') continue;

790
        saveptr = NULL;
791 792
        if ((token = strtok_r(sf, "\"\t\n", &saveptr)) != NULL) {
            VIR_FREE(*value);
793
            if (VIR_STRDUP(*value, token) < 0) {
794 795
                err = 1;
                break;
796
            }
797 798
            /* keep going - last entry wins */
        }
799
    }
800 801
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
802

803
    return err ? -1 : *value ? 1 : 0;
804 805
}

806
/*
807 808 809 810 811 812 813 814 815 816
 * Read parameter from container config
 *
 * value will be freed before a new value is assined to it, the caller is
 * responsible for freeing it afterwards.
 *
 * sample: 133, "OSTEMPLATE", &value
 * return: -1 - error
 *          0 - don't found
 *          1 - OK
 */
817
int
818
openvzReadVPSConfigParam(int vpsid, const char *param, char **value)
819
{
820 821
    char *conf_file;
    int ret;
822

823
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
824 825
        return -1;

826
    ret = openvzReadConfigParam(conf_file, param, value);
827 828
    VIR_FREE(conf_file);
    return ret;
829 830 831 832 833
}

static int
openvz_copyfile(char* from_path, char* to_path)
{
834 835 836 837
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
    int copy_fd;
838 839
    int bytes_read;

840 841
    fp = fopen(from_path, "r");
    if (fp == NULL)
842 843 844
        return -1;
    copy_fd = open(to_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (copy_fd == -1) {
845
        VIR_FORCE_FCLOSE(fp);
846 847 848
        return -1;
    }

E
Eric Blake 已提交
849
    while (1) {
850
        if (getline(&line, &line_size, fp) <= 0)
851 852 853 854 855 856 857
            break;

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

858
    if (VIR_FCLOSE(fp) < 0)
859
        goto error;
860
    if (VIR_CLOSE(copy_fd) < 0)
861 862
        goto error;

863 864
    VIR_FREE(line);

865 866 867
    return 0;

error:
868 869
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
870
    VIR_FORCE_CLOSE(copy_fd);
871 872 873 874 875 876 877 878 879 880 881
    return -1;
}

/*
* Copy the default config to the VE conf file
* return: -1 - error
*          0 - OK
*/
int
openvzCopyDefaultConfig(int vpsid)
{
882 883 884
    char *confdir = NULL;
    char *default_conf_file = NULL;
    char *configfile_value = NULL;
885
    char *conf_file = NULL;
886 887
    int ret = -1;

888
    if (openvzReadConfigParam(VZ_CONF_FILE, "CONFIGFILE", &configfile_value) < 0)
889 890 891 892 893 894
        goto cleanup;

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

895
    if (virAsprintf(&default_conf_file, "%s/ve-%s.conf-sample", confdir,
896
                    configfile_value) < 0)
897 898
        goto cleanup;

899
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
900 901 902 903 904 905 906 907 908
        goto cleanup;

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

    ret = 0;
cleanup:
    VIR_FREE(confdir);
    VIR_FREE(default_conf_file);
909
    VIR_FREE(configfile_value);
910
    VIR_FREE(conf_file);
911 912 913
    return ret;
}

914
/* Locate config file of container
915 916
 * return -1 - error
 *         0 - OK */
917
static int
918
openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext)
919
{
920
    char *confdir;
921 922 923 924 925 926
    int ret = 0;

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

927
    if (virAsprintf(conffile, "%s/%d.%s", confdir, vpsid,
928
                    ext ? ext : "conf") < 0)
929 930 931 932 933 934
        ret = -1;

    VIR_FREE(confdir);
    return ret;
}

935 936
static char *
openvzLocateConfDir(void)
937 938 939
{
    const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL};
    int i=0;
940
    char *ret = NULL;
941

E
Eric Blake 已提交
942
    while (conf_dir_list[i]) {
943 944 945 946
        if (!access(conf_dir_list[i], F_OK)) {
            ignore_value(VIR_STRDUP(ret, conf_dir_list[i]));
            goto cleanup;
        }
E
Eric Blake 已提交
947
        i++;
948 949
    }

950 951
cleanup:
    return ret;
952 953 954
}

/* Richard Steven's classic readline() function */
955
int
956
openvz_readline(int fd, char *ptr, int maxlen)
957 958 959 960
{
    int n, rc;
    char c;

E
Eric Blake 已提交
961
    for (n = 1; n < maxlen; n++) {
962
        if ((rc = read(fd, &c, 1)) == 1) {
963
            *ptr++ = c;
E
Eric Blake 已提交
964
            if (c == '\n')
965
                break;
E
Eric Blake 已提交
966 967
        } else if (rc == 0) {
            if (n == 1)
968 969 970 971 972 973 974 975 976 977 978
                return 0; /* EOF condition */
            else
                break;
        }
        else
            return -1; /* error */
    }
    *ptr = 0;
    return n;
}

979
static int
980
openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
981
{
982
    char *conf_file;
983 984
    char *line = NULL;
    size_t line_size = 0;
985
    char *saveptr = NULL;
986 987
    char *uuidbuf;
    char *iden;
988
    FILE *fp;
989
    int retval = -1;
990

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

994 995
    fp = fopen(conf_file, "r");
    if (fp == NULL)
996
        goto cleanup;
997

E
Eric Blake 已提交
998
    while (1) {
999 1000 1001 1002 1003 1004 1005
        if (getline(&line, &line_size, fp) < 0) {
            if (feof(fp)) { /* EOF, UUID was not found */
                uuidstr[0] = 0;
                break;
            } else {
                goto cleanup;
            }
1006 1007
        }

1008 1009 1010 1011
        iden = strtok_r(line, " ", &saveptr);
        uuidbuf = strtok_r(NULL, "\n", &saveptr);

        if (iden != NULL && uuidbuf != NULL && STREQ(iden, "#UUID:")) {
1012
            if (virStrcpy(uuidstr, uuidbuf, len) == NULL) {
1013 1014
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("invalid uuid %s"), uuidbuf);
1015 1016
                goto cleanup;
            }
1017 1018 1019
            break;
        }
    }
1020 1021
    retval = 0;
cleanup:
1022 1023
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
1024
    VIR_FREE(conf_file);
1025

C
Chris Lalancette 已提交
1026
    return retval;
1027 1028 1029 1030 1031
}

/* Do actual checking for UUID presence in conf file,
 * assign if not present.
 */
1032 1033
int
openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
1034
{
1035
    char *conf_file;
1036
    char uuidstr[VIR_UUID_STRING_BUFLEN];
1037
    FILE *fp = NULL;
1038
    int ret = -1;
1039 1040 1041

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

1043
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
1044
        return -1;
1045

1046
    if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
1047
        goto cleanup;
1048

J
Jim Meyering 已提交
1049
    if (uuidstr[0] == 0) {
1050
        fp = fopen(conf_file, "a"); /* append */
1051
        if (fp == NULL)
1052
            goto cleanup;
1053

1054 1055
        virUUIDFormat(uuid, uuidstr);

1056
        /* Record failure if fprintf or VIR_FCLOSE fails,
1057
           and be careful always to close the stream.  */
1058 1059
        if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0) ||
            (VIR_FCLOSE(fp) == EOF))
1060
            goto cleanup;
1061 1062
    }

1063 1064
    ret = 0;
cleanup:
1065
    VIR_FORCE_FCLOSE(fp);
1066 1067
    VIR_FREE(conf_file);
    return ret;
1068 1069
}

1070 1071 1072 1073
static int
openvzSetUUID(int vpsid){
    unsigned char uuid[VIR_UUID_BUFLEN];

1074
    if (virUUIDGenerate(uuid)) {
1075 1076
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to generate UUID"));
1077 1078
        return -1;
    }
1079 1080 1081 1082

    return openvzSetDefinedUUID(vpsid, uuid);
}

1083 1084 1085 1086 1087 1088 1089
/*
 * 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.
 *
 */

1090
static int openvzAssignUUIDs(void)
1091 1092 1093 1094
{
    DIR *dp;
    struct dirent *dent;
    char *conf_dir;
1095 1096 1097
    int vpsid;
    char *ext;
    int ret = 0;
1098 1099

    conf_dir = openvzLocateConfDir();
1100 1101
    if (conf_dir == NULL)
        return -1;
1102 1103

    dp = opendir(conf_dir);
E
Eric Blake 已提交
1104
    if (dp == NULL) {
1105
        VIR_FREE(conf_dir);
1106 1107 1108
        return 0;
    }

1109
    errno = 0;
E
Eric Blake 已提交
1110
    while ((dent = readdir(dp))) {
1111 1112 1113
        if (virStrToLong_i(dent->d_name, &ext, 10, &vpsid) < 0 ||
            *ext++ != '.' ||
            STRNEQ(ext, "conf"))
1114
            continue;
E
Eric Blake 已提交
1115
        if (vpsid > 0) /* '0.conf' belongs to the host, ignore it */
1116
            openvzSetUUID(vpsid);
1117 1118 1119
        errno = 0;
    }
    if (errno) {
1120 1121
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to scan configuration directory"));
1122
        ret = -1;
1123
    }
1124

1125
    closedir(dp);
1126
    VIR_FREE(conf_dir);
1127
    return ret;
1128
}
1129 1130 1131 1132 1133 1134 1135 1136


/*
 * Return CTID from name
 *
 */

int openvzGetVEID(const char *name) {
E
Eric Blake 已提交
1137 1138
    virCommandPtr cmd;
    char *outbuf;
1139
    char *temp;
1140
    int veid;
1141
    bool ok;
1142

E
Eric Blake 已提交
1143 1144 1145 1146 1147
    cmd = virCommandNewArgList(VZLIST, name, "-ovpsid", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0) {
        virCommandFree(cmd);
        VIR_FREE(outbuf);
1148 1149 1150
        return -1;
    }

E
Eric Blake 已提交
1151
    virCommandFree(cmd);
1152
    ok = virStrToLong_i(outbuf, &temp, 10, &veid) == 0 && *temp == '\n';
E
Eric Blake 已提交
1153
    VIR_FREE(outbuf);
1154

1155 1156 1157
    if (ok && veid >= 0)
        return veid;

1158 1159
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("Failed to parse vzlist output"));
1160 1161
    return -1;
}