openvz_conf.c 24.6 KB
Newer Older
1 2 3 4 5
/*
 * openvz_conf.c: config functions for managing OpenVZ VEs
 *
 * Copyright (C) 2006, 2007 Binary Karma
 * Copyright (C) 2006 Shuveb Hussain
6
 * Copyright (C) 2007 Anoop Joe Cyriac
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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
 *
22
 * Authors:
23 24 25
 * Shuveb Hussain <shuveb@binarykarma.com>
 * Anoop Joe Cyriac <anoop@binarykarma.com>
 *
26 27
 */

28
#include <config.h>
J
Jim Meyering 已提交
29

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 <strings.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

54 55
#define VIR_FROM_THIS VIR_FROM_OPENVZ

56
static char *openvzLocateConfDir(void);
57
static int openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len);
58
static int openvzLocateConfFile(int vpsid, char *conffile, int maxlen, const char *ext);
59
static int openvzAssignUUIDs(void);
60

61
int
62
strtoI(const char *str)
63 64 65
{
    int val;

66 67
    if (virStrToLong_i(str, NULL, 10, &val) < 0)
        return 0 ;
68

69 70 71
    return val;
}

72 73 74 75 76 77 78 79 80

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;
81 82
    unsigned long version;
    char *tmp;
83 84 85 86

    if (retversion)
        *retversion = 0;

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

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

96 97 98 99
    tmp = help;

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

102 103
    if (virParseVersionString(tmp, &version) < 0)
        goto cleanup2;
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

    if (retversion)
        *retversion = version;

    ret = 0;

cleanup2:
    VIR_FREE(help);
    if (close(newstdout) < 0)
        ret = -1;

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

    return ret;
}

int openvzExtractVersion(virConnectPtr conn,
                         struct openvz_driver *driver)
{
    if (driver->version > 0)
        return 0;

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

    return 0;
}


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

    uname(&utsname);

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

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

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

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


183 184 185 186
static int
openvzReadNetworkConf(virConnectPtr conn,
                      virDomainDefPtr def,
                      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 199
    if (ret < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
200
                 _("Could not read 'IP_ADDRESS' from config for container %d"),
201 202 203 204 205
                  veid);
        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 231
    if (ret < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
232
                     _("Could not read 'NETIF' from config for container %d"),
233 234 235 236 237 238
                     veid);
        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 257
                    len = next - p;
                    if (len > 16) {
                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
258
                                "%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 266 267 268 269
                    if (virStrncpy(net->ifname, p, len, len+1) == NULL) {
                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                                    _("Network ifname %s too long for destination"), p);
                        goto error;
                    }
270 271 272 273 274 275 276 277 278
                } else if (STRPREFIX(p, "bridge=")) {
                    p += 7;
                    len = next - p;
                    if (len > 16) {
                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Too long bridge device name"));
                        goto error;
                    }

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

C
Chris Lalancette 已提交
282 283 284 285 286
                    if (virStrncpy(net->data.bridge.brname, p, len, len+1) == NULL) {
                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                                    _("Bridge name %s too long for destination"), p);
                        goto error;
                    }
287 288 289 290 291
                } else if (STRPREFIX(p, "mac=")) {
                    p += 4;
                    len = next - p;
                    if (len != 17) { //should be 17
                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
292
                              "%s", _("Wrong length MAC address"));
293 294
                        goto error;
                    }
C
Chris Lalancette 已提交
295 296 297 298 299
                    if (virStrncpy(cpy_temp, p, len, sizeof(cpy_temp)) == NULL) {
                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                                    _("MAC address %s too long for destination"), p);
                        goto error;
                    }
300
                    if (virParseMacAddr(cpy_temp, net->mac) < 0) {
301
                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
302
                              "%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 343 344 345 346 347 348 349

    while((offset = strstr(str_start, from)))
    {
        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 362 363 364 365 366
static int
openvzReadFSConf(virConnectPtr conn,
                 virDomainDefPtr def,
                 int veid) {
    int ret;
    virDomainFSDefPtr fs = NULL;
367 368
    char* veid_str = NULL;
    char temp[100];
369

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

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

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

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

401
        VIR_FREE(veid_str);
402 403
    }

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

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


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

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



437
int openvzLoadDomains(struct openvz_driver *driver) {
438 439 440
    FILE *fp;
    int veid, ret;
    char status[16];
441
    char uuidstr[VIR_UUID_STRING_BUFLEN];
442
    virDomainObjPtr dom = NULL;
443
    char temp[50];
444

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

448
    if ((fp = popen(VZLIST " -a -ovpsid,status -H 2>/dev/null", "r")) == NULL) {
J
Jim Meyering 已提交
449
        openvzError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("popen failed"));
450 451 452 453
        return -1;
    }

    while(!feof(fp)) {
454
        if (fscanf(fp, "%d %s\n", &veid, status) != 2) {
455 456
            if (feof(fp))
                break;
457

458
            openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
459
                        "%s", _("Failed to parse vzlist output"));
460
            goto cleanup;
461
        }
462

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

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

473 474
        virDomainObjLock(dom);

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

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

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

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

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

495 496
        if (ret == -1) {
            openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
497
                        "%s", _("UUID in config file malformed"));
498
            goto cleanup;
499
        }
500

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

506
        ret = openvzReadVPSConfigParam(veid, "CPUS", temp, sizeof(temp));
507
        if (ret < 0) {
508
            openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
509
                        _("Could not read config for container %d"),
510 511
                        veid);
            goto cleanup;
512
        } else if (ret > 0) {
513
            dom->def->vcpus = strtoI(temp);
514 515
        }

516 517 518
        if (ret == 0 || dom->def->vcpus == 0)
            dom->def->vcpus = openvzGetNodeCPUs();

519
        /* XXX load rest of VM config data .... */
520

521
        openvzReadNetworkConf(NULL, dom->def, veid);
522
        openvzReadFSConf(NULL, dom->def, veid);
523

524 525
        virUUIDFormat(dom->def->uuid, uuidstr);
        if (virHashAddEntry(driver->domains.objs, uuidstr, dom) < 0)
526 527
            goto no_memory;

528
        virDomainObjUnlock(dom);
529
        dom = NULL;
530
    }
531

532
    fclose(fp);
533

534
    return 0;
535

536
 no_memory:
537
    virReportOOMError();
538

539 540
 cleanup:
    fclose(fp);
541 542
    if (dom)
        virDomainObjUnref(dom);
543
    return -1;
544 545
}

546 547 548 549 550
unsigned int
openvzGetNodeCPUs(void)
{
    virNodeInfo nodeinfo;

551
    if (nodeGetInfo(NULL, &nodeinfo) < 0)
552 553 554 555
        return 0;

    return nodeinfo.cpus;
}
556

557 558
static int
openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
559
{
560 561
    char * temp_file = NULL;
    int fd = -1, temp_fd = -1;
562 563
    char line[PATH_MAX] ;

564
    if (virAsprintf(&temp_file, "%s.tmp", conf_file)<0) {
565
        virReportOOMError();
566
        return -1;
567
    }
568 569 570

    fd = open(conf_file, O_RDONLY);
    if (fd == -1)
571
        goto error;
572 573 574
    temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (temp_fd == -1) {
        close(fd);
575
        goto error;
576 577 578 579 580 581
    }

    while(1) {
        if (openvz_readline(fd, line, sizeof(line)) <= 0)
            break;

582
        if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
            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;

    if (close(fd) < 0)
        goto error;
    fd = -1;
    if (close(temp_fd) < 0)
        goto error;
    temp_fd = -1;

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

    return 0;

error:
    if (fd != -1)
        close(fd);
    if (temp_fd != -1)
        close(temp_fd);
612 613 614
    if(temp_file)
        unlink(temp_file);
    VIR_FREE(temp_file);
615 616 617
    return -1;
}

618
int
619 620 621 622 623 624 625 626 627 628 629 630
openvzWriteVPSConfigParam(int vpsid, const char *param, const char *value)
{
    char conf_file[PATH_MAX];

    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
        return -1;

    return openvzWriteConfigParam(conf_file, param, value);
}

static int
openvzReadConfigParam(const char * conf_file ,const char * param, char *value, int maxlen)
631 632 633 634 635 636 637 638 639 640
{
    char line[PATH_MAX] ;
    int ret, found = 0;
    int fd ;
    char * sf, * token;
    char *saveptr = NULL;

    value[0] = 0;

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

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

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

    return ret ;
}

672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
/*
* 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)
{
    char conf_file[PATH_MAX] ;

    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
        return -1;

    return openvzReadConfigParam(conf_file, param, value, maxlen);
}

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) {
        close(fd);
        return -1;
    }

    while(1) {
        if (openvz_readline(fd, line, sizeof(line)) <= 0)
            break;

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

    if (close(fd) < 0)
        goto error;
    fd = -1;
    if (close(copy_fd) < 0)
        goto error;

    return 0;

error:
    if (fd != -1)
        close(fd);
    if (copy_fd != -1)
        close(copy_fd);
    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];
    char conf_file[PATH_MAX];
    int ret = -1;

    if(openvzReadConfigParam(VZ_CONF_FILE, "CONFIGFILE", configfile_value, PATH_MAX) < 0)
        goto cleanup;

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

752
    if (virAsprintf(&default_conf_file, "%s/ve-%s.conf-sample", confdir, configfile_value) < 0) {
753
        virReportOOMError();
754
        goto cleanup;
755
    }
756 757 758 759 760 761 762 763 764 765 766 767 768 769

    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
        goto cleanup;

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

    ret = 0;
cleanup:
    VIR_FREE(confdir);
    VIR_FREE(default_conf_file);
    return ret;
}

770 771 772 773 774
/* Locate config file of container
* return -1 - error
*         0 - OK
*/
static int
775
openvzLocateConfFile(int vpsid, char *conffile, int maxlen, const char *ext)
776 777 778 779 780 781 782 783
{
    char * confdir;
    int ret = 0;

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

784 785
    if (snprintf(conffile, maxlen, "%s/%d.%s",
                 confdir, vpsid, ext ? ext : "conf") >= maxlen)
786 787 788 789 790 791
        ret = -1;

    VIR_FREE(confdir);
    return ret;
}

792
static char
793
*openvzLocateConfDir(void)
794 795 796 797 798 799
{
    const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL};
    int i=0;

    while(conf_dir_list[i]) {
        if(!access(conf_dir_list[i], F_OK))
800
            return strdup(conf_dir_list[i]);
801 802 803 804 805 806 807
        i ++;
    }

    return NULL;
}

/* Richard Steven's classic readline() function */
808
int
809
openvz_readline(int fd, char *ptr, int maxlen)
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
{
    int n, rc;
    char c;

    for(n = 1; n < maxlen; n ++) {
        if( (rc = read(fd, &c, 1)) == 1) {
            *ptr++ = c;
            if(c == '\n')
                break;
        }
        else if(rc == 0) {
            if(n == 1)
                return 0; /* EOF condition */
            else
                break;
        }
        else
            return -1; /* error */
    }
    *ptr = 0;
    return n;
}

833
static int
834
openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
835 836 837
{
    char conf_file[PATH_MAX];
    char line[1024];
838
    char uuidbuf[1024];
839 840
    char iden[1024];
    int fd, ret;
C
Chris Lalancette 已提交
841
    int retval = 0;
842

843
    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
844
       return -1;
845

846
    fd = open(conf_file, O_RDONLY);
847 848 849 850 851
    if(fd == -1)
        return -1;

    while(1) {
        ret = openvz_readline(fd, line, sizeof(line));
852 853
        if(ret == -1) {
            close(fd);
854
            return -1;
855
        }
856 857

        if(ret == 0) { /* EoF, UUID was not found */
858
            uuidstr[0] = 0;
859 860 861
            break;
        }

862
        sscanf(line, "%s %s\n", iden, uuidbuf);
863
        if(STREQ(iden, "#UUID:")) {
C
Chris Lalancette 已提交
864 865
            if (virStrcpy(uuidstr, uuidbuf, len) == NULL)
                retval = -1;
866 867 868
            break;
        }
    }
869 870
    close(fd);

C
Chris Lalancette 已提交
871
    return retval;
872 873 874 875 876
}

/* Do actual checking for UUID presence in conf file,
 * assign if not present.
 */
877 878
int
openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
879 880
{
    char conf_file[PATH_MAX];
881
    char uuidstr[VIR_UUID_STRING_BUFLEN];
882 883 884

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

886
    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
887
       return -1;
888

889
    if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
890 891
        return -1;

J
Jim Meyering 已提交
892
    if (uuidstr[0] == 0) {
893 894 895
        FILE *fp = fopen(conf_file, "a"); /* append */
        if (fp == NULL)
          return -1;
896

897 898
        virUUIDFormat(uuid, uuidstr);

899 900 901 902 903
        /* Record failure if fprintf or fclose fails,
           and be careful always to close the stream.  */
        if ((fprintf(fp, "\n#UUID: %s\n", uuidstr) < 0)
            + (fclose(fp) == EOF))
            return -1;
904 905 906 907 908
    }

    return 0;
}

909 910 911 912
static int
openvzSetUUID(int vpsid){
    unsigned char uuid[VIR_UUID_BUFLEN];

913 914 915 916 917
    if (virUUIDGenerate(uuid)) {
        openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
                    "%s", _("Failed to generate UUID"));
        return -1;
    }
918 919 920 921

    return openvzSetDefinedUUID(vpsid, uuid);
}

922 923 924 925 926 927 928
/*
 * 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.
 *
 */

929
static int openvzAssignUUIDs(void)
930 931 932 933 934 935 936 937
{
    DIR *dp;
    struct dirent *dent;
    char *conf_dir;
    int vpsid, res;
    char ext[8];

    conf_dir = openvzLocateConfDir();
938 939
    if (conf_dir == NULL)
        return -1;
940 941 942

    dp = opendir(conf_dir);
    if(dp == NULL) {
943
        VIR_FREE(conf_dir);
944 945 946 947 948
        return 0;
    }

    while((dent = readdir(dp))) {
        res = sscanf(dent->d_name, "%d.%5s", &vpsid, ext);
949
        if(!(res == 2 && STREQ(ext, "conf")))
950 951 952 953 954
            continue;
        if(vpsid > 0) /* '0.conf' belongs to the host, ignore it */
            openvzSetUUID(vpsid);
    }
    closedir(dp);
955
    VIR_FREE(conf_dir);
956 957
    return 0;
}
958 959 960 961 962 963 964 965 966 967 968


/*
 * Return CTID from name
 *
 */

int openvzGetVEID(const char *name) {
    char *cmd;
    int veid;
    FILE *fp;
969
    bool ok;
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984

    if (virAsprintf(&cmd, "%s %s -ovpsid -H", VZLIST, name) < 0) {
        openvzError(NULL, VIR_ERR_INTERNAL_ERROR, "%s",
                    _("virAsprintf failed"));
        return -1;
    }

    fp = popen(cmd, "r");
    VIR_FREE(cmd);

    if (fp == NULL) {
        openvzError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("popen failed"));
        return -1;
    }

985
    ok = fscanf(fp, "%d\n", &veid ) == 1;
986
    fclose(fp);
987 988 989 990 991
    if (ok && veid >= 0)
        return veid;

    openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
                "%s", _("Failed to parse vzlist output"));
992 993
    return -1;
}