sysinfo.c 7.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
/*
 * sysinfo.c: get SMBIOS/sysinfo information from the host
 *
 * Copyright (C) 2010 Red Hat, Inc.
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * 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>

#include "virterror_internal.h"
#include "sysinfo.h"
#include "util.h"
#include "conf/domain_conf.h"
#include "logging.h"
#include "memory.h"

#define VIR_FROM_THIS VIR_FROM_SYSINFO

E
Eric Blake 已提交
42
#define virSmbiosReportError(code, ...)                               \
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
    virReportErrorHelper(NULL, VIR_FROM_SYSINFO, code, __FILE__,      \
                         __FUNCTION__, __LINE__, __VA_ARGS__)

#define SYSINFO_SMBIOS_DECODER "dmidecode"

/**
 * virSysinfoDefFree:
 * @def: a sysinfo structure
 *
 * Free up the sysinfo structure
 */

void virSysinfoDefFree(virSysinfoDefPtr def)
{
    if (def == NULL)
        return;

    VIR_FREE(def->bios_vendor);
    VIR_FREE(def->bios_version);
    VIR_FREE(def->bios_date);
    VIR_FREE(def->bios_release);

    VIR_FREE(def->system_manufacturer);
    VIR_FREE(def->system_product);
    VIR_FREE(def->system_version);
    VIR_FREE(def->system_serial);
    VIR_FREE(def->system_uuid);
    VIR_FREE(def->system_sku);
E
Eric Blake 已提交
71
    VIR_FREE(def->system_family);
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
    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
 */
#ifdef WIN32
virSysinfoDefPtr
virSysinfoRead(void) {
    /*
     * 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"));
E
Eric Blake 已提交
91
    return NULL;
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
}
#else
virSysinfoDefPtr
virSysinfoRead(void) {
    char *path, *cur, *eol, *base;
    int pid, outfd = -1, errfd = -1;
    virSysinfoDefPtr ret = NULL;
    const char *argv[] = { NULL, "-q", "-t", "0,1", NULL };
    int res, waitret, exitstatus;
    char *outbuf = NULL;
    char *errbuf = NULL;

    path = virFindFileInPath(SYSINFO_SMBIOS_DECODER);
    if (path == NULL) {
        virSmbiosReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
107
                             _("Failed to find path for %s binary"),
108
                             SYSINFO_SMBIOS_DECODER);
E
Eric Blake 已提交
109
        return NULL;
110 111 112 113 114 115 116
    }
    argv[0] = path;

    res = virExec(argv, NULL, NULL, &pid, -1, &outfd, &errfd,
                  VIR_EXEC_NONE | VIR_EXEC_NONBLOCK);
    if (res < 0) {
        virSmbiosReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
117
                             _("Failed to execute command %s"),
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
                             path);
        res = 1;
        goto cleanup;
    }

    /*
     * we are interested in the output, capture it and errors too
     */
    if (virPipeReadUntilEOF(outfd, errfd, &outbuf, &errbuf) < 0) {
        virReportSystemError(errno, _("cannot wait for '%s'"), path);
        while (waitpid(pid, &exitstatus, 0) == -1 && errno == EINTR)
            ;
        goto cleanup;
    }

    if (outbuf)
        VIR_DEBUG("Command stdout: %s", outbuf);
    if (errbuf)
        VIR_DEBUG("Command stderr: %s", errbuf);

    while ((waitret = waitpid(pid, &exitstatus, 0) == -1) &&
           (errno == EINTR));
    if (waitret == -1) {
        virReportSystemError(errno, _("Failed to wait for '%s'"), path);
        goto cleanup;
    }
    if (exitstatus != 0) {
        virSmbiosReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
146
                             _("command %s failed with error code %d:%s"),
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
                             path, exitstatus, errbuf);
        goto cleanup;
    }

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

    ret->type = VIR_DOMAIN_SYSINFO_SMBIOS;

    base = outbuf;

    if ((cur = strstr(base, "Vendor: ")) != NULL) {
        cur += 8;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->bios_vendor = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
162
            goto no_memory;
163 164 165 166 167
    }
    if ((cur = strstr(base, "Version: ")) != NULL) {
        cur += 9;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->bios_version = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
168
            goto no_memory;
169 170 171 172 173
    }
    if ((cur = strstr(base, "Release Date: ")) != NULL) {
        cur += 14;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->bios_date = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
174
            goto no_memory;
175 176 177 178 179
    }
    if ((cur = strstr(base, "BIOS Revision: ")) != NULL) {
        cur += 15;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->bios_release = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
180
            goto no_memory;
181 182 183 184 185 186 187 188
    }
    if ((base = strstr(outbuf, "System Information")) == NULL)
        goto cleanup;
    if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
        cur += 14;
        eol = strchr(cur, '\n');
        if ((eol) &&
            ((ret->system_manufacturer = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
189
            goto no_memory;
190 191 192 193 194
    }
    if ((cur = strstr(base, "Product Name: ")) != NULL) {
        cur += 14;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->system_product = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
195
            goto no_memory;
196 197 198 199 200
    }
    if ((cur = strstr(base, "Version: ")) != NULL) {
        cur += 9;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->system_version = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
201
            goto no_memory;
202 203 204 205 206
    }
    if ((cur = strstr(base, "Serial Number: ")) != NULL) {
        cur += 15;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->system_serial = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
207
            goto no_memory;
208 209 210 211 212
    }
    if ((cur = strstr(base, "UUID: ")) != NULL) {
        cur += 6;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->system_uuid = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
213
            goto no_memory;
214 215 216 217 218
    }
    if ((cur = strstr(base, "SKU Number: ")) != NULL) {
        cur += 12;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->system_sku = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
219
            goto no_memory;
220
    }
E
Eric Blake 已提交
221 222 223 224
    if ((cur = strstr(base, "Family: ")) != NULL) {
        cur += 8;
        eol = strchr(cur, '\n');
        if ((eol) && ((ret->system_family = strndup(cur, eol - cur)) == NULL))
E
Eric Blake 已提交
225
            goto no_memory;
E
Eric Blake 已提交
226
    }
227 228 229 230 231 232

cleanup:
    VIR_FREE(outbuf);
    VIR_FREE(errbuf);
    VIR_FREE(path);

E
Eric Blake 已提交
233
    return ret;
234 235 236 237 238 239 240 241 242

no_memory:
    virReportOOMError();

    virSysinfoDefFree(ret);
    ret = NULL;
    goto cleanup;
}
#endif