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_SYSINFO_PRIV_H_ALLOW__
#include "virsysinfopriv.h"

43 44 45
#define VIR_FROM_THIS VIR_FROM_SYSINFO


46 47 48
VIR_ENUM_IMPL(virSysinfo, VIR_SYSINFO_LAST,
              "smbios");

49
static const char *sysinfoDmidecode = DMIDECODE;
50 51 52 53 54 55
static const char *sysinfoSysinfo = "/proc/sysinfo";
static const char *sysinfoCpuinfo = "/proc/cpuinfo";

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

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

70 71 72 73 74 75 76 77 78 79 80 81
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);
}

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
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);
}

97 98 99 100 101 102 103 104 105 106 107 108
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);
}
109

110 111 112 113 114 115 116 117 118
/**
 * virSysinfoDefFree:
 * @def: a sysinfo structure
 *
 * Free up the sysinfo structure
 */

void virSysinfoDefFree(virSysinfoDefPtr def)
{
119
    size_t i;
120

121 122 123
    if (def == NULL)
        return;

124
    virSysinfoBIOSDefFree(def->bios);
125
    virSysinfoSystemDefFree(def->system);
126

127 128 129 130
    for (i = 0; i < def->nbaseBoard; i++)
        virSysinfoBaseBoardDefClear(def->baseBoard + i);
    VIR_FREE(def->baseBoard);

131
    for (i = 0; i < def->nprocessor; i++) {
132 133 134 135 136 137 138 139 140 141 142 143 144
        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);
145
    for (i = 0; i < def->nmemory; i++) {
146 147 148 149 150 151 152 153 154 155 156 157
        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);
158

159 160 161
    VIR_FREE(def);
}

P
Prerna Saxena 已提交
162 163

static int
164
virSysinfoParsePPCSystem(const char *base, virSysinfoSystemDefPtr *sysdef)
P
Prerna Saxena 已提交
165
{
166
    int ret = -1;
P
Prerna Saxena 已提交
167 168
    char *eol = NULL;
    const char *cur;
169
    virSysinfoSystemDefPtr def;
P
Prerna Saxena 已提交
170 171 172 173

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

174 175 176
    if (VIR_ALLOC(def) < 0)
        return ret;

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

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

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

201 202 203 204 205 206
    if (!def->manufacturer && !def->product && !def->version &&
        !def->serial && !def->uuid && !def->sku && !def->family) {
        virSysinfoSystemDefFree(def);
        def = NULL;
    }

M
Michal Privoznik 已提交
207
    *sysdef = def;
208 209 210 211 212
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    return ret;
P
Prerna Saxena 已提交
213 214 215
}

static int
216
virSysinfoParsePPCProcessor(const char *base, virSysinfoDefPtr ret)
P
Prerna Saxena 已提交
217 218 219 220 221
{
    const char *cur;
    char *eol, *tmp_base;
    virSysinfoProcessorDefPtr processor;

222
    while ((tmp_base = strstr(base, "processor")) != NULL) {
P
Prerna Saxena 已提交
223 224 225 226
        base = tmp_base;
        eol = strchr(base, '\n');
        cur = strchr(base, ':') + 1;

227
        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0)
228
            return -1;
P
Prerna Saxena 已提交
229 230 231
        processor = &ret->processor[ret->nprocessor - 1];

        virSkipSpaces(&cur);
232 233 234
        if (eol && VIR_STRNDUP(processor->processor_socket_destination,
                               cur, eol - cur) < 0)
            return -1;
P
Prerna Saxena 已提交
235 236 237 238 239

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

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

        base = cur;
    }

    return 0;
}

/* virSysinfoRead for PowerPC
 * Gathers sysinfo data from /proc/cpuinfo */
virSysinfoDefPtr
263
virSysinfoReadPPC(void)
264
{
P
Prerna Saxena 已提交
265 266 267 268 269 270
    virSysinfoDefPtr ret = NULL;
    char *outbuf = NULL;

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

271
    if (virFileReadAll(CPUINFO, CPUINFO_FILE_LEN, &outbuf) < 0) {
272 273
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to open %s"), CPUINFO);
P
Prerna Saxena 已提交
274 275 276 277 278
        return NULL;
    }

    ret->nprocessor = 0;
    ret->processor = NULL;
279
    if (virSysinfoParsePPCProcessor(outbuf, ret) < 0)
P
Prerna Saxena 已提交
280 281
        goto no_memory;

282
    if (virSysinfoParsePPCSystem(outbuf, &ret->system) < 0)
P
Prerna Saxena 已提交
283 284 285 286
        goto no_memory;

    return ret;

287
 no_memory:
P
Prerna Saxena 已提交
288 289 290 291
    VIR_FREE(outbuf);
    return NULL;
}

292

293
static int
294
virSysinfoParseARMSystem(const char *base, virSysinfoSystemDefPtr *sysdef)
295
{
296
    int ret = -1;
297 298
    char *eol = NULL;
    const char *cur;
299
    virSysinfoSystemDefPtr def;
300 301 302 303

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

304 305 306
    if (VIR_ALLOC(def) < 0)
        return ret;

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

    if ((cur = strstr(base, "model")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
319 320
        if (eol && VIR_STRNDUP(def->serial, cur, eol - cur) < 0)
            goto cleanup;
321 322 323 324 325 326
    }

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

331 332 333 334 335 336
    if (!def->manufacturer && !def->product && !def->version &&
        !def->serial && !def->uuid && !def->sku && !def->family) {
        virSysinfoSystemDefFree(def);
        def = NULL;
    }

M
Michal Privoznik 已提交
337
    *sysdef = def;
338 339 340 341 342
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    return ret;
343 344 345
}

static int
346
virSysinfoParseARMProcessor(const char *base, virSysinfoDefPtr ret)
347 348 349 350 351 352
{
    const char *cur;
    char *eol, *tmp_base;
    virSysinfoProcessorDefPtr processor;
    char *processor_type = NULL;

M
Michal Privoznik 已提交
353 354
    if (!(tmp_base = strstr(base, "model name")) &&
        !(tmp_base = strstr(base, "Processor")))
355 356
        return 0;

M
Michal Privoznik 已提交
357 358
    eol = strchr(tmp_base, '\n');
    cur = strchr(tmp_base, ':') + 1;
359
    virSkipSpaces(&cur);
360 361
    if (eol && VIR_STRNDUP(processor_type, cur, eol - cur) < 0)
        goto error;
362 363 364 365 366 367

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

368
        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0)
369
            goto error;
370 371 372 373
        processor = &ret->processor[ret->nprocessor - 1];

        virSkipSpaces(&cur);
        if (eol &&
374 375 376
            VIR_STRNDUP(processor->processor_socket_destination,
                        cur, eol - cur) < 0)
            goto error;
377

378
        if (VIR_STRDUP(processor->processor_type, processor_type) < 0)
379
            goto error;
380 381 382 383 384 385 386

        base = cur;
    }

    VIR_FREE(processor_type);
    return 0;

387
 error:
388 389 390 391 392 393 394
    VIR_FREE(processor_type);
    return -1;
}

/* virSysinfoRead for ARMv7
 * Gathers sysinfo data from /proc/cpuinfo */
virSysinfoDefPtr
395
virSysinfoReadARM(void)
396
{
397 398 399 400 401 402
    virSysinfoDefPtr ret = NULL;
    char *outbuf = NULL;

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

403
    if (virFileReadAll(CPUINFO, CPUINFO_FILE_LEN, &outbuf) < 0) {
404 405 406 407 408 409 410
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to open %s"), CPUINFO);
        return NULL;
    }

    ret->nprocessor = 0;
    ret->processor = NULL;
411
    if (virSysinfoParseARMProcessor(outbuf, ret) < 0)
412 413
        goto no_memory;

414
    if (virSysinfoParseARMSystem(outbuf, &ret->system) < 0)
415 416 417 418
        goto no_memory;

    return ret;

419
 no_memory:
420 421 422 423 424
    VIR_FREE(outbuf);
    return NULL;
}


425 426

VIR_WARNINGS_NO_WLOGICALOP_STRCHR
427

428
static char *
429 430
virSysinfoParseS390Delimited(const char *base, const char *name, char **value,
                             char delim1, char delim2)
431 432 433 434 435 436 437 438 439 440
{
    const char *start;
    char *end;

    if (delim1 != delim2 &&
        (start = strstr(base, name)) &&
        (start = strchr(start, delim1))) {
        start += 1;
        end = strchrnul(start, delim2);
        virSkipSpaces(&start);
441 442
        if (VIR_STRNDUP(*value, start, end - start) < 0)
            return NULL;
443 444
        virTrimSpaces(*value, NULL);
        return end;
445
    }
446 447
    return NULL;
}
448

449
static char *
450
virSysinfoParseS390Line(const char *base, const char *name, char **value)
451
{
452
    return virSysinfoParseS390Delimited(base, name, value, ':', '\n');
453 454 455
}

static int
456
virSysinfoParseS390System(const char *base, virSysinfoSystemDefPtr *sysdef)
457
{
458 459 460 461 462 463
    int ret = -1;
    virSysinfoSystemDefPtr def;

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

464
    if (!virSysinfoParseS390Line(base, "Manufacturer", &def->manufacturer))
465 466
        goto cleanup;

467
    if (!virSysinfoParseS390Line(base, "Type", &def->family))
468 469
        goto cleanup;

470
    if (!virSysinfoParseS390Line(base, "Sequence Code", &def->serial))
471 472 473 474 475 476 477 478
        goto cleanup;

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

M
Michal Privoznik 已提交
479
    *sysdef = def;
480 481 482 483 484
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    return ret;
485 486 487
}

static int
488
virSysinfoParseS390Processor(const char *base, virSysinfoDefPtr ret)
489
{
490 491 492 493
    char *tmp_base;
    char *manufacturer = NULL;
    char *procline = NULL;
    int result = -1;
494 495
    virSysinfoProcessorDefPtr processor;

496
    if (!(tmp_base = virSysinfoParseS390Line(base, "vendor_id", &manufacturer)))
497
        goto cleanup;
498

499 500 501
    /* Find processor N: line and gather the processor manufacturer,
       version, serial number, and family */
    while ((tmp_base = strstr(tmp_base, "processor "))
502 503
           && (tmp_base = virSysinfoParseS390Line(tmp_base, "processor ",
                                                  &procline))) {
504
        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0)
505
            goto cleanup;
506
        processor = &ret->processor[ret->nprocessor - 1];
507 508
        if (VIR_STRDUP(processor->processor_manufacturer, manufacturer) < 0)
            goto cleanup;
509 510 511 512 513 514 515 516 517
        if (!virSysinfoParseS390Delimited(procline, "version",
                                          &processor->processor_version,
                                          '=', ',') ||
            !virSysinfoParseS390Delimited(procline, "identification",
                                          &processor->processor_serial_number,
                                          '=', ',') ||
            !virSysinfoParseS390Delimited(procline, "machine",
                                          &processor->processor_family,
                                          '=', '\n'))
518
            goto cleanup;
519
    }
520
    result = 0;
521

522
 cleanup:
523 524 525
    VIR_FREE(manufacturer);
    VIR_FREE(procline);
    return result;
526 527 528 529 530
}

/* virSysinfoRead for s390x
 * Gathers sysinfo data from /proc/sysinfo and /proc/cpuinfo */
virSysinfoDefPtr
531
virSysinfoReadS390(void)
532
{
533 534 535 536 537 538 539
    virSysinfoDefPtr ret = NULL;
    char *outbuf = NULL;

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

    /* Gather info from /proc/cpuinfo */
540
    if (virFileReadAll(CPUINFO, CPUINFO_FILE_LEN, &outbuf) < 0) {
541 542
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to open %s"), CPUINFO);
543 544 545 546 547
        return NULL;
    }

    ret->nprocessor = 0;
    ret->processor = NULL;
548
    if (virSysinfoParseS390Processor(outbuf, ret) < 0)
549 550 551 552 553 554
        goto no_memory;

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

    /* Gather info from /proc/sysinfo */
555
    if (virFileReadAll(SYSINFO, 8192, &outbuf) < 0) {
556 557
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to open %s"), SYSINFO);
558 559 560
        return NULL;
    }

561
    if (virSysinfoParseS390System(outbuf, &ret->system) < 0)
562 563 564 565
        goto no_memory;

    return ret;

566
 no_memory:
567
    virSysinfoDefFree(ret);
568 569 570 571
    VIR_FREE(outbuf);
    return NULL;
}

E
Eric Blake 已提交
572

573
static int
574
virSysinfoParseBIOS(const char *base, virSysinfoBIOSDefPtr *bios)
M
Minoru Usui 已提交
575
{
576
    int ret = -1;
577
    const char *cur, *eol = NULL;
578
    virSysinfoBIOSDefPtr def;
579

M
Minoru Usui 已提交
580
    if ((cur = strstr(base, "BIOS Information")) == NULL)
581
        return 0;
M
Minoru Usui 已提交
582

583 584 585
    if (VIR_ALLOC(def) < 0)
        return ret;

M
Minoru Usui 已提交
586
    base = cur;
587 588 589
    if ((cur = strstr(base, "Vendor: ")) != NULL) {
        cur += 8;
        eol = strchr(cur, '\n');
590 591
        if (eol && VIR_STRNDUP(def->vendor, cur, eol - cur) < 0)
            goto cleanup;
592 593 594 595
    }
    if ((cur = strstr(base, "Version: ")) != NULL) {
        cur += 9;
        eol = strchr(cur, '\n');
596 597
        if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
            goto cleanup;
598 599 600 601
    }
    if ((cur = strstr(base, "Release Date: ")) != NULL) {
        cur += 14;
        eol = strchr(cur, '\n');
602 603
        if (eol && VIR_STRNDUP(def->date, cur, eol - cur) < 0)
            goto cleanup;
604 605 606 607
    }
    if ((cur = strstr(base, "BIOS Revision: ")) != NULL) {
        cur += 15;
        eol = strchr(cur, '\n');
608 609
        if (eol && VIR_STRNDUP(def->release, cur, eol - cur) < 0)
            goto cleanup;
610
    }
M
Minoru Usui 已提交
611

612 613 614 615 616 617 618 619 620 621 622 623
    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 已提交
624 625
}

626
static int
627
virSysinfoParseX86System(const char *base, virSysinfoSystemDefPtr *sysdef)
M
Minoru Usui 已提交
628
{
629
    int ret = -1;
630
    const char *cur, *eol = NULL;
631
    virSysinfoSystemDefPtr def;
M
Minoru Usui 已提交
632

M
Minoru Usui 已提交
633
    if ((cur = strstr(base, "System Information")) == NULL)
634
        return 0;
M
Minoru Usui 已提交
635

636 637 638
    if (VIR_ALLOC(def) < 0)
        return ret;

M
Minoru Usui 已提交
639
    base = cur;
640 641 642
    if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
        cur += 14;
        eol = strchr(cur, '\n');
643 644
        if (eol && VIR_STRNDUP(def->manufacturer, cur, eol - cur) < 0)
            goto cleanup;
645 646 647 648
    }
    if ((cur = strstr(base, "Product Name: ")) != NULL) {
        cur += 14;
        eol = strchr(cur, '\n');
649 650
        if (eol && VIR_STRNDUP(def->product, cur, eol - cur) < 0)
            goto cleanup;
651 652 653 654
    }
    if ((cur = strstr(base, "Version: ")) != NULL) {
        cur += 9;
        eol = strchr(cur, '\n');
655 656
        if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
            goto cleanup;
657 658 659 660
    }
    if ((cur = strstr(base, "Serial Number: ")) != NULL) {
        cur += 15;
        eol = strchr(cur, '\n');
661 662
        if (eol && VIR_STRNDUP(def->serial, cur, eol - cur) < 0)
            goto cleanup;
663 664 665 666
    }
    if ((cur = strstr(base, "UUID: ")) != NULL) {
        cur += 6;
        eol = strchr(cur, '\n');
667 668
        if (eol && VIR_STRNDUP(def->uuid, cur, eol - cur) < 0)
            goto cleanup;
669 670 671 672
    }
    if ((cur = strstr(base, "SKU Number: ")) != NULL) {
        cur += 12;
        eol = strchr(cur, '\n');
673 674
        if (eol && VIR_STRNDUP(def->sku, cur, eol - cur) < 0)
            goto cleanup;
675
    }
E
Eric Blake 已提交
676 677 678
    if ((cur = strstr(base, "Family: ")) != NULL) {
        cur += 8;
        eol = strchr(cur, '\n');
679 680
        if (eol && VIR_STRNDUP(def->family, cur, eol - cur) < 0)
            goto cleanup;
E
Eric Blake 已提交
681
    }
682

683 684 685 686 687 688
    if (!def->manufacturer && !def->product && !def->version &&
        !def->serial && !def->uuid && !def->sku && !def->family) {
        virSysinfoSystemDefFree(def);
        def = NULL;
    }

M
Michal Privoznik 已提交
689
    *sysdef = def;
690 691 692 693 694
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    return ret;
M
Minoru Usui 已提交
695 696
}

697
static int
698 699 700
virSysinfoParseX86BaseBoard(const char *base,
                            virSysinfoBaseBoardDefPtr *baseBoard,
                            size_t *nbaseBoard)
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 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
{
    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;
}

775
static int
776
virSysinfoParseX86Processor(const char *base, virSysinfoDefPtr ret)
777
{
778 779
    const char *cur, *tmp_base;
    char *eol;
780
    virSysinfoProcessorDefPtr processor;
781

782
    while ((tmp_base = strstr(base, "Processor Information")) != NULL) {
783
        base = tmp_base;
E
Eric Blake 已提交
784
        eol = NULL;
785

786 787
        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0)
            return -1;
788 789 790 791 792
        processor = &ret->processor[ret->nprocessor - 1];

        if ((cur = strstr(base, "Socket Designation: ")) != NULL) {
            cur += 20;
            eol = strchr(cur, '\n');
793
            virSkipSpacesBackwards(cur, &eol);
794 795 796
            if (eol && VIR_STRNDUP(processor->processor_socket_destination,
                                   cur, eol - cur) < 0)
                return -1;
797 798 799 800
        }
        if ((cur = strstr(base, "Type: ")) != NULL) {
            cur += 6;
            eol = strchr(cur, '\n');
801
            virSkipSpacesBackwards(cur, &eol);
802 803
            if (eol && VIR_STRNDUP(processor->processor_type, cur, eol - cur) < 0)
                return -1;
804 805 806 807
        }
        if ((cur = strstr(base, "Family: ")) != NULL) {
            cur += 8;
            eol = strchr(cur, '\n');
808
            virSkipSpacesBackwards(cur, &eol);
809 810
            if (eol && VIR_STRNDUP(processor->processor_family, cur, eol - cur) < 0)
                return -1;
811 812 813 814
        }
        if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
            cur += 14;
            eol = strchr(cur, '\n');
815
            virSkipSpacesBackwards(cur, &eol);
816 817 818
            if (eol && VIR_STRNDUP(processor->processor_manufacturer,
                                   cur, eol - cur) < 0)
                return -1;
819 820 821 822
        }
        if ((cur = strstr(base, "Signature: ")) != NULL) {
            cur += 11;
            eol = strchr(cur, '\n');
823
            virSkipSpacesBackwards(cur, &eol);
824 825 826
            if (eol && VIR_STRNDUP(processor->processor_signature,
                                   cur, eol - cur) < 0)
                return -1;
827 828 829 830
        }
        if ((cur = strstr(base, "Version: ")) != NULL) {
            cur += 9;
            eol = strchr(cur, '\n');
831
            virSkipSpacesBackwards(cur, &eol);
832 833 834
            if (eol && VIR_STRNDUP(processor->processor_version,
                                   cur, eol - cur) < 0)
                return -1;
835 836 837 838
        }
        if ((cur = strstr(base, "External Clock: ")) != NULL) {
            cur += 16;
            eol = strchr(cur, '\n');
839
            virSkipSpacesBackwards(cur, &eol);
840 841 842
            if (eol && VIR_STRNDUP(processor->processor_external_clock,
                                   cur, eol - cur) < 0)
                return -1;
843 844 845 846
        }
        if ((cur = strstr(base, "Max Speed: ")) != NULL) {
            cur += 11;
            eol = strchr(cur, '\n');
847
            virSkipSpacesBackwards(cur, &eol);
848 849 850
            if (eol && VIR_STRNDUP(processor->processor_max_speed,
                                   cur, eol - cur) < 0)
                return -1;
851 852 853 854
        }
        if ((cur = strstr(base, "Status: ")) != NULL) {
            cur += 8;
            eol = strchr(cur, '\n');
855
            virSkipSpacesBackwards(cur, &eol);
856 857
            if (eol && VIR_STRNDUP(processor->processor_status, cur, eol - cur) < 0)
                return -1;
858 859 860 861
        }
        if ((cur = strstr(base, "Serial Number: ")) != NULL) {
            cur += 15;
            eol = strchr(cur, '\n');
862
            virSkipSpacesBackwards(cur, &eol);
863 864 865
            if (eol && VIR_STRNDUP(processor->processor_serial_number,
                                   cur, eol - cur) < 0)
                return -1;
866 867 868 869
        }
        if ((cur = strstr(base, "Part Number: ")) != NULL) {
            cur += 13;
            eol = strchr(cur, '\n');
870
            virSkipSpacesBackwards(cur, &eol);
871 872 873
            if (eol && VIR_STRNDUP(processor->processor_part_number,
                                   cur, eol - cur) < 0)
                return -1;
874 875
        }

M
Minoru Usui 已提交
876
        base += strlen("Processor Information");
877 878
    }

879
    return 0;
880 881
}

882
static int
883
virSysinfoParseX86Memory(const char *base, virSysinfoDefPtr ret)
884
{
885 886
    const char *cur, *tmp_base;
    char *eol;
887
    virSysinfoMemoryDefPtr memory;
888 889 890

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

893 894
        if (VIR_EXPAND_N(ret->memory, ret->nmemory, 1) < 0)
            return -1;
895 896 897 898 899 900 901 902
        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;

903
            virSkipSpacesBackwards(cur, &eol);
904 905
            if (eol && VIR_STRNDUP(memory->memory_size, cur, eol - cur) < 0)
                return -1;
906 907 908 909
        }
        if ((cur = strstr(base, "Form Factor: ")) != NULL) {
            cur += 13;
            eol = strchr(cur, '\n');
910
            virSkipSpacesBackwards(cur, &eol);
911 912 913
            if (eol && VIR_STRNDUP(memory->memory_form_factor,
                                   cur, eol - cur) < 0)
                return -1;
914 915 916 917
        }
        if ((cur = strstr(base, "Locator: ")) != NULL) {
            cur += 9;
            eol = strchr(cur, '\n');
918
            virSkipSpacesBackwards(cur, &eol);
E
Eric Blake 已提交
919
            if (eol && VIR_STRNDUP(memory->memory_locator, cur, eol - cur) < 0)
920
                return -1;
921 922 923 924
        }
        if ((cur = strstr(base, "Bank Locator: ")) != NULL) {
            cur += 14;
            eol = strchr(cur, '\n');
925
            virSkipSpacesBackwards(cur, &eol);
926 927 928
            if (eol && VIR_STRNDUP(memory->memory_bank_locator,
                                   cur, eol - cur) < 0)
                return -1;
929 930 931 932
        }
        if ((cur = strstr(base, "Type: ")) != NULL) {
            cur += 6;
            eol = strchr(cur, '\n');
933
            virSkipSpacesBackwards(cur, &eol);
934 935
            if (eol && VIR_STRNDUP(memory->memory_type, cur, eol - cur) < 0)
                return -1;
936 937 938 939
        }
        if ((cur = strstr(base, "Type Detail: ")) != NULL) {
            cur += 13;
            eol = strchr(cur, '\n');
940
            virSkipSpacesBackwards(cur, &eol);
941 942
            if (eol && VIR_STRNDUP(memory->memory_type_detail, cur, eol - cur) < 0)
                return -1;
943 944 945 946
        }
        if ((cur = strstr(base, "Speed: ")) != NULL) {
            cur += 7;
            eol = strchr(cur, '\n');
947
            virSkipSpacesBackwards(cur, &eol);
948 949
            if (eol && VIR_STRNDUP(memory->memory_speed, cur, eol - cur) < 0)
                return -1;
950 951 952 953
        }
        if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
            cur += 14;
            eol = strchr(cur, '\n');
954
            virSkipSpacesBackwards(cur, &eol);
955 956
            if (eol && VIR_STRNDUP(memory->memory_manufacturer, cur, eol - cur) < 0)
                return -1;
957 958 959 960
        }
        if ((cur = strstr(base, "Serial Number: ")) != NULL) {
            cur += 15;
            eol = strchr(cur, '\n');
961
            virSkipSpacesBackwards(cur, &eol);
962 963 964
            if (eol && VIR_STRNDUP(memory->memory_serial_number,
                                   cur, eol - cur) < 0)
                return -1;
965 966 967 968
        }
        if ((cur = strstr(base, "Part Number: ")) != NULL) {
            cur += 13;
            eol = strchr(cur, '\n');
969
            virSkipSpacesBackwards(cur, &eol);
970 971
            if (eol && VIR_STRNDUP(memory->memory_part_number, cur, eol - cur) < 0)
                return -1;
972 973 974
        }

    next:
M
Minoru Usui 已提交
975
        base += strlen("Memory Device");
976 977
    }

978
    return 0;
979 980
}

M
Minoru Usui 已提交
981
virSysinfoDefPtr
982
virSysinfoReadX86(void)
983
{
984
    char *path;
M
Minoru Usui 已提交
985 986 987 988 989 990
    virSysinfoDefPtr ret = NULL;
    char *outbuf = NULL;
    virCommandPtr cmd;

    path = virFindFileInPath(SYSINFO_SMBIOS_DECODER);
    if (path == NULL) {
991 992 993
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to find path for %s binary"),
                       SYSINFO_SMBIOS_DECODER);
M
Minoru Usui 已提交
994 995 996
        return NULL;
    }

997
    cmd = virCommandNewArgList(path, "-q", "-t", "0,1,2,4,17", NULL);
M
Minoru Usui 已提交
998 999
    VIR_FREE(path);
    virCommandSetOutputBuffer(cmd, &outbuf);
1000
    if (virCommandRun(cmd, NULL) < 0)
M
Minoru Usui 已提交
1001 1002 1003
        goto cleanup;

    if (VIR_ALLOC(ret) < 0)
1004
        goto error;
M
Minoru Usui 已提交
1005 1006 1007

    ret->type = VIR_SYSINFO_SMBIOS;

1008
    if (virSysinfoParseBIOS(outbuf, &ret->bios) < 0)
1009
        goto error;
M
Minoru Usui 已提交
1010

1011
    if (virSysinfoParseX86System(outbuf, &ret->system) < 0)
1012
        goto error;
M
Minoru Usui 已提交
1013

1014
    if (virSysinfoParseX86BaseBoard(outbuf, &ret->baseBoard, &ret->nbaseBoard) < 0)
1015 1016
        goto error;

1017 1018
    ret->nprocessor = 0;
    ret->processor = NULL;
1019
    if (virSysinfoParseX86Processor(outbuf, ret) < 0)
1020
        goto error;
1021

1022 1023
    ret->nmemory = 0;
    ret->memory = NULL;
1024
    if (virSysinfoParseX86Memory(outbuf, ret) < 0)
1025
        goto error;
1026

1027
 cleanup:
1028
    VIR_FREE(outbuf);
E
Eric Blake 已提交
1029
    virCommandFree(cmd);
1030

E
Eric Blake 已提交
1031
    return ret;
1032

1033
 error:
1034 1035 1036 1037
    virSysinfoDefFree(ret);
    ret = NULL;
    goto cleanup;
}
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


/**
 * virSysinfoRead:
 *
 * Tries to read the SMBIOS information from the current host
 *
 * Returns: a filled up sysinfo structure or NULL in case of error
 */
virSysinfoDefPtr
virSysinfoRead(void)
{
#if defined(__powerpc__)
    return virSysinfoReadPPC();
#elif defined(__arm__) || defined(__aarch64__)
    return virSysinfoReadARM();
#elif defined(__s390__) || defined(__s390x__)
    return virSysinfoReadS390();
#elif defined(WIN32) || \
    !(defined(__x86_64__) || \
      defined(__i386__) ||   \
      defined(__amd64__) || \
      defined(__arm__) || \
      defined(__aarch64__) || \
      defined(__powerpc__))
    /*
     * this can probably be extracted from Windows using API or registry
     * http://www.microsoft.com/whdc/system/platform/firmware/SMBIOS.mspx
     */
    virReportSystemError(ENOSYS, "%s",
                         _("Host sysinfo extraction not supported on this platform"));
    return NULL;
#else /* !WIN32 && x86 */
    return virSysinfoReadX86();
1072
#endif /* !WIN32 && x86 */
1073 1074
}

E
Eric Blake 已提交
1075

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

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

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

1102 1103 1104
    virBufferAddLit(buf, "<system>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<entry name='manufacturer'>%s</entry>\n",
1105
                          def->manufacturer);
1106
    virBufferEscapeString(buf, "<entry name='product'>%s</entry>\n",
1107
                          def->product);
1108
    virBufferEscapeString(buf, "<entry name='version'>%s</entry>\n",
1109
                          def->version);
1110
    virBufferEscapeString(buf, "<entry name='serial'>%s</entry>\n",
1111
                          def->serial);
1112
    virBufferEscapeString(buf, "<entry name='uuid'>%s</entry>\n",
1113
                          def->uuid);
1114
    virBufferEscapeString(buf, "<entry name='sku'>%s</entry>\n",
1115
                          def->sku);
1116
    virBufferEscapeString(buf, "<entry name='family'>%s</entry>\n",
1117
                          def->family);
1118 1119
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</system>\n");
M
Minoru Usui 已提交
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
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");
    }
}

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

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

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
        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;

1174 1175
        virBufferAddLit(buf, "<processor>\n");
        virBufferAdjustIndent(buf, 2);
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
        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);
1199 1200
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</processor>\n");
1201 1202 1203
    }
}

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

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

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
        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;

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

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

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

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

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

1289 1290 1291 1292 1293 1294 1295 1296
    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 已提交
1297

1298
    if (virBufferCheckError(buf) < 0)
1299
        goto cleanup;
1300

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

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
#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;
}

1342 1343 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
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;
}

1370 1371 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
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;
}

1397 1398
#undef CHECK_FIELD

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

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

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

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

1422 1423
    if (!virSysinfoBIOSIsEqual(src->bios, dst->bios))
        goto cleanup;
1424

1425 1426
    if (!virSysinfoSystemIsEqual(src->system, dst->system))
        goto cleanup;
1427

1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
    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;

1440 1441
    identical = true;

1442
 cleanup:
1443 1444
    return identical;
}