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[] = {"UUIDFile"};
48 static int looks_like_a_uuid(const char *uuid) {
49 int len;
51 if (!uuid)
52 return (0);
54 len = strlen(uuid);
56 if (len < UUID_PRINTABLE_COMPACT_LENGTH)
57 return (0);
59 while (*uuid) {
60 if (!isxdigit((int)*uuid) && *uuid != '-')
61 return (0);
62 uuid++;
63 }
64 return (1);
65 }
67 static char *uuid_parse_dmidecode(FILE *file) {
68 char line[1024];
70 while (fgets(line, sizeof(line), file) != NULL) {
71 char *fields[4];
72 int fields_num;
74 strstripnewline(line);
76 /* Look for a line reading:
77 * UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
78 */
79 fields_num = strsplit(line, fields, STATIC_ARRAY_SIZE(fields));
80 if (fields_num != 2)
81 continue;
83 if (strcmp("UUID:", fields[0]) != 0)
84 continue;
86 if (!looks_like_a_uuid(fields[1]))
87 continue;
89 return (strdup(fields[1]));
90 }
91 return (NULL);
92 }
94 static char *uuid_get_from_dmidecode(void) {
95 FILE *dmidecode = popen("dmidecode -t system 2>/dev/null", "r");
96 char *uuid;
98 if (!dmidecode)
99 return (NULL);
101 uuid = uuid_parse_dmidecode(dmidecode);
103 pclose(dmidecode);
104 return (uuid);
105 }
107 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
108 static char *uuid_get_from_sysctlbyname(const char *name) {
109 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
110 size_t len = sizeof(uuid);
111 if (sysctlbyname(name, &uuid, &len, NULL, 0) == -1)
112 return NULL;
113 return (strdup(uuid));
114 }
115 #elif defined(__OpenBSD__)
116 static char *uuid_get_from_sysctl(void) {
117 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
118 size_t len = sizeof(uuid);
119 int mib[2];
121 mib[0] = CTL_HW;
122 mib[1] = HW_UUID;
124 if (sysctl(mib, 2, uuid, &len, NULL, 0) == -1)
125 return NULL;
126 return (strdup(uuid));
127 }
128 #endif
130 #if HAVE_LIBHAL_H
132 #define UUID_PATH "/org/freedesktop/Hal/devices/computer"
133 #define UUID_PROPERTY "smbios.system.uuid"
135 static char *uuid_get_from_hal(void) {
136 LibHalContext *ctx;
138 DBusError error;
139 DBusConnection *con;
141 dbus_error_init(&error);
143 if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)))
144 goto bailout_nobus;
146 ctx = libhal_ctx_new();
147 libhal_ctx_set_dbus_connection(ctx, con);
149 if (!libhal_ctx_init(ctx, &error))
150 goto bailout;
152 if (!libhal_device_property_exists(ctx, UUID_PATH, UUID_PROPERTY, &error))
153 goto bailout;
155 char *uuid =
156 libhal_device_get_property_string(ctx, UUID_PATH, UUID_PROPERTY, &error);
157 if (looks_like_a_uuid(uuid))
158 return (uuid);
160 bailout : {
161 DBusError ctxerror;
162 dbus_error_init(&ctxerror);
163 if (!(libhal_ctx_shutdown(ctx, &ctxerror)))
164 dbus_error_free(&ctxerror);
165 }
167 libhal_ctx_free(ctx);
169 bailout_nobus:
170 if (dbus_error_is_set(&error))
171 dbus_error_free(&error);
172 return (NULL);
173 }
174 #endif
176 static char *uuid_get_from_file(const char *path) {
177 FILE *file;
178 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = "";
180 file = fopen(path, "r");
181 if (file == NULL)
182 return (NULL);
184 if (!fgets(uuid, sizeof(uuid), file)) {
185 fclose(file);
186 return (NULL);
187 }
188 fclose(file);
189 strstripnewline(uuid);
191 return (strdup(uuid));
192 }
194 static char *uuid_get_local(void) {
195 char *uuid;
197 /* Check /etc/uuid / UUIDFile before any other method. */
198 if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL)
199 return (uuid);
201 #if defined(__APPLE__)
202 if ((uuid = uuid_get_from_sysctlbyname("kern.uuid")) != NULL)
203 return (uuid);
204 #elif defined(__FreeBSD__)
205 if ((uuid = uuid_get_from_sysctlbyname("kern.hostuuid")) != NULL)
206 return (uuid);
207 #elif defined(__NetBSD__)
208 if ((uuid = uuid_get_from_sysctlbyname("machdep.dmi.system-uuid")) != NULL)
209 return (uuid);
210 #elif defined(__OpenBSD__)
211 if ((uuid = uuid_get_from_sysctl()) != NULL)
212 return (uuid);
213 #elif defined(__linux__)
214 if ((uuid = uuid_get_from_file("/sys/class/dmi/id/product_uuid")) != NULL)
215 return (uuid);
216 #endif
218 #if HAVE_LIBHAL_H
219 if ((uuid = uuid_get_from_hal()) != NULL)
220 return (uuid);
221 #endif
223 if ((uuid = uuid_get_from_dmidecode()) != NULL)
224 return (uuid);
226 #if defined(__linux__)
227 if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL)
228 return (uuid);
229 #endif
231 return (NULL);
232 }
234 static int uuid_config(const char *key, const char *value) {
235 if (strcasecmp(key, "UUIDFile") == 0) {
236 char *tmp = strdup(value);
237 if (tmp == NULL)
238 return (-1);
239 sfree(uuidfile);
240 uuidfile = tmp;
241 return (0);
242 }
244 return (1);
245 }
247 static int uuid_init(void) {
248 char *uuid = uuid_get_local();
250 if (uuid) {
251 sstrncpy(hostname_g, uuid, DATA_MAX_NAME_LEN);
252 sfree(uuid);
253 return (0);
254 }
256 WARNING("uuid: could not read UUID using any known method");
257 return (0);
258 }
260 void module_register(void) {
261 plugin_register_config("uuid", uuid_config, config_keys,
262 STATIC_ARRAY_SIZE(config_keys));
263 plugin_register_init("uuid", uuid_init);
264 }
266 /*
267 * vim: set tabstop=4:
268 * vim: set shiftwidth=4:
269 * vim: set expandtab:
270 */
271 /*
272 * Local variables:
273 * indent-tabs-mode: nil
274 * c-indent-level: 4
275 * c-basic-offset: 4
276 * tab-width: 4
277 * End:
278 */