conf.c 25.2 KB
Newer Older
D
Daniel Veillard 已提交
1 2 3
/**
 * conf.c: parser for a subset of the Python encoded Xen configuration files
 *
4
 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
D
Daniel Veillard 已提交
5 6 7 8 9 10
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
 */

11
#include <config.h>
12

D
Daniel Veillard 已提交
13 14 15 16 17 18 19 20
#include <string.h>

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

21
#include "virterror_internal.h"
22
#include "buf.h"
D
Daniel Veillard 已提交
23
#include "conf.h"
24
#include "util.h"
J
Jim Meyering 已提交
25
#include "c-ctype.h"
26
#include "memory.h"
D
Daniel Veillard 已提交
27

28 29
#define VIR_FROM_THIS VIR_FROM_CONF

D
Daniel Veillard 已提交
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
/************************************************************************
 *									*
 *	Structures and macros used by the mini parser			*
 *									*
 ************************************************************************/

typedef struct _virConfParserCtxt virConfParserCtxt;
typedef virConfParserCtxt *virConfParserCtxtPtr;

struct _virConfParserCtxt {
    const char* filename;
    const char* base;
    const char* cur;
    const char *end;
    int line;

    virConfPtr conf;
};

#define CUR (*ctxt->cur)
#define NEXT if (ctxt->cur < ctxt->end) ctxt->cur++;
#define IS_EOL(c) (((c) == '\n') || ((c) == '\r'))
J
Jim Meyering 已提交
52 53 54 55 56 57 58 59

#define SKIP_BLANKS_AND_EOL                                             \
  do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR) || IS_EOL(CUR))) { \
         if (CUR == '\n') ctxt->line++;	                                \
         ctxt->cur++;}} while (0)
#define SKIP_BLANKS                                                     \
  do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR)))              \
          ctxt->cur++; } while (0)
D
Daniel Veillard 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

/************************************************************************
 *									*
 *		Structures used by configuration data			*
 *									*
 ************************************************************************/

typedef struct _virConfEntry virConfEntry;
typedef virConfEntry *virConfEntryPtr;

struct _virConfEntry {
    virConfEntryPtr next;
    char* name;
    char* comment;
    virConfValuePtr value;
};

struct _virConf {
    const char* filename;
79
    unsigned int flags;
D
Daniel Veillard 已提交
80 81 82 83 84
    virConfEntryPtr entries;
};

/**
 * virConfError:
85
 * @ctxt: the parser context if available or NULL
D
Daniel Veillard 已提交
86 87 88 89 90 91
 * @error: the error number
 * @info: extra information string
 *
 * Handle an error at the xend daemon interface
 */
static void
92 93
virConfError(virConfParserCtxtPtr ctxt,
             virErrorNumber error, const char *info)
D
Daniel Veillard 已提交
94
{
95
    const char *format;
D
Daniel Veillard 已提交
96 97 98 99

    if (error == VIR_ERR_OK)
        return;

100 101
    /* Construct the string 'filename:line: info' if we have that. */
    if (ctxt && ctxt->filename) {
102
        virRaiseError(NULL, NULL, NULL, VIR_FROM_CONF, error, VIR_ERR_ERROR,
103 104 105 106
                        info, ctxt->filename, NULL,
                        ctxt->line, 0,
                        "%s:%d: %s", ctxt->filename, ctxt->line, info);
    } else {
107 108
        format = virErrorMsg(error, info);
        virRaiseError(NULL, NULL, NULL, VIR_FROM_CONF, error, VIR_ERR_ERROR,
109 110 111 112
                        info, NULL, NULL,
                        ctxt ? ctxt->line : 0, 0,
                        format, info);
    }
D
Daniel Veillard 已提交
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
}


/************************************************************************
 *									*
 *		Structures allocations and deallocations		*
 *									*
 ************************************************************************/

/**
 * virConfFreeList:
 * @list: the list to free
 *
 * Free a list
 */
static void
virConfFreeList(virConfValuePtr list)
{
    virConfValuePtr next;

    while (list != NULL) {
        next = list->next;
135 136 137
        list->next = NULL;
        virConfFreeValue(list);
        list = next;
D
Daniel Veillard 已提交
138 139 140 141 142 143 144 145 146
    }
}

/**
 * virConfFreeValue:
 * @val: the value to free
 *
 * Free a value
 */
147
void
D
Daniel P. Berrange 已提交
148
virConfFreeValue(virConfValuePtr val)
D
Daniel Veillard 已提交
149 150 151
{
    if (val == NULL)
        return;
152 153
    if (val->type == VIR_CONF_STRING &&
        val->str != NULL)
154
        VIR_FREE(val->str);
155 156
    if (val->type == VIR_CONF_LIST &&
        val->list != NULL)
D
Daniel Veillard 已提交
157
        virConfFreeList(val->list);
158
    VIR_FREE(val);
D
Daniel Veillard 已提交
159 160
}

161
virConfPtr
D
Daniel P. Berrange 已提交
162
virConfNew(void)
D
Daniel Veillard 已提交
163 164 165
{
    virConfPtr ret;

166
    if (VIR_ALLOC(ret) < 0) {
167
        virReportOOMError();
D
Daniel Veillard 已提交
168 169
        return(NULL);
    }
170
    ret->filename = NULL;
171
    ret->flags = 0;
172 173 174

    return(ret);
}
D
Daniel Veillard 已提交
175

176 177 178
/**
 * virConfCreate:
 * @filename: the name to report errors
179
 * @flags: combination of virConfFlag(s)
180 181 182 183 184 185
 *
 * Create a configuration internal structure
 *
 * Returns a pointer or NULL in case of error.
 */
static virConfPtr
186
virConfCreate(const char *filename, unsigned int flags)
187 188
{
    virConfPtr ret = virConfNew();
189
    if (ret) {
190
        ret->filename = filename;
191 192
        ret->flags = flags;
    }
D
Daniel Veillard 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    return(ret);
}

/**
 * virConfAddEntry:
 * @conf: the conf structure
 * @name: name of the entry or NULL for comment
 * @value: the value if any
 * @comm: extra comment for that entry if any
 *
 * add one entry to the conf, the parameters are included in the conf
 * if successful and freed on virConfFree()
 *
 * Returns a pointer to the entry or NULL in case of failure
 */
static virConfEntryPtr
virConfAddEntry(virConfPtr conf, char *name, virConfValuePtr value, char *comm)
{
    virConfEntryPtr ret, prev;

    if (conf == NULL)
        return(NULL);
    if ((comm == NULL) && (name == NULL))
        return(NULL);
217

218
    if (VIR_ALLOC(ret) < 0) {
219
        virReportOOMError();
D
Daniel Veillard 已提交
220 221
        return(NULL);
    }
222

D
Daniel Veillard 已提交
223 224 225 226 227 228 229 230
    ret->name = name;
    ret->value = value;
    ret->comment = comm;

    if (conf->entries == NULL) {
        conf->entries = ret;
    } else {
        prev = conf->entries;
231 232 233
        while (prev->next != NULL)
            prev = prev->next;
        prev->next = ret;
D
Daniel Veillard 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    }
    return(ret);
}

/************************************************************************
 *									*
 *			Serialization					*
 *									*
 ************************************************************************/

/**
 * virConfSaveValue:
 * @buf: output buffer
 * @val: a value
 *
 * Serialize the value to the buffer
 *
 * Returns 0 in case of success, -1 in case of error.
 */
static int
virConfSaveValue(virBufferPtr buf, virConfValuePtr val)
{
    if (val == NULL)
        return(-1);
    switch (val->type) {
        case VIR_CONF_NONE:
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
            return(-1);
        case VIR_CONF_LONG:
            virBufferVSprintf(buf, "%ld", val->l);
            break;
        case VIR_CONF_STRING:
            if (strchr(val->str, '\n') != NULL) {
                virBufferVSprintf(buf, "\"\"\"%s\"\"\"", val->str);
            } else if (strchr(val->str, '"') == NULL) {
                virBufferVSprintf(buf, "\"%s\"", val->str);
            } else if (strchr(val->str, '\'') == NULL) {
                virBufferVSprintf(buf, "'%s'", val->str);
            } else {
                virBufferVSprintf(buf, "\"\"\"%s\"\"\"", val->str);
            }
            break;
        case VIR_CONF_LIST: {
            virConfValuePtr cur;

            cur = val->list;
            virBufferAddLit(buf, "[ ");
            if (cur != NULL) {
                virConfSaveValue(buf, cur);
                cur = cur->next;
                while (cur != NULL) {
                    virBufferAddLit(buf, ", ");
                    virConfSaveValue(buf, cur);
                    cur = cur->next;
                }
            }
            virBufferAddLit(buf, " ]");
            break;
        }
        default:
            return(-1);
D
Daniel Veillard 已提交
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    }
    return(0);
}

/**
 * virConfSaveEntry:
 * @buf: output buffer
 * @cur: a conf entry
 *
 * Serialize the entry to the buffer
 *
 * Returns 0 in case of success, -1 in case of error.
 */
static int
virConfSaveEntry(virBufferPtr buf, virConfEntryPtr cur)
{
    if (cur->name != NULL) {
        virBufferAdd(buf, cur->name, -1);
312 313 314 315 316 317
        virBufferAddLit(buf, " = ");
        virConfSaveValue(buf, cur->value);
        if (cur->comment != NULL) {
            virBufferAddLit(buf, " #");
            virBufferAdd(buf, cur->comment, -1);
        }
D
Daniel Veillard 已提交
318
    } else if (cur->comment != NULL) {
319 320
        virBufferAddLit(buf, "#");
        virBufferAdd(buf, cur->comment, -1);
D
Daniel Veillard 已提交
321
    }
322
    virBufferAddLit(buf, "\n");
D
Daniel Veillard 已提交
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
    return(0);
}

/************************************************************************
 *									*
 *			The parser core					*
 *									*
 ************************************************************************/

/**
 * virConfParseLong:
 * @ctxt: the parsing context
 * @val: the result
 *
 * Parse one long int value
 *
 * Returns 0 in case of success and -1 in case of error
 */
static int
virConfParseLong(virConfParserCtxtPtr ctxt, long *val)
{
    long l = 0;
    int neg = 0;

    if (CUR == '-') {
        neg = 1;
349
        NEXT;
D
Daniel Veillard 已提交
350 351 352
    } else if (CUR == '+') {
        NEXT;
    }
J
Jim Meyering 已提交
353
    if ((ctxt->cur >= ctxt->end) || (!c_isdigit(CUR))) {
354
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number"));
355
        return(-1);
D
Daniel Veillard 已提交
356
    }
J
Jim Meyering 已提交
357
    while ((ctxt->cur < ctxt->end) && (c_isdigit(CUR))) {
D
Daniel Veillard 已提交
358
        l = l * 10 + (CUR - '0');
359
        NEXT;
D
Daniel Veillard 已提交
360
    }
361 362
    if (neg)
        l = -l;
D
Daniel Veillard 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    *val = l;
    return(0);
}

/**
 * virConfParseString:
 * @ctxt: the parsing context
 *
 * Parse one string
 *
 * Returns a pointer to the string or NULL in case of error
 */
static char *
virConfParseString(virConfParserCtxtPtr ctxt)
{
    const char *base;
    char *ret = NULL;

    if (CUR == '\'') {
        NEXT;
383 384 385 386
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR)))
            NEXT;
        if (CUR != '\'') {
387
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
388 389 390
            return(NULL);
        }
        ret = strndup(base, ctxt->cur - base);
391
        if (ret == NULL) {
392
            virReportOOMError();
393 394
            return NULL;
        }
395
        NEXT;
D
Daniel Veillard 已提交
396 397
    } else if ((ctxt->cur + 6 < ctxt->end) && (ctxt->cur[0] == '"') &&
               (ctxt->cur[1] == '"') && (ctxt->cur[2] == '"')) {
398 399 400 401 402 403 404 405 406
        ctxt->cur += 3;
        base = ctxt->cur;
        while ((ctxt->cur + 2 < ctxt->end) && (ctxt->cur[0] == '"') &&
               (ctxt->cur[1] == '"') && (ctxt->cur[2] == '"')) {
               if (CUR == '\n') ctxt->line++;
               NEXT;
        }
        if ((ctxt->cur[0] != '"') || (ctxt->cur[1] != '"') ||
            (ctxt->cur[2] != '"')) {
407
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
408 409 410
            return(NULL);
        }
        ret = strndup(base, ctxt->cur - base);
411
        if (ret == NULL) {
412
            virReportOOMError();
413 414
            return NULL;
        }
415
        ctxt->cur += 3;
D
Daniel Veillard 已提交
416 417
    } else if (CUR == '"') {
        NEXT;
418 419 420 421
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR)))
            NEXT;
        if (CUR != '"') {
422
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
423 424 425
            return(NULL);
        }
        ret = strndup(base, ctxt->cur - base);
426
        if (ret == NULL) {
427
            virReportOOMError();
428 429
            return NULL;
        }
430
        NEXT;
D
Daniel Veillard 已提交
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
    }
    return(ret);
}

/**
 * virConfParseValue:
 * @ctxt: the parsing context
 *
 * Parse one value
 *
 * Returns a pointer to the value or NULL in case of error
 */
static virConfValuePtr
virConfParseValue(virConfParserCtxtPtr ctxt)
{
    virConfValuePtr ret, lst = NULL, tmp, prev;
    virConfType type = VIR_CONF_NONE;
    char *str = NULL;
    long  l = 0;

J
Jim Meyering 已提交
451
    SKIP_BLANKS;
D
Daniel Veillard 已提交
452
    if (ctxt->cur >= ctxt->end) {
453
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
454
        return(NULL);
D
Daniel Veillard 已提交
455 456 457 458
    }
    if ((CUR == '"') || (CUR == '\'')) {
        type = VIR_CONF_STRING;
        str = virConfParseString(ctxt);
459 460
        if (str == NULL)
            return(NULL);
D
Daniel Veillard 已提交
461
    } else if (CUR == '[') {
462 463 464 465 466
        if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                         _("lists not allowed in VMX format"));
            return(NULL);
        }
D
Daniel Veillard 已提交
467 468
        type = VIR_CONF_LIST;
        NEXT;
J
Jim Meyering 已提交
469
        SKIP_BLANKS_AND_EOL;
470
        if ((ctxt->cur < ctxt->end) && (CUR != ']')) {
471 472
            if ((lst = virConfParseValue(ctxt)) == NULL)
                return(NULL);
J
Jim Meyering 已提交
473
            SKIP_BLANKS_AND_EOL;
474 475
        }
        while ((ctxt->cur < ctxt->end) && (CUR != ']')) {
476 477 478 479 480 481 482

            /* Tell Clang that when execution reaches this point
               "lst" is guaranteed to be non-NULL.  This stops it
               from issuing an invalid NULL-dereference warning about
               "prev = lst; while (prev->next..." below.  */
            sa_assert (lst);

483
            if (CUR != ',') {
484 485
                virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                             _("expecting a separator in list"));
486 487 488 489
                virConfFreeList(lst);
                return(NULL);
            }
            NEXT;
J
Jim Meyering 已提交
490
            SKIP_BLANKS_AND_EOL;
491 492 493 494 495 496 497 498 499 500 501
            if (CUR == ']') {
                break;
            }
            tmp = virConfParseValue(ctxt);
            if (tmp == NULL) {
                virConfFreeList(lst);
                return(NULL);
            }
            prev = lst;
            while (prev->next != NULL) prev = prev->next;
            prev->next = tmp;
J
Jim Meyering 已提交
502
            SKIP_BLANKS_AND_EOL;
503 504 505 506
        }
        if (CUR == ']') {
            NEXT;
        } else {
507 508
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                         _("list is not closed with ]"));
509 510 511
            virConfFreeList(lst);
            return(NULL);
        }
J
Jim Meyering 已提交
512
    } else if (c_isdigit(CUR) || (CUR == '-') || (CUR == '+')) {
513 514 515 516 517
        if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                         _("numbers not allowed in VMX format"));
            return(NULL);
        }
D
Daniel Veillard 已提交
518
        if (virConfParseLong(ctxt, &l) < 0) {
519 520
            return(NULL);
        }
D
Daniel Veillard 已提交
521 522
        type = VIR_CONF_LONG;
    } else {
523
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
524
        return(NULL);
D
Daniel Veillard 已提交
525
    }
526
    if (VIR_ALLOC(ret) < 0) {
527
        virReportOOMError();
528 529
        virConfFreeList(lst);
        VIR_FREE(str);
D
Daniel Veillard 已提交
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
        return(NULL);
    }
    ret->type = type;
    ret->l = l;
    ret->str = str;
    ret->list = lst;
    return(ret);
}

/**
 * virConfParseName:
 * @ctxt: the parsing context
 *
 * Parse one name
 *
 * Returns a copy of the new string, NULL in case of error
 */
static char *
virConfParseName(virConfParserCtxtPtr ctxt)
{
    const char *base;
    char *ret;

J
Jim Meyering 已提交
553
    SKIP_BLANKS;
D
Daniel Veillard 已提交
554 555
    base = ctxt->cur;
    /* TODO: probably need encoding support and UTF-8 parsing ! */
556 557
    if (!c_isalpha(CUR) &&
        !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) {
558
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name"));
559
        return(NULL);
D
Daniel Veillard 已提交
560
    }
561 562
    while ((ctxt->cur < ctxt->end) &&
           (c_isalnum(CUR) || (CUR == '_') ||
563
            ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) &&
564
             ((CUR == ':') || (CUR == '.') || (CUR == '-')))))
D
Daniel Veillard 已提交
565 566 567
        NEXT;
    ret = strndup(base, ctxt->cur - base);
    if (ret == NULL) {
568
        virReportOOMError();
D
Daniel Veillard 已提交
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
        return(NULL);
    }
    return(ret);
}

/**
 * virConfParseComment:
 * @ctxt: the parsing context
 *
 * Parse one standalone comment in the configuration file
 *
 * Returns 0 in case of success and -1 in case of error
 */
static int
virConfParseComment(virConfParserCtxtPtr ctxt)
{
    const char *base;
    char *comm;

    if (CUR != '#')
        return(-1);
    NEXT;
    base = ctxt->cur;
    while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
    comm = strndup(base, ctxt->cur - base);
    if (comm == NULL) {
595
        virReportOOMError();
D
Daniel Veillard 已提交
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
        return(-1);
    }
    virConfAddEntry(ctxt->conf, NULL, NULL, comm);
    return(0);
}

/**
 * virConfParseSeparator:
 * @ctxt: the parsing context
 *
 * Parse one separator between statement if not at the end.
 *
 * Returns 0 in case of success and -1 in case of error
 */
static int
virConfParseSeparator(virConfParserCtxtPtr ctxt)
{
J
Jim Meyering 已提交
613
    SKIP_BLANKS;
D
Daniel Veillard 已提交
614
    if (ctxt->cur >= ctxt->end)
615
        return(0);
D
Daniel Veillard 已提交
616
    if (IS_EOL(CUR)) {
J
Jim Meyering 已提交
617
        SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
618
    } else if (CUR == ';') {
619
        NEXT;
J
Jim Meyering 已提交
620
        SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
621
    } else {
622
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator"));
623
        return(-1);
D
Daniel Veillard 已提交
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
    }
    return(0);
}

/**
 * virConfParseStatement:
 * @ctxt: the parsing context
 *
 * Parse one statement in the conf file
 *
 * Returns 0 in case of success and -1 in case of error
 */
static int
virConfParseStatement(virConfParserCtxtPtr ctxt)
{
    const char *base;
    char *name;
    virConfValuePtr value;
    char *comm = NULL;

J
Jim Meyering 已提交
644
    SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
645 646 647 648 649 650
    if (CUR == '#') {
        return(virConfParseComment(ctxt));
    }
    name = virConfParseName(ctxt);
    if (name == NULL)
        return(-1);
J
Jim Meyering 已提交
651
    SKIP_BLANKS;
D
Daniel Veillard 已提交
652
    if (CUR != '=') {
653
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment"));
D
Daniel Veillard 已提交
654 655 656
        return(-1);
    }
    NEXT;
J
Jim Meyering 已提交
657
    SKIP_BLANKS;
D
Daniel Veillard 已提交
658 659
    value = virConfParseValue(ctxt);
    if (value == NULL) {
660
        VIR_FREE(name);
661
        return(-1);
D
Daniel Veillard 已提交
662
    }
J
Jim Meyering 已提交
663
    SKIP_BLANKS;
D
Daniel Veillard 已提交
664
    if (CUR == '#') {
665 666 667 668 669
        NEXT;
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
        comm = strndup(base, ctxt->cur - base);
        if (comm == NULL) {
670
            virReportOOMError();
671
            VIR_FREE(name);
672 673 674
            virConfFreeValue(value);
            return(-1);
        }
D
Daniel Veillard 已提交
675 676
    }
    if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) {
677
        VIR_FREE(name);
678
        virConfFreeValue(value);
679
        VIR_FREE(comm);
680
        return(-1);
D
Daniel Veillard 已提交
681 682 683 684 685 686 687 688 689
    }
    return(0);
}

/**
 * virConfParse:
 * @filename: the name to report errors
 * @content: the configuration content in memory
 * @len: the length in bytes
690
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
691 692 693 694 695 696 697 698
 *
 * Parse the subset of the Python language needed to handle simple
 * Xen configuration files.
 *
 * Returns an handle to lookup settings or NULL if it failed to
 *         read or parse the file, use virConfFree() to free the data.
 */
static virConfPtr
699 700
virConfParse(const char *filename, const char *content, int len,
             unsigned int flags) {
D
Daniel Veillard 已提交
701 702 703 704 705 706 707
    virConfParserCtxt ctxt;

    ctxt.filename = filename;
    ctxt.base = ctxt.cur = content;
    ctxt.end = content + len - 1;
    ctxt.line = 1;

708
    ctxt.conf = virConfCreate(filename, flags);
D
Daniel Veillard 已提交
709 710 711 712 713
    if (ctxt.conf == NULL)
        return(NULL);

    while (ctxt.cur < ctxt.end) {
        if (virConfParseStatement(&ctxt) < 0)
714 715 716
            goto error;
        if (virConfParseSeparator(&ctxt) < 0)
            goto error;
D
Daniel Veillard 已提交
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
    }

    return(ctxt.conf);

error:
    virConfFree(ctxt.conf);
    return(NULL);
}

/************************************************************************
 *									*
 *			The module entry points				*
 *									*
 ************************************************************************/

732 733 734
/* 10 MB limit on config file size as a sanity check */
#define MAX_CONFIG_FILE_SIZE (1024*1024*10)

D
Daniel Veillard 已提交
735
/**
D
Daniel P. Berrange 已提交
736
 * virConfReadFile:
D
Daniel Veillard 已提交
737
 * @filename: the path to the configuration file.
738
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
739 740 741 742 743 744 745
 *
 * Reads a configuration file.
 *
 * Returns an handle to lookup settings or NULL if it failed to
 *         read or parse the file, use virConfFree() to free the data.
 */
virConfPtr
746
virConfReadFile(const char *filename, unsigned int flags)
D
Daniel Veillard 已提交
747
{
748
    char *content;
D
Daniel Veillard 已提交
749
    int len;
750
    virConfPtr conf;
D
Daniel Veillard 已提交
751 752

    if (filename == NULL) {
753
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
D
Daniel Veillard 已提交
754 755
        return(NULL);
    }
756 757 758

    if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0) {
        return NULL;
D
Daniel Veillard 已提交
759
    }
760

761
    conf = virConfParse(filename, content, len, flags);
762

763
    VIR_FREE(content);
764 765

    return conf;
D
Daniel Veillard 已提交
766 767 768
}

/**
D
Daniel P. Berrange 已提交
769
 * virConfReadMem:
D
Daniel Veillard 已提交
770
 * @memory: pointer to the content of the configuration file
D
Daniel Veillard 已提交
771
 * @len: length in byte
772
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
773 774 775 776 777 778 779 780
 *
 * Reads a configuration file loaded in memory. The string can be
 * zero terminated in which case @len can be 0
 *
 * Returns an handle to lookup settings or NULL if it failed to
 *         parse the content, use virConfFree() to free the data.
 */
virConfPtr
781
virConfReadMem(const char *memory, int len, unsigned int flags)
D
Daniel Veillard 已提交
782 783
{
    if ((memory == NULL) || (len < 0)) {
784
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
D
Daniel Veillard 已提交
785 786 787 788 789
        return(NULL);
    }
    if (len == 0)
        len = strlen(memory);

790
    return(virConfParse("memory conf", memory, len, flags));
D
Daniel Veillard 已提交
791 792 793
}

/**
D
Daniel P. Berrange 已提交
794
 * virConfFree:
D
Daniel Veillard 已提交
795 796 797 798 799 800 801
 * @conf: a configuration file handle
 *
 * Frees all data associated to the handle
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
D
Daniel P. Berrange 已提交
802
virConfFree(virConfPtr conf)
D
Daniel Veillard 已提交
803
{
804
    virConfEntryPtr tmp;
D
Daniel Veillard 已提交
805
    if (conf == NULL) {
806
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
807 808 809 810 811 812
        return(-1);
    }

    tmp = conf->entries;
    while (tmp) {
        virConfEntryPtr next;
813
        VIR_FREE(tmp->name);
814
        virConfFreeValue(tmp->value);
815
        VIR_FREE(tmp->comment);
816
        next = tmp->next;
817
        VIR_FREE(tmp);
818
        tmp = next;
D
Daniel Veillard 已提交
819
    }
820
    VIR_FREE(conf);
D
Daniel Veillard 已提交
821 822 823 824
    return(0);
}

/**
D
Daniel P. Berrange 已提交
825
 * virConfGetValue:
D
Daniel Veillard 已提交
826 827 828 829 830
 * @conf: a configuration file handle
 * @entry: the name of the entry
 *
 * Lookup the value associated to this entry in the configuration file
 *
831
 * Returns a pointer to the value or NULL if the lookup failed, the data
D
Daniel Veillard 已提交
832 833 834
 *         associated will be freed when virConfFree() is called
 */
virConfValuePtr
D
Daniel P. Berrange 已提交
835
virConfGetValue(virConfPtr conf, const char *setting)
D
Daniel Veillard 已提交
836
{
837 838 839 840
    virConfEntryPtr cur;

    cur = conf->entries;
    while (cur != NULL) {
841 842 843 844
        if ((cur->name != NULL) &&
            ((conf->flags & VIR_CONF_FLAG_VMX_FORMAT &&
              STRCASEEQ(cur->name, setting)) ||
             STREQ(cur->name, setting)))
845
            return(cur->value);
846 847 848
        cur = cur->next;
    }
    return(NULL);
D
Daniel Veillard 已提交
849 850
}

851
/**
D
Daniel P. Berrange 已提交
852
 * virConfSetValue:
853 854 855 856 857 858 859 860 861 862 863
 * @conf: a configuration file handle
 * @entry: the name of the entry
 * @value: the new configuration value
 *
 * Set (or replace) the value associated to this entry in the configuration
 * file. The passed in 'value' will be owned by the conf object upon return
 * of this method, even in case of error. It should not be referenced again
 * by the caller.
 *
 * Returns 0 on success, or -1 on failure.
 */
864
int
D
Daniel P. Berrange 已提交
865 866 867
virConfSetValue (virConfPtr conf,
                 const char *setting,
                 virConfValuePtr value)
868
{
869 870
    virConfEntryPtr cur, prev = NULL;

871 872 873
    if (value && value->type == VIR_CONF_STRING && value->str == NULL)
        return -1;

874 875
    cur = conf->entries;
    while (cur != NULL) {
876
        if ((cur->name != NULL) && (STREQ(cur->name, setting))) {
877 878 879 880 881
            break;
        }
        prev = cur;
        cur = cur->next;
    }
882

883
    if (!cur) {
884
        if (VIR_ALLOC(cur) < 0) {
885
            virReportOOMError();
886 887 888 889 890
            virConfFreeValue(value);
            return (-1);
        }
        cur->comment = NULL;
        if (!(cur->name = strdup(setting))) {
891
            virReportOOMError();
892
            virConfFreeValue(value);
893
            VIR_FREE(cur);
894 895 896 897
            return (-1);
        }
        cur->value = value;
        if (prev) {
898
            cur->next = prev->next;
899 900
            prev->next = cur;
        } else {
901
            cur->next = conf->entries;
902 903 904
            conf->entries = cur;
        }
    } else {
905
        virConfFreeValue(cur->value);
906 907 908 909 910 911
        cur->value = value;
    }
    return (0);
}


D
Daniel Veillard 已提交
912
/**
D
Daniel P. Berrange 已提交
913
 * virConfWriteFile:
D
Daniel Veillard 已提交
914 915 916 917 918 919 920 921
 * @filename: the path to the configuration file.
 * @conf: the conf
 *
 * Writes a configuration file back to a file.
 *
 * Returns the number of bytes written or -1 in case of error.
 */
int
D
Daniel P. Berrange 已提交
922
virConfWriteFile(const char *filename, virConfPtr conf)
D
Daniel Veillard 已提交
923
{
924
    virBuffer buf = VIR_BUFFER_INITIALIZER;
D
Daniel Veillard 已提交
925 926 927
    virConfEntryPtr cur;
    int ret;
    int fd;
928 929
    char *content;
    unsigned int use;
D
Daniel Veillard 已提交
930 931 932 933 934 935

    if (conf == NULL)
        return(-1);

    cur = conf->entries;
    while (cur != NULL) {
936
        virConfSaveEntry(&buf, cur);
937
        cur = cur->next;
D
Daniel Veillard 已提交
938
    }
939

940
    if (virBufferError(&buf)) {
941
        virBufferFreeAndReset(&buf);
942
        virReportOOMError();
943 944 945
        return -1;
    }

D
Daniel Veillard 已提交
946 947
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR );
    if (fd < 0) {
948
        virBufferFreeAndReset(&buf);
949
        virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file"));
950
        return -1;
D
Daniel Veillard 已提交
951 952
    }

953 954 955
    use = virBufferUse(&buf);
    content = virBufferContentAndReset(&buf);
    ret = safewrite(fd, content, use);
956
    VIR_FREE(content);
D
Daniel Veillard 已提交
957
    close(fd);
958
    if (ret != (int)use) {
959
        virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content"));
960
        return -1;
D
Daniel Veillard 已提交
961
    }
962 963

    return ret;
D
Daniel Veillard 已提交
964 965 966
}

/**
D
Daniel P. Berrange 已提交
967
 * virConfWriteMem:
D
Daniel Veillard 已提交
968
 * @memory: pointer to the memory to store the config file
969
 * @len: pointer to the length in bytes of the store, on output the size
D
Daniel Veillard 已提交
970 971 972 973 974 975 976 977 978 979
 * @conf: the conf
 *
 * Writes a configuration file back to a memory area. @len is an IN/OUT
 * parameter, it indicates the size available in bytes, and on output the
 * size required for the configuration file (even if the call fails due to
 * insufficient space).
 *
 * Returns the number of bytes written or -1 in case of error.
 */
int
D
Daniel P. Berrange 已提交
980
virConfWriteMem(char *memory, int *len, virConfPtr conf)
D
Daniel Veillard 已提交
981
{
982
    virBuffer buf = VIR_BUFFER_INITIALIZER;
D
Daniel Veillard 已提交
983
    virConfEntryPtr cur;
984 985
    char *content;
    unsigned int use;
D
Daniel Veillard 已提交
986 987 988 989 990 991

    if ((memory == NULL) || (len == NULL) || (*len <= 0) || (conf == NULL))
        return(-1);

    cur = conf->entries;
    while (cur != NULL) {
992
        virConfSaveEntry(&buf, cur);
993
        cur = cur->next;
D
Daniel Veillard 已提交
994
    }
995

996
    if (virBufferError(&buf)) {
997
        virBufferFreeAndReset(&buf);
998
        virReportOOMError();
999
        return -1;
D
Daniel Veillard 已提交
1000
    }
1001 1002 1003 1004 1005 1006

    use = virBufferUse(&buf);
    content = virBufferContentAndReset(&buf);

    if ((int)use >= *len) {
        *len = (int)use;
1007
        VIR_FREE(content);
1008 1009 1010
        return -1;
    }
    memcpy(memory, content, use);
1011
    VIR_FREE(content);
1012 1013
    *len = use;
    return use;
D
Daniel Veillard 已提交
1014
}