openvz_conf.c 26.0 KB
Newer Older
1 2 3
/*
 * openvz_conf.c: config functions for managing OpenVZ VEs
 *
4
 * Copyright (C) 2010-2011 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 20 21 22
 *
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
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/utsname.h>
44
#include <sys/wait.h>
45

46
#include "virterror_internal.h"
47
#include "openvz_conf.h"
48 49
#include "uuid.h"
#include "buf.h"
50
#include "memory.h"
51
#include "util.h"
52
#include "nodeinfo.h"
E
Eric Blake 已提交
53
#include "virfile.h"
E
Eric Blake 已提交
54
#include "command.h"
55
#include "ignore-value.h"
56

57 58
#define VIR_FROM_THIS VIR_FROM_OPENVZ

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

openvzLocateConfFileFunc openvzLocateConfFile = openvzLocateConfFileDefault;
65

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

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

74 75 76
    return val;
}

77 78

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

    if (retversion)
        *retversion = 0;

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

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

96 97 98 99
    tmp = help;

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

102
    if (virParseVersionString(tmp, &version, false) < 0)
103
        goto cleanup;
104 105 106 107 108 109

    if (retversion)
        *retversion = version;

    ret = 0;

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

    return ret;
}

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

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

    return 0;
}


132 133 134 135 136 137 138 139 140 141 142 143
virCapsPtr openvzCapsInit(void)
{
    struct utsname utsname;
    virCapsPtr caps;
    virCapsGuestPtr guest;

    uname(&utsname);

    if ((caps = virCapabilitiesNew(utsname.machine,
                                   0, 0)) == NULL)
        goto no_memory;

144
    if (nodeCapsInitNUMA(caps) < 0)
145 146
        goto no_memory;

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

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
    if ((guest = virCapabilitiesAddGuest(caps,
                                         "exe",
                                         utsname.machine,
                                         sizeof(int) == 4 ? 32 : 8,
                                         NULL,
                                         NULL,
                                         0,
                                         NULL)) == NULL)
        goto no_memory;

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

167 168 169
    caps->defaultInitPath = "/sbin/init";

    return caps;
170 171 172 173 174 175
no_memory:
    virCapabilitiesFree(caps);
    return NULL;
}


176
int
177
openvzReadNetworkConf(virDomainDefPtr def,
178
                      int veid) {
179
    int ret;
180
    virDomainNetDefPtr net = NULL;
181
    char *temp = NULL;
182 183 184 185 186 187 188
    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
     */
189
    ret = openvzReadVPSConfigParam(veid, "IP_ADDRESS", &temp);
190
    if (ret < 0) {
191 192 193
        openvzError(VIR_ERR_INTERNAL_ERROR,
                    _("Could not read 'IP_ADDRESS' from config for container %d"),
                    veid);
194 195 196 197
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, " ", &saveptr);
        while (token != NULL) {
198
            if (VIR_ALLOC(net) < 0)
199 200 201 202 203 204 205 206
                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;

207 208 209 210 211
            if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
                goto no_memory;
            def->nets[def->nnets++] = net;
            net = NULL;

212 213 214 215 216 217 218 219 220
            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 ';'
     */
221
    ret = openvzReadVPSConfigParam(veid, "NETIF", &temp);
222
    if (ret < 0) {
223 224 225
        openvzError(VIR_ERR_INTERNAL_ERROR,
                    _("Could not read 'NETIF' from config for container %d"),
                    veid);
226 227 228 229 230
        goto error;
    } else if (ret > 0) {
        token = strtok_r(temp, ";", &saveptr);
        while (token != NULL) {
            /*add new device to list*/
231
            if (VIR_ALLOC(net) < 0)
232 233 234 235
                goto no_memory;

            net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;

236
            char *p = token;
237 238 239 240 241
            char cpy_temp[32];
            int len;

            /*parse string*/
            do {
242
                char *next = strchrnul (p, ',');
243
                if (STRPREFIX(p, "ifname=")) {
244 245 246
                    /* skip in libvirt */
                } else if (STRPREFIX(p, "host_ifname=")) {
                    p += 12;
247 248
                    len = next - p;
                    if (len > 16) {
249 250
                        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                                    _("Too long network device name"));
251 252 253
                        goto error;
                    }

254 255 256
                    if (VIR_ALLOC_N(net->ifname, len+1) < 0)
                        goto no_memory;

C
Chris Lalancette 已提交
257
                    if (virStrncpy(net->ifname, p, len, len+1) == NULL) {
258
                        openvzError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
259 260 261
                                    _("Network ifname %s too long for destination"), p);
                        goto error;
                    }
262 263 264 265
                } else if (STRPREFIX(p, "bridge=")) {
                    p += 7;
                    len = next - p;
                    if (len > 16) {
266 267
                        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                                    _("Too long bridge device name"));
268 269 270
                        goto error;
                    }

271 272 273
                    if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
                        goto no_memory;

C
Chris Lalancette 已提交
274
                    if (virStrncpy(net->data.bridge.brname, p, len, len+1) == NULL) {
275
                        openvzError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
276 277 278
                                    _("Bridge name %s too long for destination"), p);
                        goto error;
                    }
279 280 281
                } else if (STRPREFIX(p, "mac=")) {
                    p += 4;
                    len = next - p;
282
                    if (len != 17) { /* should be 17 */
283 284
                        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                                    _("Wrong length MAC address"));
285 286
                        goto error;
                    }
C
Chris Lalancette 已提交
287
                    if (virStrncpy(cpy_temp, p, len, sizeof(cpy_temp)) == NULL) {
288
                        openvzError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
289 290 291
                                    _("MAC address %s too long for destination"), p);
                        goto error;
                    }
292
                    if (virParseMacAddr(cpy_temp, net->mac) < 0) {
293 294
                        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                                    _("Wrong MAC address"));
295 296 297 298 299 300
                        goto error;
                    }
                }
                p = ++next;
            } while (p < token + strlen(token));

301 302 303 304 305
            if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
                goto no_memory;
            def->nets[def->nnets++] = net;
            net = NULL;

306 307 308 309
            token = strtok_r(NULL, ";", &saveptr);
        }
    }

310 311
    VIR_FREE(temp);

312
    return 0;
313
no_memory:
314
    virReportOOMError();
315
error:
316
    VIR_FREE(temp);
317
    virDomainNetDefFree(net);
318
    return -1;
319 320 321
}


322 323 324 325 326 327 328
/* 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;
329 330
    int to_len;
    int from_len;
331 332
    virBuffer buf = VIR_BUFFER_INITIALIZER;

333
    if ((!from) || (!to))
334
        return NULL;
335 336
    from_len = strlen(from);
    to_len = strlen(to);
337

E
Eric Blake 已提交
338
    while ((offset = strstr(str_start, from)))
339 340 341 342 343 344
    {
        virBufferAdd(&buf, str_start, offset-str_start);
        virBufferAdd(&buf, to, to_len);
        str_start = offset + from_len;
    }

345
    virBufferAdd(&buf, str_start, -1);
346

347 348 349 350
    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
        return NULL;
    }
351 352 353 354 355

    return virBufferContentAndReset(&buf);
}


356
static int
357
openvzReadFSConf(virDomainDefPtr def,
358 359 360
                 int veid) {
    int ret;
    virDomainFSDefPtr fs = NULL;
361 362
    char *veid_str = NULL;
    char *temp = NULL;
363

364
    ret = openvzReadVPSConfigParam(veid, "OSTEMPLATE", &temp);
365
    if (ret < 0) {
366
        openvzError(VIR_ERR_INTERNAL_ERROR,
367
                    _("Could not read 'OSTEMPLATE' from config for container %d"),
368 369 370 371 372 373 374 375
                    veid);
        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);
376 377
    } else {
        /* OSTEMPLATE was not found, VE was booted from a private dir directly */
378
        ret = openvzReadVPSConfigParam(veid, "VE_PRIVATE", &temp);
379
        if (ret <= 0) {
380
            openvzError(VIR_ERR_INTERNAL_ERROR,
381
                        _("Could not read 'VE_PRIVATE' from config for container %d"),
382 383 384
                        veid);
            goto error;
        }
385

386
        if (VIR_ALLOC(fs) < 0)
387 388
            goto no_memory;

389 390
        if (virAsprintf(&veid_str, "%d", veid) < 0)
            goto no_memory;
391 392 393

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

395
        VIR_FREE(veid_str);
396 397
    }

398 399 400 401 402 403 404 405 406 407
    fs->dst = strdup("/");

    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;

408 409
    VIR_FREE(temp);

410 411
    return 0;
no_memory:
412
    virReportOOMError();
413
error:
414
    VIR_FREE(temp);
415 416 417 418 419
    virDomainFSDefFree(fs);
    return -1;
}


420 421 422 423 424 425
/* Free all memory associated with a openvz_driver structure */
void
openvzFreeDriver(struct openvz_driver *driver)
{
    if (!driver)
        return;
426

427
    virDomainObjListDeinit(&driver->domains);
428
    virCapabilitiesFree(driver->caps);
429
    VIR_FREE(driver);
430
}
D
Daniel Veillard 已提交
431 432 433



434
int openvzLoadDomains(struct openvz_driver *driver) {
435
    int veid, ret;
436
    char *status;
437
    char uuidstr[VIR_UUID_STRING_BUFLEN];
438
    virDomainObjPtr dom = NULL;
439
    char *temp = NULL;
E
Eric Blake 已提交
440 441 442
    char *outbuf = NULL;
    char *line;
    virCommandPtr cmd = NULL;
443

444 445
    if (openvzAssignUUIDs() < 0)
        return -1;
446

E
Eric Blake 已提交
447 448 449 450
    cmd = virCommandNewArgList(VZLIST, "-a", "-ovpsid,status", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;
451

452 453 454 455 456
    line = outbuf;
    while (line[0] != '\0') {
        if (virStrToLong_i(line, &status, 10, &veid) < 0 ||
            *status++ != ' ' ||
            (line = strchr(status, '\n')) == NULL) {
457 458
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Failed to parse vzlist output"));
459
            goto cleanup;
460
        }
461
        *line++ = '\0';
462

463
        if (VIR_ALLOC(dom) < 0)
464
            goto no_memory;
465

466
        if (virMutexInit(&dom->lock) < 0) {
467 468
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("cannot initialize mutex"));
469 470 471 472
            VIR_FREE(dom);
            goto cleanup;
        }

473 474
        virDomainObjLock(dom);

475 476
        if (VIR_ALLOC(dom->def) < 0)
            goto no_memory;
477

478 479
        dom->def->virtType = VIR_DOMAIN_VIRT_OPENVZ;

J
Jiri Denemark 已提交
480 481 482 483 484 485 486
        if (STREQ(status, "stopped")) {
            virDomainObjSetState(dom, VIR_DOMAIN_SHUTOFF,
                                 VIR_DOMAIN_SHUTOFF_UNKNOWN);
        } else {
            virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_UNKNOWN);
        }
487

488
        dom->refs = 1;
489
        dom->pid = veid;
J
Jiri Denemark 已提交
490 491 492 493
        if (virDomainObjGetState(dom, NULL) == VIR_DOMAIN_SHUTOFF)
            dom->def->id = -1;
        else
            dom->def->id = veid;
494 495
        /* XXX OpenVZ doesn't appear to have concept of a transient domain */
        dom->persistent = 1;
496

497
        if (virAsprintf(&dom->def->name, "%i", veid) < 0)
498
            goto no_memory;
499

500
        openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr));
501
        ret = virUUIDParse(uuidstr, dom->def->uuid);
502

503
        if (ret == -1) {
504 505
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("UUID in config file malformed"));
506
            goto cleanup;
507
        }
508

509 510 511 512
        if (!(dom->def->os.type = strdup("exe")))
            goto no_memory;
        if (!(dom->def->os.init = strdup("/sbin/init")))
            goto no_memory;
513

514
        ret = openvzReadVPSConfigParam(veid, "CPUS", &temp);
515
        if (ret < 0) {
516
            openvzError(VIR_ERR_INTERNAL_ERROR,
517
                        _("Could not read config for container %d"),
518 519
                        veid);
            goto cleanup;
520
        } else if (ret > 0) {
E
Eric Blake 已提交
521
            dom->def->maxvcpus = strtoI(temp);
522 523
        }

E
Eric Blake 已提交
524 525 526
        if (ret == 0 || dom->def->maxvcpus == 0)
            dom->def->maxvcpus = openvzGetNodeCPUs();
        dom->def->vcpus = dom->def->maxvcpus;
527

528
        /* XXX load rest of VM config data .... */
529

530 531
        openvzReadNetworkConf(dom->def, veid);
        openvzReadFSConf(dom->def, veid);
532

533 534
        virUUIDFormat(dom->def->uuid, uuidstr);
        if (virHashAddEntry(driver->domains.objs, uuidstr, dom) < 0)
535
            goto cleanup;
536

537
        virDomainObjUnlock(dom);
538
        dom = NULL;
539
    }
540

E
Eric Blake 已提交
541
    virCommandFree(cmd);
542
    VIR_FREE(temp);
E
Eric Blake 已提交
543
    VIR_FREE(outbuf);
544

545
    return 0;
546

547
 no_memory:
548
    virReportOOMError();
549

550
 cleanup:
E
Eric Blake 已提交
551
    virCommandFree(cmd);
552
    VIR_FREE(temp);
E
Eric Blake 已提交
553
    VIR_FREE(outbuf);
554
    /* dom hasn't been shared yet, so unref should return 0 */
555
    if (dom)
556
        ignore_value(virDomainObjUnref(dom));
557
    return -1;
558 559
}

560 561 562 563 564
unsigned int
openvzGetNodeCPUs(void)
{
    virNodeInfo nodeinfo;

565
    if (nodeGetInfo(NULL, &nodeinfo) < 0)
566 567 568 569
        return 0;

    return nodeinfo.cpus;
}
570

571 572
static int
openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
573
{
574
    char * temp_file = NULL;
575 576 577 578
    int temp_fd = -1;
    FILE *fp;
    char *line = NULL;
    size_t line_size = 0;
579

580
    if (virAsprintf(&temp_file, "%s.tmp", conf_file)<0) {
581
        virReportOOMError();
582
        return -1;
583
    }
584

585 586
    fp = fopen(conf_file, "r");
    if (fp == NULL)
587
        goto error;
588 589
    temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (temp_fd == -1) {
590
        goto error;
591 592
    }

E
Eric Blake 已提交
593
    while (1) {
594
        if (getline(&line, &line_size, fp) <= 0)
595 596
            break;

597
        if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
598 599 600 601 602 603 604 605 606 607 608 609
            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;

610
    if (VIR_FCLOSE(fp) < 0)
611
        goto error;
612
    if (VIR_CLOSE(temp_fd) < 0)
613 614 615 616 617
        goto error;

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

618 619
    VIR_FREE(line);

620 621 622
    return 0;

error:
623 624
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
625
    VIR_FORCE_CLOSE(temp_fd);
E
Eric Blake 已提交
626
    if (temp_file)
627 628
        unlink(temp_file);
    VIR_FREE(temp_file);
629 630 631
    return -1;
}

632
int
633 634
openvzWriteVPSConfigParam(int vpsid, const char *param, const char *value)
{
635 636
    char *conf_file;
    int ret;
637

638
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
639 640
        return -1;

641 642 643
    ret = openvzWriteConfigParam(conf_file, param, value);
    VIR_FREE(conf_file);
    return ret;
644 645
}

646 647 648
/*
 * value will be freed before a new value is assigned to it, the caller is
 * responsible for freeing it afterwards.
649 650
 *
 * Returns <0 on error, 0 if not found, 1 if found.
651
 */
652
int
653
openvzReadConfigParam(const char *conf_file, const char *param, char **value)
654
{
655 656 657
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
658 659
    int err = 0;
    char *sf, *token, *saveptr = NULL;
660

661 662
    fp = fopen(conf_file, "r");
    if (fp == NULL)
663 664
        return -1;

665
    VIR_FREE(*value);
666 667 668 669 670 671
    while (1) {
        if (getline(&line, &line_size, fp) < 0) {
            err = !feof(fp);
            break;
        }

672 673 674 675 676 677
        if (! STREQLEN(line, param, strlen(param)))
            continue;

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

678
        saveptr = NULL;
679 680 681 682 683 684
        if ((token = strtok_r(sf, "\"\t\n", &saveptr)) != NULL) {
            VIR_FREE(*value);
            *value = strdup(token);
            if (*value == NULL) {
                err = 1;
                break;
685
            }
686 687
            /* keep going - last entry wins */
        }
688
    }
689 690
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
691

692
    return err ? -1 : *value ? 1 : 0;
693 694
}

695
/*
696 697 698 699 700 701 702 703 704 705
 * 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
 */
706
int
707
openvzReadVPSConfigParam(int vpsid, const char *param, char **value)
708
{
709 710
    char *conf_file;
    int ret;
711

712
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
713 714
        return -1;

715
    ret = openvzReadConfigParam(conf_file, param, value);
716 717
    VIR_FREE(conf_file);
    return ret;
718 719 720 721 722
}

static int
openvz_copyfile(char* from_path, char* to_path)
{
723 724 725 726
    char *line = NULL;
    size_t line_size = 0;
    FILE *fp;
    int copy_fd;
727 728
    int bytes_read;

729 730
    fp = fopen(from_path, "r");
    if (fp == NULL)
731 732 733
        return -1;
    copy_fd = open(to_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (copy_fd == -1) {
734
        VIR_FORCE_FCLOSE(fp);
735 736 737
        return -1;
    }

E
Eric Blake 已提交
738
    while (1) {
739
        if (getline(&line, &line_size, fp) <= 0)
740 741 742 743 744 745 746
            break;

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

747
    if (VIR_FCLOSE(fp) < 0)
748
        goto error;
749
    if (VIR_CLOSE(copy_fd) < 0)
750 751
        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(copy_fd);
760 761 762 763 764 765 766 767 768 769 770
    return -1;
}

/*
* Copy the default config to the VE conf file
* return: -1 - error
*          0 - OK
*/
int
openvzCopyDefaultConfig(int vpsid)
{
771 772 773
    char *confdir = NULL;
    char *default_conf_file = NULL;
    char *configfile_value = NULL;
774
    char *conf_file = NULL;
775 776
    int ret = -1;

777
    if (openvzReadConfigParam(VZ_CONF_FILE, "CONFIGFILE", &configfile_value) < 0)
778 779 780 781 782 783
        goto cleanup;

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

784 785
    if (virAsprintf(&default_conf_file, "%s/ve-%s.conf-sample", confdir,
                    configfile_value) < 0) {
786
        virReportOOMError();
787
        goto cleanup;
788
    }
789

790
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
791 792 793 794 795 796 797 798 799
        goto cleanup;

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

    ret = 0;
cleanup:
    VIR_FREE(confdir);
    VIR_FREE(default_conf_file);
800
    VIR_FREE(configfile_value);
801
    VIR_FREE(conf_file);
802 803 804
    return ret;
}

805
/* Locate config file of container
806 807
 * return -1 - error
 *         0 - OK */
808
static int
809
openvzLocateConfFileDefault(int vpsid, char **conffile, const char *ext)
810
{
811
    char *confdir;
812 813 814 815 816 817
    int ret = 0;

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

818 819 820
    if (virAsprintf(conffile, "%s/%d.%s", confdir, vpsid,
                    ext ? ext : "conf") < 0) {
        virReportOOMError();
821
        ret = -1;
822
    }
823 824 825 826 827

    VIR_FREE(confdir);
    return ret;
}

828 829
static char *
openvzLocateConfDir(void)
830 831 832 833
{
    const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL};
    int i=0;

E
Eric Blake 已提交
834 835
    while (conf_dir_list[i]) {
        if (!access(conf_dir_list[i], F_OK))
836
            return strdup(conf_dir_list[i]);
E
Eric Blake 已提交
837
        i++;
838 839 840 841 842 843
    }

    return NULL;
}

/* Richard Steven's classic readline() function */
844
int
845
openvz_readline(int fd, char *ptr, int maxlen)
846 847 848 849
{
    int n, rc;
    char c;

E
Eric Blake 已提交
850 851
    for (n = 1; n < maxlen; n++) {
        if ( (rc = read(fd, &c, 1)) == 1) {
852
            *ptr++ = c;
E
Eric Blake 已提交
853
            if (c == '\n')
854
                break;
E
Eric Blake 已提交
855 856
        } else if (rc == 0) {
            if (n == 1)
857 858 859 860 861 862 863 864 865 866 867
                return 0; /* EOF condition */
            else
                break;
        }
        else
            return -1; /* error */
    }
    *ptr = 0;
    return n;
}

868
static int
869
openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
870
{
871
    char *conf_file;
872 873
    char *line = NULL;
    size_t line_size = 0;
874
    char *saveptr = NULL;
875 876
    char *uuidbuf;
    char *iden;
877
    FILE *fp;
878
    int retval = -1;
879

880
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
881
        return -1;
882

883 884
    fp = fopen(conf_file, "r");
    if (fp == NULL)
885
        goto cleanup;
886

E
Eric Blake 已提交
887
    while (1) {
888 889 890 891 892 893 894
        if (getline(&line, &line_size, fp) < 0) {
            if (feof(fp)) { /* EOF, UUID was not found */
                uuidstr[0] = 0;
                break;
            } else {
                goto cleanup;
            }
895 896
        }

897 898 899 900
        iden = strtok_r(line, " ", &saveptr);
        uuidbuf = strtok_r(NULL, "\n", &saveptr);

        if (iden != NULL && uuidbuf != NULL && STREQ(iden, "#UUID:")) {
901 902 903 904 905
            if (virStrcpy(uuidstr, uuidbuf, len) == NULL) {
                openvzError(VIR_ERR_INTERNAL_ERROR,
                            _("invalid uuid %s"), uuidbuf);
                goto cleanup;
            }
906 907 908
            break;
        }
    }
909 910
    retval = 0;
cleanup:
911 912
    VIR_FREE(line);
    VIR_FORCE_FCLOSE(fp);
913
    VIR_FREE(conf_file);
914

C
Chris Lalancette 已提交
915
    return retval;
916 917 918 919 920
}

/* Do actual checking for UUID presence in conf file,
 * assign if not present.
 */
921 922
int
openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
923
{
924
    char *conf_file;
925
    char uuidstr[VIR_UUID_STRING_BUFLEN];
926
    FILE *fp = NULL;
927
    int ret = -1;
928 929 930

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

932
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
933
        return -1;
934

935
    if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
936
        goto cleanup;
937

J
Jim Meyering 已提交
938
    if (uuidstr[0] == 0) {
939
        fp = fopen(conf_file, "a"); /* append */
940
        if (fp == NULL)
941
            goto cleanup;
942

943 944
        virUUIDFormat(uuid, uuidstr);

945
        /* Record failure if fprintf or VIR_FCLOSE fails,
946
           and be careful always to close the stream.  */
947 948
        if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0) ||
            (VIR_FCLOSE(fp) == EOF))
949
            goto cleanup;
950 951
    }

952 953
    ret = 0;
cleanup:
954
    VIR_FORCE_FCLOSE(fp);
955 956
    VIR_FREE(conf_file);
    return ret;
957 958
}

959 960 961 962
static int
openvzSetUUID(int vpsid){
    unsigned char uuid[VIR_UUID_BUFLEN];

963
    if (virUUIDGenerate(uuid)) {
964 965
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Failed to generate UUID"));
966 967
        return -1;
    }
968 969 970 971

    return openvzSetDefinedUUID(vpsid, uuid);
}

972 973 974 975 976 977 978
/*
 * 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.
 *
 */

979
static int openvzAssignUUIDs(void)
980 981 982 983
{
    DIR *dp;
    struct dirent *dent;
    char *conf_dir;
984 985 986
    int vpsid;
    char *ext;
    int ret = 0;
987 988

    conf_dir = openvzLocateConfDir();
989 990
    if (conf_dir == NULL)
        return -1;
991 992

    dp = opendir(conf_dir);
E
Eric Blake 已提交
993
    if (dp == NULL) {
994
        VIR_FREE(conf_dir);
995 996 997
        return 0;
    }

998
    errno = 0;
E
Eric Blake 已提交
999
    while ((dent = readdir(dp))) {
1000 1001 1002
        if (virStrToLong_i(dent->d_name, &ext, 10, &vpsid) < 0 ||
            *ext++ != '.' ||
            STRNEQ(ext, "conf"))
1003
            continue;
E
Eric Blake 已提交
1004
        if (vpsid > 0) /* '0.conf' belongs to the host, ignore it */
1005
            openvzSetUUID(vpsid);
1006 1007 1008 1009 1010 1011
        errno = 0;
    }
    if (errno) {
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Failed to scan configuration directory"));
        ret = -1;
1012
    }
1013

1014
    closedir(dp);
1015
    VIR_FREE(conf_dir);
1016
    return ret;
1017
}
1018 1019 1020 1021 1022 1023 1024 1025


/*
 * Return CTID from name
 *
 */

int openvzGetVEID(const char *name) {
E
Eric Blake 已提交
1026 1027
    virCommandPtr cmd;
    char *outbuf;
1028
    char *temp;
1029
    int veid;
1030
    bool ok;
1031

E
Eric Blake 已提交
1032 1033 1034 1035 1036
    cmd = virCommandNewArgList(VZLIST, name, "-ovpsid", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0) {
        virCommandFree(cmd);
        VIR_FREE(outbuf);
1037 1038 1039
        return -1;
    }

E
Eric Blake 已提交
1040
    virCommandFree(cmd);
1041
    ok = virStrToLong_i(outbuf, &temp, 10, &veid) == 0 && *temp == '\n';
E
Eric Blake 已提交
1042
    VIR_FREE(outbuf);
1043

1044 1045 1046
    if (ok && veid >= 0)
        return veid;

1047 1048
    openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                _("Failed to parse vzlist output"));
1049 1050
    return -1;
}