From 778c0976c0642313ea60b2861b6dba0c06b49f00 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Fri, 5 Nov 2010 15:22:13 +0100 Subject: [PATCH] Add a sysinfo util module and read host info API Move existing routines about virSysinfoDef to an util module, add a new entry point virSysinfoRead() to read the host values with dmidecode * src/conf/domain_conf.c src/conf/domain_conf.h src/util/sysinfo.c src/util/sysinfo.h: move to a new module, add virSysinfoRead() * src/Makefile.am: handle the new module build * src/libvirt_private.syms: new internal symbols * include/libvirt/virterror.h src/util/virterror.c: defined a new error code for that module * po/POTFILES.in: add new file for translations --- include/libvirt/virterror.h | 3 +- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/conf/domain_conf.c | 19 --- src/conf/domain_conf.h | 25 +--- src/libvirt_private.syms | 5 + src/util/sysinfo.c | 236 ++++++++++++++++++++++++++++++++++++ src/util/sysinfo.h | 58 +++++++++ src/util/virterror.c | 3 + 9 files changed, 307 insertions(+), 44 deletions(-) create mode 100644 src/util/sysinfo.c create mode 100644 src/util/sysinfo.h diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 94d686ce13..78114e9e09 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -73,7 +73,8 @@ typedef enum { VIR_FROM_NWFILTER, /* Error from network filter driver */ VIR_FROM_HOOK, /* Error from Synchronous hooks */ VIR_FROM_DOMAIN_SNAPSHOT, /* Error from domain snapshot */ - VIR_FROM_AUDIT /* Error from auditing subsystem */ + VIR_FROM_AUDIT, /* Error from auditing subsystem */ + VIR_FROM_SYSINFO /* Error from sysinfo/SMBIOS */ } virErrorDomain; diff --git a/po/POTFILES.in b/po/POTFILES.in index dafef47bac..ec974cc98d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -89,6 +89,7 @@ src/util/pci.c src/util/processinfo.c src/util/stats_linux.c src/util/storage_file.c +src/util/sysinfo.c src/util/util.c src/util/virtaudit.c src/util/virterror.c diff --git a/src/Makefile.am b/src/Makefile.am index 4a11c37a1a..b9376be0d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,6 +77,7 @@ UTIL_SOURCES = \ util/qparams.c util/qparams.h \ util/stats_linux.c util/stats_linux.h \ util/storage_file.c util/storage_file.h \ + util/sysinfo.c util/sysinfo.h \ util/threads.c util/threads.h \ util/threads-pthread.h \ util/threads-win32.h \ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c3184aaa89..9f3c08eadc 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -721,25 +721,6 @@ virDomainClockDefClear(virDomainClockDefPtr def) VIR_FREE(def->timers); } -static 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); -} - void virDomainDefFree(virDomainDefPtr def) { unsigned int i; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index decacd875e..8e32c3bfe0 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -39,6 +39,7 @@ # include "nwfilter_params.h" # include "nwfilter_conf.h" # include "macvtap.h" +# include "sysinfo.h" /* Private component of virDomainXMLFlags */ typedef enum { @@ -606,30 +607,6 @@ struct _virDomainMemballoonDef { }; -enum virDomainSysinfoType { - VIR_DOMAIN_SYSINFO_SMBIOS, - - VIR_DOMAIN_SYSINFO_LAST -}; - -typedef struct _virSysinfoDef virSysinfoDef; -typedef virSysinfoDef *virSysinfoDefPtr; -struct _virSysinfoDef { - int type; - - char *bios_vendor; - char *bios_version; - char *bios_date; - char *bios_release; - - char *system_manufacturer; - char *system_product; - char *system_version; - char *system_serial; - char *system_uuid; - char *system_sku; -}; - enum virDomainSmbiosMode { VIR_DOMAIN_SMBIOS_NONE, VIR_DOMAIN_SMBIOS_EMULATE, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 430c7c107f..8f267f6f2a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -694,6 +694,11 @@ virStorageFileProbeFormat; virStorageFileProbeFormatFromFD; +# sysinfo.h +virSysinfoDefFree; +virSysinfoRead; + + # threads.h virCondBroadcast; virCondDestroy; diff --git a/src/util/sysinfo.c b/src/util/sysinfo.c new file mode 100644 index 0000000000..8ad98fe20c --- /dev/null +++ b/src/util/sysinfo.c @@ -0,0 +1,236 @@ +/* + * 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); +} + +/** + * 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; + } + +cleanup: + VIR_FREE(outbuf); + VIR_FREE(errbuf); + VIR_FREE(path); + + return(ret); + +no_memory: + virReportOOMError(); + + + virSysinfoDefFree(ret); + ret = NULL; + goto cleanup; +} +#endif diff --git a/src/util/sysinfo.h b/src/util/sysinfo.h new file mode 100644 index 0000000000..611d54e79d --- /dev/null +++ b/src/util/sysinfo.h @@ -0,0 +1,58 @@ +/* + * sysinfo.h: structure and entry points for sysinfo support + * + * 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 + */ + +#ifndef __VIR_SYSINFOS_H__ +# define __VIR_SYSINFOS_H__ + +# include "internal.h" +# include "util.h" + +enum virDomainSysinfoType { + VIR_DOMAIN_SYSINFO_SMBIOS, + + VIR_DOMAIN_SYSINFO_LAST +}; + +typedef struct _virSysinfoDef virSysinfoDef; +typedef virSysinfoDef *virSysinfoDefPtr; +struct _virSysinfoDef { + int type; + + char *bios_vendor; + char *bios_version; + char *bios_date; + char *bios_release; + + char *system_manufacturer; + char *system_product; + char *system_version; + char *system_serial; + char *system_uuid; + char *system_sku; +}; + +virSysinfoDefPtr virSysinfoRead(void); + +void virSysinfoDefFree(virSysinfoDefPtr def); + +#endif /* __VIR_SYSINFOS_H__ */ diff --git a/src/util/virterror.c b/src/util/virterror.c index dc08aaa6ae..3b28b13097 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -190,6 +190,9 @@ static const char *virErrorDomainName(virErrorDomain domain) { case VIR_FROM_AUDIT: dom = "Audit "; break; + case VIR_FROM_SYSINFO: + dom = "Sysinfo"; + break; } return(dom); }