virconf.c 26.7 KB
Newer Older
1 2
/*
 * virconf.c: parser for a subset of the Python encoded Xen configuration files
D
Daniel Veillard 已提交
3
 *
4
 * Copyright (C) 2006-2014 Red Hat, Inc.
D
Daniel Veillard 已提交
5
 *
O
Osier Yang 已提交
6 7 8 9 10 11 12 13 14 15 16
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
D
Daniel Veillard 已提交
19 20 21 22
 *
 * Daniel Veillard <veillard@redhat.com>
 */

23
#include <config.h>
24

D
Daniel Veillard 已提交
25 26 27 28 29 30 31
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

32
#include "virerror.h"
33
#include "virbuffer.h"
34
#include "virconf.h"
35
#include "virutil.h"
J
Jim Meyering 已提交
36
#include "c-ctype.h"
37
#include "virlog.h"
38
#include "viralloc.h"
E
Eric Blake 已提交
39
#include "virfile.h"
40
#include "virstring.h"
D
Daniel Veillard 已提交
41

42 43
#define VIR_FROM_THIS VIR_FROM_CONF

44 45
VIR_LOG_INIT("util.conf");

D
Daniel Veillard 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
/************************************************************************
 *									*
 *	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 已提交
68 69 70 71

#define SKIP_BLANKS_AND_EOL                                             \
  do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR) || IS_EOL(CUR))) { \
         if (CUR == '\n') ctxt->line++;	                                \
72
         ctxt->cur++; } } while (0)
J
Jim Meyering 已提交
73 74 75
#define SKIP_BLANKS                                                     \
  do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR)))              \
          ctxt->cur++; } while (0)
D
Daniel Veillard 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

/************************************************************************
 *									*
 *		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;
95
    unsigned int flags;
D
Daniel Veillard 已提交
96 97 98 99 100
    virConfEntryPtr entries;
};

/**
 * virConfError:
101
 * @ctxt: the parser context if available or NULL
D
Daniel Veillard 已提交
102 103 104 105 106
 * @error: the error number
 * @info: extra information string
 *
 * Handle an error at the xend daemon interface
 */
107 108
#define virConfError(ctxt, error, info) \
    virConfErrorHelper(__FILE__, __FUNCTION__, __LINE__, ctxt, error, info)
D
Daniel Veillard 已提交
109
static void
110 111 112
virConfErrorHelper(const char *file, const char *func, size_t line,
                   virConfParserCtxtPtr ctxt,
                   virErrorNumber error, const char *info)
D
Daniel Veillard 已提交
113 114 115 116
{
    if (error == VIR_ERR_OK)
        return;

117 118
    /* Construct the string 'filename:line: info' if we have that. */
    if (ctxt && ctxt->filename) {
119 120
        virReportErrorHelper(VIR_FROM_CONF, error, file, func, line,
                             _("%s:%d: %s"), ctxt->filename, ctxt->line, info);
121
    } else {
122 123
        virReportErrorHelper(VIR_FROM_CONF, error, file, func, line,
                             "%s", info);
124
    }
D
Daniel Veillard 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
}


/************************************************************************
 *									*
 *		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;
147 148 149
        list->next = NULL;
        virConfFreeValue(list);
        list = next;
D
Daniel Veillard 已提交
150 151 152 153 154 155 156 157 158
    }
}

/**
 * virConfFreeValue:
 * @val: the value to free
 *
 * Free a value
 */
159
void
D
Daniel P. Berrange 已提交
160
virConfFreeValue(virConfValuePtr val)
D
Daniel Veillard 已提交
161 162 163
{
    if (val == NULL)
        return;
164 165
    if (val->type == VIR_CONF_STRING &&
        val->str != NULL)
166
        VIR_FREE(val->str);
167 168
    if (val->type == VIR_CONF_LIST &&
        val->list != NULL)
D
Daniel Veillard 已提交
169
        virConfFreeList(val->list);
170
    VIR_FREE(val);
D
Daniel Veillard 已提交
171 172
}

173
virConfPtr
D
Daniel P. Berrange 已提交
174
virConfNew(void)
D
Daniel Veillard 已提交
175 176 177
{
    virConfPtr ret;

178
    if (VIR_ALLOC(ret) < 0)
179
        return NULL;
180
    ret->filename = NULL;
181
    ret->flags = 0;
182

183
    return ret;
184
}
D
Daniel Veillard 已提交
185

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

/**
 * 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)
224
        return NULL;
D
Daniel Veillard 已提交
225
    if ((comm == NULL) && (name == NULL))
226
        return NULL;
227

228
    if (VIR_ALLOC(ret) < 0)
229
        return NULL;
230

D
Daniel Veillard 已提交
231 232 233 234 235 236 237 238
    ret->name = name;
    ret->value = value;
    ret->comment = comm;

    if (conf->entries == NULL) {
        conf->entries = ret;
    } else {
        prev = conf->entries;
239 240 241
        while (prev->next != NULL)
            prev = prev->next;
        prev->next = ret;
D
Daniel Veillard 已提交
242
    }
243
    return ret;
D
Daniel Veillard 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
}

/************************************************************************
 *									*
 *			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)
265
        return -1;
D
Daniel Veillard 已提交
266 267
    switch (val->type) {
        case VIR_CONF_NONE:
268
            return -1;
269
        case VIR_CONF_LONG:
270
            virBufferAsprintf(buf, "%ld", val->l);
271 272 273
            break;
        case VIR_CONF_STRING:
            if (strchr(val->str, '\n') != NULL) {
274
                virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str);
275
            } else if (strchr(val->str, '"') == NULL) {
276
                virBufferAsprintf(buf, "\"%s\"", val->str);
277
            } else if (strchr(val->str, '\'') == NULL) {
278
                virBufferAsprintf(buf, "'%s'", val->str);
279
            } else {
280
                virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str);
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
            }
            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:
301
            return -1;
D
Daniel Veillard 已提交
302
    }
303
    return 0;
D
Daniel Veillard 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
}

/**
 * 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);
320 321 322 323 324 325
        virBufferAddLit(buf, " = ");
        virConfSaveValue(buf, cur->value);
        if (cur->comment != NULL) {
            virBufferAddLit(buf, " #");
            virBufferAdd(buf, cur->comment, -1);
        }
D
Daniel Veillard 已提交
326
    } else if (cur->comment != NULL) {
327 328
        virBufferAddLit(buf, "#");
        virBufferAdd(buf, cur->comment, -1);
D
Daniel Veillard 已提交
329
    }
330
    virBufferAddLit(buf, "\n");
331
    return 0;
D
Daniel Veillard 已提交
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
}

/************************************************************************
 *									*
 *			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;
357
        NEXT;
D
Daniel Veillard 已提交
358 359 360
    } else if (CUR == '+') {
        NEXT;
    }
J
Jim Meyering 已提交
361
    if ((ctxt->cur >= ctxt->end) || (!c_isdigit(CUR))) {
362
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number"));
363
        return -1;
D
Daniel Veillard 已提交
364
    }
J
Jim Meyering 已提交
365
    while ((ctxt->cur < ctxt->end) && (c_isdigit(CUR))) {
D
Daniel Veillard 已提交
366
        l = l * 10 + (CUR - '0');
367
        NEXT;
D
Daniel Veillard 已提交
368
    }
369 370
    if (neg)
        l = -l;
D
Daniel Veillard 已提交
371
    *val = l;
372
    return 0;
D
Daniel Veillard 已提交
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
}

/**
 * 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;
391 392 393 394
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR)))
            NEXT;
        if (CUR != '\'') {
395
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
396
            return NULL;
397
        }
398
        if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0)
399
            return NULL;
400
        NEXT;
401 402 403
    } else if ((ctxt->cur + 6 < ctxt->end) &&
               (STRPREFIX(ctxt->cur, "\"\"\""))) {
        /* String starts with python-style triple quotes """ */
404 405
        ctxt->cur += 3;
        base = ctxt->cur;
406

407
        /* Find the ending triple quotes */
408
        while ((ctxt->cur + 2 < ctxt->end) &&
409
               !(STRPREFIX(ctxt->cur, "\"\"\""))) {
410 411 412
            if (CUR == '\n')
                ctxt->line++;
            NEXT;
413
        }
414 415

        if (!STRPREFIX(ctxt->cur, "\"\"\"")) {
416
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
417
            return NULL;
418
        }
419
        if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0)
420
            return NULL;
421
        ctxt->cur += 3;
D
Daniel Veillard 已提交
422 423
    } else if (CUR == '"') {
        NEXT;
424 425 426 427
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR)))
            NEXT;
        if (CUR != '"') {
428
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
429
            return NULL;
430
        }
431
        if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0)
432
            return NULL;
433
        NEXT;
434 435 436 437 438 439 440 441 442 443
    } else if (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) {
        base = ctxt->cur;
        /* LXC config format doesn't support comments after the value */
        while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR)))
            NEXT;
        /* Reverse to exclude the trailing blanks from the value */
        while ((ctxt->cur > base) && (c_isblank(CUR)))
            ctxt->cur--;
        if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0)
            return NULL;
D
Daniel Veillard 已提交
444
    }
445
    return ret;
D
Daniel Veillard 已提交
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
}

/**
 * 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 已提交
464
    SKIP_BLANKS;
D
Daniel Veillard 已提交
465
    if (ctxt->cur >= ctxt->end) {
466
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
467
        return NULL;
D
Daniel Veillard 已提交
468
    }
469 470
    if ((CUR == '"') || (CUR == '\'') ||
         (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT)) {
D
Daniel Veillard 已提交
471 472
        type = VIR_CONF_STRING;
        str = virConfParseString(ctxt);
473
        if (str == NULL)
474
            return NULL;
D
Daniel Veillard 已提交
475
    } else if (CUR == '[') {
476 477 478
        if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                         _("lists not allowed in VMX format"));
479
            return NULL;
480
        }
D
Daniel Veillard 已提交
481 482
        type = VIR_CONF_LIST;
        NEXT;
J
Jim Meyering 已提交
483
        SKIP_BLANKS_AND_EOL;
484
        if ((ctxt->cur < ctxt->end) && (CUR != ']')) {
485
            if ((lst = virConfParseValue(ctxt)) == NULL)
486
                return NULL;
J
Jim Meyering 已提交
487
            SKIP_BLANKS_AND_EOL;
488 489
        }
        while ((ctxt->cur < ctxt->end) && (CUR != ']')) {
490 491 492 493 494

            /* 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.  */
495
            sa_assert(lst);
496

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

/**
 * 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 已提交
566
    SKIP_BLANKS;
D
Daniel Veillard 已提交
567 568
    base = ctxt->cur;
    /* TODO: probably need encoding support and UTF-8 parsing ! */
569 570
    if (!c_isalpha(CUR) &&
        !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) {
571
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name"));
572
        return NULL;
D
Daniel Veillard 已提交
573
    }
574 575
    while ((ctxt->cur < ctxt->end) &&
           (c_isalnum(CUR) || (CUR == '_') ||
576
            ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) &&
577 578 579
             ((CUR == ':') || (CUR == '.') || (CUR == '-'))) ||
            ((ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) &&
             (CUR == '.'))))
D
Daniel Veillard 已提交
580
        NEXT;
581
    if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0)
582 583
        return NULL;
    return ret;
D
Daniel Veillard 已提交
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
}

/**
 * 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 != '#')
601
        return -1;
D
Daniel Veillard 已提交
602 603 604
    NEXT;
    base = ctxt->cur;
    while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
605
    if (VIR_STRNDUP(comm, base, ctxt->cur - base) < 0)
606
        return -1;
607 608 609 610
    if (virConfAddEntry(ctxt->conf, NULL, NULL, comm) == NULL) {
        VIR_FREE(comm);
        return -1;
    }
611
    return 0;
D
Daniel Veillard 已提交
612 613 614 615 616 617 618 619 620 621 622 623 624
}

/**
 * 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 已提交
625
    SKIP_BLANKS;
D
Daniel Veillard 已提交
626
    if (ctxt->cur >= ctxt->end)
627
        return 0;
D
Daniel Veillard 已提交
628
    if (IS_EOL(CUR)) {
J
Jim Meyering 已提交
629
        SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
630
    } else if (CUR == ';') {
631
        NEXT;
J
Jim Meyering 已提交
632
        SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
633
    } else {
634
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator"));
635
        return -1;
D
Daniel Veillard 已提交
636
    }
637
    return 0;
D
Daniel Veillard 已提交
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
}

/**
 * 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 已提交
656
    SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
657
    if (CUR == '#') {
P
Phil Petty 已提交
658
        return virConfParseComment(ctxt);
D
Daniel Veillard 已提交
659 660 661
    }
    name = virConfParseName(ctxt);
    if (name == NULL)
P
Phil Petty 已提交
662
        return -1;
J
Jim Meyering 已提交
663
    SKIP_BLANKS;
D
Daniel Veillard 已提交
664
    if (CUR != '=') {
665
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment"));
P
Phil Petty 已提交
666 667
        VIR_FREE(name);
        return -1;
D
Daniel Veillard 已提交
668 669
    }
    NEXT;
J
Jim Meyering 已提交
670
    SKIP_BLANKS;
D
Daniel Veillard 已提交
671 672
    value = virConfParseValue(ctxt);
    if (value == NULL) {
673
        VIR_FREE(name);
P
Phil Petty 已提交
674
        return -1;
D
Daniel Veillard 已提交
675
    }
J
Jim Meyering 已提交
676
    SKIP_BLANKS;
D
Daniel Veillard 已提交
677
    if (CUR == '#') {
678 679 680
        NEXT;
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
681
        if (VIR_STRNDUP(comm, base, ctxt->cur - base) < 0) {
682
            VIR_FREE(name);
683
            virConfFreeValue(value);
P
Phil Petty 已提交
684
            return -1;
685
        }
D
Daniel Veillard 已提交
686 687
    }
    if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) {
688
        VIR_FREE(name);
689
        virConfFreeValue(value);
690
        VIR_FREE(comm);
P
Phil Petty 已提交
691
        return -1;
D
Daniel Veillard 已提交
692
    }
P
Phil Petty 已提交
693
    return 0;
D
Daniel Veillard 已提交
694 695 696 697 698 699 700
}

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

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

720
    ctxt.conf = virConfCreate(filename, flags);
D
Daniel Veillard 已提交
721
    if (ctxt.conf == NULL)
722
        return NULL;
D
Daniel Veillard 已提交
723 724 725

    while (ctxt.cur < ctxt.end) {
        if (virConfParseStatement(&ctxt) < 0)
726 727 728
            goto error;
        if (virConfParseSeparator(&ctxt) < 0)
            goto error;
D
Daniel Veillard 已提交
729 730
    }

731
    return ctxt.conf;
D
Daniel Veillard 已提交
732

733
 error:
D
Daniel Veillard 已提交
734
    virConfFree(ctxt.conf);
735
    return NULL;
D
Daniel Veillard 已提交
736 737 738 739 740 741 742 743
}

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

744 745 746
/* 10 MB limit on config file size as a sanity check */
#define MAX_CONFIG_FILE_SIZE (1024*1024*10)

D
Daniel Veillard 已提交
747
/**
D
Daniel P. Berrange 已提交
748
 * virConfReadFile:
D
Daniel Veillard 已提交
749
 * @filename: the path to the configuration file.
750
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
751 752 753
 *
 * Reads a configuration file.
 *
E
Eric Blake 已提交
754
 * Returns a handle to lookup settings or NULL if it failed to
D
Daniel Veillard 已提交
755 756 757
 *         read or parse the file, use virConfFree() to free the data.
 */
virConfPtr
758
virConfReadFile(const char *filename, unsigned int flags)
D
Daniel Veillard 已提交
759
{
760
    char *content;
D
Daniel Veillard 已提交
761
    int len;
762
    virConfPtr conf;
D
Daniel Veillard 已提交
763

764 765
    VIR_DEBUG("filename=%s", NULLSTR(filename));

D
Daniel Veillard 已提交
766
    if (filename == NULL) {
767
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
768
        return NULL;
D
Daniel Veillard 已提交
769
    }
770 771 772

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

775
    conf = virConfParse(filename, content, len, flags);
776

777
    VIR_FREE(content);
778 779

    return conf;
D
Daniel Veillard 已提交
780 781 782
}

/**
D
Daniel P. Berrange 已提交
783
 * virConfReadMem:
D
Daniel Veillard 已提交
784
 * @memory: pointer to the content of the configuration file
D
Daniel Veillard 已提交
785
 * @len: length in byte
786
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
787 788 789 790
 *
 * Reads a configuration file loaded in memory. The string can be
 * zero terminated in which case @len can be 0
 *
E
Eric Blake 已提交
791
 * Returns a handle to lookup settings or NULL if it failed to
D
Daniel Veillard 已提交
792 793 794
 *         parse the content, use virConfFree() to free the data.
 */
virConfPtr
795
virConfReadMem(const char *memory, int len, unsigned int flags)
D
Daniel Veillard 已提交
796 797
{
    if ((memory == NULL) || (len < 0)) {
798
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
799
        return NULL;
D
Daniel Veillard 已提交
800 801 802 803
    }
    if (len == 0)
        len = strlen(memory);

804
    return virConfParse("memory conf", memory, len, flags);
D
Daniel Veillard 已提交
805 806 807
}

/**
D
Daniel P. Berrange 已提交
808
 * virConfFree:
D
Daniel Veillard 已提交
809 810 811 812 813 814 815
 * @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 已提交
816
virConfFree(virConfPtr conf)
D
Daniel Veillard 已提交
817
{
818
    virConfEntryPtr tmp;
819 820
    if (conf == NULL)
        return 0;
821 822 823 824

    tmp = conf->entries;
    while (tmp) {
        virConfEntryPtr next;
825
        VIR_FREE(tmp->name);
826
        virConfFreeValue(tmp->value);
827
        VIR_FREE(tmp->comment);
828
        next = tmp->next;
829
        VIR_FREE(tmp);
830
        tmp = next;
D
Daniel Veillard 已提交
831
    }
832
    VIR_FREE(conf);
833
    return 0;
D
Daniel Veillard 已提交
834 835 836
}

/**
D
Daniel P. Berrange 已提交
837
 * virConfGetValue:
D
Daniel Veillard 已提交
838 839 840 841 842
 * @conf: a configuration file handle
 * @entry: the name of the entry
 *
 * Lookup the value associated to this entry in the configuration file
 *
843
 * Returns a pointer to the value or NULL if the lookup failed, the data
D
Daniel Veillard 已提交
844 845 846
 *         associated will be freed when virConfFree() is called
 */
virConfValuePtr
D
Daniel P. Berrange 已提交
847
virConfGetValue(virConfPtr conf, const char *setting)
D
Daniel Veillard 已提交
848
{
849 850
    virConfEntryPtr cur;

851 852 853
    if (conf == NULL)
        return NULL;

854 855
    cur = conf->entries;
    while (cur != NULL) {
856 857 858 859
        if ((cur->name != NULL) &&
            ((conf->flags & VIR_CONF_FLAG_VMX_FORMAT &&
              STRCASEEQ(cur->name, setting)) ||
             STREQ(cur->name, setting)))
860
            return cur->value;
861 862
        cur = cur->next;
    }
863
    return NULL;
D
Daniel Veillard 已提交
864 865
}

866
/**
D
Daniel P. Berrange 已提交
867
 * virConfSetValue:
868 869 870 871 872 873 874 875 876 877 878
 * @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.
 */
879
int
880 881 882
virConfSetValue(virConfPtr conf,
                const char *setting,
                virConfValuePtr value)
883
{
884 885
    virConfEntryPtr cur, prev = NULL;

886 887 888
    if (value && value->type == VIR_CONF_STRING && value->str == NULL)
        return -1;

889 890
    cur = conf->entries;
    while (cur != NULL) {
891
        if ((cur->name != NULL) && (STREQ(cur->name, setting))) {
892 893 894 895 896
            break;
        }
        prev = cur;
        cur = cur->next;
    }
897

898
    if (!cur) {
899
        if (VIR_ALLOC(cur) < 0) {
900
            virConfFreeValue(value);
901
            return -1;
902 903
        }
        cur->comment = NULL;
904
        if (VIR_STRDUP(cur->name, setting) < 0) {
905
            virConfFreeValue(value);
906
            VIR_FREE(cur);
907
            return -1;
908 909 910
        }
        cur->value = value;
        if (prev) {
911
            cur->next = prev->next;
912 913
            prev->next = cur;
        } else {
914
            cur->next = conf->entries;
915 916 917
            conf->entries = cur;
        }
    } else {
918
        virConfFreeValue(cur->value);
919 920
        cur->value = value;
    }
921
    return 0;
922 923
}

924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
/**
 * virConfWalk:
 * @conf: a configuration file handle
 * @callback: the function to call to process each entry
 * @data: obscure data passed to callback
 *
 * Walk over all entries of the configuration file and run the callback
 * for each with entry name, value and the obscure data.
 *
 * Returns 0 on success, or -1 on failure.
 */
int virConfWalk(virConfPtr conf,
                 virConfWalkCallback callback,
                 void *opaque)
{
    virConfEntryPtr cur;

    if (!conf)
        return 0;

    cur = conf->entries;
    while (cur != NULL) {
        if (cur->name && cur->value &&
                callback(cur->name, cur->value, opaque) < 0)
            return -1;
        cur = cur->next;
    }
    return 0;
}
953

D
Daniel Veillard 已提交
954
/**
D
Daniel P. Berrange 已提交
955
 * virConfWriteFile:
D
Daniel Veillard 已提交
956 957 958 959 960 961 962 963
 * @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 已提交
964
virConfWriteFile(const char *filename, virConfPtr conf)
D
Daniel Veillard 已提交
965
{
966
    virBuffer buf = VIR_BUFFER_INITIALIZER;
D
Daniel Veillard 已提交
967 968 969
    virConfEntryPtr cur;
    int ret;
    int fd;
970 971
    char *content;
    unsigned int use;
D
Daniel Veillard 已提交
972 973

    if (conf == NULL)
974
        return -1;
D
Daniel Veillard 已提交
975 976 977

    cur = conf->entries;
    while (cur != NULL) {
978
        virConfSaveEntry(&buf, cur);
979
        cur = cur->next;
D
Daniel Veillard 已提交
980
    }
981

982
    if (virBufferError(&buf)) {
983
        virBufferFreeAndReset(&buf);
984
        virReportOOMError();
985 986 987
        return -1;
    }

988
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
D
Daniel Veillard 已提交
989
    if (fd < 0) {
990
        virBufferFreeAndReset(&buf);
991
        virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file"));
992
        return -1;
D
Daniel Veillard 已提交
993 994
    }

995 996 997
    use = virBufferUse(&buf);
    content = virBufferContentAndReset(&buf);
    ret = safewrite(fd, content, use);
998
    VIR_FREE(content);
999
    VIR_FORCE_CLOSE(fd);
1000
    if (ret != (int)use) {
1001
        virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content"));
1002
        return -1;
D
Daniel Veillard 已提交
1003
    }
1004 1005

    return ret;
D
Daniel Veillard 已提交
1006 1007 1008
}

/**
D
Daniel P. Berrange 已提交
1009
 * virConfWriteMem:
D
Daniel Veillard 已提交
1010
 * @memory: pointer to the memory to store the config file
1011
 * @len: pointer to the length in bytes of the store, on output the size
D
Daniel Veillard 已提交
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
 * @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 已提交
1022
virConfWriteMem(char *memory, int *len, virConfPtr conf)
D
Daniel Veillard 已提交
1023
{
1024
    virBuffer buf = VIR_BUFFER_INITIALIZER;
D
Daniel Veillard 已提交
1025
    virConfEntryPtr cur;
1026 1027
    char *content;
    unsigned int use;
D
Daniel Veillard 已提交
1028 1029

    if ((memory == NULL) || (len == NULL) || (*len <= 0) || (conf == NULL))
1030
        return -1;
D
Daniel Veillard 已提交
1031 1032 1033

    cur = conf->entries;
    while (cur != NULL) {
1034
        virConfSaveEntry(&buf, cur);
1035
        cur = cur->next;
D
Daniel Veillard 已提交
1036
    }
1037

1038
    if (virBufferError(&buf)) {
1039
        virBufferFreeAndReset(&buf);
1040
        virReportOOMError();
1041
        return -1;
D
Daniel Veillard 已提交
1042
    }
1043 1044 1045 1046 1047 1048

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

    if ((int)use >= *len) {
        *len = (int)use;
1049
        VIR_FREE(content);
1050 1051 1052
        return -1;
    }
    memcpy(memory, content, use);
1053
    VIR_FREE(content);
1054 1055
    *len = use;
    return use;
D
Daniel Veillard 已提交
1056
}