virsysinfo.c 43.6 KB
Newer Older
1
/*
2
 * virsysinfo.c: get SMBIOS/sysinfo information from the host
3
 *
4
 * Copyright (C) 2010-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2010 Daniel Veillard
 *
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 * Author: Daniel Veillard <veillard@redhat.com>
 */

#include <config.h>

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

33
#include "virerror.h"
34
#include "virsysinfo.h"
35
#include "viralloc.h"
36
#include "vircommand.h"
37
#include "virfile.h"
38
#include "virstring.h"
39 40 41 42

#define VIR_FROM_THIS VIR_FROM_SYSINFO


43 44 45
VIR_ENUM_IMPL(virSysinfo, VIR_SYSINFO_LAST,
              "smbios");

46
static const char *sysinfoDmidecode = DMIDECODE;
47 48 49 50 51 52
static const char *sysinfoSysinfo = "/proc/sysinfo";
static const char *sysinfoCpuinfo = "/proc/cpuinfo";

#define SYSINFO_SMBIOS_DECODER sysinfoDmidecode
#define SYSINFO sysinfoSysinfo
#define CPUINFO sysinfoCpuinfo
53
#define CPUINFO_FILE_LEN (1024*1024)	/* 1MB limit for /proc/cpuinfo file */
54 55 56 57 58 59 60 61 62 63 64 65 66

/* only to be used test programs, therefore not in sysinfo.h */
extern void virSysinfoSetup(const char *dmidecode, const char *sysinfo,
                            const char *cpuinfo);

void virSysinfoSetup(const char *dmidecode, const char *sysinfo,
                     const char *cpuinfo)
{
    sysinfoDmidecode = dmidecode;
    sysinfoSysinfo = sysinfo;
    sysinfoCpuinfo = cpuinfo;
}

67 68 69 70 71 72 73 74 75 76 77 78
void virSysinfoBIOSDefFree(virSysinfoBIOSDefPtr def)
{
    if (def == NULL)
        return;

    VIR_FREE(def->vendor);
    VIR_FREE(def->version);
    VIR_FREE(def->date);
    VIR_FREE(def->release);
    VIR_FREE(def);
}

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
void virSysinfoSystemDefFree(virSysinfoSystemDefPtr def)
{
    if (def == NULL)
        return;

    VIR_FREE(def->manufacturer);
    VIR_FREE(def->product);
    VIR_FREE(def->version);
    VIR_FREE(def->serial);
    VIR_FREE(def->uuid);
    VIR_FREE(def->sku);
    VIR_FREE(def->family);
    VIR_FREE(def);
}

94 95 96 97 98 99 100 101 102 103 104 105
void virSysinfoBaseBoardDefClear(virSysinfoBaseBoardDefPtr def)
{
    if (def == NULL)
        return;

    VIR_FREE(def->manufacturer);
    VIR_FREE(def->product);
    VIR_FREE(def->version);
    VIR_FREE(def->serial);
    VIR_FREE(def->asset);
    VIR_FREE(def->location);
}
106

107 108 109 110 111 112 113 114 115
/**
 * virSysinfoDefFree:
 * @def: a sysinfo structure
 *
 * Free up the sysinfo structure
 */

void virSysinfoDefFree(virSysinfoDefPtr def)
{
116
    size_t i;
117

118 119 120
    if (def == NULL)
        return;

121
    virSysinfoBIOSDefFree(def->bios);
122
    virSysinfoSystemDefFree(def->system);
123

124 125 126 127
    for (i = 0; i < def->nbaseBoard; i++)
        virSysinfoBaseBoardDefClear(def->baseBoard + i);
    VIR_FREE(def->baseBoard);

128
    for (i = 0; i < def->nprocessor; i++) {
129 130 131 132 133 134 135 136 137 138 139 140 141
        VIR_FREE(def->processor[i].processor_socket_destination);
        VIR_FREE(def->processor[i].processor_type);
        VIR_FREE(def->processor[i].processor_family);
        VIR_FREE(def->processor[i].processor_manufacturer);
        VIR_FREE(def->processor[i].processor_signature);
        VIR_FREE(def->processor[i].processor_version);
        VIR_FREE(def->processor[i].processor_external_clock);
        VIR_FREE(def->processor[i].processor_max_speed);
        VIR_FREE(def->processor[i].processor_status);
        VIR_FREE(def->processor[i].processor_serial_number);
        VIR_FREE(def->processor[i].processor_part_number);
    }
    VIR_FREE(def->processor);
142
    for (i = 0; i < def->nmemory; i++) {
143 144 145 146 147 148 149 150 151 152 153 154
        VIR_FREE(def->memory[i].memory_size);
        VIR_FREE(def->memory[i].memory_form_factor);
        VIR_FREE(def->memory[i].memory_locator);
        VIR_FREE(def->memory[i].memory_bank_locator);
        VIR_FREE(def->memory[i].memory_type);
        VIR_FREE(def->memory[i].memory_type_detail);
        VIR_FREE(def->memory[i].memory_speed);
        VIR_FREE(def->memory[i].memory_manufacturer);
        VIR_FREE(def->memory[i].memory_serial_number);
        VIR_FREE(def->memory[i].memory_part_number);
    }
    VIR_FREE(def->memory);
155

156 157 158 159 160 161 162 163 164 165
    VIR_FREE(def);
}

/**
 * virSysinfoRead:
 *
 * Tries to read the SMBIOS information from the current host
 *
 * Returns: a filled up sysinfo structure or NULL in case of error
 */
P
Prerna Saxena 已提交
166 167 168

#if defined(__powerpc__)
static int
M
Michal Privoznik 已提交
169
virSysinfoParseSystem(const char *base, virSysinfoSystemDefPtr *sysdef)
P
Prerna Saxena 已提交
170
{
171
    int ret = -1;
P
Prerna Saxena 已提交
172 173
    char *eol = NULL;
    const char *cur;
174
    virSysinfoSystemDefPtr def;
P
Prerna Saxena 已提交
175 176 177 178

    if ((cur = strstr(base, "platform")) == NULL)
        return 0;

179 180 181
    if (VIR_ALLOC(def) < 0)
        return ret;

P
Prerna Saxena 已提交
182 183 184 185 186
    base = cur;
    /* Account for format 'platform    : XXXX'*/
    cur = strchr(cur, ':') + 1;
    eol = strchr(cur, '\n');
    virSkipSpaces(&cur);
187 188
    if (eol && VIR_STRNDUP(def->family, cur, eol - cur) < 0)
        goto cleanup;
P
Prerna Saxena 已提交
189 190 191 192 193

    if ((cur = strstr(base, "model")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
194 195
        if (eol && VIR_STRNDUP(def->serial, cur, eol - cur) < 0)
            goto cleanup;
P
Prerna Saxena 已提交
196 197 198 199 200 201
    }

    if ((cur = strstr(base, "machine")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
202 203
        if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
            goto cleanup;
P
Prerna Saxena 已提交
204 205
    }

206 207 208 209 210 211
    if (!def->manufacturer && !def->product && !def->version &&
        !def->serial && !def->uuid && !def->sku && !def->family) {
        virSysinfoSystemDefFree(def);
        def = NULL;
    }

M
Michal Privoznik 已提交
212
    *sysdef = def;
213 214 215 216 217
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    return ret;
P
Prerna Saxena 已提交
218 219 220 221 222 223 224 225 226
}

static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
{
    const char *cur;
    char *eol, *tmp_base;
    virSysinfoProcessorDefPtr processor;

227
    while ((tmp_base = strstr(base, "processor")) != NULL) {
P
Prerna Saxena 已提交
228 229 230 231
        base = tmp_base;
        eol = strchr(base, '\n');
        cur = strchr(base, ':') + 1;

232
        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0)
233
            return -1;
P
Prerna Saxena 已提交
234 235 236
        processor = &ret->processor[ret->nprocessor - 1];

        virSkipSpaces(&cur);
237 238 239
        if (eol && VIR_STRNDUP(processor->processor_socket_destination,
                               cur, eol - cur) < 0)
            return -1;
P
Prerna Saxena 已提交
240 241 242 243 244

        if ((cur = strstr(base, "cpu")) != NULL) {
            cur = strchr(cur, ':') + 1;
            eol = strchr(cur, '\n');
            virSkipSpaces(&cur);
245 246 247
            if (eol && VIR_STRNDUP(processor->processor_type,
                                   cur, eol - cur) < 0)
                return -1;
P
Prerna Saxena 已提交
248 249 250 251 252 253
        }

        if ((cur = strstr(base, "revision")) != NULL) {
            cur = strchr(cur, ':') + 1;
            eol = strchr(cur, '\n');
            virSkipSpaces(&cur);
254 255 256
            if (eol && VIR_STRNDUP(processor->processor_version,
                                   cur, eol - cur) < 0)
                return -1;
P
Prerna Saxena 已提交
257 258 259 260 261 262 263 264 265 266 267
        }

        base = cur;
    }

    return 0;
}

/* virSysinfoRead for PowerPC
 * Gathers sysinfo data from /proc/cpuinfo */
virSysinfoDefPtr
268 269
virSysinfoRead(void)
{
P
Prerna Saxena 已提交
270 271 272 273 274 275
    virSysinfoDefPtr ret = NULL;
    char *outbuf = NULL;

    if (VIR_ALLOC(ret) < 0)
        goto no_memory;

276
    if (virFileReadAll(CPUINFO, CPUINFO_FILE_LEN, &outbuf) < 0) {
277 278
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to open %s"), CPUINFO);
P
Prerna Saxena 已提交
279 280 281 282 283 284 285 286
        return NULL;
    }

    ret->nprocessor = 0;
    ret->processor = NULL;
    if (virSysinfoParseProcessor(outbuf, ret) < 0)
        goto no_memory;

287
    if (virSysinfoParseSystem(outbuf, &ret->system) < 0)
P
Prerna Saxena 已提交
288 289 290 291
        goto no_memory;

    return ret;

292
 no_memory:
P
Prerna Saxena 已提交
293 294 295 296
    VIR_FREE(outbuf);
    return NULL;
}

297
#elif defined(__arm__) || defined(__aarch64__)
298
static int
M
Michal Privoznik 已提交
299
virSysinfoParseSystem(const char *base, virSysinfoSystemDefPtr *sysdef)
300
{
301
    int ret = -1;
302 303
    char *eol = NULL;
    const char *cur;
304
    virSysinfoSystemDefPtr def;
305 306 307 308

    if ((cur = strstr(base, "platform")) == NULL)
        return 0;

309 310 311
    if (VIR_ALLOC(def) < 0)
        return ret;

312 313 314 315 316
    base = cur;
    /* Account for format 'platform    : XXXX'*/
    cur = strchr(cur, ':') + 1;
    eol = strchr(cur, '\n');
    virSkipSpaces(&cur);
317 318
    if (eol && VIR_STRNDUP(def->family, cur, eol - cur) < 0)
        goto cleanup;
319 320 321 322 323

    if ((cur = strstr(base, "model")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
324 325
        if (eol && VIR_STRNDUP(def->serial, cur, eol - cur) < 0)
            goto cleanup;
326 327 328 329 330 331
    }

    if ((cur = strstr(base, "machine")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
332 333
        if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
            goto cleanup;
334
    }
335

336 337 338 339 340 341
    if (!def->manufacturer && !def->product && !def->version &&
        !def->serial && !def->uuid && !def->sku && !def->family) {
        virSysinfoSystemDefFree(def);
        def = NULL;
    }

M
Michal Privoznik 已提交
342
    *sysdef = def;
343 344 345 346 347
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    return ret;
348 349 350 351 352 353 354 355 356 357
}

static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
{
    const char *cur;
    char *eol, *tmp_base;
    virSysinfoProcessorDefPtr processor;
    char *processor_type = NULL;

M
Michal Privoznik 已提交
358 359
    if (!(tmp_base = strstr(base, "model name")) &&
        !(tmp_base = strstr(base, "Processor")))
360 361
        return 0;

M
Michal Privoznik 已提交
362 363
    eol = strchr(tmp_base, '\n');
    cur = strchr(tmp_base, ':') + 1;
364
    virSkipSpaces(&cur);
365 366
    if (eol && VIR_STRNDUP(processor_type, cur, eol - cur) < 0)
        goto error;
367 368 369 370 371 372

    while ((tmp_base = strstr(base, "processor")) != NULL) {
        base = tmp_base;
        eol = strchr(base, '\n');
        cur = strchr(base, ':') + 1;

373
        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0)
374
            goto error;
375 376 377 378
        processor = &ret->processor[ret->nprocessor - 1];

        virSkipSpaces(&cur);
        if (eol &&
379 380 381
            VIR_STRNDUP(processor->processor_socket_destination,
                        cur, eol - cur) < 0)
            goto error;
382

383
        if (VIR_STRDUP(processor->processor_type, processor_type) < 0)
384
            goto error;
385 386 387 388 389 390 391

        base = cur;
    }

    VIR_FREE(processor_type);
    return 0;

392
 error:
393 394 395 396 397 398 399
    VIR_FREE(processor_type);
    return -1;
}

/* virSysinfoRead for ARMv7
 * Gathers sysinfo data from /proc/cpuinfo */
virSysinfoDefPtr
400 401
virSysinfoRead(void)
{
402 403 404 405 406 407
    virSysinfoDefPtr ret = NULL;
    char *outbuf = NULL;

    if (VIR_ALLOC(ret) < 0)
        goto no_memory;

408
    if (virFileReadAll(CPUINFO, CPUINFO_FILE_LEN, &outbuf) < 0) {
409 410 411 412 413 414 415 416 417 418
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to open %s"), CPUINFO);
        return NULL;
    }

    ret->nprocessor = 0;
    ret->processor = NULL;
    if (virSysinfoParseProcessor(outbuf, ret) < 0)
        goto no_memory;

419
    if (virSysinfoParseSystem(outbuf, &ret->system) < 0)
420 421 422 423
        goto no_memory;

    return ret;

424
 no_memory:
425 426 427 428 429 430
    VIR_FREE(outbuf);
    return NULL;
}


#elif defined(__s390__) || defined(__s390x__)
431 432 433 434 435 436 437 438 439 440 441
/*
  we need to ignore warnings about strchr caused by -Wlogical-op
  for some GCC versions.
  Doing it via a local pragma keeps the damage smaller than
  disabling it on the package level.
  Unfortunately, the affected GCCs don't allow diagnostic push/pop
  which would have further reduced the impact.
 */
# if BROKEN_GCC_WLOGICALOP
#  pragma GCC diagnostic ignored "-Wlogical-op"
# endif
442

443 444 445 446 447 448 449 450 451 452 453 454 455
static char *
virSysinfoParseDelimited(const char *base, const char *name, char **value,
                         char delim1, char delim2)
{
    const char *start;
    char *end;

    if (delim1 != delim2 &&
        (start = strstr(base, name)) &&
        (start = strchr(start, delim1))) {
        start += 1;
        end = strchrnul(start, delim2);
        virSkipSpaces(&start);
456 457
        if (VIR_STRNDUP(*value, start, end - start) < 0)
            return NULL;
458 459
        virTrimSpaces(*value, NULL);
        return end;
460
    }
461 462
    return NULL;
}
463

464 465 466 467 468 469 470
static char *
virSysinfoParseLine(const char *base, const char *name, char **value)
{
    return virSysinfoParseDelimited(base, name, value, ':', '\n');
}

static int
M
Michal Privoznik 已提交
471
virSysinfoParseSystem(const char *base, virSysinfoSystemDefPtr *sysdef)
472
{
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
    int ret = -1;
    virSysinfoSystemDefPtr def;

    if (VIR_ALLOC(def) < 0)
        return ret;

    if (!virSysinfoParseLine(base, "Manufacturer",
                             &def->manufacturer))
        goto cleanup;

    if (!virSysinfoParseLine(base, "Type",
                             &def->family))
        goto cleanup;

    if (!virSysinfoParseLine(base, "Sequence Code",
                             &def->serial))
        goto cleanup;

    if (!def->manufacturer && !def->product && !def->version &&
        !def->serial && !def->uuid && !def->sku && !def->family) {
        virSysinfoSystemDefFree(def);
        def = NULL;
    }

M
Michal Privoznik 已提交
497
    *sysdef = def;
498 499 500 501 502
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    return ret;
503 504 505 506 507
}

static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
{
508 509 510 511
    char *tmp_base;
    char *manufacturer = NULL;
    char *procline = NULL;
    int result = -1;
512 513
    virSysinfoProcessorDefPtr processor;

514
    if (!(tmp_base = virSysinfoParseLine(base, "vendor_id", &manufacturer)))
515
        goto cleanup;
516

517 518 519 520 521
    /* Find processor N: line and gather the processor manufacturer,
       version, serial number, and family */
    while ((tmp_base = strstr(tmp_base, "processor "))
           && (tmp_base = virSysinfoParseLine(tmp_base, "processor ",
                                              &procline))) {
522
        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0)
523
            goto cleanup;
524
        processor = &ret->processor[ret->nprocessor - 1];
525 526
        if (VIR_STRDUP(processor->processor_manufacturer, manufacturer) < 0)
            goto cleanup;
527 528 529 530 531 532 533 534 535 536
        if (!virSysinfoParseDelimited(procline, "version",
                                      &processor->processor_version,
                                      '=', ',') ||
            !virSysinfoParseDelimited(procline, "identification",
                                      &processor->processor_serial_number,
                                      '=', ',') ||
            !virSysinfoParseDelimited(procline, "machine",
                                      &processor->processor_family,
                                      '=', '\n'))
            goto cleanup;
537
    }
538
    result = 0;
539

540
 cleanup:
541 542 543
    VIR_FREE(manufacturer);
    VIR_FREE(procline);
    return result;
544 545 546 547 548
}

/* virSysinfoRead for s390x
 * Gathers sysinfo data from /proc/sysinfo and /proc/cpuinfo */
virSysinfoDefPtr
549 550
virSysinfoRead(void)
{
551 552 553 554 555 556 557
    virSysinfoDefPtr ret = NULL;
    char *outbuf = NULL;

    if (VIR_ALLOC(ret) < 0)
        goto no_memory;

    /* Gather info from /proc/cpuinfo */
558
    if (virFileReadAll(CPUINFO, CPUINFO_FILE_LEN, &outbuf) < 0) {
559 560
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to open %s"), CPUINFO);
561 562 563 564 565 566 567 568 569 570 571 572
        return NULL;
    }

    ret->nprocessor = 0;
    ret->processor = NULL;
    if (virSysinfoParseProcessor(outbuf, ret) < 0)
        goto no_memory;

    /* Free buffer before reading next file */
    VIR_FREE(outbuf);

    /* Gather info from /proc/sysinfo */
573
    if (virFileReadAll(SYSINFO, 8192, &outbuf) < 0) {
574 575
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to open %s"), SYSINFO);
576 577 578
        return NULL;
    }

579
    if (virSysinfoParseSystem(outbuf, &ret->system) < 0)
580 581 582 583
        goto no_memory;

    return ret;

584
 no_memory:
585
    virSysinfoDefFree(ret);
586 587 588 589
    VIR_FREE(outbuf);
    return NULL;
}

P
Prerna Saxena 已提交
590
#elif defined(WIN32) || \
591 592
    !(defined(__x86_64__) || \
      defined(__i386__) ||   \
P
Prerna Saxena 已提交
593
      defined(__amd64__) || \
594
      defined(__arm__) || \
595
      defined(__aarch64__) || \
P
Prerna Saxena 已提交
596
      defined(__powerpc__))
597
virSysinfoDefPtr
598 599
virSysinfoRead(void)
{
600 601 602 603 604
    /*
     * this can probably be extracted from Windows using API or registry
     * http://www.microsoft.com/whdc/system/platform/firmware/SMBIOS.mspx
     */
    virReportSystemError(ENOSYS, "%s",
605
                         _("Host sysinfo extraction not supported on this platform"));
E
Eric Blake 已提交
606
    return NULL;
607
}
E
Eric Blake 已提交
608

609
#else /* !WIN32 && x86 */
E
Eric Blake 已提交
610

611
static int
612
virSysinfoParseBIOS(const char *base, virSysinfoBIOSDefPtr *bios)
M
Minoru Usui 已提交
613
{
614
    int ret = -1;
615
    const char *cur, *eol = NULL;
616
    virSysinfoBIOSDefPtr def;
617

M
Minoru Usui 已提交
618
    if ((cur = strstr(base, "BIOS Information")) == NULL)
619
        return 0;
M
Minoru Usui 已提交
620

621 622 623
    if (VIR_ALLOC(def) < 0)
        return ret;

M
Minoru Usui 已提交
624
    base = cur;
625 626 627
    if ((cur = strstr(base, "Vendor: ")) != NULL) {
        cur += 8;
        eol = strchr(cur, '\n');
628 629
        if (eol && VIR_STRNDUP(def->vendor, cur, eol - cur) < 0)
            goto cleanup;
630 631 632 633
    }
    if ((cur = strstr(base, "Version: ")) != NULL) {
        cur += 9;
        eol = strchr(cur, '\n');
634 635
        if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
            goto cleanup;
636 637 638 639
    }
    if ((cur = strstr(base, "Release Date: ")) != NULL) {
        cur += 14;
        eol = strchr(cur, '\n');
640 641
        if (eol && VIR_STRNDUP(def->date, cur, eol - cur) < 0)
            goto cleanup;
642 643 644 645
    }
    if ((cur = strstr(base, "BIOS Revision: ")) != NULL) {
        cur += 15;
        eol = strchr(cur, '\n');
646 647
        if (eol && VIR_STRNDUP(def->release, cur, eol - cur) < 0)
            goto cleanup;
648
    }
M
Minoru Usui 已提交
649

650 651 652 653 654 655 656 657 658 659 660 661
    if (!def->vendor && !def->version &&
        !def->date && !def->release) {
        virSysinfoBIOSDefFree(def);
        def = NULL;
    }

    *bios = def;
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoBIOSDefFree(def);
    return ret;
M
Minoru Usui 已提交
662 663
}

664
static int
M
Michal Privoznik 已提交
665
virSysinfoParseSystem(const char *base, virSysinfoSystemDefPtr *sysdef)
M
Minoru Usui 已提交
666
{
667
    int ret = -1;
668
    const char *cur, *eol = NULL;
669
    virSysinfoSystemDefPtr def;
M
Minoru Usui 已提交
670

M
Minoru Usui 已提交
671
    if ((cur = strstr(base, "System Information")) == NULL)
672
        return 0;
M
Minoru Usui 已提交
673

674 675 676
    if (VIR_ALLOC(def) < 0)
        return ret;

M
Minoru Usui 已提交
677
    base = cur;
678 679 680
    if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
        cur += 14;
        eol = strchr(cur, '\n');
681 682
        if (eol && VIR_STRNDUP(def->manufacturer, cur, eol - cur) < 0)
            goto cleanup;
683 684 685 686
    }
    if ((cur = strstr(base, "Product Name: ")) != NULL) {
        cur += 14;
        eol = strchr(cur, '\n');
687 688
        if (eol && VIR_STRNDUP(def->product, cur, eol - cur) < 0)
            goto cleanup;
689 690 691 692
    }
    if ((cur = strstr(base, "Version: ")) != NULL) {
        cur += 9;
        eol = strchr(cur, '\n');
693 694
        if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
            goto cleanup;
695 696 697 698
    }
    if ((cur = strstr(base, "Serial Number: ")) != NULL) {
        cur += 15;
        eol = strchr(cur, '\n');
699 700
        if (eol && VIR_STRNDUP(def->serial, cur, eol - cur) < 0)
            goto cleanup;
701 702 703 704
    }
    if ((cur = strstr(base, "UUID: ")) != NULL) {
        cur += 6;
        eol = strchr(cur, '\n');
705 706
        if (eol && VIR_STRNDUP(def->uuid, cur, eol - cur) < 0)
            goto cleanup;
707 708 709 710
    }
    if ((cur = strstr(base, "SKU Number: ")) != NULL) {
        cur += 12;
        eol = strchr(cur, '\n');
711 712
        if (eol && VIR_STRNDUP(def->sku, cur, eol - cur) < 0)
            goto cleanup;
713
    }
E
Eric Blake 已提交
714 715 716
    if ((cur = strstr(base, "Family: ")) != NULL) {
        cur += 8;
        eol = strchr(cur, '\n');
717 718
        if (eol && VIR_STRNDUP(def->family, cur, eol - cur) < 0)
            goto cleanup;
E
Eric Blake 已提交
719
    }
720

721 722 723 724 725 726
    if (!def->manufacturer && !def->product && !def->version &&
        !def->serial && !def->uuid && !def->sku && !def->family) {
        virSysinfoSystemDefFree(def);
        def = NULL;
    }

M
Michal Privoznik 已提交
727
    *sysdef = def;
728 729 730 731 732
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    return ret;
M
Minoru Usui 已提交
733 734
}

735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
static int
virSysinfoParseBaseBoard(const char *base,
                         virSysinfoBaseBoardDefPtr *baseBoard,
                         size_t *nbaseBoard)
{
    int ret = -1;
    const char *cur, *eol = NULL;
    virSysinfoBaseBoardDefPtr boards = NULL;
    size_t nboards = 0;
    char *board_type = NULL;

    while (base && (cur = strstr(base, "Base Board Information"))) {
        virSysinfoBaseBoardDefPtr def;

        if (VIR_EXPAND_N(boards, nboards, 1) < 0)
            goto cleanup;

        def = &boards[nboards - 1];

        base = cur + 22;
        if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
            cur += 14;
            eol = strchr(cur, '\n');
            if (eol && VIR_STRNDUP(def->manufacturer, cur, eol - cur) < 0)
                goto cleanup;
        }
        if ((cur = strstr(base, "Product Name: ")) != NULL) {
            cur += 14;
            eol = strchr(cur, '\n');
            if (eol && VIR_STRNDUP(def->product, cur, eol - cur) < 0)
                goto cleanup;
        }
        if ((cur = strstr(base, "Version: ")) != NULL) {
            cur += 9;
            eol = strchr(cur, '\n');
            if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
                goto cleanup;
        }
        if ((cur = strstr(base, "Serial Number: ")) != NULL) {
            cur += 15;
            eol = strchr(cur, '\n');
            if (eol && VIR_STRNDUP(def->serial, cur, eol - cur) < 0)
                goto cleanup;
        }
        if ((cur = strstr(base, "Asset Tag: ")) != NULL) {
            cur += 11;
            eol = strchr(cur, '\n');
            if (eol && VIR_STRNDUP(def->asset, cur, eol - cur) < 0)
                goto cleanup;
        }
        if ((cur = strstr(base, "Location In Chassis: ")) != NULL) {
            cur += 21;
            eol = strchr(cur, '\n');
            if (eol && VIR_STRNDUP(def->location, cur, eol - cur) < 0)
                goto cleanup;
        }

        if (!def->manufacturer && !def->product && !def->version &&
            !def->serial && !def->asset && !def->location)
            nboards--;
    }

    /* This is safe, as we can be only shrinking the memory */
    ignore_value(VIR_REALLOC_N(boards, nboards));

    *baseBoard = boards;
    *nbaseBoard = nboards;
    boards = NULL;
    nboards = 0;
    ret = 0;
 cleanup:
    while (nboards--)
        virSysinfoBaseBoardDefClear(&boards[nboards]);
    VIR_FREE(boards);
    VIR_FREE(board_type);
    return ret;
}

813 814
static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
815
{
816 817
    const char *cur, *tmp_base;
    char *eol;
818
    virSysinfoProcessorDefPtr processor;
819

820
    while ((tmp_base = strstr(base, "Processor Information")) != NULL) {
821
        base = tmp_base;
E
Eric Blake 已提交
822
        eol = NULL;
823

824 825
        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0)
            return -1;
826 827 828 829 830
        processor = &ret->processor[ret->nprocessor - 1];

        if ((cur = strstr(base, "Socket Designation: ")) != NULL) {
            cur += 20;
            eol = strchr(cur, '\n');
831
            virSkipSpacesBackwards(cur, &eol);
832 833 834
            if (eol && VIR_STRNDUP(processor->processor_socket_destination,
                                   cur, eol - cur) < 0)
                return -1;
835 836 837 838
        }
        if ((cur = strstr(base, "Type: ")) != NULL) {
            cur += 6;
            eol = strchr(cur, '\n');
839
            virSkipSpacesBackwards(cur, &eol);
840 841
            if (eol && VIR_STRNDUP(processor->processor_type, cur, eol - cur) < 0)
                return -1;
842 843 844 845
        }
        if ((cur = strstr(base, "Family: ")) != NULL) {
            cur += 8;
            eol = strchr(cur, '\n');
846
            virSkipSpacesBackwards(cur, &eol);
847 848
            if (eol && VIR_STRNDUP(processor->processor_family, cur, eol - cur) < 0)
                return -1;
849 850 851 852
        }
        if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
            cur += 14;
            eol = strchr(cur, '\n');
853
            virSkipSpacesBackwards(cur, &eol);
854 855 856
            if (eol && VIR_STRNDUP(processor->processor_manufacturer,
                                   cur, eol - cur) < 0)
                return -1;
857 858 859 860
        }
        if ((cur = strstr(base, "Signature: ")) != NULL) {
            cur += 11;
            eol = strchr(cur, '\n');
861
            virSkipSpacesBackwards(cur, &eol);
862 863 864
            if (eol && VIR_STRNDUP(processor->processor_signature,
                                   cur, eol - cur) < 0)
                return -1;
865 866 867 868
        }
        if ((cur = strstr(base, "Version: ")) != NULL) {
            cur += 9;
            eol = strchr(cur, '\n');
869
            virSkipSpacesBackwards(cur, &eol);
870 871 872
            if (eol && VIR_STRNDUP(processor->processor_version,
                                   cur, eol - cur) < 0)
                return -1;
873 874 875 876
        }
        if ((cur = strstr(base, "External Clock: ")) != NULL) {
            cur += 16;
            eol = strchr(cur, '\n');
877
            virSkipSpacesBackwards(cur, &eol);
878 879 880
            if (eol && VIR_STRNDUP(processor->processor_external_clock,
                                   cur, eol - cur) < 0)
                return -1;
881 882 883 884
        }
        if ((cur = strstr(base, "Max Speed: ")) != NULL) {
            cur += 11;
            eol = strchr(cur, '\n');
885
            virSkipSpacesBackwards(cur, &eol);
886 887 888
            if (eol && VIR_STRNDUP(processor->processor_max_speed,
                                   cur, eol - cur) < 0)
                return -1;
889 890 891 892
        }
        if ((cur = strstr(base, "Status: ")) != NULL) {
            cur += 8;
            eol = strchr(cur, '\n');
893
            virSkipSpacesBackwards(cur, &eol);
894 895
            if (eol && VIR_STRNDUP(processor->processor_status, cur, eol - cur) < 0)
                return -1;
896 897 898 899
        }
        if ((cur = strstr(base, "Serial Number: ")) != NULL) {
            cur += 15;
            eol = strchr(cur, '\n');
900
            virSkipSpacesBackwards(cur, &eol);
901 902 903
            if (eol && VIR_STRNDUP(processor->processor_serial_number,
                                   cur, eol - cur) < 0)
                return -1;
904 905 906 907
        }
        if ((cur = strstr(base, "Part Number: ")) != NULL) {
            cur += 13;
            eol = strchr(cur, '\n');
908
            virSkipSpacesBackwards(cur, &eol);
909 910 911
            if (eol && VIR_STRNDUP(processor->processor_part_number,
                                   cur, eol - cur) < 0)
                return -1;
912 913
        }

M
Minoru Usui 已提交
914
        base += strlen("Processor Information");
915 916
    }

917
    return 0;
918 919
}

920 921
static int
virSysinfoParseMemory(const char *base, virSysinfoDefPtr ret)
922
{
923 924
    const char *cur, *tmp_base;
    char *eol;
925
    virSysinfoMemoryDefPtr memory;
926 927 928

    while ((tmp_base = strstr(base, "Memory Device")) != NULL) {
        base = tmp_base;
E
Eric Blake 已提交
929
        eol = NULL;
930

931 932
        if (VIR_EXPAND_N(ret->memory, ret->nmemory, 1) < 0)
            return -1;
933 934 935 936 937 938 939 940
        memory = &ret->memory[ret->nmemory - 1];

        if ((cur = strstr(base, "Size: ")) != NULL) {
            cur += 6;
            eol = strchr(cur, '\n');
            if (STREQLEN(cur, "No Module Installed", eol - cur))
                goto next;

941
            virSkipSpacesBackwards(cur, &eol);
942 943
            if (eol && VIR_STRNDUP(memory->memory_size, cur, eol - cur) < 0)
                return -1;
944 945 946 947
        }
        if ((cur = strstr(base, "Form Factor: ")) != NULL) {
            cur += 13;
            eol = strchr(cur, '\n');
948
            virSkipSpacesBackwards(cur, &eol);
949 950 951
            if (eol && VIR_STRNDUP(memory->memory_form_factor,
                                   cur, eol - cur) < 0)
                return -1;
952 953 954 955
        }
        if ((cur = strstr(base, "Locator: ")) != NULL) {
            cur += 9;
            eol = strchr(cur, '\n');
956
            virSkipSpacesBackwards(cur, &eol);
E
Eric Blake 已提交
957
            if (eol && VIR_STRNDUP(memory->memory_locator, cur, eol - cur) < 0)
958
                return -1;
959 960 961 962
        }
        if ((cur = strstr(base, "Bank Locator: ")) != NULL) {
            cur += 14;
            eol = strchr(cur, '\n');
963
            virSkipSpacesBackwards(cur, &eol);
964 965 966
            if (eol && VIR_STRNDUP(memory->memory_bank_locator,
                                   cur, eol - cur) < 0)
                return -1;
967 968 969 970
        }
        if ((cur = strstr(base, "Type: ")) != NULL) {
            cur += 6;
            eol = strchr(cur, '\n');
971
            virSkipSpacesBackwards(cur, &eol);
972 973
            if (eol && VIR_STRNDUP(memory->memory_type, cur, eol - cur) < 0)
                return -1;
974 975 976 977
        }
        if ((cur = strstr(base, "Type Detail: ")) != NULL) {
            cur += 13;
            eol = strchr(cur, '\n');
978
            virSkipSpacesBackwards(cur, &eol);
979 980
            if (eol && VIR_STRNDUP(memory->memory_type_detail, cur, eol - cur) < 0)
                return -1;
981 982 983 984
        }
        if ((cur = strstr(base, "Speed: ")) != NULL) {
            cur += 7;
            eol = strchr(cur, '\n');
985
            virSkipSpacesBackwards(cur, &eol);
986 987
            if (eol && VIR_STRNDUP(memory->memory_speed, cur, eol - cur) < 0)
                return -1;
988 989 990 991
        }
        if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
            cur += 14;
            eol = strchr(cur, '\n');
992
            virSkipSpacesBackwards(cur, &eol);
993 994
            if (eol && VIR_STRNDUP(memory->memory_manufacturer, cur, eol - cur) < 0)
                return -1;
995 996 997 998
        }
        if ((cur = strstr(base, "Serial Number: ")) != NULL) {
            cur += 15;
            eol = strchr(cur, '\n');
999
            virSkipSpacesBackwards(cur, &eol);
1000 1001 1002
            if (eol && VIR_STRNDUP(memory->memory_serial_number,
                                   cur, eol - cur) < 0)
                return -1;
1003 1004 1005 1006
        }
        if ((cur = strstr(base, "Part Number: ")) != NULL) {
            cur += 13;
            eol = strchr(cur, '\n');
1007
            virSkipSpacesBackwards(cur, &eol);
1008 1009
            if (eol && VIR_STRNDUP(memory->memory_part_number, cur, eol - cur) < 0)
                return -1;
1010 1011 1012
        }

    next:
M
Minoru Usui 已提交
1013
        base += strlen("Memory Device");
1014 1015
    }

1016
    return 0;
1017 1018
}

M
Minoru Usui 已提交
1019
virSysinfoDefPtr
1020 1021
virSysinfoRead(void)
{
1022
    char *path;
M
Minoru Usui 已提交
1023 1024 1025 1026 1027 1028
    virSysinfoDefPtr ret = NULL;
    char *outbuf = NULL;
    virCommandPtr cmd;

    path = virFindFileInPath(SYSINFO_SMBIOS_DECODER);
    if (path == NULL) {
1029 1030 1031
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to find path for %s binary"),
                       SYSINFO_SMBIOS_DECODER);
M
Minoru Usui 已提交
1032 1033 1034
        return NULL;
    }

1035
    cmd = virCommandNewArgList(path, "-q", "-t", "0,1,2,4,17", NULL);
M
Minoru Usui 已提交
1036 1037
    VIR_FREE(path);
    virCommandSetOutputBuffer(cmd, &outbuf);
1038
    if (virCommandRun(cmd, NULL) < 0)
M
Minoru Usui 已提交
1039 1040 1041
        goto cleanup;

    if (VIR_ALLOC(ret) < 0)
1042
        goto error;
M
Minoru Usui 已提交
1043 1044 1045

    ret->type = VIR_SYSINFO_SMBIOS;

1046
    if (virSysinfoParseBIOS(outbuf, &ret->bios) < 0)
1047
        goto error;
M
Minoru Usui 已提交
1048

1049
    if (virSysinfoParseSystem(outbuf, &ret->system) < 0)
1050
        goto error;
M
Minoru Usui 已提交
1051

1052 1053 1054
    if (virSysinfoParseBaseBoard(outbuf, &ret->baseBoard, &ret->nbaseBoard) < 0)
        goto error;

1055 1056
    ret->nprocessor = 0;
    ret->processor = NULL;
1057
    if (virSysinfoParseProcessor(outbuf, ret) < 0)
1058
        goto error;
1059

1060 1061
    ret->nmemory = 0;
    ret->memory = NULL;
1062
    if (virSysinfoParseMemory(outbuf, ret) < 0)
1063
        goto error;
1064

1065
 cleanup:
1066
    VIR_FREE(outbuf);
E
Eric Blake 已提交
1067
    virCommandFree(cmd);
1068

E
Eric Blake 已提交
1069
    return ret;
1070

1071
 error:
1072 1073 1074 1075
    virSysinfoDefFree(ret);
    ret = NULL;
    goto cleanup;
}
1076
#endif /* !WIN32 && x86 */
E
Eric Blake 已提交
1077

M
Minoru Usui 已提交
1078
static void
1079
virSysinfoBIOSFormat(virBufferPtr buf, virSysinfoBIOSDefPtr def)
E
Eric Blake 已提交
1080
{
1081
    if (!def)
1082
        return;
M
Minoru Usui 已提交
1083

1084 1085 1086
    virBufferAddLit(buf, "<bios>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<entry name='vendor'>%s</entry>\n",
1087
                          def->vendor);
1088
    virBufferEscapeString(buf, "<entry name='version'>%s</entry>\n",
1089
                          def->version);
1090
    virBufferEscapeString(buf, "<entry name='date'>%s</entry>\n",
1091
                          def->date);
1092
    virBufferEscapeString(buf, "<entry name='release'>%s</entry>\n",
1093
                          def->release);
1094 1095
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</bios>\n");
M
Minoru Usui 已提交
1096 1097 1098
}

static void
1099
virSysinfoSystemFormat(virBufferPtr buf, virSysinfoSystemDefPtr def)
M
Minoru Usui 已提交
1100
{
1101
    if (!def)
1102
        return;
M
Minoru Usui 已提交
1103

1104 1105 1106
    virBufferAddLit(buf, "<system>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<entry name='manufacturer'>%s</entry>\n",
1107
                          def->manufacturer);
1108
    virBufferEscapeString(buf, "<entry name='product'>%s</entry>\n",
1109
                          def->product);
1110
    virBufferEscapeString(buf, "<entry name='version'>%s</entry>\n",
1111
                          def->version);
1112
    virBufferEscapeString(buf, "<entry name='serial'>%s</entry>\n",
1113
                          def->serial);
1114
    virBufferEscapeString(buf, "<entry name='uuid'>%s</entry>\n",
1115
                          def->uuid);
1116
    virBufferEscapeString(buf, "<entry name='sku'>%s</entry>\n",
1117
                          def->sku);
1118
    virBufferEscapeString(buf, "<entry name='family'>%s</entry>\n",
1119
                          def->family);
1120 1121
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</system>\n");
M
Minoru Usui 已提交
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
static void
virSysinfoBaseBoardFormat(virBufferPtr buf,
                          virSysinfoBaseBoardDefPtr baseBoard,
                          size_t nbaseBoard)
{
    virSysinfoBaseBoardDefPtr def;
    size_t i;

    for (i = 0; i < nbaseBoard; i++) {
        def = baseBoard + i;

        virBufferAddLit(buf, "<baseBoard>\n");
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<entry name='manufacturer'>%s</entry>\n",
                              def->manufacturer);
        virBufferEscapeString(buf, "<entry name='product'>%s</entry>\n",
                              def->product);
        virBufferEscapeString(buf, "<entry name='version'>%s</entry>\n",
                              def->version);
        virBufferEscapeString(buf, "<entry name='serial'>%s</entry>\n",
                              def->serial);
        virBufferEscapeString(buf, "<entry name='asset'>%s</entry>\n",
                              def->asset);
        virBufferEscapeString(buf, "<entry name='location'>%s</entry>\n",
                              def->location);
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</baseBoard>\n");
    }
}

1154
static void
1155
virSysinfoProcessorFormat(virBufferPtr buf, virSysinfoDefPtr def)
1156
{
1157
    size_t i;
1158
    virSysinfoProcessorDefPtr processor;
1159 1160 1161 1162

    for (i = 0; i < def->nprocessor; i++) {
        processor = &def->processor[i];

1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
        if (!processor->processor_socket_destination &&
            !processor->processor_type &&
            !processor->processor_family &&
            !processor->processor_manufacturer &&
            !processor->processor_signature &&
            !processor->processor_version &&
            !processor->processor_external_clock &&
            !processor->processor_max_speed &&
            !processor->processor_status &&
            !processor->processor_serial_number &&
            !processor->processor_part_number)
            continue;

1176 1177
        virBufferAddLit(buf, "<processor>\n");
        virBufferAdjustIndent(buf, 2);
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
        virBufferEscapeString(buf,
                              "<entry name='socket_destination'>%s</entry>\n",
                              processor->processor_socket_destination);
        virBufferEscapeString(buf, "<entry name='type'>%s</entry>\n",
                              processor->processor_type);
        virBufferEscapeString(buf, "<entry name='family'>%s</entry>\n",
                              processor->processor_family);
        virBufferEscapeString(buf, "<entry name='manufacturer'>%s</entry>\n",
                              processor->processor_manufacturer);
        virBufferEscapeString(buf, "<entry name='signature'>%s</entry>\n",
                              processor->processor_signature);
        virBufferEscapeString(buf, "<entry name='version'>%s</entry>\n",
                              processor->processor_version);
        virBufferEscapeString(buf, "<entry name='external_clock'>%s</entry>\n",
                              processor->processor_external_clock);
        virBufferEscapeString(buf, "<entry name='max_speed'>%s</entry>\n",
                              processor->processor_max_speed);
        virBufferEscapeString(buf, "<entry name='status'>%s</entry>\n",
                              processor->processor_status);
        virBufferEscapeString(buf, "<entry name='serial_number'>%s</entry>\n",
                              processor->processor_serial_number);
        virBufferEscapeString(buf, "<entry name='part_number'>%s</entry>\n",
                              processor->processor_part_number);
1201 1202
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</processor>\n");
1203 1204 1205
    }
}

1206
static void
1207
virSysinfoMemoryFormat(virBufferPtr buf, virSysinfoDefPtr def)
1208
{
1209
    size_t i;
1210
    virSysinfoMemoryDefPtr memory;
1211 1212 1213 1214

    for (i = 0; i < def->nmemory; i++) {
        memory = &def->memory[i];

1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
        if (!memory->memory_size &&
            !memory->memory_form_factor &&
            !memory->memory_locator &&
            !memory->memory_bank_locator &&
            !memory->memory_type &&
            !memory->memory_type_detail &&
            !memory->memory_speed &&
            !memory->memory_manufacturer &&
            !memory->memory_serial_number &&
            !memory->memory_part_number)
            continue;

1227 1228 1229
        virBufferAddLit(buf, "<memory_device>\n");
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<entry name='size'>%s</entry>\n",
1230 1231
                              memory->memory_size);
        virBufferEscapeString(buf,
1232
                              "<entry name='form_factor'>%s</entry>\n",
1233
                              memory->memory_form_factor);
1234
        virBufferEscapeString(buf, "<entry name='locator'>%s</entry>\n",
1235 1236
                              memory->memory_locator);
        virBufferEscapeString(buf,
1237
                              "<entry name='bank_locator'>%s</entry>\n",
1238
                              memory->memory_bank_locator);
1239
        virBufferEscapeString(buf, "<entry name='type'>%s</entry>\n",
1240 1241
                              memory->memory_type);
        virBufferEscapeString(buf,
1242
                              "<entry name='type_detail'>%s</entry>\n",
1243
                              memory->memory_type_detail);
1244
        virBufferEscapeString(buf, "<entry name='speed'>%s</entry>\n",
1245 1246
                              memory->memory_speed);
        virBufferEscapeString(buf,
1247
                              "<entry name='manufacturer'>%s</entry>\n",
1248 1249
                              memory->memory_manufacturer);
        virBufferEscapeString(buf,
1250
                              "<entry name='serial_number'>%s</entry>\n",
1251 1252
                              memory->memory_serial_number);
        virBufferEscapeString(buf,
1253
                              "<entry name='part_number'>%s</entry>\n",
1254
                              memory->memory_part_number);
1255 1256
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</memory_device>\n");
1257 1258 1259
    }
}

M
Minoru Usui 已提交
1260 1261
/**
 * virSysinfoFormat:
1262
 * @buf: buffer to append output to (may use auto-indentation)
M
Minoru Usui 已提交
1263 1264
 * @def: structure to convert to xml string
 *
1265
 * Returns 0 on success, -1 on failure after generating an error message.
M
Minoru Usui 已提交
1266
 */
1267 1268
int
virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def)
M
Minoru Usui 已提交
1269
{
1270
    virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
M
Minoru Usui 已提交
1271
    const char *type = virSysinfoTypeToString(def->type);
1272 1273
    int indent = virBufferGetIndent(buf, false);
    int ret = -1;
M
Minoru Usui 已提交
1274 1275

    if (!type) {
1276 1277 1278
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected sysinfo type model %d"),
                       def->type);
1279
        virBufferFreeAndReset(buf);
1280
        goto cleanup;
E
Eric Blake 已提交
1281 1282
    }

1283
    virBufferAdjustIndent(&childrenBuf, indent + 2);
M
Minoru Usui 已提交
1284

1285
    virSysinfoBIOSFormat(&childrenBuf, def->bios);
1286
    virSysinfoSystemFormat(&childrenBuf, def->system);
1287
    virSysinfoBaseBoardFormat(&childrenBuf, def->baseBoard, def->nbaseBoard);
1288 1289
    virSysinfoProcessorFormat(&childrenBuf, def);
    virSysinfoMemoryFormat(&childrenBuf, def);
M
Minoru Usui 已提交
1290

1291 1292 1293 1294 1295 1296 1297 1298
    virBufferAsprintf(buf, "<sysinfo type='%s'", type);
    if (virBufferUse(&childrenBuf)) {
        virBufferAddLit(buf, ">\n");
        virBufferAddBuffer(buf, &childrenBuf);
        virBufferAddLit(buf, "</sysinfo>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }
E
Eric Blake 已提交
1299

1300
    if (virBufferCheckError(buf) < 0)
1301
        goto cleanup;
1302

1303 1304 1305 1306
    ret = 0;
 cleanup:
    virBufferFreeAndReset(&childrenBuf);
    return ret;
E
Eric Blake 已提交
1307 1308
}

1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
#define CHECK_FIELD(name, desc)                                         \
    do {                                                                \
        if (STRNEQ_NULLABLE(src->name, dst->name)) {                    \
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,                  \
                           _("Target sysinfo %s %s does not match source %s"), \
                           desc, NULLSTR(dst->name), NULLSTR(src->name)); \
            goto cleanup;                                               \
        }                                                               \
    } while (0)

static bool
virSysinfoBIOSIsEqual(virSysinfoBIOSDefPtr src,
                      virSysinfoBIOSDefPtr dst)
{
    bool identical = false;

    if (!src && !dst)
        return true;

    if ((src && !dst) || (!src && dst)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target sysinfo does not match source"));
        goto cleanup;
    }

    CHECK_FIELD(vendor, "BIOS vendor");
    CHECK_FIELD(version, "BIOS version");
    CHECK_FIELD(date, "BIOS date");
    CHECK_FIELD(release, "BIOS release");

    identical = true;
 cleanup:
    return identical;
}

1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
static bool
virSysinfoSystemIsEqual(virSysinfoSystemDefPtr src,
                        virSysinfoSystemDefPtr dst)
{
    bool identical = false;

    if (!src && !dst)
        return true;

    if ((src && !dst) || (!src && dst)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target sysinfo does not match source"));
        goto cleanup;
    }

    CHECK_FIELD(manufacturer, "system vendor");
    CHECK_FIELD(product, "system product");
    CHECK_FIELD(version, "system version");
    CHECK_FIELD(serial, "system serial");
    CHECK_FIELD(uuid, "system uuid");
    CHECK_FIELD(sku, "system sku");
    CHECK_FIELD(family, "system family");

    identical = true;
 cleanup:
    return identical;
}

1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
static bool
virSysinfoBaseBoardIsEqual(virSysinfoBaseBoardDefPtr src,
                           virSysinfoBaseBoardDefPtr dst)
{
    bool identical = false;

    if (!src && !dst)
        return true;

    if ((src && !dst) || (!src && dst)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target base board does not match source"));
        goto cleanup;
    }

    CHECK_FIELD(manufacturer, "base board vendor");
    CHECK_FIELD(product, "base board product");
    CHECK_FIELD(version, "base board version");
    CHECK_FIELD(serial, "base board serial");
    CHECK_FIELD(asset, "base board asset");
    CHECK_FIELD(location, "base board location");

    identical = true;
 cleanup:
    return identical;
}

1399 1400
#undef CHECK_FIELD

1401 1402 1403 1404
bool virSysinfoIsEqual(virSysinfoDefPtr src,
                       virSysinfoDefPtr dst)
{
    bool identical = false;
1405
    size_t i;
1406 1407 1408 1409 1410

    if (!src && !dst)
        return true;

    if ((src && !dst) || (!src && dst)) {
1411 1412
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target sysinfo does not match source"));
1413 1414 1415 1416
        goto cleanup;
    }

    if (src->type != dst->type) {
1417 1418 1419 1420
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target sysinfo %s does not match source %s"),
                       virSysinfoTypeToString(dst->type),
                       virSysinfoTypeToString(src->type));
1421 1422 1423
        goto cleanup;
    }

1424 1425
    if (!virSysinfoBIOSIsEqual(src->bios, dst->bios))
        goto cleanup;
1426

1427 1428
    if (!virSysinfoSystemIsEqual(src->system, dst->system))
        goto cleanup;
1429

1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
    if (src->nbaseBoard != dst->nbaseBoard) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target sysinfo base board count '%zu' does not match source '%zu'"),
                       dst->nbaseBoard, src->nbaseBoard);
        goto cleanup;
    }

    for (i = 0; i < src->nbaseBoard; i++)
        if (!virSysinfoBaseBoardIsEqual(src->baseBoard + i,
                                        dst->baseBoard + i))
            goto cleanup;

1442 1443
    identical = true;

1444
 cleanup:
1445 1446
    return identical;
}