virconf.c 42.4 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"
41
#include "configmake.h"
D
Daniel Veillard 已提交
42

43 44
#define VIR_FROM_THIS VIR_FROM_CONF

45 46
VIR_LOG_INIT("util.conf");

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

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

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

84 85 86
VIR_ENUM_IMPL(virConf, VIR_CONF_LAST,
              "*unexpected*",
              "long",
87
              "unsigned long",
88 89 90
              "string",
              "list");

D
Daniel Veillard 已提交
91 92 93 94 95 96 97 98 99 100 101
typedef struct _virConfEntry virConfEntry;
typedef virConfEntry *virConfEntryPtr;

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

struct _virConf {
102
    char *filename;
103
    unsigned int flags;
D
Daniel Veillard 已提交
104 105 106 107 108
    virConfEntryPtr entries;
};

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

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


/************************************************************************
 *									*
 *		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;
155 156 157
        list->next = NULL;
        virConfFreeValue(list);
        list = next;
D
Daniel Veillard 已提交
158 159 160 161 162 163 164 165 166
    }
}

/**
 * virConfFreeValue:
 * @val: the value to free
 *
 * Free a value
 */
167
void
D
Daniel P. Berrange 已提交
168
virConfFreeValue(virConfValuePtr val)
D
Daniel Veillard 已提交
169 170 171
{
    if (val == NULL)
        return;
172 173
    if (val->type == VIR_CONF_STRING &&
        val->str != NULL)
174
        VIR_FREE(val->str);
175 176
    if (val->type == VIR_CONF_LIST &&
        val->list != NULL)
D
Daniel Veillard 已提交
177
        virConfFreeList(val->list);
178
    VIR_FREE(val);
D
Daniel Veillard 已提交
179 180
}

181
virConfPtr
D
Daniel P. Berrange 已提交
182
virConfNew(void)
D
Daniel Veillard 已提交
183 184 185
{
    virConfPtr ret;

186
    if (VIR_ALLOC(ret) < 0)
187
        return NULL;
188
    ret->filename = NULL;
189
    ret->flags = 0;
190

191
    return ret;
192
}
D
Daniel Veillard 已提交
193

194 195 196
/**
 * virConfCreate:
 * @filename: the name to report errors
197
 * @flags: combination of virConfFlag(s)
198 199 200 201 202 203
 *
 * Create a configuration internal structure
 *
 * Returns a pointer or NULL in case of error.
 */
static virConfPtr
204
virConfCreate(const char *filename, unsigned int flags)
205 206
{
    virConfPtr ret = virConfNew();
207 208 209 210 211 212
    if (!ret)
        return NULL;

    if (VIR_STRDUP(ret->filename, filename) < 0) {
        VIR_FREE(ret);
        return NULL;
213
    }
214 215

    ret->flags = flags;
216
    return ret;
D
Daniel Veillard 已提交
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
}

/**
 * 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)
237
        return NULL;
D
Daniel Veillard 已提交
238
    if ((comm == NULL) && (name == NULL))
239
        return NULL;
240

241
    VIR_DEBUG("Add entry %s %p", name, value);
242
    if (VIR_ALLOC(ret) < 0)
243
        return NULL;
244

D
Daniel Veillard 已提交
245 246 247 248 249 250 251 252
    ret->name = name;
    ret->value = value;
    ret->comment = comm;

    if (conf->entries == NULL) {
        conf->entries = ret;
    } else {
        prev = conf->entries;
253 254 255
        while (prev->next != NULL)
            prev = prev->next;
        prev->next = ret;
D
Daniel Veillard 已提交
256
    }
257
    return ret;
D
Daniel Veillard 已提交
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
}

/************************************************************************
 *									*
 *			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)
279
        return -1;
D
Daniel Veillard 已提交
280 281
    switch (val->type) {
        case VIR_CONF_NONE:
282
            return -1;
283
        case VIR_CONF_LONG:
284 285
            virBufferAsprintf(buf, "%lld", val->l);
            break;
286
        case VIR_CONF_ULONG:
287
            virBufferAsprintf(buf, "%llu", val->l);
288 289 290
            break;
        case VIR_CONF_STRING:
            if (strchr(val->str, '\n') != NULL) {
291
                virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str);
292
            } else if (strchr(val->str, '"') == NULL) {
293
                virBufferAsprintf(buf, "\"%s\"", val->str);
294
            } else if (strchr(val->str, '\'') == NULL) {
295
                virBufferAsprintf(buf, "'%s'", val->str);
296
            } else {
297
                virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str);
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
            }
            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:
318
            return -1;
D
Daniel Veillard 已提交
319
    }
320
    return 0;
D
Daniel Veillard 已提交
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
}

/**
 * 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);
337 338 339 340 341 342
        virBufferAddLit(buf, " = ");
        virConfSaveValue(buf, cur->value);
        if (cur->comment != NULL) {
            virBufferAddLit(buf, " #");
            virBufferAdd(buf, cur->comment, -1);
        }
D
Daniel Veillard 已提交
343
    } else if (cur->comment != NULL) {
344 345
        virBufferAddLit(buf, "#");
        virBufferAdd(buf, cur->comment, -1);
D
Daniel Veillard 已提交
346
    }
347
    virBufferAddLit(buf, "\n");
348
    return 0;
D
Daniel Veillard 已提交
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
}

/************************************************************************
 *									*
 *			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
367
virConfParseLong(virConfParserCtxtPtr ctxt, long long *val)
D
Daniel Veillard 已提交
368
{
369
    long long l = 0;
D
Daniel Veillard 已提交
370 371 372 373
    int neg = 0;

    if (CUR == '-') {
        neg = 1;
374
        NEXT;
D
Daniel Veillard 已提交
375 376 377
    } else if (CUR == '+') {
        NEXT;
    }
J
Jim Meyering 已提交
378
    if ((ctxt->cur >= ctxt->end) || (!c_isdigit(CUR))) {
379
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number"));
380
        return -1;
D
Daniel Veillard 已提交
381
    }
J
Jim Meyering 已提交
382
    while ((ctxt->cur < ctxt->end) && (c_isdigit(CUR))) {
D
Daniel Veillard 已提交
383
        l = l * 10 + (CUR - '0');
384
        NEXT;
D
Daniel Veillard 已提交
385
    }
386 387
    if (neg)
        l = -l;
D
Daniel Veillard 已提交
388
    *val = l;
389
    return 0;
D
Daniel Veillard 已提交
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
}

/**
 * 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;
408 409 410 411
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR)))
            NEXT;
        if (CUR != '\'') {
412
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
413
            return NULL;
414
        }
415
        if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0)
416
            return NULL;
417
        NEXT;
418 419 420
    } else if ((ctxt->cur + 6 < ctxt->end) &&
               (STRPREFIX(ctxt->cur, "\"\"\""))) {
        /* String starts with python-style triple quotes """ */
421 422
        ctxt->cur += 3;
        base = ctxt->cur;
423

424
        /* Find the ending triple quotes */
425
        while ((ctxt->cur + 2 < ctxt->end) &&
426
               !(STRPREFIX(ctxt->cur, "\"\"\""))) {
427 428 429
            if (CUR == '\n')
                ctxt->line++;
            NEXT;
430
        }
431 432

        if (!STRPREFIX(ctxt->cur, "\"\"\"")) {
433
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
434
            return NULL;
435
        }
436
        if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0)
437
            return NULL;
438
        ctxt->cur += 3;
D
Daniel Veillard 已提交
439 440
    } else if (CUR == '"') {
        NEXT;
441 442 443 444
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR)))
            NEXT;
        if (CUR != '"') {
445
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
446
            return NULL;
447
        }
448
        if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0)
449
            return NULL;
450
        NEXT;
451 452 453 454 455 456 457 458 459 460
    } 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 已提交
461
    }
462
    return ret;
D
Daniel Veillard 已提交
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
}

/**
 * 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;
479
    long long l = 0;
D
Daniel Veillard 已提交
480

J
Jim Meyering 已提交
481
    SKIP_BLANKS;
D
Daniel Veillard 已提交
482
    if (ctxt->cur >= ctxt->end) {
483
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
484
        return NULL;
D
Daniel Veillard 已提交
485
    }
486 487
    if ((CUR == '"') || (CUR == '\'') ||
         (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT)) {
D
Daniel Veillard 已提交
488 489
        type = VIR_CONF_STRING;
        str = virConfParseString(ctxt);
490
        if (str == NULL)
491
            return NULL;
D
Daniel Veillard 已提交
492
    } else if (CUR == '[') {
493 494 495
        if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                         _("lists not allowed in VMX format"));
496
            return NULL;
497
        }
D
Daniel Veillard 已提交
498 499
        type = VIR_CONF_LIST;
        NEXT;
J
Jim Meyering 已提交
500
        SKIP_BLANKS_AND_EOL;
501
        if ((ctxt->cur < ctxt->end) && (CUR != ']')) {
502
            if ((lst = virConfParseValue(ctxt)) == NULL)
503
                return NULL;
J
Jim Meyering 已提交
504
            SKIP_BLANKS_AND_EOL;
505 506
        }
        while ((ctxt->cur < ctxt->end) && (CUR != ']')) {
507 508 509 510 511

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

514
            if (CUR != ',') {
515 516
                virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                             _("expecting a separator in list"));
517
                virConfFreeList(lst);
518
                return NULL;
519 520
            }
            NEXT;
J
Jim Meyering 已提交
521
            SKIP_BLANKS_AND_EOL;
522
            if (CUR == ']')
523 524 525 526
                break;
            tmp = virConfParseValue(ctxt);
            if (tmp == NULL) {
                virConfFreeList(lst);
527
                return NULL;
528 529 530 531
            }
            prev = lst;
            while (prev->next != NULL) prev = prev->next;
            prev->next = tmp;
J
Jim Meyering 已提交
532
            SKIP_BLANKS_AND_EOL;
533 534 535 536
        }
        if (CUR == ']') {
            NEXT;
        } else {
537 538
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                         _("list is not closed with ]"));
539
            virConfFreeList(lst);
540
            return NULL;
541
        }
J
Jim Meyering 已提交
542
    } else if (c_isdigit(CUR) || (CUR == '-') || (CUR == '+')) {
543 544 545
        if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
            virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
                         _("numbers not allowed in VMX format"));
546
            return NULL;
547
        }
548
        type = (c_isdigit(CUR) || CUR == '+') ? VIR_CONF_ULONG : VIR_CONF_LONG;
549
        if (virConfParseLong(ctxt, &l) < 0)
550
            return NULL;
D
Daniel Veillard 已提交
551
    } else {
552
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
553
        return NULL;
D
Daniel Veillard 已提交
554
    }
555 556 557
    if (VIR_ALLOC(ret) < 0) {
        virConfFreeList(lst);
        VIR_FREE(str);
558
        return NULL;
D
Daniel Veillard 已提交
559 560 561 562 563
    }
    ret->type = type;
    ret->l = l;
    ret->str = str;
    ret->list = lst;
564
    return ret;
D
Daniel Veillard 已提交
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
}

/**
 * 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 已提交
581
    SKIP_BLANKS;
D
Daniel Veillard 已提交
582 583
    base = ctxt->cur;
    /* TODO: probably need encoding support and UTF-8 parsing ! */
584 585
    if (!c_isalpha(CUR) &&
        !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) {
586
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name"));
587
        return NULL;
D
Daniel Veillard 已提交
588
    }
589 590
    while ((ctxt->cur < ctxt->end) &&
           (c_isalnum(CUR) || (CUR == '_') ||
591
            ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) &&
592 593 594
             ((CUR == ':') || (CUR == '.') || (CUR == '-'))) ||
            ((ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) &&
             (CUR == '.'))))
D
Daniel Veillard 已提交
595
        NEXT;
596
    if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0)
597 598
        return NULL;
    return ret;
D
Daniel Veillard 已提交
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
}

/**
 * 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 != '#')
616
        return -1;
D
Daniel Veillard 已提交
617 618 619
    NEXT;
    base = ctxt->cur;
    while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
620
    if (VIR_STRNDUP(comm, base, ctxt->cur - base) < 0)
621
        return -1;
622 623 624 625
    if (virConfAddEntry(ctxt->conf, NULL, NULL, comm) == NULL) {
        VIR_FREE(comm);
        return -1;
    }
626
    return 0;
D
Daniel Veillard 已提交
627 628 629 630 631 632 633 634 635 636 637 638 639
}

/**
 * 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 已提交
640
    SKIP_BLANKS;
D
Daniel Veillard 已提交
641
    if (ctxt->cur >= ctxt->end)
642
        return 0;
D
Daniel Veillard 已提交
643
    if (IS_EOL(CUR)) {
J
Jim Meyering 已提交
644
        SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
645
    } else if (CUR == ';') {
646
        NEXT;
J
Jim Meyering 已提交
647
        SKIP_BLANKS_AND_EOL;
D
Daniel Veillard 已提交
648
    } else {
649
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator"));
650
        return -1;
D
Daniel Veillard 已提交
651
    }
652
    return 0;
D
Daniel Veillard 已提交
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
}

/**
 * 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 已提交
671
    SKIP_BLANKS_AND_EOL;
672
    if (CUR == '#')
P
Phil Petty 已提交
673
        return virConfParseComment(ctxt);
D
Daniel Veillard 已提交
674 675
    name = virConfParseName(ctxt);
    if (name == NULL)
P
Phil Petty 已提交
676
        return -1;
J
Jim Meyering 已提交
677
    SKIP_BLANKS;
D
Daniel Veillard 已提交
678
    if (CUR != '=') {
679
        virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment"));
P
Phil Petty 已提交
680 681
        VIR_FREE(name);
        return -1;
D
Daniel Veillard 已提交
682 683
    }
    NEXT;
J
Jim Meyering 已提交
684
    SKIP_BLANKS;
D
Daniel Veillard 已提交
685 686
    value = virConfParseValue(ctxt);
    if (value == NULL) {
687
        VIR_FREE(name);
P
Phil Petty 已提交
688
        return -1;
D
Daniel Veillard 已提交
689
    }
J
Jim Meyering 已提交
690
    SKIP_BLANKS;
D
Daniel Veillard 已提交
691
    if (CUR == '#') {
692 693 694
        NEXT;
        base = ctxt->cur;
        while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
695
        if (VIR_STRNDUP(comm, base, ctxt->cur - base) < 0) {
696
            VIR_FREE(name);
697
            virConfFreeValue(value);
P
Phil Petty 已提交
698
            return -1;
699
        }
D
Daniel Veillard 已提交
700 701
    }
    if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) {
702
        VIR_FREE(name);
703
        virConfFreeValue(value);
704
        VIR_FREE(comm);
P
Phil Petty 已提交
705
        return -1;
D
Daniel Veillard 已提交
706
    }
P
Phil Petty 已提交
707
    return 0;
D
Daniel Veillard 已提交
708 709 710 711 712 713 714
}

/**
 * virConfParse:
 * @filename: the name to report errors
 * @content: the configuration content in memory
 * @len: the length in bytes
715
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
716 717 718 719
 *
 * Parse the subset of the Python language needed to handle simple
 * Xen configuration files.
 *
E
Eric Blake 已提交
720
 * Returns a handle to lookup settings or NULL if it failed to
D
Daniel Veillard 已提交
721 722 723
 *         read or parse the file, use virConfFree() to free the data.
 */
static virConfPtr
724
virConfParse(const char *filename, const char *content, int len,
725 726
             unsigned int flags)
{
D
Daniel Veillard 已提交
727 728 729 730 731 732 733
    virConfParserCtxt ctxt;

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

734
    ctxt.conf = virConfCreate(filename, flags);
D
Daniel Veillard 已提交
735
    if (ctxt.conf == NULL)
736
        return NULL;
D
Daniel Veillard 已提交
737 738 739

    while (ctxt.cur < ctxt.end) {
        if (virConfParseStatement(&ctxt) < 0)
740 741 742
            goto error;
        if (virConfParseSeparator(&ctxt) < 0)
            goto error;
D
Daniel Veillard 已提交
743 744
    }

745
    return ctxt.conf;
D
Daniel Veillard 已提交
746

747
 error:
D
Daniel Veillard 已提交
748
    virConfFree(ctxt.conf);
749
    return NULL;
D
Daniel Veillard 已提交
750 751 752 753 754 755 756 757
}

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

758 759 760
/* 10 MB limit on config file size as a sanity check */
#define MAX_CONFIG_FILE_SIZE (1024*1024*10)

D
Daniel Veillard 已提交
761
/**
D
Daniel P. Berrange 已提交
762
 * virConfReadFile:
D
Daniel Veillard 已提交
763
 * @filename: the path to the configuration file.
764
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
765 766 767
 *
 * Reads a configuration file.
 *
E
Eric Blake 已提交
768
 * Returns a handle to lookup settings or NULL if it failed to
D
Daniel Veillard 已提交
769 770 771
 *         read or parse the file, use virConfFree() to free the data.
 */
virConfPtr
772
virConfReadFile(const char *filename, unsigned int flags)
D
Daniel Veillard 已提交
773
{
774
    char *content;
D
Daniel Veillard 已提交
775
    int len;
776
    virConfPtr conf = NULL;
D
Daniel Veillard 已提交
777

778 779
    VIR_DEBUG("filename=%s", NULLSTR(filename));

D
Daniel Veillard 已提交
780
    if (filename == NULL) {
781
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
782
        return NULL;
D
Daniel Veillard 已提交
783
    }
784

785
    if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0)
786 787
        return NULL;

788 789
    if (len && len < MAX_CONFIG_FILE_SIZE && content[len - 1] != '\n') {
        VIR_DEBUG("appending newline to busted config file %s", filename);
790
        if (VIR_REALLOC_N(content, len + 2) < 0)
791 792 793 794 795
            goto cleanup;
        content[len++] = '\n';
        content[len] = '\0';
    }

796
    conf = virConfParse(filename, content, len, flags);
797

798
 cleanup:
799
    VIR_FREE(content);
800 801

    return conf;
D
Daniel Veillard 已提交
802 803 804
}

/**
D
Daniel P. Berrange 已提交
805
 * virConfReadMem:
D
Daniel Veillard 已提交
806
 * @memory: pointer to the content of the configuration file
D
Daniel Veillard 已提交
807
 * @len: length in byte
808
 * @flags: combination of virConfFlag(s)
D
Daniel Veillard 已提交
809 810 811 812
 *
 * Reads a configuration file loaded in memory. The string can be
 * zero terminated in which case @len can be 0
 *
E
Eric Blake 已提交
813
 * Returns a handle to lookup settings or NULL if it failed to
D
Daniel Veillard 已提交
814 815 816
 *         parse the content, use virConfFree() to free the data.
 */
virConfPtr
817
virConfReadMem(const char *memory, int len, unsigned int flags)
D
Daniel Veillard 已提交
818 819
{
    if ((memory == NULL) || (len < 0)) {
820
        virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
821
        return NULL;
D
Daniel Veillard 已提交
822 823 824 825
    }
    if (len == 0)
        len = strlen(memory);

826
    return virConfParse("memory conf", memory, len, flags);
D
Daniel Veillard 已提交
827 828 829
}

/**
D
Daniel P. Berrange 已提交
830
 * virConfFree:
D
Daniel Veillard 已提交
831 832 833 834 835 836 837
 * @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 已提交
838
virConfFree(virConfPtr conf)
D
Daniel Veillard 已提交
839
{
840
    virConfEntryPtr tmp;
841 842
    if (conf == NULL)
        return 0;
843 844 845 846

    tmp = conf->entries;
    while (tmp) {
        virConfEntryPtr next;
847
        VIR_FREE(tmp->name);
848
        virConfFreeValue(tmp->value);
849
        VIR_FREE(tmp->comment);
850
        next = tmp->next;
851
        VIR_FREE(tmp);
852
        tmp = next;
D
Daniel Veillard 已提交
853
    }
854
    VIR_FREE(conf->filename);
855
    VIR_FREE(conf);
856
    return 0;
D
Daniel Veillard 已提交
857 858 859
}

/**
D
Daniel P. Berrange 已提交
860
 * virConfGetValue:
D
Daniel Veillard 已提交
861
 * @conf: a configuration file handle
C
Cao jin 已提交
862
 * @setting: the name of the entry
D
Daniel Veillard 已提交
863 864 865
 *
 * Lookup the value associated to this entry in the configuration file
 *
866
 * Returns a pointer to the value or NULL if the lookup failed, the data
D
Daniel Veillard 已提交
867 868 869
 *         associated will be freed when virConfFree() is called
 */
virConfValuePtr
D
Daniel P. Berrange 已提交
870
virConfGetValue(virConfPtr conf, const char *setting)
D
Daniel Veillard 已提交
871
{
872 873
    virConfEntryPtr cur;

874 875 876
    if (conf == NULL)
        return NULL;

877 878
    cur = conf->entries;
    while (cur != NULL) {
879 880 881 882
        if ((cur->name != NULL) &&
            ((conf->flags & VIR_CONF_FLAG_VMX_FORMAT &&
              STRCASEEQ(cur->name, setting)) ||
             STREQ(cur->name, setting)))
883
            return cur->value;
884 885
        cur = cur->next;
    }
886
    return NULL;
D
Daniel Veillard 已提交
887 888
}

889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 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 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072

/**
 * virConfGetValueType:
 * @conf: the config object
 * @setting: the config entry name
 *
 * Query the type of the configuration entry @setting.
 *
 * Returns: the entry type, or VIR_CONF_NONE if not set.
 */
virConfType virConfGetValueType(virConfPtr conf,
                                const char *setting)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);
    if (!cval)
        return VIR_CONF_NONE;

    return cval->type;
}


/**
 * virConfGetValueString:
 * @conf: the config object
 * @setting: the config entry name
 * @value: pointer to hold string value
 *
 * Get the string value of the config name @setting, storing
 * it in @value. If the config entry is not present, then
 * @value will be unmodified.
 *
 * Reports an error if the config entry is set but has
 * an unexpected type.
 *
 * Returns: 1 if the value was present, 0 if missing, -1 on error
 */
int virConfGetValueString(virConfPtr conf,
                          const char *setting,
                          char **value)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);

    VIR_DEBUG("Get value string %p %d",
              cval, cval ? cval->type : VIR_CONF_NONE);

    if (!cval)
        return 0;

    if (cval->type != VIR_CONF_STRING) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: expected a string for '%s' parameter"),
                       conf->filename, setting);
        return -1;
    }

    VIR_FREE(*value);
    if (VIR_STRDUP(*value, cval->str) < 0)
        return -1;

    return 1;
}


/**
 * virConfGetValueStringList:
 * @conf: the config object
 * @setting: the config entry name
 * @compatString: true to treat string entry as a 1 element list
 * @value: pointer to hold NULL terminated string list
 *
 * Get the string list value of the config name @setting, storing
 * it in @value. If the config entry is not present, then
 * @value will be unmodified. If @compatString is set to true
 * and the value is present as a string, this will be turned into
 * a 1 element list. The returned @value will be NULL terminated
 * if set.
 *
 * Reports an error if the config entry is set but has
 * an unexpected type.
 *
 * Returns: 1 if the value was present, 0 if missing, -1 on error
 */
int virConfGetValueStringList(virConfPtr conf,
                              const char *setting,
                              bool compatString,
                              char ***values)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);
    size_t len;
    virConfValuePtr eval;

    VIR_DEBUG("Get value string list %p %d",
              cval, cval ? cval->type : VIR_CONF_NONE);

    if (!cval)
        return 0;

    virStringFreeList(*values);
    *values = NULL;

    switch (cval->type) {
    case VIR_CONF_LIST:
        /* Calc length and check items */
        for (len = 0, eval = cval->list; eval; len++, eval = eval->next) {
            if (eval->type != VIR_CONF_STRING) {
                virReportError(VIR_ERR_CONF_SYNTAX,
                               _("%s: expected a string list for '%s' parameter"),
                               conf->filename, setting);
                return -1;
            }
        }

        if (VIR_ALLOC_N(*values, len + 1) < 0)
            return -1;

        for (len = 0, eval = cval->list; eval; len++, eval = eval->next) {
            if (VIR_STRDUP((*values)[len], eval->str) < 0) {
                virStringFreeList(*values);
                *values = NULL;
                return -1;
            }
        }
        break;

    case VIR_CONF_STRING:
        if (compatString) {
            if (VIR_ALLOC_N(*values, cval->str ? 2 : 1) < 0)
                return -1;
            if (cval->str &&
                VIR_STRDUP((*values)[0], cval->str) < 0) {
                VIR_FREE(values);
                return -1;
            }
            break;
        }
        /* fallthrough */

    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       compatString ?
                       _("%s: expected a string or string list for '%s' parameter") :
                       _("%s: expected a string list for '%s' parameter"),
                       conf->filename, setting);
        return -1;
    }

    return 1;
}


/**
 * virConfGetValueBool:
 * @conf: the config object
 * @setting: the config entry name
 * @value: pointer to hold boolean value
 *
 * Get the boolean value of the config name @setting, storing
 * it in @value. If the config entry is not present, then
 * @value will be unmodified.
 *
 * Reports an error if the config entry is set but has
 * an unexpected type, or if the value set is not 1 or 0.
 *
 * Returns: 1 if the value was present, 0 if missing, -1 on error
 */
int virConfGetValueBool(virConfPtr conf,
                        const char *setting,
                        bool *value)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);

    VIR_DEBUG("Get value bool %p %d",
              cval, cval ? cval->type : VIR_CONF_NONE);

    if (!cval)
        return 0;

    if (cval->type != VIR_CONF_ULONG) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: expected a bool for '%s' parameter"),
                       conf->filename, setting);
        return -1;
    }

1073
    if (((unsigned long long)cval->l) > 1) {
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: value for '%s' parameter must be 0 or 1"),
                       conf->filename, setting);
        return -1;
    }

    *value = cval->l == 1;

    return 1;
}


/**
 * virConfGetValueInt:
 * @conf: the config object
 * @setting: the config entry name
 * @value: pointer to hold integer value
 *
 * Get the integer value of the config name @setting, storing
 * it in @value. If the config entry is not present, then
 * @value will be unmodified.
 *
 * Reports an error if the config entry is set but has
 * an unexpected type, or if the value is outside the
 * range that can be stored in an 'int'
 *
 * Returns: 1 if the value was present, 0 if missing, -1 on error
 */
int virConfGetValueInt(virConfPtr conf,
                       const char *setting,
                       int *value)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);

    VIR_DEBUG("Get value int %p %d",
              cval, cval ? cval->type : VIR_CONF_NONE);

    if (!cval)
        return 0;

    if (cval->type != VIR_CONF_LONG &&
        cval->type != VIR_CONF_ULONG) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: expected a signed integer for '%s' parameter"),
                       conf->filename, setting);
        return -1;
    }

    if (cval->l > INT_MAX || cval->l < INT_MIN) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: value for '%s' parameter must be in range %d:%d"),
                       conf->filename, setting, INT_MIN, INT_MAX);
        return -1;
    }

    *value = cval->l;

    return 1;
}


/**
 * virConfGetValueUInt:
 * @conf: the config object
 * @setting: the config entry name
 * @value: pointer to hold integer value
 *
 * Get the unsigned integer value of the config name @setting, storing
 * it in @value. If the config entry is not present, then
 * @value will be unmodified.
 *
 * Reports an error if the config entry is set but has
 * an unexpected type, or if the value is outside the
 * range that can be stored in an 'unsigned int'
 *
 * Returns: 1 if the value was present, 0 if missing, -1 on error
 */
int virConfGetValueUInt(virConfPtr conf,
                        const char *setting,
                        unsigned int *value)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);

    VIR_DEBUG("Get value uint %p %d",
              cval, cval ? cval->type : VIR_CONF_NONE);

    if (!cval)
        return 0;

    if (cval->type != VIR_CONF_ULONG) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: expected an unsigned integer for '%s' parameter"),
                       conf->filename, setting);
        return -1;
    }

1170
    if (((unsigned long long)cval->l) > UINT_MAX) {
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: value for '%s' parameter must be in range 0:%u"),
                       conf->filename, setting, UINT_MAX);
        return -1;
    }

    *value = cval->l;

    return 1;
}


/**
 * virConfGetValueSizeT:
 * @conf: the config object
 * @setting: the config entry name
 * @value: pointer to hold integer value
 *
 * Get the integer value of the config name @setting, storing
 * it in @value. If the config entry is not present, then
 * @value will be unmodified.
 *
 * Reports an error if the config entry is set but has
 * an unexpected type, or if the value is outside the
 * range that can be stored in a 'size_t'
 *
 * Returns: 1 if the value was present, 0 if missing, -1 on error
 */
int virConfGetValueSizeT(virConfPtr conf,
                         const char *setting,
                         size_t *value)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);

    VIR_DEBUG("Get value size_t %p %d",
              cval, cval ? cval->type : VIR_CONF_NONE);

    if (!cval)
        return 0;

1211
    if (cval->type != VIR_CONF_ULONG) {
1212 1213 1214 1215 1216 1217
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: expected an unsigned integer for '%s' parameter"),
                       conf->filename, setting);
        return -1;
    }

1218 1219 1220 1221 1222 1223 1224 1225 1226
#if ULLONG_MAX > SIZE_MAX
    if (((unsigned long long)cval->l) > SIZE_MAX) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: value for '%s' parameter must be in range 0:%zu"),
                       conf->filename, setting, SIZE_MAX);
        return -1;
    }
#endif

1227
    *value = (size_t)cval->l;
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260

    return 1;
}


/**
 * virConfGetValueSSizeT:
 * @conf: the config object
 * @setting: the config entry name
 * @value: pointer to hold integer value
 *
 * Get the integer value of the config name @setting, storing
 * it in @value. If the config entry is not present, then
 * @value will be unmodified.
 *
 * Reports an error if the config entry is set but has
 * an unexpected type, or if the value is outside the
 * range that can be stored in an 'ssize_t'
 *
 * Returns: 1 if the value was present, 0 if missing, -1 on error
 */
int virConfGetValueSSizeT(virConfPtr conf,
                          const char *setting,
                          ssize_t *value)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);

    VIR_DEBUG("Get value ssize_t %p %d",
              cval, cval ? cval->type : VIR_CONF_NONE);

    if (!cval)
        return 0;

1261 1262 1263 1264 1265 1266 1267 1268
    if (cval->type == VIR_CONF_ULONG) {
        if (((unsigned long long)cval->l) > SSIZE_MAX) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("%s: value for '%s' parameter must be in range %zd:%zd"),
                           conf->filename, setting, (ssize_t)-SSIZE_MAX - 1, (ssize_t)SSIZE_MAX);
            return -1;
        }
    } else if (cval->type == VIR_CONF_LONG) {
1269
#if SSIZE_MAX < LLONG_MAX
1270 1271 1272 1273 1274 1275
        if (cval->l < (-SSIZE_MAX - 1) || cval->l > SSIZE_MAX) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("%s: value for '%s' parameter must be in range %zd:%zd"),
                           conf->filename, setting, (ssize_t)-SSIZE_MAX - 1, (ssize_t)SSIZE_MAX);
            return -1;
        }
1276
#endif
1277
    } else {
1278 1279 1280 1281 1282 1283
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: expected a signed integer for '%s' parameter"),
                       conf->filename, setting);
        return -1;
    }

1284
    *value = (ssize_t)cval->l;
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317

    return 1;
}


/**
 * virConfGetValueLLong:
 * @conf: the config object
 * @setting: the config entry name
 * @value: pointer to hold integer value
 *
 * Get the integer value of the config name @setting, storing
 * it in @value. If the config entry is not present, then
 * @value will be unmodified.
 *
 * Reports an error if the config entry is set but has
 * an unexpected type, or if the value is outside the
 * range that can be stored in an 'long long'
 *
 * Returns: 1 if the value was present, 0 if missing, -1 on error
 */
int virConfGetValueLLong(virConfPtr conf,
                        const char *setting,
                        long long *value)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);

    VIR_DEBUG("Get value long long %p %d",
              cval, cval ? cval->type : VIR_CONF_NONE);

    if (!cval)
        return 0;

1318 1319 1320 1321 1322 1323 1324 1325
    if (cval->type == VIR_CONF_ULONG) {
        if (((unsigned long long)cval->l) > LLONG_MAX) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("%s: value for '%s' parameter must be in range 0:%lld"),
                           conf->filename, setting, LLONG_MAX);
            return -1;
        }
    } else if (cval->type != VIR_CONF_LONG) {
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: expected a signed integer for '%s' parameter"),
                       conf->filename, setting);
        return -1;
    }

    *value = cval->l;

    return 1;
}


/**
 * virConfGetValueULongLong:
 * @conf: the config object
 * @setting: the config entry name
 * @value: pointer to hold integer value
 *
 * Get the integer value of the config name @setting, storing
 * it in @value. If the config entry is not present, then
 * @value will be unmodified.
 *
 * Reports an error if the config entry is set but has
 * an unexpected type.
 *
 * Returns: 1 if the value was present, 0 if missing, -1 on error
 */
int virConfGetValueULLong(virConfPtr conf,
                          const char *setting,
                          unsigned long long *value)
{
    virConfValuePtr cval = virConfGetValue(conf, setting);

    VIR_DEBUG("Get value unsigned long long %p %d",
              cval, cval ? cval->type : VIR_CONF_NONE);

    if (!cval)
        return 0;

1365
    if (cval->type != VIR_CONF_ULONG) {
1366 1367 1368 1369 1370 1371
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("%s: expected an unsigned integer for '%s' parameter"),
                       conf->filename, setting);
        return -1;
    }

1372
    *value = (unsigned long long)cval->l;
1373 1374 1375 1376

    return 1;
}

1377
/**
D
Daniel P. Berrange 已提交
1378
 * virConfSetValue:
1379
 * @conf: a configuration file handle
C
Cao jin 已提交
1380
 * @setting: the name of the entry
1381 1382 1383 1384 1385 1386 1387 1388 1389
 * @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.
 */
1390
int
1391 1392 1393
virConfSetValue(virConfPtr conf,
                const char *setting,
                virConfValuePtr value)
1394
{
1395 1396
    virConfEntryPtr cur, prev = NULL;

1397 1398
    if (value && value->type == VIR_CONF_STRING && value->str == NULL) {
        virConfFreeValue(value);
1399
        return -1;
1400
    }
1401

1402 1403
    cur = conf->entries;
    while (cur != NULL) {
1404
        if (STREQ_NULLABLE(cur->name, setting))
1405 1406 1407 1408
            break;
        prev = cur;
        cur = cur->next;
    }
1409

1410
    if (!cur) {
1411
        if (VIR_ALLOC(cur) < 0) {
1412
            virConfFreeValue(value);
1413
            return -1;
1414 1415
        }
        cur->comment = NULL;
1416
        if (VIR_STRDUP(cur->name, setting) < 0) {
1417
            virConfFreeValue(value);
1418
            VIR_FREE(cur);
1419
            return -1;
1420 1421 1422
        }
        cur->value = value;
        if (prev) {
1423
            cur->next = prev->next;
1424 1425
            prev->next = cur;
        } else {
1426
            cur->next = conf->entries;
1427 1428 1429
            conf->entries = cur;
        }
    } else {
1430
        virConfFreeValue(cur->value);
1431 1432
        cur->value = value;
    }
1433
    return 0;
1434 1435
}

1436 1437 1438 1439
/**
 * virConfWalk:
 * @conf: a configuration file handle
 * @callback: the function to call to process each entry
C
Cao jin 已提交
1440
 * @opaque: obscure data passed to callback
1441 1442 1443 1444 1445 1446 1447
 *
 * 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,
C
Cao jin 已提交
1448 1449
                virConfWalkCallback callback,
                void *opaque)
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
{
    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;
}
1465

D
Daniel Veillard 已提交
1466
/**
D
Daniel P. Berrange 已提交
1467
 * virConfWriteFile:
D
Daniel Veillard 已提交
1468 1469 1470 1471 1472 1473 1474 1475
 * @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 已提交
1476
virConfWriteFile(const char *filename, virConfPtr conf)
D
Daniel Veillard 已提交
1477
{
1478
    virBuffer buf = VIR_BUFFER_INITIALIZER;
D
Daniel Veillard 已提交
1479 1480 1481
    virConfEntryPtr cur;
    int ret;
    int fd;
1482 1483
    char *content;
    unsigned int use;
D
Daniel Veillard 已提交
1484 1485

    if (conf == NULL)
1486
        return -1;
D
Daniel Veillard 已提交
1487 1488 1489

    cur = conf->entries;
    while (cur != NULL) {
1490
        virConfSaveEntry(&buf, cur);
1491
        cur = cur->next;
D
Daniel Veillard 已提交
1492
    }
1493

1494
    if (virBufferCheckError(&buf) < 0)
1495 1496
        return -1;

1497
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
D
Daniel Veillard 已提交
1498
    if (fd < 0) {
1499
        virBufferFreeAndReset(&buf);
1500
        virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file"));
1501
        return -1;
D
Daniel Veillard 已提交
1502 1503
    }

1504 1505 1506
    use = virBufferUse(&buf);
    content = virBufferContentAndReset(&buf);
    ret = safewrite(fd, content, use);
1507
    VIR_FREE(content);
1508
    VIR_FORCE_CLOSE(fd);
1509
    if (ret != (int)use) {
1510
        virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content"));
1511
        return -1;
D
Daniel Veillard 已提交
1512
    }
1513 1514

    return ret;
D
Daniel Veillard 已提交
1515 1516 1517
}

/**
D
Daniel P. Berrange 已提交
1518
 * virConfWriteMem:
D
Daniel Veillard 已提交
1519
 * @memory: pointer to the memory to store the config file
1520
 * @len: pointer to the length in bytes of the store, on output the size
D
Daniel Veillard 已提交
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530
 * @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 已提交
1531
virConfWriteMem(char *memory, int *len, virConfPtr conf)
D
Daniel Veillard 已提交
1532
{
1533
    virBuffer buf = VIR_BUFFER_INITIALIZER;
D
Daniel Veillard 已提交
1534
    virConfEntryPtr cur;
1535 1536
    char *content;
    unsigned int use;
D
Daniel Veillard 已提交
1537 1538

    if ((memory == NULL) || (len == NULL) || (*len <= 0) || (conf == NULL))
1539
        return -1;
D
Daniel Veillard 已提交
1540 1541 1542

    cur = conf->entries;
    while (cur != NULL) {
1543
        virConfSaveEntry(&buf, cur);
1544
        cur = cur->next;
D
Daniel Veillard 已提交
1545
    }
1546

1547
    if (virBufferCheckError(&buf) < 0)
1548 1549 1550 1551 1552 1553 1554
        return -1;

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

    if ((int)use >= *len) {
        *len = (int)use;
1555
        VIR_FREE(content);
1556 1557 1558
        return -1;
    }
    memcpy(memory, content, use);
1559
    VIR_FREE(content);
1560 1561
    *len = use;
    return use;
D
Daniel Veillard 已提交
1562
}
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617

static char *
virConfLoadConfigPath(const char *name)
{
    char *path;
    if (geteuid() == 0) {
        if (virAsprintf(&path, "%s/libvirt/libvirt%s%s.conf",
                        SYSCONFDIR,
                        name ? "-" : "",
                        name ? name : "") < 0)
            return NULL;
    } else {
        char *userdir = virGetUserConfigDirectory();
        if (!userdir)
            return NULL;

        if (virAsprintf(&path, "%s/libvirt%s%s.conf",
                        userdir,
                        name ? "-" : "",
                        name ? name : "") < 0) {
            VIR_FREE(userdir);
            return NULL;
        }
        VIR_FREE(userdir);
    }

    return path;
}

int
virConfLoadConfig(virConfPtr *conf, const char *name)
{
    char *path = NULL;
    int ret = -1;

    *conf = NULL;

    if (!(path = virConfLoadConfigPath(name)))
        goto cleanup;

    if (!virFileExists(path)) {
        ret = 0;
        goto cleanup;
    }

    VIR_DEBUG("Loading config file '%s'", path);
    if (!(*conf = virConfReadFile(path, 0)))
        goto cleanup;

    ret = 0;

 cleanup:
    VIR_FREE(path);
    return ret;
}