/** * collectd - src/uuid.c * Copyright (C) 2007 Red Hat Inc. * Copyright (C) 2015 Ruben Kerkhof * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; only version 2 of the License is applicable. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: * Dan Berrange * Richard W.M. Jones * * Derived from UUID detection code by Dan Berrange * http://hg.et.redhat.com/virt/daemons/spectre--devel?f=f6e3a1b06433;file=lib/uuid.c **/ #include "collectd.h" #include "plugin.h" #include "utils/common/common.h" #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME) || \ defined(__OpenBSD__) /* Implies have BSD variant */ #include #endif #define UUID_RAW_LENGTH 16 #define UUID_PRINTABLE_COMPACT_LENGTH (UUID_RAW_LENGTH * 2) #define UUID_PRINTABLE_NORMAL_LENGTH (UUID_PRINTABLE_COMPACT_LENGTH + 4) static char *uuidfile; static const char *config_keys[] = {"UUIDFile"}; static int looks_like_a_uuid(const char *uuid) { if (!uuid) return 0; size_t len = strlen(uuid); if (len < UUID_PRINTABLE_COMPACT_LENGTH) return 0; while (*uuid) { if (!isxdigit((int)*uuid) && *uuid != '-') return 0; uuid++; } return 1; } static char *uuid_parse_dmidecode(FILE *file) { char line[1024]; while (fgets(line, sizeof(line), file) != NULL) { char *fields[4]; int fields_num; strstripnewline(line); /* Look for a line reading: * UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ fields_num = strsplit(line, fields, STATIC_ARRAY_SIZE(fields)); if (fields_num != 2) continue; if (strcmp("UUID:", fields[0]) != 0) continue; if (!looks_like_a_uuid(fields[1])) continue; return strdup(fields[1]); } return NULL; } static char *uuid_get_from_dmidecode(void) { FILE *dmidecode = popen("dmidecode -t system 2>/dev/null", "r"); char *uuid; if (!dmidecode) return NULL; uuid = uuid_parse_dmidecode(dmidecode); pclose(dmidecode); return uuid; } #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) static char *uuid_get_from_sysctlbyname(const char *name) { char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1]; size_t len = sizeof(uuid); if (sysctlbyname(name, &uuid, &len, NULL, 0) == -1) return NULL; return strdup(uuid); } #elif defined(__OpenBSD__) static char *uuid_get_from_sysctl(void) { char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1]; size_t len = sizeof(uuid); int mib[2]; mib[0] = CTL_HW; mib[1] = HW_UUID; if (sysctl(mib, 2, uuid, &len, NULL, 0) == -1) return NULL; return strdup(uuid); } #endif static char *uuid_get_from_file(const char *path) { FILE *file; char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = ""; file = fopen(path, "r"); if (file == NULL) return NULL; if (!fgets(uuid, sizeof(uuid), file)) { fclose(file); return NULL; } fclose(file); strstripnewline(uuid); return strdup(uuid); } static char *uuid_get_local(void) { char *uuid; /* Check /etc/uuid / UUIDFile before any other method. */ if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL) return uuid; #if defined(__APPLE__) if ((uuid = uuid_get_from_sysctlbyname("kern.uuid")) != NULL) return uuid; #elif defined(__FreeBSD__) if ((uuid = uuid_get_from_sysctlbyname("kern.hostuuid")) != NULL) return uuid; #elif defined(__NetBSD__) if ((uuid = uuid_get_from_sysctlbyname("machdep.dmi.system-uuid")) != NULL) return uuid; #elif defined(__OpenBSD__) if ((uuid = uuid_get_from_sysctl()) != NULL) return uuid; #elif defined(__linux__) if ((uuid = uuid_get_from_file("/sys/class/dmi/id/product_uuid")) != NULL) return uuid; #endif if ((uuid = uuid_get_from_dmidecode()) != NULL) return uuid; #if defined(__linux__) if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL) return uuid; #endif return NULL; } static int uuid_config(const char *key, const char *value) { if (strcasecmp(key, "UUIDFile") == 0) { char *tmp = strdup(value); if (tmp == NULL) return -1; sfree(uuidfile); uuidfile = tmp; return 0; } return 1; } static int uuid_init(void) { char *uuid = uuid_get_local(); if (uuid) { hostname_set(uuid); sfree(uuid); return 0; } WARNING("uuid: could not read UUID using any known method"); return 0; } void module_register(void) { plugin_register_config("uuid", uuid_config, config_keys, STATIC_ARRAY_SIZE(config_keys)); plugin_register_init("uuid", uuid_init); }