You need to sign in or sign up before continuing.
openvz_conf.c 25.3 KB
Newer Older
1 2 3
/*
 * openvz_conf.c: config functions for managing OpenVZ VEs
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2010 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"
53
#include "files.h"
E
Eric Blake 已提交
54
#include "command.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 openvzLocateConfFile(int vpsid, char **conffile, const char *ext);
61
static int openvzAssignUUIDs(void);
62

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

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

71 72 73
    return val;
}

74 75 76 77 78 79 80 81 82

static int
openvzExtractVersionInfo(const char *cmd, int *retversion)
{
    const char *const vzarg[] = { cmd, "--help", NULL };
    const char *const vzenv[] = { "LC_ALL=C", NULL };
    pid_t child;
    int newstdout = -1;
    int ret = -1, status;
83 84
    unsigned long version;
    char *tmp;
85 86 87 88

    if (retversion)
        *retversion = 0;

89
    if (virExec(vzarg, vzenv, NULL,
90 91 92 93
                &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0)
        return -1;

    char *help = NULL;
94
    int len = virFileReadLimFD(newstdout, 4096, &help);
95 96 97
    if (len < 0)
        goto cleanup2;

98 99 100 101
    tmp = help;

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

104 105
    if (virParseVersionString(tmp, &version) < 0)
        goto cleanup2;
106 107 108 109 110 111 112 113

    if (retversion)
        *retversion = version;

    ret = 0;

cleanup2:
    VIR_FREE(help);
114
    if (VIR_CLOSE(newstdout) < 0)
115 116 117 118 119 120 121 122 123 124 125 126
        ret = -1;

rewait:
    if (waitpid(child, &status, 0) != child) {
        if (errno == EINTR)
            goto rewait;
        ret = -1;
    }

    return ret;
}

127
int openvzExtractVersion(struct openvz_driver *driver)
128 129 130 131 132
{
    if (driver->version > 0)
        return 0;

    if (openvzExtractVersionInfo(VZCTL, &driver->version) < 0) {
133 134
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Could not extract vzctl version"));
135 136 137 138 139 140 141
        return -1;
    }

    return 0;
}


142 143 144 145 146 147 148 149 150 151 152 153
virCapsPtr openvzCapsInit(void)
{
    struct utsname utsname;
    virCapsPtr caps;
    virCapsGuestPtr guest;

    uname(&utsname);

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

154
    if (nodeCapsInitNUMA(caps) < 0)
155 156
        goto no_memory;

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

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    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;
    return caps;

no_memory:
    virCapabilitiesFree(caps);
    return NULL;
}


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

215 216 217 218 219
            if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
                goto no_memory;
            def->nets[def->nnets++] = net;
            net = NULL;

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

            net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;

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

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

262 263 264
                    if (VIR_ALLOC_N(net->ifname, len+1) < 0)
                        goto no_memory;

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

279 280 281
                    if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
                        goto no_memory;

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

309 310 311 312 313
            if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
                goto no_memory;
            def->nets[def->nnets++] = net;
            net = NULL;

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

318
    return 0;
319
no_memory:
320
    virReportOOMError();
321 322
error:
    virDomainNetDefFree(net);
323
    return -1;
324 325 326
}


327 328 329 330 331 332 333
/* 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;
334 335
    int to_len;
    int from_len;
336 337
    virBuffer buf = VIR_BUFFER_INITIALIZER;

338
    if ((!from) || (!to))
339
        return NULL;
340 341
    from_len = strlen(from);
    to_len = strlen(to);
342

E
Eric Blake 已提交
343
    while ((offset = strstr(str_start, from)))
344 345 346 347 348 349
    {
        virBufferAdd(&buf, str_start, offset-str_start);
        virBufferAdd(&buf, to, to_len);
        str_start = offset + from_len;
    }

350
    virBufferAdd(&buf, str_start, -1);
351

352 353 354 355
    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
        return NULL;
    }
356 357 358 359 360

    return virBufferContentAndReset(&buf);
}


361
static int
362
openvzReadFSConf(virDomainDefPtr def,
363 364 365
                 int veid) {
    int ret;
    virDomainFSDefPtr fs = NULL;
366 367
    char* veid_str = NULL;
    char temp[100];
368

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

391
        if (VIR_ALLOC(fs) < 0)
392 393
            goto no_memory;

394 395
        if (virAsprintf(&veid_str, "%d", veid) < 0)
            goto no_memory;
396 397 398

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

400
        VIR_FREE(veid_str);
401 402
    }

403 404 405 406 407 408 409 410 411 412
    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;

413 414
    return 0;
no_memory:
415
    virReportOOMError();
416 417 418 419 420 421
error:
    virDomainFSDefFree(fs);
    return -1;
}


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

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



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

446 447
    if (openvzAssignUUIDs() < 0)
        return -1;
448

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

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

465
        if (VIR_ALLOC(dom) < 0)
466
            goto no_memory;
467

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

475 476
        virDomainObjLock(dom);

477 478
        if (VIR_ALLOC(dom->def) < 0)
            goto no_memory;
479

480 481 482 483
        if (STREQ(status, "stopped"))
            dom->state = VIR_DOMAIN_SHUTOFF;
        else
            dom->state = VIR_DOMAIN_RUNNING;
484

485
        dom->refs = 1;
486 487
        dom->pid = veid;
        dom->def->id = dom->state == VIR_DOMAIN_SHUTOFF ? -1 : veid;
488 489
        /* XXX OpenVZ doesn't appear to have concept of a transient domain */
        dom->persistent = 1;
490

491
        if (virAsprintf(&dom->def->name, "%i", veid) < 0)
492
            goto no_memory;
493

494
        openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr));
495
        ret = virUUIDParse(uuidstr, dom->def->uuid);
496

497
        if (ret == -1) {
498 499
            openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("UUID in config file malformed"));
500
            goto cleanup;
501
        }
502

503 504 505 506
        if (!(dom->def->os.type = strdup("exe")))
            goto no_memory;
        if (!(dom->def->os.init = strdup("/sbin/init")))
            goto no_memory;
507

508
        ret = openvzReadVPSConfigParam(veid, "CPUS", temp, sizeof(temp));
509
        if (ret < 0) {
510
            openvzError(VIR_ERR_INTERNAL_ERROR,
511
                        _("Could not read config for container %d"),
512 513
                        veid);
            goto cleanup;
514
        } else if (ret > 0) {
E
Eric Blake 已提交
515
            dom->def->maxvcpus = strtoI(temp);
516 517
        }

E
Eric Blake 已提交
518 519 520
        if (ret == 0 || dom->def->maxvcpus == 0)
            dom->def->maxvcpus = openvzGetNodeCPUs();
        dom->def->vcpus = dom->def->maxvcpus;
521

522
        /* XXX load rest of VM config data .... */
523

524 525
        openvzReadNetworkConf(dom->def, veid);
        openvzReadFSConf(dom->def, veid);
526

527 528
        virUUIDFormat(dom->def->uuid, uuidstr);
        if (virHashAddEntry(driver->domains.objs, uuidstr, dom) < 0)
529 530
            goto no_memory;

531
        virDomainObjUnlock(dom);
532
        dom = NULL;
533
    }
534

E
Eric Blake 已提交
535 536
    virCommandFree(cmd);
    VIR_FREE(outbuf);
537

538
    return 0;
539

540
 no_memory:
541
    virReportOOMError();
542

543
 cleanup:
E
Eric Blake 已提交
544 545
    virCommandFree(cmd);
    VIR_FREE(outbuf);
546 547
    if (dom)
        virDomainObjUnref(dom);
548
    return -1;
549 550
}

551 552 553 554 555
unsigned int
openvzGetNodeCPUs(void)
{
    virNodeInfo nodeinfo;

556
    if (nodeGetInfo(NULL, &nodeinfo) < 0)
557 558 559 560
        return 0;

    return nodeinfo.cpus;
}
561

562 563
static int
openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
564
{
565 566
    char * temp_file = NULL;
    int fd = -1, temp_fd = -1;
E
Eric Blake 已提交
567
    char line[PATH_MAX];
568

569
    if (virAsprintf(&temp_file, "%s.tmp", conf_file)<0) {
570
        virReportOOMError();
571
        return -1;
572
    }
573 574 575

    fd = open(conf_file, O_RDONLY);
    if (fd == -1)
576
        goto error;
577 578
    temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (temp_fd == -1) {
579
        VIR_FORCE_CLOSE(fd);
580
        goto error;
581 582
    }

E
Eric Blake 已提交
583
    while (1) {
584 585 586
        if (openvz_readline(fd, line, sizeof(line)) <= 0)
            break;

587
        if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
588 589 590 591 592 593 594 595 596 597 598 599
            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;

600
    if (VIR_CLOSE(fd) < 0)
601
        goto error;
602
    if (VIR_CLOSE(temp_fd) < 0)
603 604 605 606 607 608 609 610
        goto error;

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

    return 0;

error:
611 612
    VIR_FORCE_CLOSE(fd);
    VIR_FORCE_CLOSE(temp_fd);
E
Eric Blake 已提交
613
    if (temp_file)
614 615
        unlink(temp_file);
    VIR_FREE(temp_file);
616 617 618
    return -1;
}

619
int
620 621
openvzWriteVPSConfigParam(int vpsid, const char *param, const char *value)
{
622 623
    char *conf_file;
    int ret;
624

625
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
626 627
        return -1;

628 629 630
    ret = openvzWriteConfigParam(conf_file, param, value);
    VIR_FREE(conf_file);
    return ret;
631 632 633 634
}

static int
openvzReadConfigParam(const char * conf_file ,const char * param, char *value, int maxlen)
635
{
E
Eric Blake 已提交
636
    char line[PATH_MAX];
637
    int ret, found = 0;
E
Eric Blake 已提交
638
    int fd;
639 640 641 642 643 644
    char * sf, * token;
    char *saveptr = NULL;

    value[0] = 0;

    fd = open(conf_file, O_RDONLY);
D
Daniel Veillard 已提交
645
    if (fd == -1)
646 647
        return -1;

E
Eric Blake 已提交
648
    while (1) {
649
        ret = openvz_readline(fd, line, sizeof(line));
E
Eric Blake 已提交
650
        if (ret <= 0)
651 652
            break;
        saveptr = NULL;
D
Daniel Veillard 已提交
653
        if (STREQLEN(line, param, strlen(param))) {
654 655
            sf = line;
            sf += strlen(param);
656
            if (sf[0] == '=' && sf[1] != '\0' ) {
E
Eric Blake 已提交
657
                sf++;
658
                if ((token = strtok_r(sf,"\"\t\n", &saveptr)) != NULL) {
C
Chris Lalancette 已提交
659 660 661 662
                    if (virStrcpy(value, token, maxlen) == NULL) {
                        ret = -1;
                        break;
                    }
663 664
                    found = 1;
                }
665
            }
D
Daniel Veillard 已提交
666
       }
667
    }
668
    VIR_FORCE_CLOSE(fd);
669 670 671 672

    if (ret == 0 && found)
        ret = 1;

E
Eric Blake 已提交
673
    return ret;
674 675
}

676 677 678 679 680 681 682 683 684 685
/*
* Read parameter from container config
* sample: 133, "OSTEMPLATE", value, 1024
* return: -1 - error
*	   0 - don't found
*          1 - OK
*/
int
openvzReadVPSConfigParam(int vpsid ,const char * param, char *value, int maxlen)
{
686 687
    char *conf_file;
    int ret;
688

689
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
690 691
        return -1;

692 693 694
    ret = openvzReadConfigParam(conf_file, param, value, maxlen);
    VIR_FREE(conf_file);
    return ret;
695 696 697 698 699 700 701 702 703 704 705 706 707 708
}

static int
openvz_copyfile(char* from_path, char* to_path)
{
    char line[PATH_MAX];
    int fd, copy_fd;
    int bytes_read;

    fd = open(from_path, O_RDONLY);
    if (fd == -1)
        return -1;
    copy_fd = open(to_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (copy_fd == -1) {
709
        VIR_FORCE_CLOSE(fd);
710 711 712
        return -1;
    }

E
Eric Blake 已提交
713
    while (1) {
714 715 716 717 718 719 720 721
        if (openvz_readline(fd, line, sizeof(line)) <= 0)
            break;

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

722
    if (VIR_CLOSE(fd) < 0)
723
        goto error;
724
    if (VIR_CLOSE(copy_fd) < 0)
725 726 727 728 729
        goto error;

    return 0;

error:
730 731
    VIR_FORCE_CLOSE(fd);
    VIR_FORCE_CLOSE(copy_fd);
732 733 734 735 736 737 738 739 740 741 742 743 744 745
    return -1;
}

/*
* Copy the default config to the VE conf file
* return: -1 - error
*          0 - OK
*/
int
openvzCopyDefaultConfig(int vpsid)
{
    char * confdir = NULL;
    char * default_conf_file = NULL;
    char configfile_value[PATH_MAX];
746
    char *conf_file = NULL;
747 748
    int ret = -1;

E
Eric Blake 已提交
749 750
    if (openvzReadConfigParam(VZ_CONF_FILE, "CONFIGFILE", configfile_value,
                              PATH_MAX) < 0)
751 752 753 754 755 756
        goto cleanup;

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

757 758
    if (virAsprintf(&default_conf_file, "%s/ve-%s.conf-sample", confdir,
                    configfile_value) < 0) {
759
        virReportOOMError();
760
        goto cleanup;
761
    }
762

763
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
764 765 766 767 768 769 770 771 772
        goto cleanup;

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

    ret = 0;
cleanup:
    VIR_FREE(confdir);
    VIR_FREE(default_conf_file);
773
    VIR_FREE(conf_file);
774 775 776
    return ret;
}

777 778 779 780 781
/* Locate config file of container
* return -1 - error
*         0 - OK
*/
static int
782
openvzLocateConfFile(int vpsid, char **conffile, const char *ext)
783 784 785 786 787 788 789 790
{
    char * confdir;
    int ret = 0;

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

791 792 793
    if (virAsprintf(conffile, "%s/%d.%s", confdir, vpsid,
                    ext ? ext : "conf") < 0) {
        virReportOOMError();
794
        ret = -1;
795
    }
796 797 798 799 800

    VIR_FREE(confdir);
    return ret;
}

801
static char
802
*openvzLocateConfDir(void)
803 804 805 806
{
    const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL};
    int i=0;

E
Eric Blake 已提交
807 808
    while (conf_dir_list[i]) {
        if (!access(conf_dir_list[i], F_OK))
809
            return strdup(conf_dir_list[i]);
E
Eric Blake 已提交
810
        i++;
811 812 813 814 815 816
    }

    return NULL;
}

/* Richard Steven's classic readline() function */
817
int
818
openvz_readline(int fd, char *ptr, int maxlen)
819 820 821 822
{
    int n, rc;
    char c;

E
Eric Blake 已提交
823 824
    for (n = 1; n < maxlen; n++) {
        if ( (rc = read(fd, &c, 1)) == 1) {
825
            *ptr++ = c;
E
Eric Blake 已提交
826
            if (c == '\n')
827
                break;
E
Eric Blake 已提交
828 829
        } else if (rc == 0) {
            if (n == 1)
830 831 832 833 834 835 836 837 838 839 840
                return 0; /* EOF condition */
            else
                break;
        }
        else
            return -1; /* error */
    }
    *ptr = 0;
    return n;
}

841
static int
842
openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
843
{
844
    char *conf_file;
845
    char line[1024];
846
    char *saveptr = NULL;
847 848
    char *uuidbuf;
    char *iden;
849
    int fd, ret;
850
    int retval = -1;
851

852
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
853
        return -1;
854

855
    fd = open(conf_file, O_RDONLY);
E
Eric Blake 已提交
856
    if (fd == -1)
857
        goto cleanup;
858

E
Eric Blake 已提交
859
    while (1) {
860
        ret = openvz_readline(fd, line, sizeof(line));
861 862
        if (ret == -1)
            goto cleanup;
863

E
Eric Blake 已提交
864
        if (ret == 0) { /* EoF, UUID was not found */
865
            uuidstr[0] = 0;
866 867 868
            break;
        }

869 870 871 872
        iden = strtok_r(line, " ", &saveptr);
        uuidbuf = strtok_r(NULL, "\n", &saveptr);

        if (iden != NULL && uuidbuf != NULL && STREQ(iden, "#UUID:")) {
873 874 875 876 877
            if (virStrcpy(uuidstr, uuidbuf, len) == NULL) {
                openvzError(VIR_ERR_INTERNAL_ERROR,
                            _("invalid uuid %s"), uuidbuf);
                goto cleanup;
            }
878 879 880
            break;
        }
    }
881 882
    retval = 0;
cleanup:
883
    VIR_FORCE_CLOSE(fd);
884
    VIR_FREE(conf_file);
885

C
Chris Lalancette 已提交
886
    return retval;
887 888 889 890 891
}

/* Do actual checking for UUID presence in conf file,
 * assign if not present.
 */
892 893
int
openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
894
{
895
    char *conf_file;
896
    char uuidstr[VIR_UUID_STRING_BUFLEN];
897
    FILE *fp = NULL;
898
    int ret = -1;
899 900 901

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

903
    if (openvzLocateConfFile(vpsid, &conf_file, "conf") < 0)
E
Eric Blake 已提交
904
        return -1;
905

906
    if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
907
        goto cleanup;
908

J
Jim Meyering 已提交
909
    if (uuidstr[0] == 0) {
910
        fp = fopen(conf_file, "a"); /* append */
911
        if (fp == NULL)
912
            goto cleanup;
913

914 915
        virUUIDFormat(uuid, uuidstr);

916
        /* Record failure if fprintf or VIR_FCLOSE fails,
917
           and be careful always to close the stream.  */
918 919
        if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0) ||
            (VIR_FCLOSE(fp) == EOF))
920
            goto cleanup;
921 922
    }

923 924
    ret = 0;
cleanup:
925
    VIR_FORCE_FCLOSE(fp);
926 927
    VIR_FREE(conf_file);
    return ret;
928 929
}

930 931 932 933
static int
openvzSetUUID(int vpsid){
    unsigned char uuid[VIR_UUID_BUFLEN];

934
    if (virUUIDGenerate(uuid)) {
935 936
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Failed to generate UUID"));
937 938
        return -1;
    }
939 940 941 942

    return openvzSetDefinedUUID(vpsid, uuid);
}

943 944 945 946 947 948 949
/*
 * 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.
 *
 */

950
static int openvzAssignUUIDs(void)
951 952 953 954
{
    DIR *dp;
    struct dirent *dent;
    char *conf_dir;
955 956 957
    int vpsid;
    char *ext;
    int ret = 0;
958 959

    conf_dir = openvzLocateConfDir();
960 961
    if (conf_dir == NULL)
        return -1;
962 963

    dp = opendir(conf_dir);
E
Eric Blake 已提交
964
    if (dp == NULL) {
965
        VIR_FREE(conf_dir);
966 967 968
        return 0;
    }

969
    errno = 0;
E
Eric Blake 已提交
970
    while ((dent = readdir(dp))) {
971 972 973
        if (virStrToLong_i(dent->d_name, &ext, 10, &vpsid) < 0 ||
            *ext++ != '.' ||
            STRNEQ(ext, "conf"))
974
            continue;
E
Eric Blake 已提交
975
        if (vpsid > 0) /* '0.conf' belongs to the host, ignore it */
976
            openvzSetUUID(vpsid);
977 978 979 980 981 982
        errno = 0;
    }
    if (errno) {
        openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Failed to scan configuration directory"));
        ret = -1;
983
    }
984

985
    closedir(dp);
986
    VIR_FREE(conf_dir);
987
    return ret;
988
}
989 990 991 992 993 994 995 996


/*
 * Return CTID from name
 *
 */

int openvzGetVEID(const char *name) {
E
Eric Blake 已提交
997 998
    virCommandPtr cmd;
    char *outbuf;
999
    char *temp;
1000
    int veid;
1001
    bool ok;
1002

E
Eric Blake 已提交
1003 1004 1005 1006 1007
    cmd = virCommandNewArgList(VZLIST, name, "-ovpsid", "-H", NULL);
    virCommandSetOutputBuffer(cmd, &outbuf);
    if (virCommandRun(cmd, NULL) < 0) {
        virCommandFree(cmd);
        VIR_FREE(outbuf);
1008 1009 1010
        return -1;
    }

E
Eric Blake 已提交
1011
    virCommandFree(cmd);
1012
    ok = virStrToLong_i(outbuf, &temp, 10, &veid) == 0 && *temp == '\n';
E
Eric Blake 已提交
1013
    VIR_FREE(outbuf);
1014

1015 1016 1017
    if (ok && veid >= 0)
        return veid;

1018 1019
    openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                _("Failed to parse vzlist output"));
1020 1021
    return -1;
}