openvz_conf.c 27.8 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
 */

24
#include <config.h>
J
Jim Meyering 已提交
25

26 27 28 29 30
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
31
#include <sys/stat.h>
32
#include <sys/wait.h>
33

34
#include "virerror.h"
35
#include "openvz_conf.h"
36
#include "openvz_util.h"
37
#include "viruuid.h"
38
#include "virbuffer.h"
39
#include "viralloc.h"
E
Eric Blake 已提交
40
#include "virfile.h"
41
#include "vircommand.h"
42
#include "virstring.h"
43
#include "virhostcpu.h"
44

45 46
#define VIR_FROM_THIS VIR_FROM_OPENVZ

47
static char *openvzLocateConfDir(void);
48
static int openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len);
49
static int openvzAssignUUIDs(void);
50 51 52
static int openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext);

openvzLocateConfFileFunc openvzLocateConfFile = openvzLocateConfFileDefault;
53

54
int
55
strtoI(const char *str)
56 57 58
{
    int val;

59
    if (virStrToLong_i(str, NULL, 10, &val) < 0)
E
Eric Blake 已提交
60
        return 0;
61

62 63 64
    return val;
}

65 66

static int
67
openvzExtractVersionInfo(const char *cmdstr, int *retversion)
68
{
69
    int ret = -1;
70
    unsigned long version;
71
    char *help = NULL;
72
    char *tmp;
73
    virCommandPtr cmd = virCommandNewArgList(cmdstr, "--help", NULL);
74 75 76 77

    if (retversion)
        *retversion = 0;

78 79
    virCommandAddEnvString(cmd, "LC_ALL=C");
    virCommandSetOutputBuffer(cmd, &help);
80

81 82
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;
83

84 85 86 87
    tmp = help;

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

I
Ilja Livenson 已提交
90
    if (virParseVersionString(tmp, &version, true) < 0)
91
        goto cleanup;
92 93 94 95 96 97

    if (retversion)
        *retversion = version;

    ret = 0;

98
 cleanup:
99
    virCommandFree(cmd);
100 101 102 103 104
    VIR_FREE(help);

    return ret;
}

105
int openvzExtractVersion(struct openvz_driver *driver)
106 107 108 109 110
{
    if (driver->version > 0)
        return 0;

    if (openvzExtractVersionInfo(VZCTL, &driver->version) < 0) {
111 112
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not extract vzctl version"));
113 114 115 116 117 118 119
        return -1;
    }

    return 0;
}


120 121 122 123 124 125
/* 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)
{
126 127
    char **tmp = NULL;
    size_t ntmp = 0;
P
Pavel Hrdina 已提交
128
    int ret = -1;
129

130
    if (!(tmp = virStringSplitCount(value, ":", 0, &ntmp)))
131 132
        goto error;

133
    if (ntmp != 2)
134
        goto error;
135 136

    if (barrier && virStrToLong_ull(tmp[0], NULL, 10, barrier) < 0)
137
        goto error;
138 139 140 141

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

P
Pavel Hrdina 已提交
142
    ret = 0;
143
 error:
144
    virStringListFreeCount(tmp, ntmp);
P
Pavel Hrdina 已提交
145
    return ret;
146 147 148
}


149 150 151 152 153
virCapsPtr openvzCapsInit(void)
{
    virCapsPtr caps;
    virCapsGuestPtr guest;

154
    if ((caps = virCapabilitiesNew(virArchFromHost(),
155
                                   false, false)) == NULL)
156 157
        goto no_memory;

M
Martin Kletzander 已提交
158
    if (virCapabilitiesInitNUMA(caps) < 0)
159 160
        goto no_memory;

161 162 163
    if (virCapabilitiesInitCaches(caps) < 0)
        goto no_memory;

164
    if ((guest = virCapabilitiesAddGuest(caps,
165
                                         VIR_DOMAIN_OSTYPE_EXE,
166
                                         caps->host.arch,
167 168 169 170 171 172 173
                                         NULL,
                                         NULL,
                                         0,
                                         NULL)) == NULL)
        goto no_memory;

    if (virCapabilitiesAddGuestDomain(guest,
174
                                      VIR_DOMAIN_VIRT_OPENVZ,
175 176 177 178 179 180
                                      NULL,
                                      NULL,
                                      0,
                                      NULL) == NULL)
        goto no_memory;

181
    return caps;
182

183
 no_memory:
184
    virObjectUnref(caps);
185 186 187 188
    return NULL;
}


189
int
190
openvzReadNetworkConf(virDomainDefPtr def,
191 192
                      int veid)
{
193
    int ret;
194
    virDomainNetDefPtr net = NULL;
195
    char *temp = NULL;
196 197 198 199 200
    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 已提交
201
     * IPs split by space
202
     */
203
    ret = openvzReadVPSConfigParam(veid, "IP_ADDRESS", &temp);
204
    if (ret < 0) {
205 206 207
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'IP_ADDRESS' from config for container %d"),
                       veid);
208 209 210 211
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, " ", &saveptr);
        while (token != NULL) {
212
            if (VIR_ALLOC(net) < 0)
213
                goto error;
214 215

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
216
            if (virDomainNetAppendIPAddress(net, token, AF_UNSPEC, 0) < 0)
217
                goto error;
218

219
            if (VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net) < 0)
220
                goto error;
221

222 223 224 225 226 227
            token = strtok_r(NULL, " ", &saveptr);
        }
    }

    /*parse bridge devices*/
    /*Sample from config:
N
Nehal J Wani 已提交
228 229
     * 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 ';'
230
     */
231
    ret = openvzReadVPSConfigParam(veid, "NETIF", &temp);
232
    if (ret < 0) {
233 234 235
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'NETIF' from config for container %d"),
                       veid);
236 237 238 239 240
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, ";", &saveptr);
        while (token != NULL) {
            /*add new device to list*/
241
            if (VIR_ALLOC(net) < 0)
242
                goto error;
243 244 245

            net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;

246
            char *p = token;
247 248 249 250 251
            char cpy_temp[32];
            int len;

            /*parse string*/
            do {
252
                char *next = strchrnul(p, ',');
253
                if (STRPREFIX(p, "ifname=")) {
254 255 256
                    /* skip in libvirt */
                } else if (STRPREFIX(p, "host_ifname=")) {
                    p += 12;
257 258
                    len = next - p;
                    if (len > 16) {
259 260
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Too long network device name"));
261 262 263
                        goto error;
                    }

264
                    if (VIR_ALLOC_N(net->ifname, len+1) < 0)
265
                        goto error;
266

267
                    if (virStrncpy(net->ifname, p, len, len+1) < 0) {
268 269
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Network ifname %s too long for destination"), p);
C
Chris Lalancette 已提交
270 271
                        goto error;
                    }
272 273 274 275
                } else if (STRPREFIX(p, "bridge=")) {
                    p += 7;
                    len = next - p;
                    if (len > 16) {
276 277
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Too long bridge device name"));
278 279 280
                        goto error;
                    }

281
                    if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
282
                        goto error;
283

284
                    if (virStrncpy(net->data.bridge.brname, p, len, len+1) < 0) {
285 286
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Bridge name %s too long for destination"), p);
C
Chris Lalancette 已提交
287 288
                        goto error;
                    }
289 290 291
                } else if (STRPREFIX(p, "mac=")) {
                    p += 4;
                    len = next - p;
292
                    if (len != 17) { /* should be 17 */
293 294
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Wrong length MAC address"));
295 296
                        goto error;
                    }
297
                    if (virStrncpy(cpy_temp, p, len, sizeof(cpy_temp)) < 0) {
298 299
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("MAC address %s too long for destination"), p);
C
Chris Lalancette 已提交
300 301
                        goto error;
                    }
302
                    if (virMacAddrParse(cpy_temp, &net->mac) < 0) {
303 304
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("Wrong MAC address"));
305 306 307 308 309 310
                        goto error;
                    }
                }
                p = ++next;
            } while (p < token + strlen(token));

311
            if (VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net) < 0)
312
                goto error;
313

314 315 316 317
            token = strtok_r(NULL, ";", &saveptr);
        }
    }

318 319
    VIR_FREE(temp);

320
    return 0;
321

322
 error:
323
    VIR_FREE(temp);
324
    virDomainNetDefFree(net);
325
    return -1;
326 327 328
}


329
static int
330
openvzReadFSConf(virDomainDefPtr def,
331 332
                 int veid)
{
333 334
    int ret;
    virDomainFSDefPtr fs = NULL;
335 336
    char *veid_str = NULL;
    char *temp = NULL;
337 338
    const char *param;
    unsigned long long barrier, limit;
339

340
    ret = openvzReadVPSConfigParam(veid, "OSTEMPLATE", &temp);
341
    if (ret < 0) {
342 343 344
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read 'OSTEMPLATE' from config for container %d"),
                       veid);
345 346
        goto error;
    } else if (ret > 0) {
347
        if (!(fs = virDomainFSDefNew()))
348
            goto error;
349 350

        fs->type = VIR_DOMAIN_FS_TYPE_TEMPLATE;
351
        fs->src->path = g_strdup(temp);
352 353
    } else {
        /* OSTEMPLATE was not found, VE was booted from a private dir directly */
354
        ret = openvzReadVPSConfigParam(veid, "VE_PRIVATE", &temp);
355
        if (ret <= 0) {
356 357 358
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read 'VE_PRIVATE' from config for container %d"),
                           veid);
359 360
            goto error;
        }
361

362
        if (VIR_ALLOC(fs) < 0)
363
            goto error;
364

365
        if (virAsprintf(&veid_str, "%d", veid) < 0)
366
            goto error;
367 368

        fs->type = VIR_DOMAIN_FS_TYPE_MOUNT;
369
        if (!(fs->src->path = virStringReplace(temp, "$VEID", veid_str)))
370
            goto error;
371

372
        VIR_FREE(veid_str);
373 374
    }

375
    fs->dst = g_strdup("/");
376

377 378 379 380
    param = "DISKSPACE";
    ret = openvzReadVPSConfigParam(veid, param, &temp);
    if (ret > 0) {
        if (openvzParseBarrierLimit(temp, &barrier, &limit)) {
381 382 383
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read '%s' from config for container %d"),
                           param, veid);
384 385 386
            goto error;
        } else {
            /* Ensure that we can multiply by 1024 without overflowing. */
387
            if (barrier > ULLONG_MAX / 1024 ||
388
                limit > ULLONG_MAX / 1024) {
J
Jiri Denemark 已提交
389 390
                virReportError(VIR_ERR_OVERFLOW, "%s",
                               _("Unable to parse quota"));
391 392 393 394 395 396 397
                goto error;
            }
            fs->space_soft_limit = barrier * 1024; /* unit is bytes */
            fs->space_hard_limit = limit * 1024;   /* unit is bytes */
        }
    }

398
    if (VIR_APPEND_ELEMENT(def->fss, def->nfss, fs) < 0)
399
        goto error;
400

401 402
    VIR_FREE(temp);

403
    return 0;
404
 error:
405
    VIR_FREE(temp);
406 407 408 409 410
    virDomainFSDefFree(fs);
    return -1;
}


411 412 413
static int
openvzReadMemConf(virDomainDefPtr def, int veid)
{
414
    int ret = -1;
415 416 417
    char *temp = NULL;
    unsigned long long barrier, limit;
    const char *param;
418
    long kb_per_pages;
419

420 421
    kb_per_pages = openvzKBPerPages();
    if (kb_per_pages < 0)
422 423 424 425 426 427
        goto error;

    /* Memory allocation guarantee */
    param = "VMGUARPAGES";
    ret = openvzReadVPSConfigParam(veid, param, &temp);
    if (ret < 0) {
428 429 430
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read '%s' from config for container %d"),
                       param, veid);
431 432 433 434
        goto error;
    } else if (ret > 0) {
        ret = openvzParseBarrierLimit(temp, &barrier, NULL);
        if (ret < 0) {
435 436 437
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse barrier of '%s' "
                             "from config for container %d"), param, veid);
438 439 440 441 442 443 444 445 446 447 448 449
            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) {
450 451 452
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not read '%s' from config for container %d"),
                       param, veid);
453 454 455 456
        goto error;
    } else if (ret > 0) {
        ret = openvzParseBarrierLimit(temp, &barrier, &limit);
        if (ret < 0) {
457 458 459
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not parse barrier and limit of '%s' "
                             "from config for container %d"), param, veid);
460 461 462
            goto error;
        }
        if (barrier == LONG_MAX)
463
            def->mem.soft_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
464 465 466 467
        else
            def->mem.soft_limit = barrier * kb_per_pages;

        if (limit == LONG_MAX)
468
            def->mem.hard_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
469 470 471 472 473
        else
            def->mem.hard_limit = limit * kb_per_pages;
    }

    ret = 0;
474
 error:
475 476 477 478 479
    VIR_FREE(temp);
    return ret;
}


480 481 482 483 484 485
/* Free all memory associated with a openvz_driver structure */
void
openvzFreeDriver(struct openvz_driver *driver)
{
    if (!driver)
        return;
486

487
    virObjectUnref(driver->xmlopt);
488
    virObjectUnref(driver->domains);
489
    virObjectUnref(driver->caps);
490
    VIR_FREE(driver);
491
}
D
Daniel Veillard 已提交
492 493 494



495 496
int openvzLoadDomains(struct openvz_driver *driver)
{
497
    int veid, ret;
498
    char *status;
499
    char uuidstr[VIR_UUID_STRING_BUFLEN];
500
    virDomainObjPtr dom = NULL;
501
    virDomainDefPtr def = NULL;
502
    char *temp = NULL;
E
Eric Blake 已提交
503 504 505
    char *outbuf = NULL;
    char *line;
    virCommandPtr cmd = NULL;
506
    unsigned int vcpus = 0;
507

508 509
    if (openvzAssignUUIDs() < 0)
        return -1;
510

E
Eric Blake 已提交
511 512 513 514
    cmd = virCommandNewArgList(VZLIST, "-a", "-ovpsid,status", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;
515

516 517
    line = outbuf;
    while (line[0] != '\0') {
518
        unsigned int flags = 0;
519 520 521
        if (virStrToLong_i(line, &status, 10, &veid) < 0 ||
            *status++ != ' ' ||
            (line = strchr(status, '\n')) == NULL) {
522 523
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Failed to parse vzlist output"));
524
            goto cleanup;
525
        }
526
        *line++ = '\0';
527

528
        if (!(def = virDomainDefNew()))
529
            goto cleanup;
530

531
        def->virtType = VIR_DOMAIN_VIRT_OPENVZ;
532

533 534
        if (STREQ(status, "stopped"))
            def->id = -1;
J
Jiri Denemark 已提交
535
        else
536 537
            def->id = veid;
        if (virAsprintf(&def->name, "%i", veid) < 0)
538
            goto cleanup;
539

540
        openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr));
541
        ret = virUUIDParse(uuidstr, def->uuid);
542

543
        if (ret == -1) {
544 545
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("UUID in config file malformed"));
546
            goto cleanup;
547
        }
548

549
        def->os.type = VIR_DOMAIN_OSTYPE_EXE;
550
        def->os.init = g_strdup("/sbin/init");
551

552
        ret = openvzReadVPSConfigParam(veid, "CPUS", &temp);
553
        if (ret < 0) {
554 555 556
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not read config for container %d"),
                           veid);
557
            goto cleanup;
558
        } else if (ret > 0) {
559
            vcpus = strtoI(temp);
560 561
        }

562
        if (ret == 0 || vcpus == 0)
563
            vcpus = virHostCPUGetCount();
564

565
        if (virDomainDefSetVcpusMax(def, vcpus, driver->xmlopt) < 0)
566 567
            goto cleanup;

568 569
        if (virDomainDefSetVcpus(def, vcpus) < 0)
            goto cleanup;
570

571
        /* XXX load rest of VM config data .... */
572

573 574 575
        openvzReadNetworkConf(def, veid);
        openvzReadFSConf(def, veid);
        openvzReadMemConf(def, veid);
576

577
        virUUIDFormat(def->uuid, uuidstr);
578 579 580 581
        flags = VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE;
        if (STRNEQ(status, "stopped"))
            flags |= VIR_DOMAIN_OBJ_LIST_ADD_LIVE;

582 583
        if (!(dom = virDomainObjListAdd(driver->domains,
                                        def,
584
                                        driver->xmlopt,
585 586
                                        flags,
                                        NULL)))
587
            goto cleanup;
588 589 590 591 592 593 594 595 596

        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;
597
        }
598 599
        /* XXX OpenVZ doesn't appear to have concept of a transient domain */
        dom->persistent = 1;
600

601
        virDomainObjEndAPI(&dom);
602
        dom = NULL;
603
        def = NULL;
604
    }
605

E
Eric Blake 已提交
606
    virCommandFree(cmd);
607
    VIR_FREE(temp);
E
Eric Blake 已提交
608
    VIR_FREE(outbuf);
609

610
    return 0;
611

612
 cleanup:
E
Eric Blake 已提交
613
    virCommandFree(cmd);
614
    VIR_FREE(temp);
E
Eric Blake 已提交
615
    VIR_FREE(outbuf);
616
    virDomainDefFree(def);
617
    return -1;
618 619
}

620 621
static int
openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
622
{
623
    char * temp_file = NULL;
624 625 626 627
    int temp_fd = -1;
    FILE *fp;
    char *line = NULL;
    size_t line_size = 0;
628

629
    if (virAsprintf(&temp_file, "%s.tmp", conf_file)<0)
630 631
        return -1;

632 633
    fp = fopen(conf_file, "r");
    if (fp == NULL)
634
        goto error;
635
    temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
636
    if (temp_fd == -1)
637
        goto error;
638

E
Eric Blake 已提交
639
    while (1) {
640
        if (getline(&line, &line_size, fp) <= 0)
641 642
            break;

643
        if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
644 645 646 647 648 649 650 651 652 653 654 655
            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;

656
    if (VIR_FCLOSE(fp) < 0)
657
        goto error;
658
    if (VIR_CLOSE(temp_fd) < 0)
659 660 661 662 663
        goto error;

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

664 665
    VIR_FREE(line);

666 667
    return 0;

668
 error:
669 670
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
671
    VIR_FORCE_CLOSE(temp_fd);
E
Eric Blake 已提交
672
    if (temp_file)
673 674
        unlink(temp_file);
    VIR_FREE(temp_file);
675 676 677
    return -1;
}

678
int
679 680
openvzWriteVPSConfigParam(int vpsid, const char *param, const char *value)
{
681 682
    char *conf_file;
    int ret;
683

684
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
685 686
        return -1;

687 688 689
    ret = openvzWriteConfigParam(conf_file, param, value);
    VIR_FREE(conf_file);
    return ret;
690 691
}

692 693 694
/*
 * value will be freed before a new value is assigned to it, the caller is
 * responsible for freeing it afterwards.
695 696
 *
 * Returns <0 on error, 0 if not found, 1 if found.
697
 */
698
int
699
openvzReadConfigParam(const char *conf_file, const char *param, char **value)
700
{
701 702 703
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
704 705
    int err = 0;
    char *sf, *token, *saveptr = NULL;
706

707 708
    fp = fopen(conf_file, "r");
    if (fp == NULL)
709 710
        return -1;

711
    VIR_FREE(*value);
712 713 714 715 716 717
    while (1) {
        if (getline(&line, &line_size, fp) < 0) {
            err = !feof(fp);
            break;
        }

J
Ján Tomko 已提交
718
        if (!(sf = STRSKIP(line, param)))
719 720
            continue;

J
Ján Tomko 已提交
721 722
        if (*sf++ != '=')
            continue;
723

724
        saveptr = NULL;
725 726
        if ((token = strtok_r(sf, "\"\t\n", &saveptr)) != NULL) {
            VIR_FREE(*value);
727
            *value = g_strdup(token);
728 729
            /* keep going - last entry wins */
        }
730
    }
731 732
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
733

734
    return err ? -1 : *value ? 1 : 0;
735 736
}

737
/*
738 739
 * Read parameter from container config
 *
N
Nitesh Konkar 已提交
740
 * value will be freed before a new value is assigned to it, the caller is
741 742 743 744 745 746 747
 * responsible for freeing it afterwards.
 *
 * sample: 133, "OSTEMPLATE", &value
 * return: -1 - error
 *          0 - don't found
 *          1 - OK
 */
748
int
749
openvzReadVPSConfigParam(int vpsid, const char *param, char **value)
750
{
751 752
    char *conf_file;
    int ret;
753

754
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
755 756
        return -1;

757
    ret = openvzReadConfigParam(conf_file, param, value);
758 759
    VIR_FREE(conf_file);
    return ret;
760 761 762 763 764
}

static int
openvz_copyfile(char* from_path, char* to_path)
{
765 766 767 768
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
    int copy_fd;
769 770
    int bytes_read;

771 772
    fp = fopen(from_path, "r");
    if (fp == NULL)
773 774 775
        return -1;
    copy_fd = open(to_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (copy_fd == -1) {
776
        VIR_FORCE_FCLOSE(fp);
777 778 779
        return -1;
    }

E
Eric Blake 已提交
780
    while (1) {
781
        if (getline(&line, &line_size, fp) <= 0)
782 783 784 785 786 787 788
            break;

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

789
    if (VIR_FCLOSE(fp) < 0)
790
        goto error;
791
    if (VIR_CLOSE(copy_fd) < 0)
792 793
        goto error;

794 795
    VIR_FREE(line);

796 797
    return 0;

798
 error:
799 800
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
801
    VIR_FORCE_CLOSE(copy_fd);
802 803 804 805 806 807 808 809 810 811 812
    return -1;
}

/*
* Copy the default config to the VE conf file
* return: -1 - error
*          0 - OK
*/
int
openvzCopyDefaultConfig(int vpsid)
{
813 814 815
    char *confdir = NULL;
    char *default_conf_file = NULL;
    char *configfile_value = NULL;
816
    char *conf_file = NULL;
817 818
    int ret = -1;

819
    if (openvzReadConfigParam(VZ_CONF_FILE, "CONFIGFILE", &configfile_value) < 0)
820 821 822 823 824 825
        goto cleanup;

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

826
    if (virAsprintf(&default_conf_file, "%s/ve-%s.conf-sample", confdir,
827
                    configfile_value) < 0)
828 829
        goto cleanup;

830
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
831 832 833 834 835 836
        goto cleanup;

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

    ret = 0;
837
 cleanup:
838 839
    VIR_FREE(confdir);
    VIR_FREE(default_conf_file);
840
    VIR_FREE(configfile_value);
841
    VIR_FREE(conf_file);
842 843 844
    return ret;
}

845
/* Locate config file of container
846 847
 * return -1 - error
 *         0 - OK */
848
static int
849
openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext)
850
{
851
    char *confdir;
852 853 854 855 856 857
    int ret = 0;

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

858
    if (virAsprintf(conffile, "%s/%d.%s", confdir, vpsid,
859
                    ext ? ext : "conf") < 0)
860 861 862 863 864 865
        ret = -1;

    VIR_FREE(confdir);
    return ret;
}

866 867
static char *
openvzLocateConfDir(void)
868 869
{
    const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL};
870
    size_t i = 0;
871
    char *ret = NULL;
872

E
Eric Blake 已提交
873
    while (conf_dir_list[i]) {
874
        if (virFileExists(conf_dir_list[i])) {
875
            ret = g_strdup(conf_dir_list[i]);
876 877
            goto cleanup;
        }
E
Eric Blake 已提交
878
        i++;
879 880
    }

881
 cleanup:
882
    return ret;
883 884 885
}

/* Richard Steven's classic readline() function */
886
int
887
openvz_readline(int fd, char *ptr, int maxlen)
888 889 890 891
{
    int n, rc;
    char c;

E
Eric Blake 已提交
892
    for (n = 1; n < maxlen; n++) {
893
        if ((rc = read(fd, &c, 1)) == 1) {
894
            *ptr++ = c;
E
Eric Blake 已提交
895
            if (c == '\n')
896
                break;
E
Eric Blake 已提交
897 898
        } else if (rc == 0) {
            if (n == 1)
899 900 901 902 903 904 905 906 907 908 909
                return 0; /* EOF condition */
            else
                break;
        }
        else
            return -1; /* error */
    }
    *ptr = 0;
    return n;
}

910
static int
911
openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
912
{
913
    char *conf_file;
914 915
    char *line = NULL;
    size_t line_size = 0;
916
    char *saveptr = NULL;
917 918
    char *uuidbuf;
    char *iden;
919
    FILE *fp;
920
    int retval = -1;
921

922
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
923
        return -1;
924

925 926
    fp = fopen(conf_file, "r");
    if (fp == NULL)
927
        goto cleanup;
928

E
Eric Blake 已提交
929
    while (1) {
930 931 932 933 934 935 936
        if (getline(&line, &line_size, fp) < 0) {
            if (feof(fp)) { /* EOF, UUID was not found */
                uuidstr[0] = 0;
                break;
            } else {
                goto cleanup;
            }
937 938
        }

939 940 941 942
        iden = strtok_r(line, " ", &saveptr);
        uuidbuf = strtok_r(NULL, "\n", &saveptr);

        if (iden != NULL && uuidbuf != NULL && STREQ(iden, "#UUID:")) {
943
            if (virStrcpy(uuidstr, uuidbuf, len) < 0) {
944 945
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("invalid uuid %s"), uuidbuf);
946 947
                goto cleanup;
            }
948 949 950
            break;
        }
    }
951
    retval = 0;
952
 cleanup:
953 954
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
955
    VIR_FREE(conf_file);
956

C
Chris Lalancette 已提交
957
    return retval;
958 959 960 961 962
}

/* Do actual checking for UUID presence in conf file,
 * assign if not present.
 */
963 964
int
openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
965
{
966
    char *conf_file;
967
    char uuidstr[VIR_UUID_STRING_BUFLEN];
968
    FILE *fp = NULL;
969
    int ret = -1;
970 971 972

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

974
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
975
        return -1;
976

977
    if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
978
        goto cleanup;
979

J
Jim Meyering 已提交
980
    if (uuidstr[0] == 0) {
981
        fp = fopen(conf_file, "a"); /* append */
982
        if (fp == NULL)
983
            goto cleanup;
984

985 986
        virUUIDFormat(uuid, uuidstr);

987
        /* Record failure if fprintf or VIR_FCLOSE fails,
988
           and be careful always to close the stream.  */
989 990
        if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0) ||
            (VIR_FCLOSE(fp) == EOF))
991
            goto cleanup;
992 993
    }

994
    ret = 0;
995
 cleanup:
996
    VIR_FORCE_FCLOSE(fp);
997 998
    VIR_FREE(conf_file);
    return ret;
999 1000
}

1001
static int
1002 1003
openvzSetUUID(int vpsid)
{
1004 1005
    unsigned char uuid[VIR_UUID_BUFLEN];

1006
    if (virUUIDGenerate(uuid) < 0) {
1007 1008
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to generate UUID"));
1009 1010
        return -1;
    }
1011 1012 1013 1014

    return openvzSetDefinedUUID(vpsid, uuid);
}

1015 1016 1017 1018 1019 1020 1021
/*
 * 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.
 *
 */

1022
static int openvzAssignUUIDs(void)
1023 1024 1025 1026
{
    DIR *dp;
    struct dirent *dent;
    char *conf_dir;
1027 1028 1029
    int vpsid;
    char *ext;
    int ret = 0;
1030 1031

    conf_dir = openvzLocateConfDir();
1032 1033
    if (conf_dir == NULL)
        return -1;
1034

J
Ján Tomko 已提交
1035
    if (virDirOpenQuiet(&dp, conf_dir) < 0) {
1036
        VIR_FREE(conf_dir);
1037 1038 1039
        return 0;
    }

E
Eric Blake 已提交
1040
    while ((ret = virDirRead(dp, &dent, conf_dir)) > 0) {
1041 1042 1043
        if (virStrToLong_i(dent->d_name, &ext, 10, &vpsid) < 0 ||
            *ext++ != '.' ||
            STRNEQ(ext, "conf"))
1044
            continue;
E
Eric Blake 已提交
1045
        if (vpsid > 0) /* '0.conf' belongs to the host, ignore it */
1046 1047
            openvzSetUUID(vpsid);
    }
1048

J
Ján Tomko 已提交
1049
    VIR_DIR_CLOSE(dp);
1050
    VIR_FREE(conf_dir);
1051
    return ret;
1052
}
1053 1054 1055 1056 1057 1058 1059


/*
 * Return CTID from name
 *
 */

1060 1061
int openvzGetVEID(const char *name)
{
E
Eric Blake 已提交
1062 1063
    virCommandPtr cmd;
    char *outbuf;
1064
    char *temp;
1065
    int veid;
1066
    bool ok;
1067

E
Eric Blake 已提交
1068 1069 1070 1071 1072
    cmd = virCommandNewArgList(VZLIST, name, "-ovpsid", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0) {
        virCommandFree(cmd);
        VIR_FREE(outbuf);
1073 1074 1075
        return -1;
    }

E
Eric Blake 已提交
1076
    virCommandFree(cmd);
1077
    ok = virStrToLong_i(outbuf, &temp, 10, &veid) == 0 && *temp == '\n';
E
Eric Blake 已提交
1078
    VIR_FREE(outbuf);
1079

1080 1081 1082
    if (ok && veid >= 0)
        return veid;

1083 1084
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("Failed to parse vzlist output"));
1085 1086
    return -1;
}