/* * 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 */ #include #include #include #include #include #include #include #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 #define virSmbiosReportError(code, ...) \ 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); VIR_FREE(def->system_family); 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")); return(NULL); } #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, _("Failed to find path for %s binary"), SYSINFO_SMBIOS_DECODER); return(NULL); } 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, _("Failed to execute command %s"), 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, _("command %s failed with error code %d:%s"), 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)) goto no_memory; } if ((cur = strstr(base, "Version: ")) != NULL) { cur += 9; eol = strchr(cur, '\n'); if ((eol) && ((ret->bios_version = strndup(cur, eol - cur)) == NULL)) goto no_memory; } if ((cur = strstr(base, "Release Date: ")) != NULL) { cur += 14; eol = strchr(cur, '\n'); if ((eol) && ((ret->bios_date = strndup(cur, eol - cur)) == NULL)) goto no_memory; } if ((cur = strstr(base, "BIOS Revision: ")) != NULL) { cur += 15; eol = strchr(cur, '\n'); if ((eol) && ((ret->bios_release = strndup(cur, eol - cur)) == NULL)) goto no_memory; } 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)) goto no_memory; } if ((cur = strstr(base, "Product Name: ")) != NULL) { cur += 14; eol = strchr(cur, '\n'); if ((eol) && ((ret->system_product = strndup(cur, eol - cur)) == NULL)) goto no_memory; } if ((cur = strstr(base, "Version: ")) != NULL) { cur += 9; eol = strchr(cur, '\n'); if ((eol) && ((ret->system_version = strndup(cur, eol - cur)) == NULL)) goto no_memory; } if ((cur = strstr(base, "Serial Number: ")) != NULL) { cur += 15; eol = strchr(cur, '\n'); if ((eol) && ((ret->system_serial = strndup(cur, eol - cur)) == NULL)) goto no_memory; } if ((cur = strstr(base, "UUID: ")) != NULL) { cur += 6; eol = strchr(cur, '\n'); if ((eol) && ((ret->system_uuid = strndup(cur, eol - cur)) == NULL)) goto no_memory; } if ((cur = strstr(base, "SKU Number: ")) != NULL) { cur += 12; eol = strchr(cur, '\n'); if ((eol) && ((ret->system_sku = strndup(cur, eol - cur)) == NULL)) goto no_memory; } if ((cur = strstr(base, "Family: ")) != NULL) { cur += 8; eol = strchr(cur, '\n'); if ((eol) && ((ret->system_family = strndup(cur, eol - cur)) == NULL)) goto no_memory; } cleanup: VIR_FREE(outbuf); VIR_FREE(errbuf); VIR_FREE(path); return(ret); no_memory: virReportOOMError(); virSysinfoDefFree(ret); ret = NULL; goto cleanup; } #endif