conf.c 25.1 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-2012 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"
E
Eric Blake 已提交
27
#include "virfile.h"
D
Daniel Veillard 已提交
28

29 30
#define VIR_FROM_THIS VIR_FROM_CONF

D
Daniel Veillard 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/************************************************************************
 *									*
 *	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 已提交
53 54 55 56 57 58 59 60

#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 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

/************************************************************************
 *									*
 *		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;
80
    unsigned int flags;
D
Daniel Veillard 已提交
81 82 83 84 85
    virConfEntryPtr entries;
};

/**
 * virConfError:
86
 * @ctxt: the parser context if available or NULL
D
Daniel Veillard 已提交
87 88 89 90 91
 * @error: the error number
 * @info: extra information string
 *
 * Handle an error at the xend daemon interface
 */
92 93
#define virConfError(ctxt, error, info) \
    virConfErrorHelper(__FILE__, __FUNCTION__, __LINE__, ctxt, error, info)
D
Daniel Veillard 已提交
94
static void
95 96 97
virConfErrorHelper(const char *file, const char *func, size_t line,
                   virConfParserCtxtPtr ctxt,
                   virErrorNumber error, const char *info)
D
Daniel Veillard 已提交
98 99 100 101
{
    if (error == VIR_ERR_OK)
        return;

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


/************************************************************************
 *									*
 *		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;
132 133 134
        list->next = NULL;
        virConfFreeValue(list);
        list = next;
D
Daniel Veillard 已提交
135 136 137 138 139 140 141 142 143
    }
}

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

158
virConfPtr
D
Daniel P. Berrange 已提交
159
virConfNew(void)
D
Daniel Veillard 已提交
160 161 162
{
    virConfPtr ret;

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

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

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

215
    if (VIR_ALLOC(ret) < 0) {
216
        virReportOOMError();
D
Daniel Veillard 已提交
217 218
        return(NULL);
    }
219

D
Daniel Veillard 已提交
220 221 222 223 224 225 226 227
    ret->name = name;
    ret->value = value;
    ret->comment = comm;

    if (conf->entries == NULL) {
        conf->entries = ret;
    } else {
        prev = conf->entries;
228 229 230
        while (prev->next != NULL)
            prev = prev->next;
        prev->next = ret;
D
Daniel Veillard 已提交
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    }
    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:
257 258
            return(-1);
        case VIR_CONF_LONG:
259
            virBufferAsprintf(buf, "%ld", val->l);
260 261 262
            break;
        case VIR_CONF_STRING:
            if (strchr(val->str, '\n') != NULL) {
263
                virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str);
264
            } else if (strchr(val->str, '"') == NULL) {
265
                virBufferAsprintf(buf, "\"%s\"", val->str);
266
            } else if (strchr(val->str, '\'') == NULL) {
267
                virBufferAsprintf(buf, "'%s'", val->str);
268
            } else {
269
                virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str);
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
            }
            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 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
    }
    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);
309 310 311 312 313 314
        virBufferAddLit(buf, " = ");
        virConfSaveValue(buf, cur->value);
        if (cur->comment != NULL) {
            virBufferAddLit(buf, " #");
            virBufferAdd(buf, cur->comment, -1);
        }
D
Daniel Veillard 已提交
315
    } else if (cur->comment != NULL) {
316 317
        virBufferAddLit(buf, "#");
        virBufferAdd(buf, cur->comment, -1);
D
Daniel Veillard 已提交
318
    }
319
    virBufferAddLit(buf, "\n");
D
Daniel Veillard 已提交
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
    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;
346
        NEXT;
D
Daniel Veillard 已提交
347 348 349
    } else if (CUR == '+') {
        NEXT;
    }
J
Jim Meyering 已提交
350
    if ((ctxt->cur >= ctxt->end) || (!c_isdigit(CUR))) {
351
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number"));
352
        return(-1);
D
Daniel Veillard 已提交
353
    }
J
Jim Meyering 已提交
354
    while ((ctxt->cur < ctxt->end) && (c_isdigit(CUR))) {
D
Daniel Veillard 已提交
355
        l = l * 10 + (CUR - '0');
356
        NEXT;
D
Daniel Veillard 已提交
357
    }
358 359
    if (neg)
        l = -l;
D
Daniel Veillard 已提交
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    *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;
380 381 382 383
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR)))
            NEXT;
        if (CUR != '\'') {
384
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
385 386 387
            return(NULL);
        }
        ret = strndup(base, ctxt->cur - base);
388
        if (ret == NULL) {
389
            virReportOOMError();
390 391
            return NULL;
        }
392
        NEXT;
393 394 395
    } else if ((ctxt->cur + 6 < ctxt->end) &&
               (STRPREFIX(ctxt->cur, "\"\"\""))) {
        /* String starts with python-style triple quotes """ */
396 397
        ctxt->cur += 3;
        base = ctxt->cur;
398

399
        /* Find the ending triple quotes */
400
        while ((ctxt->cur + 2 < ctxt->end) &&
401
               !(STRPREFIX(ctxt->cur, "\"\"\""))) {
402 403 404
            if (CUR == '\n')
                ctxt->line++;
            NEXT;
405
        }
406 407

        if (!STRPREFIX(ctxt->cur, "\"\"\"")) {
408
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
409 410 411
            return(NULL);
        }
        ret = strndup(base, ctxt->cur - base);
412
        if (ret == NULL) {
413
            virReportOOMError();
414 415
            return NULL;
        }
416
        ctxt->cur += 3;
D
Daniel Veillard 已提交
417 418
    } else if (CUR == '"') {
        NEXT;
419 420 421 422
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR)))
            NEXT;
        if (CUR != '"') {
423
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
424 425 426
            return(NULL);
        }
        ret = strndup(base, ctxt->cur - base);
427
        if (ret == NULL) {
428
            virReportOOMError();
429 430
            return NULL;
        }
431
        NEXT;
D
Daniel Veillard 已提交
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
    }
    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 已提交
452
    SKIP_BLANKS;
D
Daniel Veillard 已提交
453
    if (ctxt->cur >= ctxt->end) {
454
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
455
        return(NULL);
D
Daniel Veillard 已提交
456 457 458 459
    }
    if ((CUR == '"') || (CUR == '\'')) {
        type = VIR_CONF_STRING;
        str = virConfParseString(ctxt);
460 461
        if (str == NULL)
            return(NULL);
D
Daniel Veillard 已提交
462
    } else if (CUR == '[') {
463 464 465 466 467
        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 已提交
468 469
        type = VIR_CONF_LIST;
        NEXT;
J
Jim Meyering 已提交
470
        SKIP_BLANKS_AND_EOL;
471
        if ((ctxt->cur < ctxt->end) && (CUR != ']')) {
472 473
            if ((lst = virConfParseValue(ctxt)) == NULL)
                return(NULL);
J
Jim Meyering 已提交
474
            SKIP_BLANKS_AND_EOL;
475 476
        }
        while ((ctxt->cur < ctxt->end) && (CUR != ']')) {
477 478 479 480 481 482 483

            /* 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);

484
            if (CUR != ',') {
485 486
                virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                             _("expecting a separator in list"));
487 488 489 490
                virConfFreeList(lst);
                return(NULL);
            }
            NEXT;
J
Jim Meyering 已提交
491
            SKIP_BLANKS_AND_EOL;
492 493 494 495 496 497 498 499 500 501 502
            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 已提交
503
            SKIP_BLANKS_AND_EOL;
504 505 506 507
        }
        if (CUR == ']') {
            NEXT;
        } else {
508 509
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                         _("list is not closed with ]"));
510 511 512
            virConfFreeList(lst);
            return(NULL);
        }
J
Jim Meyering 已提交
513
    } else if (c_isdigit(CUR) || (CUR == '-') || (CUR == '+')) {
514 515 516 517 518
        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 已提交
519
        if (virConfParseLong(ctxt, &l) < 0) {
520 521
            return(NULL);
        }
D
Daniel Veillard 已提交
522 523
        type = VIR_CONF_LONG;
    } else {
524
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
525
        return(NULL);
D
Daniel Veillard 已提交
526
    }
527
    if (VIR_ALLOC(ret) < 0) {
528
        virReportOOMError();
529 530
        virConfFreeList(lst);
        VIR_FREE(str);
D
Daniel Veillard 已提交
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
        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 已提交
554
    SKIP_BLANKS;
D
Daniel Veillard 已提交
555 556
    base = ctxt->cur;
    /* TODO: probably need encoding support and UTF-8 parsing ! */
557 558
    if (!c_isalpha(CUR) &&
        !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) {
559
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name"));
560
        return(NULL);
D
Daniel Veillard 已提交
561
    }
562 563
    while ((ctxt->cur < ctxt->end) &&
           (c_isalnum(CUR) || (CUR == '_') ||
564
            ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) &&
565
             ((CUR == ':') || (CUR == '.') || (CUR == '-')))))
D
Daniel Veillard 已提交
566 567 568
        NEXT;
    ret = strndup(base, ctxt->cur - base);
    if (ret == NULL) {
569
        virReportOOMError();
D
Daniel Veillard 已提交
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 595
        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) {
596
        virReportOOMError();
D
Daniel Veillard 已提交
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
        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 已提交
614
    SKIP_BLANKS;
D
Daniel Veillard 已提交
615
    if (ctxt->cur >= ctxt->end)
616
        return(0);
D
Daniel Veillard 已提交
617
    if (IS_EOL(CUR)) {
J
Jim Meyering 已提交
618
        SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
619
    } else if (CUR == ';') {
620
        NEXT;
J
Jim Meyering 已提交
621
        SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
622
    } else {
623
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator"));
624
        return(-1);
D
Daniel Veillard 已提交
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
    }
    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 已提交
645
    SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
646
    if (CUR == '#') {
P
Phil Petty 已提交
647
        return virConfParseComment(ctxt);
D
Daniel Veillard 已提交
648 649 650
    }
    name = virConfParseName(ctxt);
    if (name == NULL)
P
Phil Petty 已提交
651
        return -1;
J
Jim Meyering 已提交
652
    SKIP_BLANKS;
D
Daniel Veillard 已提交
653
    if (CUR != '=') {
654
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment"));
P
Phil Petty 已提交
655 656
        VIR_FREE(name);
        return -1;
D
Daniel Veillard 已提交
657 658
    }
    NEXT;
J
Jim Meyering 已提交
659
    SKIP_BLANKS;
D
Daniel Veillard 已提交
660 661
    value = virConfParseValue(ctxt);
    if (value == NULL) {
662
        VIR_FREE(name);
P
Phil Petty 已提交
663
        return -1;
D
Daniel Veillard 已提交
664
    }
J
Jim Meyering 已提交
665
    SKIP_BLANKS;
D
Daniel Veillard 已提交
666
    if (CUR == '#') {
667 668 669 670 671
        NEXT;
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
        comm = strndup(base, ctxt->cur - base);
        if (comm == NULL) {
672
            virReportOOMError();
673
            VIR_FREE(name);
674
            virConfFreeValue(value);
P
Phil Petty 已提交
675
            return -1;
676
        }
D
Daniel Veillard 已提交
677 678
    }
    if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) {
679
        VIR_FREE(name);
680
        virConfFreeValue(value);
681
        VIR_FREE(comm);
P
Phil Petty 已提交
682
        return -1;
D
Daniel Veillard 已提交
683
    }
P
Phil Petty 已提交
684
    return 0;
D
Daniel Veillard 已提交
685 686 687 688 689 690 691
}

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

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

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

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

    return(ctxt.conf);

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

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

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

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

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

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

763
    conf = virConfParse(filename, content, len, flags);
764

765
    VIR_FREE(content);
766 767

    return conf;
D
Daniel Veillard 已提交
768 769 770
}

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

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

/**
D
Daniel P. Berrange 已提交
796
 * virConfFree:
D
Daniel Veillard 已提交
797 798 799 800 801 802 803
 * @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 已提交
804
virConfFree(virConfPtr conf)
D
Daniel Veillard 已提交
805
{
806
    virConfEntryPtr tmp;
807 808
    if (conf == NULL)
        return 0;
809 810 811 812

    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
    virConfEntryPtr cur;

839 840 841
    if (conf == NULL)
        return NULL;

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

854
/**
D
Daniel P. Berrange 已提交
855
 * virConfSetValue:
856 857 858 859 860 861 862 863 864 865 866
 * @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.
 */
867
int
D
Daniel P. Berrange 已提交
868 869 870
virConfSetValue (virConfPtr conf,
                 const char *setting,
                 virConfValuePtr value)
871
{
872 873
    virConfEntryPtr cur, prev = NULL;

874 875 876
    if (value && value->type == VIR_CONF_STRING && value->str == NULL)
        return -1;

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

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


D
Daniel Veillard 已提交
915
/**
D
Daniel P. Berrange 已提交
916
 * virConfWriteFile:
D
Daniel Veillard 已提交
917 918 919 920 921 922 923 924
 * @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 已提交
925
virConfWriteFile(const char *filename, virConfPtr conf)
D
Daniel Veillard 已提交
926
{
927
    virBuffer buf = VIR_BUFFER_INITIALIZER;
D
Daniel Veillard 已提交
928 929 930
    virConfEntryPtr cur;
    int ret;
    int fd;
931 932
    char *content;
    unsigned int use;
D
Daniel Veillard 已提交
933 934 935 936 937 938

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

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

943
    if (virBufferError(&buf)) {
944
        virBufferFreeAndReset(&buf);
945
        virReportOOMError();
946 947 948
        return -1;
    }

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

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

    return ret;
D
Daniel Veillard 已提交
967 968 969
}

/**
D
Daniel P. Berrange 已提交
970
 * virConfWriteMem:
D
Daniel Veillard 已提交
971
 * @memory: pointer to the memory to store the config file
972
 * @len: pointer to the length in bytes of the store, on output the size
D
Daniel Veillard 已提交
973 974 975 976 977 978 979 980 981 982
 * @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 已提交
983
virConfWriteMem(char *memory, int *len, virConfPtr conf)
D
Daniel Veillard 已提交
984
{
985
    virBuffer buf = VIR_BUFFER_INITIALIZER;
D
Daniel Veillard 已提交
986
    virConfEntryPtr cur;
987 988
    char *content;
    unsigned int use;
D
Daniel Veillard 已提交
989 990 991 992 993 994

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

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

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

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

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