openvz_conf.c 22.8 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 81 82 83 84 85 86 87 88 89 90 91

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;
    unsigned int major, minor, micro;
    unsigned int version;

    if (retversion)
        *retversion = 0;

    if (virExec(NULL, vzarg, vzenv, NULL,
                &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0)
        return -1;

    char *help = NULL;
92
    int len = virFileReadLimFD(newstdout, 4096, &help);
93 94 95 96 97 98 99 100 101 102 103 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
    if (len < 0)
        goto cleanup2;

    if (sscanf(help, "vzctl version %u.%u.%u",
               &major, &minor, &micro) != 3) {
        goto cleanup2;
    }

    version = (major * 1000 * 1000) + (minor * 1000) + micro;

    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,
131
                    "%s", _("Could not extract vzctl version"));
132 133 134 135 136 137 138
        return -1;
    }

    return 0;
}


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

    uname(&utsname);

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

151
    if (nodeCapsInitNUMA(caps) < 0)
152 153
        goto no_memory;

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

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


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

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

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

            net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;

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

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

260 261 262 263 264 265 266 267 268 269 270 271 272 273
                    if (VIR_ALLOC_N(net->ifname, len+1) < 0)
                        goto no_memory;

                    strncpy(net->ifname, p, len);
                    net->ifname[len] = '\0';
                } 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;
                    }

274 275 276 277 278 279 280 281 282 283
                    if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
                        goto no_memory;

                    strncpy(net->data.bridge.brname, p, len);
                    net->data.bridge.brname[len] = '\0';
                } 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 已提交
284
                              "%s", _("Wrong length MAC address"));
285 286 287 288
                        goto error;
                    }
                    strncpy(cpy_temp, p, len);
                    cpy_temp[len] = '\0';
289
                    if (virParseMacAddr(cpy_temp, net->mac) < 0) {
290
                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
291
                              "%s", _("Wrong MAC address"));
292 293 294 295 296 297
                        goto error;
                    }
                }
                p = ++next;
            } while (p < token + strlen(token));

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

303 304 305 306
            token = strtok_r(NULL, ";", &saveptr);
        }
    }

307
    return 0;
308
no_memory:
309
    virReportOOMError(conn);
310 311
error:
    virDomainNetDefFree(net);
312
    return -1;
313 314 315
}


316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
/* 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;
    int to_len = strlen(to);
    int from_len = strlen(from);
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    if(!from)
        return NULL;

    while((offset = strstr(str_start, from)))
    {
        virBufferAdd(&buf, str_start, offset-str_start);
        virBufferAdd(&buf, to, to_len);
        str_start = offset + from_len;
    }

     virBufferAdd(&buf, str_start, strlen(str_start));

    if(virBufferError(&buf))
      return NULL;

    return virBufferContentAndReset(&buf);
}


346 347 348 349 350 351
static int
openvzReadFSConf(virConnectPtr conn,
                 virDomainDefPtr def,
                 int veid) {
    int ret;
    virDomainFSDefPtr fs = NULL;
352 353
    char* veid_str = NULL;
    char temp[100];
354

355
    ret = openvzReadVPSConfigParam(veid, "OSTEMPLATE", temp, sizeof(temp));
356 357
    if (ret < 0) {
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
358
                    _("Could not read 'OSTEMPLATE' from config for container %d"),
359 360 361 362 363 364 365 366
                    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);
367 368 369 370 371
    } 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,
372
                        _("Could not read 'VE_PRIVATE' from config for container %d"),
373 374 375
                        veid);
            goto error;
        }
376

377
        if (VIR_ALLOC(fs) < 0)
378 379
            goto no_memory;

380 381 382 383 384
        if(virAsprintf(&veid_str, "%d", veid) < 0)
          goto error;

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

386
        VIR_FREE(veid_str);
387 388
    }

389 390 391 392 393 394 395 396 397 398
    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;

399 400
    return 0;
no_memory:
401
    virReportOOMError(conn);
402 403 404 405 406 407
error:
    virDomainFSDefFree(fs);
    return -1;
}


408 409 410 411 412 413
/* Free all memory associated with a openvz_driver structure */
void
openvzFreeDriver(struct openvz_driver *driver)
{
    if (!driver)
        return;
414

415
    virDomainObjListFree(&driver->domains);
416
    virCapabilitiesFree(driver->caps);
417
}
D
Daniel Veillard 已提交
418 419 420



421
int openvzLoadDomains(struct openvz_driver *driver) {
422 423 424
    FILE *fp;
    int veid, ret;
    char status[16];
425
    char uuidstr[VIR_UUID_STRING_BUFLEN];
426
    virDomainObjPtr dom = NULL;
427
    char temp[50];
428

429 430
    if (openvzAssignUUIDs() < 0)
        return -1;
431

432
    if ((fp = popen(VZLIST " -a -ovpsid,status -H 2>/dev/null", "r")) == NULL) {
J
Jim Meyering 已提交
433
        openvzError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("popen failed"));
434 435 436 437
        return -1;
    }

    while(!feof(fp)) {
438
        if (fscanf(fp, "%d %s\n", &veid, status) != 2) {
439 440
            if (feof(fp))
                break;
441

442
            openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
443
                        "%s", _("Failed to parse vzlist output"));
444
            goto cleanup;
445
        }
446

447
        if (VIR_ALLOC(dom) < 0)
448
            goto no_memory;
449

450 451 452 453 454 455 456 457 458
        if (virMutexInit(&dom->lock) < 0) {
            openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot initialize mutex"));
            VIR_FREE(dom);
            goto cleanup;
        }

        if (VIR_ALLOC(dom->def) < 0)
            goto no_memory;
459

460 461 462 463
        if (STREQ(status, "stopped"))
            dom->state = VIR_DOMAIN_SHUTOFF;
        else
            dom->state = VIR_DOMAIN_RUNNING;
464

465 466
        dom->pid = veid;
        dom->def->id = dom->state == VIR_DOMAIN_SHUTOFF ? -1 : veid;
467

468
        if (virAsprintf(&dom->def->name, "%i", veid) < 0)
469
            goto no_memory;
470

471
        openvzGetVPSUUID(veid, uuidstr, sizeof(uuidstr));
472
        ret = virUUIDParse(uuidstr, dom->def->uuid);
473

474 475
        if (ret == -1) {
            openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
476
                        "%s", _("UUID in config file malformed"));
477
            goto cleanup;
478
        }
479

480 481 482 483
        if (!(dom->def->os.type = strdup("exe")))
            goto no_memory;
        if (!(dom->def->os.init = strdup("/sbin/init")))
            goto no_memory;
484

485
        ret = openvzReadVPSConfigParam(veid, "CPUS", temp, sizeof(temp));
486
        if (ret < 0) {
487
            openvzError(NULL, VIR_ERR_INTERNAL_ERROR,
488
                        _("Could not read config for container %d"),
489 490
                        veid);
            goto cleanup;
491
        } else if (ret > 0) {
492
            dom->def->vcpus = strtoI(temp);
493 494
        }

495 496 497
        if (ret == 0 || dom->def->vcpus == 0)
            dom->def->vcpus = openvzGetNodeCPUs();

498
        /* XXX load rest of VM config data .... */
499

500
        openvzReadNetworkConf(NULL, dom->def, veid);
501
        openvzReadFSConf(NULL, dom->def, veid);
502

503 504 505 506 507 508
        if (VIR_REALLOC_N(driver->domains.objs,
                          driver->domains.count + 1) < 0)
            goto no_memory;

        driver->domains.objs[driver->domains.count++] = dom;
        dom = NULL;
509
    }
510

511
    fclose(fp);
512

513
    return 0;
514

515
 no_memory:
516
    virReportOOMError(NULL);
517

518 519 520 521
 cleanup:
    fclose(fp);
    virDomainObjFree(dom);
    return -1;
522 523
}

524 525 526 527 528
unsigned int
openvzGetNodeCPUs(void)
{
    virNodeInfo nodeinfo;

529
    if (nodeGetInfo(NULL, &nodeinfo) < 0)
530 531 532 533
        return 0;

    return nodeinfo.cpus;
}
534

535 536
static int
openvzWriteConfigParam(const char * conf_file, const char *param, const char *value)
537
{
538 539
    char * temp_file = NULL;
    int fd = -1, temp_fd = -1;
540 541
    char line[PATH_MAX] ;

542
    if (virAsprintf(&temp_file, "%s.tmp", conf_file)<0)
543 544 545 546
        return -1;

    fd = open(conf_file, O_RDONLY);
    if (fd == -1)
547
        goto error;
548 549 550
    temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (temp_fd == -1) {
        close(fd);
551
        goto error;
552 553 554 555 556 557
    }

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

558
        if (!(STRPREFIX(line, param) && line[strlen(param)] == '=')) {
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
            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);
588 589 590
    if(temp_file)
        unlink(temp_file);
    VIR_FREE(temp_file);
591 592 593
    return -1;
}

594
int
595 596 597 598 599 600 601 602 603 604 605 606
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)
607 608 609 610 611 612 613 614 615 616
{
    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 已提交
617
    if (fd == -1)
618 619 620 621 622 623 624
        return -1;

    while(1) {
        ret = openvz_readline(fd, line, sizeof(line));
        if(ret <= 0)
            break;
        saveptr = NULL;
D
Daniel Veillard 已提交
625
        if (STREQLEN(line, param, strlen(param))) {
626 627
            sf = line;
            sf += strlen(param);
628 629 630 631 632 633 634
            if (sf[0] == '=' && sf[1] != '\0' ) {
                sf ++;
                if ((token = strtok_r(sf,"\"\t\n", &saveptr)) != NULL) {
                    strncpy(value, token, maxlen) ;
                    value[maxlen-1] = '\0';
                    found = 1;
                }
635
            }
D
Daniel Veillard 已提交
636
       }
637 638 639 640 641 642 643 644 645
    }
    close(fd);

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

    return ret ;
}

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 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
/*
* 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;

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

    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;
}

742 743 744 745 746
/* Locate config file of container
* return -1 - error
*         0 - OK
*/
static int
747
openvzLocateConfFile(int vpsid, char *conffile, int maxlen, const char *ext)
748 749 750 751 752 753 754 755
{
    char * confdir;
    int ret = 0;

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

756 757
    if (snprintf(conffile, maxlen, "%s/%d.%s",
                 confdir, vpsid, ext ? ext : "conf") >= maxlen)
758 759 760 761 762 763
        ret = -1;

    VIR_FREE(confdir);
    return ret;
}

764
static char
765
*openvzLocateConfDir(void)
766 767 768 769 770 771
{
    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))
772
            return strdup(conf_dir_list[i]);
773 774 775 776 777 778 779
        i ++;
    }

    return NULL;
}

/* Richard Steven's classic readline() function */
780
int
781
openvz_readline(int fd, char *ptr, int maxlen)
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
{
    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;
}

805
static int
806
openvzGetVPSUUID(int vpsid, char *uuidstr, size_t len)
807 808 809
{
    char conf_file[PATH_MAX];
    char line[1024];
810
    char uuidbuf[1024];
811 812 813
    char iden[1024];
    int fd, ret;

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

817
    fd = open(conf_file, O_RDONLY);
818 819 820 821 822
    if(fd == -1)
        return -1;

    while(1) {
        ret = openvz_readline(fd, line, sizeof(line));
823 824
        if(ret == -1) {
            close(fd);
825
            return -1;
826
        }
827 828

        if(ret == 0) { /* EoF, UUID was not found */
829
            uuidstr[0] = 0;
830 831 832
            break;
        }

833
        sscanf(line, "%s %s\n", iden, uuidbuf);
834
        if(STREQ(iden, "#UUID:")) {
835
            strncpy(uuidstr, uuidbuf, len);
836 837 838
            break;
        }
    }
839 840
    close(fd);

841 842 843 844 845 846
    return 0;
}

/* Do actual checking for UUID presence in conf file,
 * assign if not present.
 */
847 848
int
openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
849 850
{
    char conf_file[PATH_MAX];
851
    char uuidstr[VIR_UUID_STRING_BUFLEN];
852 853 854

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

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

859
    if (openvzGetVPSUUID(vpsid, uuidstr, sizeof(uuidstr)))
860 861
        return -1;

J
Jim Meyering 已提交
862
    if (uuidstr[0] == 0) {
863 864 865
        FILE *fp = fopen(conf_file, "a"); /* append */
        if (fp == NULL)
          return -1;
866

867 868
        virUUIDFormat(uuid, uuidstr);

869 870 871 872 873
        /* 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;
874 875 876 877 878
    }

    return 0;
}

879 880 881 882 883 884 885 886 887
static int
openvzSetUUID(int vpsid){
    unsigned char uuid[VIR_UUID_BUFLEN];

    virUUIDGenerate(uuid);

    return openvzSetDefinedUUID(vpsid, uuid);
}

888 889 890 891 892 893 894
/*
 * 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.
 *
 */

895
static int openvzAssignUUIDs(void)
896 897 898 899 900 901 902 903
{
    DIR *dp;
    struct dirent *dent;
    char *conf_dir;
    int vpsid, res;
    char ext[8];

    conf_dir = openvzLocateConfDir();
904 905
    if (conf_dir == NULL)
        return -1;
906 907 908

    dp = opendir(conf_dir);
    if(dp == NULL) {
909
        VIR_FREE(conf_dir);
910 911 912 913 914
        return 0;
    }

    while((dent = readdir(dp))) {
        res = sscanf(dent->d_name, "%d.%5s", &vpsid, ext);
915
        if(!(res == 2 && STREQ(ext, "conf")))
916 917 918 919 920
            continue;
        if(vpsid > 0) /* '0.conf' belongs to the host, ignore it */
            openvzSetUUID(vpsid);
    }
    closedir(dp);
921
    VIR_FREE(conf_dir);
922 923
    return 0;
}