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

#ifdef WITH_OPENVZ

30
#include <config.h>
J
Jim Meyering 已提交
31

32 33 34 35 36 37 38 39
#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>
40 41 42 43
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
D
Daniel P. Berrange 已提交
44
#include <string.h>
45 46 47 48 49 50

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/uri.h>

D
Daniel P. Berrange 已提交
51
#include "internal.h"
52 53

#include "openvz_driver.h"
54
#include "openvz_conf.h"
55 56
#include "uuid.h"
#include "buf.h"
57
#include "memory.h"
58

59 60 61 62
static char *openvzLocateConfDir(void);
static struct openvz_vm_def *openvzParseXML(virConnectPtr conn, xmlDocPtr xml);
static int openvzGetVPSUUID(int vpsid, char *uuidstr);
static int openvzSetUUID(int vpsid);
63
static int openvzLocateConfFile(int vpsid, char *conffile, int maxlen);
64

65
void
D
Daniel Veillard 已提交
66
openvzError (virConnectPtr conn, virErrorNumber code, const char *fmt, ...)
67
{
68 69
    va_list args;
    char errorMessage[OPENVZ_MAX_ERROR_LEN];
70 71
    const char *errmsg;

72 73 74 75 76 77 78 79 80
    if (fmt) {
        va_start(args, fmt);
        vsnprintf(errorMessage, OPENVZ_MAX_ERROR_LEN-1, fmt, args);
        va_end(args);
    } else {
        errorMessage[0] = '\0';
    }

    errmsg = __virErrorMsg(code, (errorMessage[0] ? errorMessage : NULL));
81
    __virRaiseError (conn, NULL, NULL, VIR_FROM_OPENVZ,
82 83
                     code, VIR_ERR_ERROR, errmsg, errorMessage, NULL, 0, 0,
                     errmsg, errorMessage);
84 85
}

86
struct openvz_vm
87
*openvzFindVMByID(const struct openvz_driver *driver, int id) {
88 89 90 91 92 93 94 95 96 97 98
    struct openvz_vm *vm = driver->vms;

    while (vm) {
        if (vm->vpsid == id)
            return vm;
        vm = vm->next;
    }

    return NULL;
}

99
struct openvz_vm
100
*openvzFindVMByUUID(const struct openvz_driver *driver,
101 102 103 104
                                   const unsigned char *uuid) {
    struct openvz_vm *vm = driver->vms;

    while (vm) {
105
        if (!memcmp(vm->vmdef->uuid, uuid, VIR_UUID_BUFLEN))
106 107 108 109 110 111 112
            return vm;
        vm = vm->next;
    }

    return NULL;
}

113
struct openvz_vm
114
*openvzFindVMByName(const struct openvz_driver *driver,
115 116 117 118
                                   const char *name) {
    struct  openvz_vm *vm = driver->vms;

    while (vm) {
119
        if (STREQ(vm->vmdef->name, name))
120 121 122 123 124 125 126
            return vm;
        vm = vm->next;
    }

    return NULL;
}

127
int
128
strtoI(const char *str)
129 130 131 132 133 134
{
    int base = 10;
    char *endptr;
    int val;

    val = (int) strtol(str, &endptr, base);
135

136 137
    /* Check for various possible errors */
    if ((endptr == str)         /* "No digits were found" */
138
        ||((*endptr != '\0')
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
            && (*endptr != ' ')) /*"Name contain characters other than integers" */ )
        return 0;
    return val;
}

void
openvzRemoveInactiveVM(struct openvz_driver *driver, struct openvz_vm *vm)
{
    driver->num_inactive--;
    openvzFreeVM(driver, vm, 1);
}

/* Free all memory associated with a openvz_vm_def structure */
void
openvzFreeVMDef(struct openvz_vm_def *def)
{
    if (def) {
        struct ovz_quota *quota = def->fs.quota;
        struct ovz_ip *ip = def->net.ips;
        struct ovz_ns *ns = def->net.ns;

        while (quota) {
            struct ovz_quota *prev = quota;

            quota = quota->next;
164
            VIR_FREE(prev);
165 166 167 168 169
        }
        while (ip) {
            struct ovz_ip *prev = ip;

            ip = ip->next;
170
            VIR_FREE(prev);
171 172 173 174 175
        }
        while (ns) {
            struct ovz_ns *prev = ns;

            ns = ns->next;
176
            VIR_FREE(prev);
177 178
        }

179
        VIR_FREE(def);
180
    }
181 182
}

183
/* Free all memory associated with a openvz_vm structure
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
 * @checkCallee == 0 then openvzFreeDriver() is callee else some other function
 */
void
openvzFreeVM(struct openvz_driver *driver, struct openvz_vm *vm,
             int checkCallee)
{
    struct openvz_vm *vms;

    if (!vm && !driver)
        return;
    vms = driver->vms;
    if (checkCallee) {
        if (vms == vm)
            driver->vms = vm->next;
        else {
            while (vms) {
                struct openvz_vm *prev = vms;

                vms = vms->next;
                if (vms == vm) {
                    prev->next = vms->next;
                    break;
                }
            }
        }
209
    }
210 211
    if (vms) {
        openvzFreeVMDef(vm->vmdef);
212
        VIR_FREE(vm);
213
    }
214
}
215

216 217 218 219 220 221 222 223 224 225 226
/* Free all memory associated with a openvz_driver structure */
void
openvzFreeDriver(struct openvz_driver *driver)
{
    struct openvz_vm *next;

    if (!driver)
        return;
    if (driver->vms)
        for(next = driver->vms->next; driver->vms; driver->vms = next)
            openvzFreeVM(driver, driver->vms, 0);
227
    VIR_FREE(driver);
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
}

struct openvz_vm *
openvzAssignVMDef(virConnectPtr conn,
                  struct openvz_driver *driver, struct openvz_vm_def *def)
{
    struct openvz_vm *vm = NULL;

    if (!driver || !def)
        return NULL;

    if ((vm = openvzFindVMByName(driver, def->name))) {
        if (!openvzIsActiveVM(vm)) {
            openvzFreeVMDef(vm->vmdef);
            vm->vmdef = def;
        }
        else
        {
246
            openvzLog(OPENVZ_ERR,
247 248
                      _("Error already an active OPENVZ VM having id '%s'"),
                      def->name);
249 250 251 252 253 254 255
            openvzFreeVMDef(def);
            return NULL; /* can't redefine an active domain */
        }

        return vm;
    }

256
    if (VIR_ALLOC(vm) < 0) {
257
        openvzFreeVMDef(def);
D
Daniel Veillard 已提交
258
        openvzError(conn, VIR_ERR_NO_MEMORY, _("vm"));
259 260 261 262 263 264 265 266 267 268 269 270 271 272
        return NULL;
    }

    vm->vpsid = -1;     /* -1 needed for to represent inactiveness of domain before 'start' */
    vm->status = VIR_DOMAIN_SHUTOFF;
    vm->vmdef = def;
    vm->next = driver->vms;

    driver->vms = vm;
    driver->num_inactive++;

    return vm;
}

273
struct openvz_vm_def
274 275 276 277 278 279
*openvzParseVMDef(virConnectPtr conn,
                 const char *xmlStr, const char *displayName)
{
    xmlDocPtr xml;
    struct openvz_vm_def *def = NULL;

280
    xml = xmlReadDoc(BAD_CAST xmlStr, displayName ? displayName : "domain.xml", NULL,
281 282
            XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
    if (!xml) {
D
Daniel Veillard 已提交
283
        openvzError(conn, VIR_ERR_XML_ERROR, NULL);
284 285 286 287 288 289 290
        return NULL;
    }

    def = openvzParseXML(conn, xml);
    xmlFreeDoc(xml);

    return def;
291 292 293 294 295 296
}

/*
 * Parses a libvirt XML definition of a guest, and populates the
 * the openvz_vm struct with matching data about the guests config
 */
297
static struct openvz_vm_def
298 299
*openvzParseXML(virConnectPtr conn,
                        xmlDocPtr xml) {
300 301 302 303 304
    xmlNodePtr root = NULL;
    xmlChar *prop = NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlXPathObjectPtr obj = NULL;
    struct openvz_vm_def *def;
305 306
    struct ovz_ip *ovzIp;
    struct ovz_ns *ovzNs;
307

308
    if (VIR_ALLOC(def) < 0) {
D
Daniel Veillard 已提交
309
        openvzError(conn, VIR_ERR_NO_MEMORY, _("xmlXPathContext"));
310 311 312 313
        return NULL;
    }

    /* Prepare parser / xpath context */
314

315 316
    root = xmlDocGetRootElement(xml);
    if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) {
D
Daniel Veillard 已提交
317
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("incorrect root element"));
318 319 320 321 322
        goto bail_out;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
D
Daniel Veillard 已提交
323
        openvzError(conn, VIR_ERR_NO_MEMORY, _("xmlXPathContext"));
324 325 326
        goto bail_out;
    }

327
    /* Find out what type of OPENVZ virtualization to use */
328
    if (!(prop = xmlGetProp(root, BAD_CAST "type"))) {
D
Daniel Veillard 已提交
329
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("missing domain type attribute"));
330 331 332
        goto bail_out;
    }

333
    if (STRNEQ((char *)prop, "openvz")){
D
Daniel Veillard 已提交
334
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("invalid domain type attribute"));
335 336
        goto bail_out;
    }
337
    VIR_FREE(prop);
338 339 340

    /* Extract domain name */
    obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt);
341
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
342
        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
D
Daniel Veillard 已提交
343
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("invalid domain name"));
344 345
        goto bail_out;
    }
346

347
    /* rejecting VPS ID <= OPENVZ_RSRV_VM_LIMIT for they are reserved */
348
    if (strtoI((const char *) obj->stringval) <= OPENVZ_RSRV_VM_LIMIT) {
D
Daniel Veillard 已提交
349
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
350
              _("VPS ID Error (must be an integer greater than 100"));
351 352
        goto bail_out;
    }
353
    strncpy(def->name, (const char *) obj->stringval, OPENVZ_NAME_MAX);
354 355 356 357 358 359 360
    xmlXPathFreeObject(obj);

    /* Extract domain uuid */
    obj = xmlXPathEval(BAD_CAST "string(/domain/uuid[1])", ctxt);
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
        int err;
361

362
        if ((err = virUUIDGenerate(def->uuid))) {
D
Daniel Veillard 已提交
363
            openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("Failed to generate UUID"));
364 365 366
            goto bail_out;
        }
    } else if (virUUIDParse((const char *)obj->stringval, def->uuid) < 0) {
D
Daniel Veillard 已提交
367
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("malformed uuid element"));
368 369 370 371 372
        goto bail_out;
    }
    xmlXPathFreeObject(obj);

    /* Extract filesystem info */
373
    obj = xmlXPathEval(BAD_CAST "string(/domain/container/filesystem/template[1])", ctxt);
374
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||	(obj->stringval == NULL)
375
            || (obj->stringval[0] == 0)) {
D
Daniel Veillard 已提交
376
        openvzError(conn, VIR_ERR_OS_TYPE, NULL);
377 378
        goto bail_out;
    }
379
    strncpy(def->fs.tmpl, (const char *) obj->stringval, OPENVZ_TMPL_MAX);
380 381 382 383 384 385 386
    xmlXPathFreeObject(obj);

    /* TODO Add quota processing here */

    /* TODO analysis of the network devices */


387 388 389
    /*          Extract network                 */
        /*              Extract ipaddress           */
    obj = xmlXPathEval(BAD_CAST"string(/domain/container/network/ipaddress[1])", ctxt);
390
    if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL)
391
            || (obj->stringval[0] == 0)) {
392
        openvzLog(OPENVZ_WARN,
393 394
                  _("No IP address in the given xml config file '%s'"),
                  xml->name);
395 396
    }
    if (xmlStrlen(obj->stringval) >= (OPENVZ_IP_MAX)) {
D
Daniel Veillard 已提交
397 398
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("ipaddress length too long"));
399 400
        goto bail_out;
    }
401
    if (VIR_ALLOC(ovzIp) < 0) {
402
        openvzLog(OPENVZ_ERR,
403
                  _("Failed to Create Memory for 'ovz_ip' structure"));
404 405 406 407 408 409 410 411 412 413
        goto bail_out;
    }
    strncpy(ovzIp->ip, (const char *) obj->stringval, OPENVZ_IP_MAX);
    def->net.ips = ovzIp;
    xmlXPathFreeObject(obj);

        /*              Extract netmask             */
    obj = xmlXPathEval(BAD_CAST "string(/domain/container/network/netmask[1])", ctxt);
    if ((obj == NULL) || (obj->type != XPATH_STRING)
        || (obj->stringval == NULL) || (obj->stringval[0] == 0))
414
        openvzLog(OPENVZ_WARN,
415 416
                  _("No Netmask address in the given xml config file '%s'"),
                  xml->name);
417

418
    if (strlen((const char *) obj->stringval) >= (OPENVZ_IP_MAX)) {
D
Daniel Veillard 已提交
419 420
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("netmask length too long"));
421 422 423 424 425 426 427
        goto bail_out;
    }
    strncpy(def->net.ips->netmask, (const char *) obj->stringval, OPENVZ_IP_MAX);
    xmlXPathFreeObject(obj);

        /*              Extract hostname            */
    obj = xmlXPathEval(BAD_CAST "string(/domain/container/network/hostname[1])", ctxt);
428
    if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL)
429
            || (obj->stringval[0] == 0))
430
        openvzLog(OPENVZ_WARN,
431 432
                  _("No hostname in the given xml config file '%s'"),
                  xml->name);
433

434
    if (strlen((const char *) obj->stringval) >= (OPENVZ_HOSTNAME_MAX - 1)) {
D
Daniel Veillard 已提交
435 436
        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                     _("hostname length too long"));
437 438 439 440 441 442 443
        goto bail_out;
    }
    strncpy(def->net.hostname, (const char *) obj->stringval, OPENVZ_HOSTNAME_MAX - 1);
    xmlXPathFreeObject(obj);

        /*              Extract gateway             */
    obj = xmlXPathEval(BAD_CAST"string(/domain/container/network/gateway[1])", ctxt);
444
    if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL)
445
            || (obj->stringval[0] == 0))
446
        openvzLog(OPENVZ_WARN,
447 448
                  _("No Gateway address in the given xml config file '%s'"),
                  xml->name);
449

450
    if (strlen((const char *) obj->stringval) >= (OPENVZ_IP_MAX)) {
D
Daniel Veillard 已提交
451
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("gateway length too long"));
452 453 454 455 456 457 458
        goto bail_out;
    }
    strncpy(def->net.def_gw, (const char *) obj->stringval, OPENVZ_IP_MAX);
    xmlXPathFreeObject(obj);

        /*              Extract nameserver          */
    obj = xmlXPathEval(BAD_CAST "string(/domain/container/network/nameserver[1])", ctxt);
459
    if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL)
460
            || (obj->stringval[0] == 0))
461
        openvzLog(OPENVZ_WARN,
462 463
                  _("No Nameserver address inthe given xml config file '%s'"),
                  xml->name);
464

465
    if (strlen((const char *) obj->stringval) >= (OPENVZ_IP_MAX)) {
D
Daniel Veillard 已提交
466
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("nameserver length too long"));
467 468
        goto bail_out;
    }
469
    if (VIR_ALLOC(ovzNs) < 0) {
470 471
        openvzLog(OPENVZ_ERR,
                  _("Failed to Create Memory for 'ovz_ns' structure"));
472 473 474 475 476 477 478 479
        goto bail_out;
    }
    strncpy(ovzNs->ip, (const char *) obj->stringval, OPENVZ_IP_MAX);
    def->net.ns = ovzNs;
    xmlXPathFreeObject(obj);

    /*          Extract profile         */
    obj = xmlXPathEval(BAD_CAST "string(/domain/container/profile[1])", ctxt);
480
    if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL)
481
            || (obj->stringval[0] == 0)) {
D
Daniel Veillard 已提交
482
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, NULL);
483 484 485
        goto bail_out;
    }
    if (strlen((const char *) obj->stringval) >= (OPENVZ_PROFILE_MAX - 1)) {
D
Daniel Veillard 已提交
486
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("profile length too long"));
487 488 489 490 491 492
        goto bail_out;
    }
    strncpy(def->profile, (const char *) obj->stringval, OPENVZ_PROFILE_MAX - 1);
    xmlXPathFreeObject(obj);

    xmlXPathFreeContext(ctxt);
493 494 495
    return def;

 bail_out:
496
    VIR_FREE(prop);
497
    xmlXPathFreeObject(obj);
498
    xmlXPathFreeContext(ctxt);
499 500
    openvzFreeVMDef(def);

501
    return NULL;
502 503 504 505 506 507 508
}

struct openvz_vm *
openvzGetVPSInfo(virConnectPtr conn) {
    FILE *fp;
    int veid, ret;
    char status[16];
509
    char uuidstr[VIR_UUID_STRING_BUFLEN];
510 511 512 513 514 515 516 517 518
    struct openvz_vm *vm;
    struct openvz_vm  **pnext;
    struct openvz_driver *driver;
    struct openvz_vm_def *vmdef;

    vm =  NULL;
    driver = conn->privateData;
    driver->num_active = 0;
    driver->num_inactive = 0;
519

520
    if((fp = popen(VZLIST " -a -ovpsid,status -H 2>/dev/null", "r")) == NULL) {
D
Daniel Veillard 已提交
521
        openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("popen failed"));
522 523
        return NULL;
    }
524 525
    pnext = &vm;
    while(!feof(fp)) {
526
        if (VIR_ALLOC(*pnext) < 0) {
D
Daniel Veillard 已提交
527
            openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("calloc failed"));
528
            goto error;
529
        }
530

531 532 533
        if(!vm)
            vm = *pnext;

534
        if (fscanf(fp, "%d %s\n", &veid, status) != 2) {
D
Daniel Veillard 已提交
535
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
536 537 538
                  _("Failed to parse vzlist output"));
            goto error;
        }
539
        if(STRNEQ(status, "stopped")) {
540 541 542 543 544 545 546
            (*pnext)->status = VIR_DOMAIN_RUNNING;
            driver->num_active ++;
            (*pnext)->vpsid = veid;
        }
        else {
            (*pnext)->status = VIR_DOMAIN_SHUTOFF;
            driver->num_inactive ++;
547 548 549 550
            /*
             * inactive domains don't have their ID set in libvirt,
             * thought this doesn't make sense for OpenVZ
             */
551
            (*pnext)->vpsid = -1;
552 553
        }

554
        if (VIR_ALLOC(vmdef) < 0) {
D
Daniel Veillard 已提交
555
            openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("calloc failed"));
556
            goto error;
557
        }
558

559 560
        snprintf(vmdef->name, OPENVZ_NAME_MAX,  "%i", veid);
        openvzGetVPSUUID(veid, uuidstr);
561 562 563
        ret = virUUIDParse(uuidstr, vmdef->uuid);

        if(ret == -1) {
D
Daniel Veillard 已提交
564
            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
565
                  _("UUID in config file malformed"));
566
            VIR_FREE(vmdef);
567
            goto error;
568 569 570 571 572 573
        }

        (*pnext)->vmdef = vmdef;
        pnext = &(*pnext)->next;
    }
    return vm;
574 575 576 577
error:
    while (vm != NULL) {
        struct openvz_vm *next;

578
        next = vm->next;
579 580
        VIR_FREE(vm->vmdef);
        VIR_FREE(vm);
581
        vm = next;
582 583
    }
    return NULL;
584 585
}

586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
/*
* Read parameter from container config
* sample: 133, "OSTEMPLATE", value, 1024
* return: -1 - error
*	   0 - don't found
*          1 - OK
*/
int
openvzReadConfigParam(int vpsid ,const char * param, char *value, int maxlen)
{
    char conf_file[PATH_MAX] ;
    char line[PATH_MAX] ;
    int ret, found = 0;
    int fd ;
    char * sf, * token;
    char *saveptr = NULL;

603
    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX)<0)
604 605 606 607 608
        return -1;

    value[0] = 0;

    fd = open(conf_file, O_RDONLY);
D
Daniel Veillard 已提交
609
    if (fd == -1)
610 611 612 613 614 615 616
        return -1;

    while(1) {
        ret = openvz_readline(fd, line, sizeof(line));
        if(ret <= 0)
            break;
        saveptr = NULL;
D
Daniel Veillard 已提交
617
        if (STREQLEN(line, param, strlen(param))) {
618 619 620 621 622 623 624
            sf = line;
            sf += strlen(param);
            if (sf[0] == '=' && (token = strtok_r(sf,"\"\t=\n", &saveptr)) != NULL) {
                strncpy(value, token, maxlen) ;
                value[maxlen-1] = '\0';
                found = 1;
            }
D
Daniel Veillard 已提交
625
       }
626 627 628 629 630 631 632 633 634
    }
    close(fd);

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

    return ret ;
}

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
/* Locate config file of container
* return -1 - error
*         0 - OK
*/
static int
openvzLocateConfFile(int vpsid, char *conffile, int maxlen)
{
    char * confdir;
    int ret = 0;

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

    if (snprintf(conffile, maxlen, "%s/%d.conf", confdir, vpsid) >= maxlen)
        ret = -1;

    VIR_FREE(confdir);
    return ret;
}

656
static char
657
*openvzLocateConfDir(void)
658 659 660 661 662 663
{
    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))
664
            return strdup(conf_dir_list[i]);
665 666 667 668 669 670 671
        i ++;
    }

    return NULL;
}

/* Richard Steven's classic readline() function */
672
int
673
openvz_readline(int fd, char *ptr, int maxlen)
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
{
    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;
}

697
static int
698
openvzGetVPSUUID(int vpsid, char *uuidstr)
699 700 701
{
    char conf_file[PATH_MAX];
    char line[1024];
702
    char uuidbuf[1024];
703 704 705
    char iden[1024];
    int fd, ret;

706 707
   if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX)<0)
       return -1;
708

709
    fd = open(conf_file, O_RDONLY);
710 711 712 713 714 715 716 717 718
    if(fd == -1)
        return -1;

    while(1) {
        ret = openvz_readline(fd, line, sizeof(line));
        if(ret == -1)
            return -1;

        if(ret == 0) { /* EoF, UUID was not found */
719
            uuidstr[0] = 0;
720 721 722
            break;
        }

723
        sscanf(line, "%s %s\n", iden, uuidbuf);
724
        if(STREQ(iden, "#UUID:")) {
725
            strncpy(uuidstr, uuidbuf, VIR_UUID_STRING_BUFLEN);
726 727 728
            break;
        }
    }
729 730
    close(fd);

731 732 733 734 735 736 737
    return 0;
}

/* Do actual checking for UUID presence in conf file,
 * assign if not present.
 */

738
static int
739
openvzSetUUID(int vpsid)
740 741
{
    char conf_file[PATH_MAX];
742 743
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    unsigned char uuid[VIR_UUID_BUFLEN];
744

745 746
   if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX)<0)
       return -1;
747

J
Jim Meyering 已提交
748
    if (openvzGetVPSUUID(vpsid, uuidstr))
749 750
        return -1;

J
Jim Meyering 已提交
751
    if (uuidstr[0] == 0) {
752 753 754
        FILE *fp = fopen(conf_file, "a"); /* append */
        if (fp == NULL)
          return -1;
755

756 757 758
        virUUIDGenerate(uuid);
        virUUIDFormat(uuid, uuidstr);

759 760 761 762 763
        /* 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;
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
    }

    return 0;
}

/*
 * 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.
 *
 */

int openvzAssignUUIDs(void)
{
    DIR *dp;
    struct dirent *dent;
    char *conf_dir;
    int vpsid, res;
    char ext[8];

    conf_dir = openvzLocateConfDir();
785 786
    if (conf_dir == NULL)
        return -1;
787 788 789

    dp = opendir(conf_dir);
    if(dp == NULL) {
790
        VIR_FREE(conf_dir);
791 792 793 794 795
        return 0;
    }

    while((dent = readdir(dp))) {
        res = sscanf(dent->d_name, "%d.%5s", &vpsid, ext);
796
        if(!(res == 2 && STREQ(ext, "conf")))
797 798 799 800 801
            continue;
        if(vpsid > 0) /* '0.conf' belongs to the host, ignore it */
            openvzSetUUID(vpsid);
    }
    closedir(dp);
802
    VIR_FREE(conf_dir);
803 804 805 806
    return 0;
}

#endif