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 "configfile.h"
31 #include "plugin.h"
33 #if HAVE_SYS_SYSCTL_H
34 #include <sys/sysctl.h>
35 #endif
37 #if HAVE_LIBHAL_H
38 #include <libhal.h>
39 #endif
41 #define UUID_RAW_LENGTH 16
42 #define UUID_PRINTABLE_COMPACT_LENGTH (UUID_RAW_LENGTH * 2)
43 #define UUID_PRINTABLE_NORMAL_LENGTH (UUID_PRINTABLE_COMPACT_LENGTH + 4)
45 static char *uuidfile = NULL;
47 static const char *config_keys[] = {
48 "UUIDFile"
49 };
51 static int
52 looks_like_a_uuid (const char *uuid)
53 {
54 int len;
56 if (!uuid)
57 return (0);
59 len = strlen (uuid);
61 if (len < UUID_PRINTABLE_COMPACT_LENGTH)
62 return (0);
64 while (*uuid) {
65 if (!isxdigit ((int)*uuid) && *uuid != '-')
66 return (0);
67 uuid++;
68 }
69 return (1);
70 }
72 static char *
73 uuid_parse_dmidecode(FILE *file)
74 {
75 char line[1024];
77 while (fgets (line, sizeof (line), file) != NULL)
78 {
79 char *fields[4];
80 int fields_num;
82 strstripnewline (line);
84 /* Look for a line reading:
85 * UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
86 */
87 fields_num = strsplit (line, fields, STATIC_ARRAY_SIZE (fields));
88 if (fields_num != 2)
89 continue;
91 if (strcmp("UUID:", fields[0]) != 0)
92 continue;
94 if (!looks_like_a_uuid (fields[1]))
95 continue;
97 return (strdup (fields[1]));
98 }
99 return (NULL);
100 }
102 static char *
103 uuid_get_from_dmidecode(void)
104 {
105 FILE *dmidecode = popen("dmidecode -t system 2>/dev/null", "r");
106 char *uuid;
108 if (!dmidecode)
109 return (NULL);
111 uuid = uuid_parse_dmidecode(dmidecode);
113 pclose(dmidecode);
114 return (uuid);
115 }
117 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
118 static char *
119 uuid_get_from_sysctlbyname(const char *name)
120 {
121 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
122 size_t len = sizeof (uuid);
123 if (sysctlbyname(name, &uuid, &len, NULL, 0) == -1)
124 return NULL;
125 return (strdup (uuid));
126 }
127 #elif defined(__OpenBSD__)
128 static char *
129 uuid_get_from_sysctl(void)
130 {
131 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
132 size_t len = sizeof (uuid);
133 int mib[2];
135 mib[0] = CTL_HW;
136 mib[1] = HW_UUID;
138 if (sysctl(mib, 2, uuid, &len, NULL, 0) == -1)
139 return NULL;
140 return (strdup (uuid));
141 }
142 #endif
144 #if HAVE_LIBHAL_H
146 #define UUID_PATH "/org/freedesktop/Hal/devices/computer"
147 #define UUID_PROPERTY "smbios.system.uuid"
149 static char *
150 uuid_get_from_hal(void)
151 {
152 LibHalContext *ctx;
154 DBusError error;
155 DBusConnection *con;
157 dbus_error_init(&error);
159 if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)))
160 goto bailout_nobus;
162 ctx = libhal_ctx_new();
163 libhal_ctx_set_dbus_connection(ctx, con);
165 if (!libhal_ctx_init(ctx, &error))
166 goto bailout;
168 if (!libhal_device_property_exists(ctx,
169 UUID_PATH,
170 UUID_PROPERTY,
171 &error))
172 goto bailout;
174 char *uuid = libhal_device_get_property_string(ctx,
175 UUID_PATH,
176 UUID_PROPERTY,
177 &error);
178 if (looks_like_a_uuid (uuid))
179 return (uuid);
181 bailout:
182 {
183 DBusError ctxerror;
184 dbus_error_init(&ctxerror);
185 if (!(libhal_ctx_shutdown(ctx, &ctxerror)))
186 dbus_error_free(&ctxerror);
187 }
189 libhal_ctx_free(ctx);
191 bailout_nobus:
192 if (dbus_error_is_set(&error))
193 dbus_error_free(&error);
194 return (NULL);
195 }
196 #endif
198 static char *
199 uuid_get_from_file(const char *path)
200 {
201 FILE *file;
202 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = "";
204 file = fopen (path, "r");
205 if (file == NULL)
206 return (NULL);
208 if (!fgets(uuid, sizeof(uuid), file)) {
209 fclose(file);
210 return (NULL);
211 }
212 fclose(file);
213 strstripnewline (uuid);
215 return (strdup (uuid));
216 }
218 static char *
219 uuid_get_local(void)
220 {
221 char *uuid;
223 /* Check /etc/uuid / UUIDFile before any other method. */
224 if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL)
225 return (uuid);
227 #if defined(__APPLE__)
228 if ((uuid = uuid_get_from_sysctlbyname("kern.uuid")) != NULL)
229 return (uuid);
230 #elif defined(__FreeBSD__)
231 if ((uuid = uuid_get_from_sysctlbyname("kern.hostuuid")) != NULL)
232 return (uuid);
233 #elif defined(__NetBSD__)
234 if ((uuid = uuid_get_from_sysctlbyname("machdep.dmi.system-uuid")) != NULL)
235 return (uuid);
236 #elif defined(__OpenBSD__)
237 if ((uuid = uuid_get_from_sysctl()) != NULL)
238 return (uuid);
239 #elif defined(__linux__)
240 if ((uuid = uuid_get_from_file("/sys/class/dmi/id/product_uuid")) != NULL)
241 return (uuid);
242 #endif
244 #if HAVE_LIBHAL_H
245 if ((uuid = uuid_get_from_hal()) != NULL)
246 return (uuid);
247 #endif
249 if ((uuid = uuid_get_from_dmidecode()) != NULL)
250 return (uuid);
252 #if defined(__linux__)
253 if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL)
254 return (uuid);
255 #endif
257 return (NULL);
258 }
260 static int
261 uuid_config (const char *key, const char *value)
262 {
263 if (strcasecmp (key, "UUIDFile") == 0) {
264 char *tmp = strdup (value);
265 if (tmp == NULL)
266 return (-1);
267 sfree (uuidfile);
268 uuidfile = tmp;
269 return (0);
270 }
272 return (1);
273 }
275 static int
276 uuid_init (void)
277 {
278 char *uuid = uuid_get_local ();
280 if (uuid) {
281 sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
282 sfree (uuid);
283 return (0);
284 }
286 WARNING ("uuid: could not read UUID using any known method");
287 return (0);
288 }
290 void module_register (void)
291 {
292 plugin_register_config ("uuid", uuid_config,
293 config_keys, STATIC_ARRAY_SIZE (config_keys));
294 plugin_register_init ("uuid", uuid_init);
295 }
297 /*
298 * vim: set tabstop=4:
299 * vim: set shiftwidth=4:
300 * vim: set expandtab:
301 */
302 /*
303 * Local variables:
304 * indent-tabs-mode: nil
305 * c-indent-level: 4
306 * c-basic-offset: 4
307 * tab-width: 4
308 * End:
309 */