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

/**
 * virConfParse:
 * @filename: the name to report errors
 * @content: the configuration content in memory
 * @len: the length in bytes
683
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
684 685 686 687 688 689 690 691
 *
 * 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
692 693
virConfParse(const char *filename, const char *content, int len,
             unsigned int flags) {
D
Daniel Veillard 已提交
694 695 696 697 698 699 700
    virConfParserCtxt ctxt;

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

701
    ctxt.conf = virConfCreate(filename, flags);
D
Daniel Veillard 已提交
702 703 704 705 706
    if (ctxt.conf == NULL)
        return(NULL);

    while (ctxt.cur < ctxt.end) {
        if (virConfParseStatement(&ctxt) < 0)
707 708 709
            goto error;
        if (virConfParseSeparator(&ctxt) < 0)
            goto error;
D
Daniel Veillard 已提交
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
    }

    return(ctxt.conf);

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

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

725 726 727
/* 10 MB limit on config file size as a sanity check */
#define MAX_CONFIG_FILE_SIZE (1024*1024*10)

D
Daniel Veillard 已提交
728
/**
D
Daniel P. Berrange 已提交
729
 * virConfReadFile:
D
Daniel Veillard 已提交
730
 * @filename: the path to the configuration file.
731
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
732 733 734 735 736 737 738
 *
 * 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
739
virConfReadFile(const char *filename, unsigned int flags)
D
Daniel Veillard 已提交
740
{
741
    char *content;
D
Daniel Veillard 已提交
742
    int len;
743
    virConfPtr conf;
D
Daniel Veillard 已提交
744 745

    if (filename == NULL) {
746
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
D
Daniel Veillard 已提交
747 748
        return(NULL);
    }
749 750 751

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

754
    conf = virConfParse(filename, content, len, flags);
755

756
    VIR_FREE(content);
757 758

    return conf;
D
Daniel Veillard 已提交
759 760 761
}

/**
D
Daniel P. Berrange 已提交
762
 * virConfReadMem:
D
Daniel Veillard 已提交
763
 * @memory: pointer to the content of the configuration file
D
Daniel Veillard 已提交
764
 * @len: length in byte
765
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
766 767 768 769 770 771 772 773
 *
 * 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
774
virConfReadMem(const char *memory, int len, unsigned int flags)
D
Daniel Veillard 已提交
775 776
{
    if ((memory == NULL) || (len < 0)) {
777
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
D
Daniel Veillard 已提交
778 779 780 781 782
        return(NULL);
    }
    if (len == 0)
        len = strlen(memory);

783
    return(virConfParse("memory conf", memory, len, flags));
D
Daniel Veillard 已提交
784 785 786
}

/**
D
Daniel P. Berrange 已提交
787
 * virConfFree:
D
Daniel Veillard 已提交
788 789 790 791 792 793 794
 * @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 已提交
795
virConfFree(virConfPtr conf)
D
Daniel Veillard 已提交
796
{
797
    virConfEntryPtr tmp;
D
Daniel Veillard 已提交
798
    if (conf == NULL) {
799
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
800 801 802 803 804 805
        return(-1);
    }

    tmp = conf->entries;
    while (tmp) {
        virConfEntryPtr next;
806
        VIR_FREE(tmp->name);
807
        virConfFreeValue(tmp->value);
808
        VIR_FREE(tmp->comment);
809
        next = tmp->next;
810
        VIR_FREE(tmp);
811
        tmp = next;
D
Daniel Veillard 已提交
812
    }
813
    VIR_FREE(conf);
D
Daniel Veillard 已提交
814 815 816 817
    return(0);
}

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

    cur = conf->entries;
    while (cur != NULL) {
834 835 836 837
        if ((cur->name != NULL) &&
            ((conf->flags & VIR_CONF_FLAG_VMX_FORMAT &&
              STRCASEEQ(cur->name, setting)) ||
             STREQ(cur->name, setting)))
838
            return(cur->value);
839 840 841
        cur = cur->next;
    }
    return(NULL);
D
Daniel Veillard 已提交
842 843
}

844
/**
D
Daniel P. Berrange 已提交
845
 * virConfSetValue:
846 847 848 849 850 851 852 853 854 855 856
 * @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.
 */
857
int
D
Daniel P. Berrange 已提交
858 859 860
virConfSetValue (virConfPtr conf,
                 const char *setting,
                 virConfValuePtr value)
861
{
862 863
    virConfEntryPtr cur, prev = NULL;

864 865 866
    if (value && value->type == VIR_CONF_STRING && value->str == NULL)
        return -1;

867 868
    cur = conf->entries;
    while (cur != NULL) {
869
        if ((cur->name != NULL) && (STREQ(cur->name, setting))) {
870 871 872 873 874
            break;
        }
        prev = cur;
        cur = cur->next;
    }
875

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


D
Daniel Veillard 已提交
907
/**
D
Daniel P. Berrange 已提交
908
 * virConfWriteFile:
D
Daniel Veillard 已提交
909 910 911 912 913 914 915 916
 * @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 已提交
917
virConfWriteFile(const char *filename, virConfPtr conf)
D
Daniel Veillard 已提交
918
{
919
    virBuffer buf = VIR_BUFFER_INITIALIZER;
D
Daniel Veillard 已提交
920 921 922
    virConfEntryPtr cur;
    int ret;
    int fd;
923 924
    char *content;
    unsigned int use;
D
Daniel Veillard 已提交
925 926 927 928 929 930

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

    cur = conf->entries;
    while (cur != NULL) {
931
        virConfSaveEntry(&buf, cur);
932
        cur = cur->next;
D
Daniel Veillard 已提交
933
    }
934

935
    if (virBufferError(&buf)) {
936
        virBufferFreeAndReset(&buf);
937
        virReportOOMError();
938 939 940
        return -1;
    }

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

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

    return ret;
D
Daniel Veillard 已提交
959 960 961
}

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

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

    cur = conf->entries;
    while (cur != NULL) {
987
        virConfSaveEntry(&buf, cur);
988
        cur = cur->next;
D
Daniel Veillard 已提交
989
    }
990

991
    if (virBufferError(&buf)) {
992
        virBufferFreeAndReset(&buf);
993
        virReportOOMError();
994
        return -1;
D
Daniel Veillard 已提交
995
    }
996 997 998 999 1000 1001

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

    if ((int)use >= *len) {
        *len = (int)use;
1002
        VIR_FREE(content);
1003 1004 1005
        return -1;
    }
    memcpy(memory, content, use);
1006
    VIR_FREE(content);
1007 1008
    *len = use;
    return use;
D
Daniel Veillard 已提交
1009
}