Merge pull request #1874 from rubenk/utils-dns-fix-compiler-warning
[collectd.git] / src / uuid.c
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  **/
26
27 #include "collectd.h"
28
29 #include "common.h"
30 #include "plugin.h"
31
32 #if HAVE_SYS_SYSCTL_H
33 #include <sys/sysctl.h>
34 #endif
35
36 #if HAVE_LIBHAL_H
37 #include <libhal.h>
38 #endif
39
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)
43
44 static char *uuidfile = NULL;
45
46 static const char *config_keys[] = {
47     "UUIDFile"
48 };
49
50 static int
51 looks_like_a_uuid (const char *uuid)
52 {
53     int len;
54
55     if (!uuid)
56         return (0);
57
58     len = strlen (uuid);
59
60     if (len < UUID_PRINTABLE_COMPACT_LENGTH)
61         return (0);
62
63     while (*uuid) {
64         if (!isxdigit ((int)*uuid) && *uuid != '-')
65             return (0);
66         uuid++;
67     }
68     return (1);
69 }
70
71 static char *
72 uuid_parse_dmidecode(FILE *file)
73 {
74     char line[1024];
75
76     while (fgets (line, sizeof (line), file) != NULL)
77     {
78         char *fields[4];
79         int fields_num;
80
81         strstripnewline (line);
82
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;
89
90         if (strcmp("UUID:", fields[0]) != 0)
91             continue;
92
93         if (!looks_like_a_uuid (fields[1]))
94             continue;
95
96         return (strdup (fields[1]));
97     }
98     return (NULL);
99 }
100
101 static char *
102 uuid_get_from_dmidecode(void)
103 {
104     FILE *dmidecode = popen("dmidecode -t system 2>/dev/null", "r");
105     char *uuid;
106
107     if (!dmidecode)
108         return (NULL);
109
110     uuid = uuid_parse_dmidecode(dmidecode);
111
112     pclose(dmidecode);
113     return (uuid);
114 }
115
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];
133
134     mib[0] = CTL_HW;
135     mib[1] = HW_UUID;
136
137     if (sysctl(mib, 2, uuid, &len, NULL, 0) == -1)
138         return NULL;
139     return (strdup (uuid));
140 }
141 #endif
142
143 #if HAVE_LIBHAL_H
144
145 #define UUID_PATH "/org/freedesktop/Hal/devices/computer"
146 #define UUID_PROPERTY "smbios.system.uuid"
147
148 static char *
149 uuid_get_from_hal(void)
150 {
151     LibHalContext *ctx;
152
153     DBusError error;
154     DBusConnection *con;
155
156     dbus_error_init(&error);
157
158     if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)))
159         goto bailout_nobus;
160
161     ctx = libhal_ctx_new();
162     libhal_ctx_set_dbus_connection(ctx, con);
163
164     if (!libhal_ctx_init(ctx, &error))
165         goto bailout;
166
167     if (!libhal_device_property_exists(ctx,
168                                        UUID_PATH,
169                                        UUID_PROPERTY,
170                                        &error))
171         goto bailout;
172
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);
179
180  bailout:
181     {
182         DBusError ctxerror;
183         dbus_error_init(&ctxerror);
184         if (!(libhal_ctx_shutdown(ctx, &ctxerror)))
185             dbus_error_free(&ctxerror);
186     }
187
188     libhal_ctx_free(ctx);
189
190  bailout_nobus:
191     if (dbus_error_is_set(&error))
192         dbus_error_free(&error);
193     return (NULL);
194 }
195 #endif
196
197 static char *
198 uuid_get_from_file(const char *path)
199 {
200     FILE *file;
201     char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = "";
202
203     file = fopen (path, "r");
204     if (file == NULL)
205         return (NULL);
206
207     if (!fgets(uuid, sizeof(uuid), file)) {
208         fclose(file);
209         return (NULL);
210     }
211     fclose(file);
212     strstripnewline (uuid);
213
214     return (strdup (uuid));
215 }
216
217 static char *
218 uuid_get_local(void)
219 {
220     char *uuid;
221
222     /* Check /etc/uuid / UUIDFile before any other method. */
223     if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL)
224         return (uuid);
225
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
242
243 #if HAVE_LIBHAL_H
244     if ((uuid = uuid_get_from_hal()) != NULL)
245         return (uuid);
246 #endif
247
248     if ((uuid = uuid_get_from_dmidecode()) != NULL)
249         return (uuid);
250
251 #if defined(__linux__)
252     if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL)
253         return (uuid);
254 #endif
255
256     return (NULL);
257 }
258
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     }
270
271     return (1);
272 }
273
274 static int
275 uuid_init (void)
276 {
277     char *uuid = uuid_get_local ();
278
279     if (uuid) {
280         sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
281         sfree (uuid);
282         return (0);
283     }
284
285     WARNING ("uuid: could not read UUID using any known method");
286     return (0);
287 }
288
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 }
295
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  */