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 #if HAVE_LIBHAL_H
37 #include <libhal.h>
38 #endif
40 #define UUID_RAW_LENGTH 16
41 #define UUID_PRINTABLE_COMPACT_LENGTH (UUID_RAW_LENGTH * 2)
42 #define UUID_PRINTABLE_NORMAL_LENGTH (UUID_PRINTABLE_COMPACT_LENGTH + 4)
44 static char *uuidfile = NULL;
46 static const char *config_keys[] = {
47 "UUIDFile"
48 };
50 static int
51 looks_like_a_uuid (const char *uuid)
52 {
53 int len;
55 if (!uuid)
56 return (0);
58 len = strlen (uuid);
60 if (len < UUID_PRINTABLE_COMPACT_LENGTH)
61 return (0);
63 while (*uuid) {
64 if (!isxdigit ((int)*uuid) && *uuid != '-')
65 return (0);
66 uuid++;
67 }
68 return (1);
69 }
71 static char *
72 uuid_parse_dmidecode(FILE *file)
73 {
74 char line[1024];
76 while (fgets (line, sizeof (line), file) != NULL)
77 {
78 char *fields[4];
79 int fields_num;
81 strstripnewline (line);
83 /* Look for a line reading:
84 * UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
85 */
86 fields_num = strsplit (line, fields, STATIC_ARRAY_SIZE (fields));
87 if (fields_num != 2)
88 continue;
90 if (strcmp("UUID:", fields[0]) != 0)
91 continue;
93 if (!looks_like_a_uuid (fields[1]))
94 continue;
96 return (strdup (fields[1]));
97 }
98 return (NULL);
99 }
101 static char *
102 uuid_get_from_dmidecode(void)
103 {
104 FILE *dmidecode = popen("dmidecode -t system 2>/dev/null", "r");
105 char *uuid;
107 if (!dmidecode)
108 return (NULL);
110 uuid = uuid_parse_dmidecode(dmidecode);
112 pclose(dmidecode);
113 return (uuid);
114 }
116 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
117 static char *
118 uuid_get_from_sysctlbyname(const char *name)
119 {
120 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
121 size_t len = sizeof (uuid);
122 if (sysctlbyname(name, &uuid, &len, NULL, 0) == -1)
123 return NULL;
124 return (strdup (uuid));
125 }
126 #elif defined(__OpenBSD__)
127 static char *
128 uuid_get_from_sysctl(void)
129 {
130 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
131 size_t len = sizeof (uuid);
132 int mib[2];
134 mib[0] = CTL_HW;
135 mib[1] = HW_UUID;
137 if (sysctl(mib, 2, uuid, &len, NULL, 0) == -1)
138 return NULL;
139 return (strdup (uuid));
140 }
141 #endif
143 #if HAVE_LIBHAL_H
145 #define UUID_PATH "/org/freedesktop/Hal/devices/computer"
146 #define UUID_PROPERTY "smbios.system.uuid"
148 static char *
149 uuid_get_from_hal(void)
150 {
151 LibHalContext *ctx;
153 DBusError error;
154 DBusConnection *con;
156 dbus_error_init(&error);
158 if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)))
159 goto bailout_nobus;
161 ctx = libhal_ctx_new();
162 libhal_ctx_set_dbus_connection(ctx, con);
164 if (!libhal_ctx_init(ctx, &error))
165 goto bailout;
167 if (!libhal_device_property_exists(ctx,
168 UUID_PATH,
169 UUID_PROPERTY,
170 &error))
171 goto bailout;
173 char *uuid = libhal_device_get_property_string(ctx,
174 UUID_PATH,
175 UUID_PROPERTY,
176 &error);
177 if (looks_like_a_uuid (uuid))
178 return (uuid);
180 bailout:
181 {
182 DBusError ctxerror;
183 dbus_error_init(&ctxerror);
184 if (!(libhal_ctx_shutdown(ctx, &ctxerror)))
185 dbus_error_free(&ctxerror);
186 }
188 libhal_ctx_free(ctx);
190 bailout_nobus:
191 if (dbus_error_is_set(&error))
192 dbus_error_free(&error);
193 return (NULL);
194 }
195 #endif
197 static char *
198 uuid_get_from_file(const char *path)
199 {
200 FILE *file;
201 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = "";
203 file = fopen (path, "r");
204 if (file == NULL)
205 return (NULL);
207 if (!fgets(uuid, sizeof(uuid), file)) {
208 fclose(file);
209 return (NULL);
210 }
211 fclose(file);
212 strstripnewline (uuid);
214 return (strdup (uuid));
215 }
217 static char *
218 uuid_get_local(void)
219 {
220 char *uuid;
222 /* Check /etc/uuid / UUIDFile before any other method. */
223 if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL)
224 return (uuid);
226 #if defined(__APPLE__)
227 if ((uuid = uuid_get_from_sysctlbyname("kern.uuid")) != NULL)
228 return (uuid);
229 #elif defined(__FreeBSD__)
230 if ((uuid = uuid_get_from_sysctlbyname("kern.hostuuid")) != NULL)
231 return (uuid);
232 #elif defined(__NetBSD__)
233 if ((uuid = uuid_get_from_sysctlbyname("machdep.dmi.system-uuid")) != NULL)
234 return (uuid);
235 #elif defined(__OpenBSD__)
236 if ((uuid = uuid_get_from_sysctl()) != NULL)
237 return (uuid);
238 #elif defined(__linux__)
239 if ((uuid = uuid_get_from_file("/sys/class/dmi/id/product_uuid")) != NULL)
240 return (uuid);
241 #endif
243 #if HAVE_LIBHAL_H
244 if ((uuid = uuid_get_from_hal()) != NULL)
245 return (uuid);
246 #endif
248 if ((uuid = uuid_get_from_dmidecode()) != NULL)
249 return (uuid);
251 #if defined(__linux__)
252 if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL)
253 return (uuid);
254 #endif
256 return (NULL);
257 }
259 static int
260 uuid_config (const char *key, const char *value)
261 {
262 if (strcasecmp (key, "UUIDFile") == 0) {
263 char *tmp = strdup (value);
264 if (tmp == NULL)
265 return (-1);
266 sfree (uuidfile);
267 uuidfile = tmp;
268 return (0);
269 }
271 return (1);
272 }
274 static int
275 uuid_init (void)
276 {
277 char *uuid = uuid_get_local ();
279 if (uuid) {
280 sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
281 sfree (uuid);
282 return (0);
283 }
285 WARNING ("uuid: could not read UUID using any known method");
286 return (0);
287 }
289 void module_register (void)
290 {
291 plugin_register_config ("uuid", uuid_config,
292 config_keys, STATIC_ARRAY_SIZE (config_keys));
293 plugin_register_init ("uuid", uuid_init);
294 }
296 /*
297 * vim: set tabstop=4:
298 * vim: set shiftwidth=4:
299 * vim: set expandtab:
300 */
301 /*
302 * Local variables:
303 * indent-tabs-mode: nil
304 * c-indent-level: 4
305 * c-basic-offset: 4
306 * tab-width: 4
307 * End:
308 */