546d481d81d8daa5ec116fc857ffc9caa146e919
1 /**
2 * collectd - src/uuid.c
3 * Copyright (C) 2007 Red Hat Inc.
4 * Copyright (C) 2015 Ruben Kerkhof
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; only version 2 of the License is applicable.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Authors:
20 * Dan Berrange <berrange@redhat.com>
21 * Richard W.M. Jones <rjones@redhat.com>
22 *
23 * Derived from UUID detection code by Dan Berrange <berrange@redhat.com>
24 * http://hg.et.redhat.com/virt/daemons/spectre--devel?f=f6e3a1b06433;file=lib/uuid.c
25 **/
27 #include "collectd.h"
29 #include "common.h"
30 #include "plugin.h"
32 #if HAVE_SYS_SYSCTL_H
33 #include <sys/sysctl.h>
34 #endif
36 #define UUID_RAW_LENGTH 16
37 #define UUID_PRINTABLE_COMPACT_LENGTH (UUID_RAW_LENGTH * 2)
38 #define UUID_PRINTABLE_NORMAL_LENGTH (UUID_PRINTABLE_COMPACT_LENGTH + 4)
40 static char *uuidfile = NULL;
42 static const char *config_keys[] = {"UUIDFile"};
44 static int looks_like_a_uuid(const char *uuid) {
45 int len;
47 if (!uuid)
48 return (0);
50 len = strlen(uuid);
52 if (len < UUID_PRINTABLE_COMPACT_LENGTH)
53 return (0);
55 while (*uuid) {
56 if (!isxdigit((int)*uuid) && *uuid != '-')
57 return (0);
58 uuid++;
59 }
60 return (1);
61 }
63 static char *uuid_parse_dmidecode(FILE *file) {
64 char line[1024];
66 while (fgets(line, sizeof(line), file) != NULL) {
67 char *fields[4];
68 int fields_num;
70 strstripnewline(line);
72 /* Look for a line reading:
73 * UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
74 */
75 fields_num = strsplit(line, fields, STATIC_ARRAY_SIZE(fields));
76 if (fields_num != 2)
77 continue;
79 if (strcmp("UUID:", fields[0]) != 0)
80 continue;
82 if (!looks_like_a_uuid(fields[1]))
83 continue;
85 return (strdup(fields[1]));
86 }
87 return (NULL);
88 }
90 static char *uuid_get_from_dmidecode(void) {
91 FILE *dmidecode = popen("dmidecode -t system 2>/dev/null", "r");
92 char *uuid;
94 if (!dmidecode)
95 return (NULL);
97 uuid = uuid_parse_dmidecode(dmidecode);
99 pclose(dmidecode);
100 return (uuid);
101 }
103 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
104 static char *uuid_get_from_sysctlbyname(const char *name) {
105 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
106 size_t len = sizeof(uuid);
107 if (sysctlbyname(name, &uuid, &len, NULL, 0) == -1)
108 return NULL;
109 return (strdup(uuid));
110 }
111 #elif defined(__OpenBSD__)
112 static char *uuid_get_from_sysctl(void) {
113 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
114 size_t len = sizeof(uuid);
115 int mib[2];
117 mib[0] = CTL_HW;
118 mib[1] = HW_UUID;
120 if (sysctl(mib, 2, uuid, &len, NULL, 0) == -1)
121 return NULL;
122 return (strdup(uuid));
123 }
124 #endif
126 static char *uuid_get_from_file(const char *path) {
127 FILE *file;
128 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = "";
130 file = fopen(path, "r");
131 if (file == NULL)
132 return (NULL);
134 if (!fgets(uuid, sizeof(uuid), file)) {
135 fclose(file);
136 return (NULL);
137 }
138 fclose(file);
139 strstripnewline(uuid);
141 return (strdup(uuid));
142 }
144 static char *uuid_get_local(void) {
145 char *uuid;
147 /* Check /etc/uuid / UUIDFile before any other method. */
148 if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL)
149 return (uuid);
151 #if defined(__APPLE__)
152 if ((uuid = uuid_get_from_sysctlbyname("kern.uuid")) != NULL)
153 return (uuid);
154 #elif defined(__FreeBSD__)
155 if ((uuid = uuid_get_from_sysctlbyname("kern.hostuuid")) != NULL)
156 return (uuid);
157 #elif defined(__NetBSD__)
158 if ((uuid = uuid_get_from_sysctlbyname("machdep.dmi.system-uuid")) != NULL)
159 return (uuid);
160 #elif defined(__OpenBSD__)
161 if ((uuid = uuid_get_from_sysctl()) != NULL)
162 return (uuid);
163 #elif defined(__linux__)
164 if ((uuid = uuid_get_from_file("/sys/class/dmi/id/product_uuid")) != NULL)
165 return (uuid);
166 #endif
168 if ((uuid = uuid_get_from_dmidecode()) != NULL)
169 return (uuid);
171 #if defined(__linux__)
172 if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL)
173 return (uuid);
174 #endif
176 return (NULL);
177 }
179 static int uuid_config(const char *key, const char *value) {
180 if (strcasecmp(key, "UUIDFile") == 0) {
181 char *tmp = strdup(value);
182 if (tmp == NULL)
183 return (-1);
184 sfree(uuidfile);
185 uuidfile = tmp;
186 return (0);
187 }
189 return (1);
190 }
192 static int uuid_init(void) {
193 char *uuid = uuid_get_local();
195 if (uuid) {
196 sstrncpy(hostname_g, uuid, DATA_MAX_NAME_LEN);
197 sfree(uuid);
198 return (0);
199 }
201 WARNING("uuid: could not read UUID using any known method");
202 return (0);
203 }
205 void module_register(void) {
206 plugin_register_config("uuid", uuid_config, config_keys,
207 STATIC_ARRAY_SIZE(config_keys));
208 plugin_register_init("uuid", uuid_init);
209 }