openvz_conf.c 30.0 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 41
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
D
Daniel P. Berrange 已提交
42
#include <string.h>
43
#include <sys/wait.h>
44

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

56 57
#define VIR_FROM_THIS VIR_FROM_OPENVZ

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

openvzLocateConfFileFunc openvzLocateConfFile = openvzLocateConfFileDefault;
64

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

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

73 74 75
    return val;
}

76 77

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

    if (retversion)
        *retversion = 0;

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

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

95 96 97 98
    tmp = help;

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

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

    if (retversion)
        *retversion = version;

    ret = 0;

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

    return ret;
}

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

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

    return 0;
}


131 132 133 134 135 136 137 138 139 140 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 168 169 170
/* 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;
    char *str = strdup(value);

    if (str == NULL) {
        virReportOOMError();
        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;
}


171
static int openvzDefaultConsoleType(const char *ostype ATTRIBUTE_UNUSED,
172
                                    virArch arch ATTRIBUTE_UNUSED)
173 174 175 176
{
    return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_OPENVZ;
}

177

178 179 180 181 182
virCapsPtr openvzCapsInit(void)
{
    virCapsPtr caps;
    virCapsGuestPtr guest;

183
    if ((caps = virCapabilitiesNew(virArchFromHost(),
184 185 186
                                   0, 0)) == NULL)
        goto no_memory;

187
    if (nodeCapsInitNUMA(caps) < 0)
188 189
        goto no_memory;

190 191
    virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x52, 0x54, 0x00 });

192 193
    if ((guest = virCapabilitiesAddGuest(caps,
                                         "exe",
194
                                         caps->host.arch,
195 196 197 198 199 200 201 202 203 204 205 206 207 208
                                         NULL,
                                         NULL,
                                         0,
                                         NULL)) == NULL)
        goto no_memory;

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

209
    caps->defaultInitPath = "/sbin/init";
210
    caps->defaultConsoleTargetType = openvzDefaultConsoleType;
211 212

    return caps;
213
no_memory:
214
    virObjectUnref(caps);
215 216 217 218
    return NULL;
}


219
int
220
openvzReadNetworkConf(virDomainDefPtr def,
221
                      int veid) {
222
    int ret;
223
    virDomainNetDefPtr net = NULL;
224
    char *temp = NULL;
225 226 227 228 229 230 231
    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
     */
232
    ret = openvzReadVPSConfigParam(veid, "IP_ADDRESS", &temp);
233
    if (ret < 0) {
234 235 236
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'IP_ADDRESS' from config for container %d"),
                       veid);
237 238 239 240
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, " ", &saveptr);
        while (token != NULL) {
241
            if (VIR_ALLOC(net) < 0)
242 243 244 245 246 247 248 249
                goto no_memory;

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
            net->data.ethernet.ipaddr = strdup(token);

            if (net->data.ethernet.ipaddr == NULL)
                goto no_memory;

250 251 252 253 254
            if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
                goto no_memory;
            def->nets[def->nnets++] = net;
            net = NULL;

255 256 257 258 259 260 261 262 263
            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 ';'
     */
264
    ret = openvzReadVPSConfigParam(veid, "NETIF", &temp);
265
    if (ret < 0) {
266 267 268
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'NETIF' from config for container %d"),
                       veid);
269 270 271 272 273
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, ";", &saveptr);
        while (token != NULL) {
            /*add new device to list*/
274
            if (VIR_ALLOC(net) < 0)
275 276 277 278
                goto no_memory;

            net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;

279
            char *p = token;
280 281 282 283 284
            char cpy_temp[32];
            int len;

            /*parse string*/
            do {
285
                char *next = strchrnul(p, ',');
286
                if (STRPREFIX(p, "ifname=")) {
287 288 289
                    /* skip in libvirt */
                } else if (STRPREFIX(p, "host_ifname=")) {
                    p += 12;
290 291
                    len = next - p;
                    if (len > 16) {
292 293
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Too long network device name"));
294 295 296
                        goto error;
                    }

297 298 299
                    if (VIR_ALLOC_N(net->ifname, len+1) < 0)
                        goto no_memory;

C
Chris Lalancette 已提交
300
                    if (virStrncpy(net->ifname, p, len, len+1) == NULL) {
301 302
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Network ifname %s too long for destination"), p);
C
Chris Lalancette 已提交
303 304
                        goto error;
                    }
305 306 307 308
                } else if (STRPREFIX(p, "bridge=")) {
                    p += 7;
                    len = next - p;
                    if (len > 16) {
309 310
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Too long bridge device name"));
311 312 313
                        goto error;
                    }

314 315 316
                    if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
                        goto no_memory;

C
Chris Lalancette 已提交
317
                    if (virStrncpy(net->data.bridge.brname, p, len, len+1) == NULL) {
318 319
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Bridge name %s too long for destination"), p);
C
Chris Lalancette 已提交
320 321
                        goto error;
                    }
322 323 324
                } else if (STRPREFIX(p, "mac=")) {
                    p += 4;
                    len = next - p;
325
                    if (len != 17) { /* should be 17 */
326 327
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Wrong length MAC address"));
328 329
                        goto error;
                    }
C
Chris Lalancette 已提交
330
                    if (virStrncpy(cpy_temp, p, len, sizeof(cpy_temp)) == NULL) {
331 332
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("MAC address %s too long for destination"), p);
C
Chris Lalancette 已提交
333 334
                        goto error;
                    }
335
                    if (virMacAddrParse(cpy_temp, &net->mac) < 0) {
336 337
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Wrong MAC address"));
338 339 340 341 342 343
                        goto error;
                    }
                }
                p = ++next;
            } while (p < token + strlen(token));

344 345 346 347 348
            if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
                goto no_memory;
            def->nets[def->nnets++] = net;
            net = NULL;

349 350 351 352
            token = strtok_r(NULL, ";", &saveptr);
        }
    }

353 354
    VIR_FREE(temp);

355
    return 0;
356
no_memory:
357
    virReportOOMError();
358
error:
359
    VIR_FREE(temp);
360
    virDomainNetDefFree(net);
361
    return -1;
362 363 364
}


365 366 367 368 369 370 371
/* 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;
372 373
    int to_len;
    int from_len;
374 375
    virBuffer buf = VIR_BUFFER_INITIALIZER;

376
    if ((!from) || (!to))
377
        return NULL;
378 379
    from_len = strlen(from);
    to_len = strlen(to);
380

E
Eric Blake 已提交
381
    while ((offset = strstr(str_start, from)))
382 383 384 385 386 387
    {
        virBufferAdd(&buf, str_start, offset-str_start);
        virBufferAdd(&buf, to, to_len);
        str_start = offset + from_len;
    }

388
    virBufferAdd(&buf, str_start, -1);
389

390 391 392 393
    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
        return NULL;
    }
394 395 396 397 398

    return virBufferContentAndReset(&buf);
}


399
static int
400
openvzReadFSConf(virDomainDefPtr def,
401 402 403
                 int veid) {
    int ret;
    virDomainFSDefPtr fs = NULL;
404 405
    char *veid_str = NULL;
    char *temp = NULL;
406 407
    const char *param;
    unsigned long long barrier, limit;
408

409
    ret = openvzReadVPSConfigParam(veid, "OSTEMPLATE", &temp);
410
    if (ret < 0) {
411 412 413
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'OSTEMPLATE' from config for container %d"),
                       veid);
414 415 416 417 418 419 420
        goto error;
    } else if (ret > 0) {
        if (VIR_ALLOC(fs) < 0)
            goto no_memory;

        fs->type = VIR_DOMAIN_FS_TYPE_TEMPLATE;
        fs->src = strdup(temp);
421 422
    } else {
        /* OSTEMPLATE was not found, VE was booted from a private dir directly */
423
        ret = openvzReadVPSConfigParam(veid, "VE_PRIVATE", &temp);
424
        if (ret <= 0) {
425 426 427
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read 'VE_PRIVATE' from config for container %d"),
                           veid);
428 429
            goto error;
        }
430

431
        if (VIR_ALLOC(fs) < 0)
432 433
            goto no_memory;

434 435
        if (virAsprintf(&veid_str, "%d", veid) < 0)
            goto no_memory;
436 437 438

        fs->type = VIR_DOMAIN_FS_TYPE_MOUNT;
        fs->src = openvz_replace(temp, "$VEID", veid_str);
439

440
        VIR_FREE(veid_str);
441 442
    }

443 444
    fs->dst = strdup("/");

445 446 447 448
    param = "DISKSPACE";
    ret = openvzReadVPSConfigParam(veid, param, &temp);
    if (ret > 0) {
        if (openvzParseBarrierLimit(temp, &barrier, &limit)) {
449 450 451
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read '%s' from config for container %d"),
                           param, veid);
452 453 454
            goto error;
        } else {
            /* Ensure that we can multiply by 1024 without overflowing. */
455
            if (barrier > ULLONG_MAX / 1024 ||
456
                limit > ULLONG_MAX / 1024) {
457 458
                virReportSystemError(VIR_ERR_OVERFLOW, "%s",
                                     _("Unable to parse quota"));
459 460 461 462 463 464 465
                goto error;
            }
            fs->space_soft_limit = barrier * 1024; /* unit is bytes */
            fs->space_hard_limit = limit * 1024;   /* unit is bytes */
        }
    }

466 467 468 469 470 471 472 473
    if (fs->src == NULL || fs->dst == NULL)
        goto no_memory;

    if (VIR_REALLOC_N(def->fss, def->nfss + 1) < 0)
        goto no_memory;
    def->fss[def->nfss++] = fs;
    fs = NULL;

474 475
    VIR_FREE(temp);

476 477
    return 0;
no_memory:
478
    virReportOOMError();
479
error:
480
    VIR_FREE(temp);
481 482 483 484 485
    virDomainFSDefFree(fs);
    return -1;
}


486 487 488
static int
openvzReadMemConf(virDomainDefPtr def, int veid)
{
489
    int ret = -1;
490 491 492
    char *temp = NULL;
    unsigned long long barrier, limit;
    const char *param;
493
    long kb_per_pages;
494

495 496
    kb_per_pages = openvzKBPerPages();
    if (kb_per_pages < 0)
497 498 499 500 501 502
        goto error;

    /* Memory allocation guarantee */
    param = "VMGUARPAGES";
    ret = openvzReadVPSConfigParam(veid, param, &temp);
    if (ret < 0) {
503 504 505
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read '%s' from config for container %d"),
                       param, veid);
506 507 508 509
        goto error;
    } else if (ret > 0) {
        ret = openvzParseBarrierLimit(temp, &barrier, NULL);
        if (ret < 0) {
510 511 512
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse barrier of '%s' "
                             "from config for container %d"), param, veid);
513 514 515 516 517 518 519 520 521 522 523 524
            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) {
525 526 527
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read '%s' from config for container %d"),
                       param, veid);
528 529 530 531
        goto error;
    } else if (ret > 0) {
        ret = openvzParseBarrierLimit(temp, &barrier, &limit);
        if (ret < 0) {
532 533 534
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse barrier and limit of '%s' "
                             "from config for container %d"), param, veid);
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
            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;
}


555 556 557 558 559 560
/* Free all memory associated with a openvz_driver structure */
void
openvzFreeDriver(struct openvz_driver *driver)
{
    if (!driver)
        return;
561

562
    virObjectUnref(driver->xmlopt);
563
    virObjectUnref(driver->domains);
564
    virObjectUnref(driver->caps);
565
    VIR_FREE(driver);
566
}
D
Daniel Veillard 已提交
567 568 569



570
int openvzLoadDomains(struct openvz_driver *driver) {
571
    int veid, ret;
572
    char *status;
573
    char uuidstr[VIR_UUID_STRING_BUFLEN];
574
    virDomainObjPtr dom = NULL;
575
    virDomainDefPtr def = NULL;
576
    char *temp = NULL;
E
Eric Blake 已提交
577 578 579
    char *outbuf = NULL;
    char *line;
    virCommandPtr cmd = NULL;
580

581 582
    if (openvzAssignUUIDs() < 0)
        return -1;
583

E
Eric Blake 已提交
584 585 586 587
    cmd = virCommandNewArgList(VZLIST, "-a", "-ovpsid,status", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;
588

589 590
    line = outbuf;
    while (line[0] != '\0') {
591
        unsigned int flags = 0;
592 593 594
        if (virStrToLong_i(line, &status, 10, &veid) < 0 ||
            *status++ != ' ' ||
            (line = strchr(status, '\n')) == NULL) {
595 596
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Failed to parse vzlist output"));
597
            goto cleanup;
598
        }
599
        *line++ = '\0';
600

601
        if (VIR_ALLOC(def) < 0)
602
            goto no_memory;
603

604
        def->virtType = VIR_DOMAIN_VIRT_OPENVZ;
605

606 607
        if (STREQ(status, "stopped"))
            def->id = -1;
J
Jiri Denemark 已提交
608
        else
609 610
            def->id = veid;
        if (virAsprintf(&def->name, "%i", veid) < 0)
611
            goto no_memory;
612

613
        openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr));
614
        ret = virUUIDParse(uuidstr, def->uuid);
615

616
        if (ret == -1) {
617 618
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("UUID in config file malformed"));
619
            goto cleanup;
620
        }
621

622
        if (!(def->os.type = strdup("exe")))
623
            goto no_memory;
624
        if (!(def->os.init = strdup("/sbin/init")))
625
            goto no_memory;
626

627
        ret = openvzReadVPSConfigParam(veid, "CPUS", &temp);
628
        if (ret < 0) {
629 630 631
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read config for container %d"),
                           veid);
632
            goto cleanup;
633
        } else if (ret > 0) {
634
            def->maxvcpus = strtoI(temp);
635 636
        }

637 638 639
        if (ret == 0 || def->maxvcpus == 0)
            def->maxvcpus = openvzGetNodeCPUs();
        def->vcpus = def->maxvcpus;
640

641
        /* XXX load rest of VM config data .... */
642

643 644 645
        openvzReadNetworkConf(def, veid);
        openvzReadFSConf(def, veid);
        openvzReadMemConf(def, veid);
646

647
        virUUIDFormat(def->uuid, uuidstr);
648 649 650 651
        flags = VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE;
        if (STRNEQ(status, "stopped"))
            flags |= VIR_DOMAIN_OBJ_LIST_ADD_LIVE;

652 653
        if (!(dom = virDomainObjListAdd(driver->domains,
                                        def,
654
                                        driver->xmlopt,
655 656
                                        flags,
                                        NULL)))
657
            goto cleanup;
658 659 660 661 662 663 664 665 666

        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;
667
        }
668 669
        /* XXX OpenVZ doesn't appear to have concept of a transient domain */
        dom->persistent = 1;
670

671
        virObjectUnlock(dom);
672
        dom = NULL;
673
        def = NULL;
674
    }
675

E
Eric Blake 已提交
676
    virCommandFree(cmd);
677
    VIR_FREE(temp);
E
Eric Blake 已提交
678
    VIR_FREE(outbuf);
679

680
    return 0;
681

682
 no_memory:
683
    virReportOOMError();
684

685
 cleanup:
E
Eric Blake 已提交
686
    virCommandFree(cmd);
687
    VIR_FREE(temp);
E
Eric Blake 已提交
688
    VIR_FREE(outbuf);
689
    virObjectUnref(dom);
690
    virDomainDefFree(def);
691
    return -1;
692 693
}

694 695 696 697 698
unsigned int
openvzGetNodeCPUs(void)
{
    virNodeInfo nodeinfo;

699
    if (nodeGetInfo(NULL, &nodeinfo) < 0)
700 701 702 703
        return 0;

    return nodeinfo.cpus;
}
704

705 706
static int
openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
707
{
708
    char * temp_file = NULL;
709 710 711 712
    int temp_fd = -1;
    FILE *fp;
    char *line = NULL;
    size_t line_size = 0;
713

714
    if (virAsprintf(&temp_file, "%s.tmp", conf_file)<0) {
715
        virReportOOMError();
716
        return -1;
717
    }
718

719 720
    fp = fopen(conf_file, "r");
    if (fp == NULL)
721
        goto error;
722 723
    temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (temp_fd == -1) {
724
        goto error;
725 726
    }

E
Eric Blake 已提交
727
    while (1) {
728
        if (getline(&line, &line_size, fp) <= 0)
729 730
            break;

731
        if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
732 733 734 735 736 737 738 739 740 741 742 743
            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;

744
    if (VIR_FCLOSE(fp) < 0)
745
        goto error;
746
    if (VIR_CLOSE(temp_fd) < 0)
747 748 749 750 751
        goto error;

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

752 753
    VIR_FREE(line);

754 755 756
    return 0;

error:
757 758
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
759
    VIR_FORCE_CLOSE(temp_fd);
E
Eric Blake 已提交
760
    if (temp_file)
761 762
        unlink(temp_file);
    VIR_FREE(temp_file);
763 764 765
    return -1;
}

766
int
767 768
openvzWriteVPSConfigParam(int vpsid, const char *param, const char *value)
{
769 770
    char *conf_file;
    int ret;
771

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

775 776 777
    ret = openvzWriteConfigParam(conf_file, param, value);
    VIR_FREE(conf_file);
    return ret;
778 779
}

780 781 782
/*
 * value will be freed before a new value is assigned to it, the caller is
 * responsible for freeing it afterwards.
783 784
 *
 * Returns <0 on error, 0 if not found, 1 if found.
785
 */
786
int
787
openvzReadConfigParam(const char *conf_file, const char *param, char **value)
788
{
789 790 791
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
792 793
    int err = 0;
    char *sf, *token, *saveptr = NULL;
794

795 796
    fp = fopen(conf_file, "r");
    if (fp == NULL)
797 798
        return -1;

799
    VIR_FREE(*value);
800 801 802 803 804 805
    while (1) {
        if (getline(&line, &line_size, fp) < 0) {
            err = !feof(fp);
            break;
        }

806 807 808 809 810 811
        if (! STREQLEN(line, param, strlen(param)))
            continue;

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

812
        saveptr = NULL;
813 814 815 816 817 818
        if ((token = strtok_r(sf, "\"\t\n", &saveptr)) != NULL) {
            VIR_FREE(*value);
            *value = strdup(token);
            if (*value == NULL) {
                err = 1;
                break;
819
            }
820 821
            /* keep going - last entry wins */
        }
822
    }
823 824
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
825

826
    return err ? -1 : *value ? 1 : 0;
827 828
}

829
/*
830 831 832 833 834 835 836 837 838 839
 * 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
 */
840
int
841
openvzReadVPSConfigParam(int vpsid, const char *param, char **value)
842
{
843 844
    char *conf_file;
    int ret;
845

846
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
847 848
        return -1;

849
    ret = openvzReadConfigParam(conf_file, param, value);
850 851
    VIR_FREE(conf_file);
    return ret;
852 853 854 855 856
}

static int
openvz_copyfile(char* from_path, char* to_path)
{
857 858 859 860
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
    int copy_fd;
861 862
    int bytes_read;

863 864
    fp = fopen(from_path, "r");
    if (fp == NULL)
865 866 867
        return -1;
    copy_fd = open(to_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (copy_fd == -1) {
868
        VIR_FORCE_FCLOSE(fp);
869 870 871
        return -1;
    }

E
Eric Blake 已提交
872
    while (1) {
873
        if (getline(&line, &line_size, fp) <= 0)
874 875 876 877 878 879 880
            break;

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

881
    if (VIR_FCLOSE(fp) < 0)
882
        goto error;
883
    if (VIR_CLOSE(copy_fd) < 0)
884 885
        goto error;

886 887
    VIR_FREE(line);

888 889 890
    return 0;

error:
891 892
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
893
    VIR_FORCE_CLOSE(copy_fd);
894 895 896 897 898 899 900 901 902 903 904
    return -1;
}

/*
* Copy the default config to the VE conf file
* return: -1 - error
*          0 - OK
*/
int
openvzCopyDefaultConfig(int vpsid)
{
905 906 907
    char *confdir = NULL;
    char *default_conf_file = NULL;
    char *configfile_value = NULL;
908
    char *conf_file = NULL;
909 910
    int ret = -1;

911
    if (openvzReadConfigParam(VZ_CONF_FILE, "CONFIGFILE", &configfile_value) < 0)
912 913 914 915 916 917
        goto cleanup;

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

918 919
    if (virAsprintf(&default_conf_file, "%s/ve-%s.conf-sample", confdir,
                    configfile_value) < 0) {
920
        virReportOOMError();
921
        goto cleanup;
922
    }
923

924
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
925 926 927 928 929 930 931 932 933
        goto cleanup;

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

    ret = 0;
cleanup:
    VIR_FREE(confdir);
    VIR_FREE(default_conf_file);
934
    VIR_FREE(configfile_value);
935
    VIR_FREE(conf_file);
936 937 938
    return ret;
}

939
/* Locate config file of container
940 941
 * return -1 - error
 *         0 - OK */
942
static int
943
openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext)
944
{
945
    char *confdir;
946 947 948 949 950 951
    int ret = 0;

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

952 953 954
    if (virAsprintf(conffile, "%s/%d.%s", confdir, vpsid,
                    ext ? ext : "conf") < 0) {
        virReportOOMError();
955
        ret = -1;
956
    }
957 958 959 960 961

    VIR_FREE(confdir);
    return ret;
}

962 963
static char *
openvzLocateConfDir(void)
964 965 966 967
{
    const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL};
    int i=0;

E
Eric Blake 已提交
968 969
    while (conf_dir_list[i]) {
        if (!access(conf_dir_list[i], F_OK))
970
            return strdup(conf_dir_list[i]);
E
Eric Blake 已提交
971
        i++;
972 973 974 975 976 977
    }

    return NULL;
}

/* Richard Steven's classic readline() function */
978
int
979
openvz_readline(int fd, char *ptr, int maxlen)
980 981 982 983
{
    int n, rc;
    char c;

E
Eric Blake 已提交
984
    for (n = 1; n < maxlen; n++) {
985
        if ((rc = read(fd, &c, 1)) == 1) {
986
            *ptr++ = c;
E
Eric Blake 已提交
987
            if (c == '\n')
988
                break;
E
Eric Blake 已提交
989 990
        } else if (rc == 0) {
            if (n == 1)
991 992 993 994 995 996 997 998 999 1000 1001
                return 0; /* EOF condition */
            else
                break;
        }
        else
            return -1; /* error */
    }
    *ptr = 0;
    return n;
}

1002
static int
1003
openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
1004
{
1005
    char *conf_file;
1006 1007
    char *line = NULL;
    size_t line_size = 0;
1008
    char *saveptr = NULL;
1009 1010
    char *uuidbuf;
    char *iden;
1011
    FILE *fp;
1012
    int retval = -1;
1013

1014
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
1015
        return -1;
1016

1017 1018
    fp = fopen(conf_file, "r");
    if (fp == NULL)
1019
        goto cleanup;
1020

E
Eric Blake 已提交
1021
    while (1) {
1022 1023 1024 1025 1026 1027 1028
        if (getline(&line, &line_size, fp) < 0) {
            if (feof(fp)) { /* EOF, UUID was not found */
                uuidstr[0] = 0;
                break;
            } else {
                goto cleanup;
            }
1029 1030
        }

1031 1032 1033 1034
        iden = strtok_r(line, " ", &saveptr);
        uuidbuf = strtok_r(NULL, "\n", &saveptr);

        if (iden != NULL && uuidbuf != NULL && STREQ(iden, "#UUID:")) {
1035
            if (virStrcpy(uuidstr, uuidbuf, len) == NULL) {
1036 1037
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("invalid uuid %s"), uuidbuf);
1038 1039
                goto cleanup;
            }
1040 1041 1042
            break;
        }
    }
1043 1044
    retval = 0;
cleanup:
1045 1046
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
1047
    VIR_FREE(conf_file);
1048

C
Chris Lalancette 已提交
1049
    return retval;
1050 1051 1052 1053 1054
}

/* Do actual checking for UUID presence in conf file,
 * assign if not present.
 */
1055 1056
int
openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
1057
{
1058
    char *conf_file;
1059
    char uuidstr[VIR_UUID_STRING_BUFLEN];
1060
    FILE *fp = NULL;
1061
    int ret = -1;
1062 1063 1064

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

1066
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
1067
        return -1;
1068

1069
    if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
1070
        goto cleanup;
1071

J
Jim Meyering 已提交
1072
    if (uuidstr[0] == 0) {
1073
        fp = fopen(conf_file, "a"); /* append */
1074
        if (fp == NULL)
1075
            goto cleanup;
1076

1077 1078
        virUUIDFormat(uuid, uuidstr);

1079
        /* Record failure if fprintf or VIR_FCLOSE fails,
1080
           and be careful always to close the stream.  */
1081 1082
        if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0) ||
            (VIR_FCLOSE(fp) == EOF))
1083
            goto cleanup;
1084 1085
    }

1086 1087
    ret = 0;
cleanup:
1088
    VIR_FORCE_FCLOSE(fp);
1089 1090
    VIR_FREE(conf_file);
    return ret;
1091 1092
}

1093 1094 1095 1096
static int
openvzSetUUID(int vpsid){
    unsigned char uuid[VIR_UUID_BUFLEN];

1097
    if (virUUIDGenerate(uuid)) {
1098 1099
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to generate UUID"));
1100 1101
        return -1;
    }
1102 1103 1104 1105

    return openvzSetDefinedUUID(vpsid, uuid);
}

1106 1107 1108 1109 1110 1111 1112
/*
 * 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.
 *
 */

1113
static int openvzAssignUUIDs(void)
1114 1115 1116 1117
{
    DIR *dp;
    struct dirent *dent;
    char *conf_dir;
1118 1119 1120
    int vpsid;
    char *ext;
    int ret = 0;
1121 1122

    conf_dir = openvzLocateConfDir();
1123 1124
    if (conf_dir == NULL)
        return -1;
1125 1126

    dp = opendir(conf_dir);
E
Eric Blake 已提交
1127
    if (dp == NULL) {
1128
        VIR_FREE(conf_dir);
1129 1130 1131
        return 0;
    }

1132
    errno = 0;
E
Eric Blake 已提交
1133
    while ((dent = readdir(dp))) {
1134 1135 1136
        if (virStrToLong_i(dent->d_name, &ext, 10, &vpsid) < 0 ||
            *ext++ != '.' ||
            STRNEQ(ext, "conf"))
1137
            continue;
E
Eric Blake 已提交
1138
        if (vpsid > 0) /* '0.conf' belongs to the host, ignore it */
1139
            openvzSetUUID(vpsid);
1140 1141 1142
        errno = 0;
    }
    if (errno) {
1143 1144
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to scan configuration directory"));
1145
        ret = -1;
1146
    }
1147

1148
    closedir(dp);
1149
    VIR_FREE(conf_dir);
1150
    return ret;
1151
}
1152 1153 1154 1155 1156 1157 1158 1159


/*
 * Return CTID from name
 *
 */

int openvzGetVEID(const char *name) {
E
Eric Blake 已提交
1160 1161
    virCommandPtr cmd;
    char *outbuf;
1162
    char *temp;
1163
    int veid;
1164
    bool ok;
1165

E
Eric Blake 已提交
1166 1167 1168 1169 1170
    cmd = virCommandNewArgList(VZLIST, name, "-ovpsid", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0) {
        virCommandFree(cmd);
        VIR_FREE(outbuf);
1171 1172 1173
        return -1;
    }

E
Eric Blake 已提交
1174
    virCommandFree(cmd);
1175
    ok = virStrToLong_i(outbuf, &temp, 10, &veid) == 0 && *temp == '\n';
E
Eric Blake 已提交
1176
    VIR_FREE(outbuf);
1177

1178 1179 1180
    if (ok && veid >= 0)
        return veid;

1181 1182
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("Failed to parse vzlist output"));
1183 1184
    return -1;
}