Merge branch 'collectd-5.5'
[collectd.git] / src / uuid.c
1 /**
2  * collectd - src/uuid.c
3  * Copyright (C) 2007  Red Hat Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Dan Berrange <berrange@redhat.com>
20  *   Richard W.M. Jones <rjones@redhat.com>
21  *
22  * Derived from UUID detection code by Dan Berrange <berrange@redhat.com>
23  * http://hg.et.redhat.com/virt/daemons/spectre--devel?f=f6e3a1b06433;file=lib/uuid.c
24  **/
25
26 #include "collectd.h"
27
28 #include "common.h"
29 #include "configfile.h"
30 #include "plugin.h"
31
32 #if HAVE_LIBHAL_H
33 #include <libhal.h>
34 #endif
35
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)
39
40 static char *uuidfile = NULL;
41
42 static const char *config_keys[] = {
43     "UUIDFile"
44 };
45
46 static int
47 looks_like_a_uuid (const char *uuid)
48 {
49     int len;
50
51     if (!uuid) return 0;
52
53     len = strlen (uuid);
54
55     if (len < UUID_PRINTABLE_COMPACT_LENGTH)
56         return 0;
57
58     while (*uuid) {
59         if (!isxdigit ((int)*uuid) && *uuid != '-') return 0;
60         uuid++;
61     }
62     return 1;
63 }
64
65 static char *
66 uuid_parse_dmidecode(FILE *file)
67 {
68     char line[1024];
69
70     while (fgets (line, sizeof (line), file) != NULL)
71     {
72         char *fields[4];
73         int fields_num;
74
75         strstripnewline (line);
76
77         /* Look for a line reading:
78          *   UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
79          */
80         fields_num = strsplit (line, fields, STATIC_ARRAY_SIZE (fields));
81         if (fields_num != 2)
82             continue;
83
84         if (strcmp("UUID:", fields[0]) != 0)
85             continue;
86
87         if (!looks_like_a_uuid (fields[1]))
88             continue;
89
90         return strdup (fields[1]);
91     }
92     return NULL;
93 }
94
95 static char *
96 uuid_get_from_dmidecode(void)
97 {
98     FILE *dmidecode = popen("dmidecode 2>/dev/null", "r");
99     char *uuid;
100
101     if (!dmidecode) {
102         return NULL;
103     }
104
105     uuid = uuid_parse_dmidecode(dmidecode);
106
107     pclose(dmidecode);
108     return uuid;
109 }
110
111 #if HAVE_LIBHAL_H
112
113 #define UUID_PATH "/org/freedesktop/Hal/devices/computer"
114 #define UUID_PROPERTY "smbios.system.uuid"
115
116 static char *
117 uuid_get_from_hal(void)
118 {
119     LibHalContext *ctx;
120
121     DBusError error;
122     DBusConnection *con;
123
124     dbus_error_init(&error);
125
126     if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) ) {
127         goto bailout_nobus;
128     }
129
130     ctx = libhal_ctx_new();
131     libhal_ctx_set_dbus_connection(ctx, con);
132
133     if (!libhal_ctx_init(ctx, &error)) {
134         goto bailout;
135     }
136
137     if (!libhal_device_property_exists(ctx,
138                                        UUID_PATH,
139                                        UUID_PROPERTY,
140                                        &error)) {
141         goto bailout;
142     }
143
144     char *uuid  = libhal_device_get_property_string(ctx,
145                                                     UUID_PATH,
146                                                     UUID_PROPERTY,
147                                                     &error);
148     if (looks_like_a_uuid (uuid)) {
149         return uuid;
150     }
151
152  bailout:
153     {
154         DBusError ctxerror;
155         dbus_error_init(&ctxerror);
156         if (!(libhal_ctx_shutdown(ctx, &ctxerror))) {
157             dbus_error_free(&ctxerror);
158         }
159     }
160
161     libhal_ctx_free(ctx);
162     //dbus_connection_unref(con);
163
164  bailout_nobus:
165     if (dbus_error_is_set(&error)) {
166         /*printf("Error %s\n", error.name);*/
167         dbus_error_free(&error);
168     }
169     return NULL;
170 }
171 #endif
172
173 static char *
174 uuid_get_from_file(const char *path)
175 {
176     FILE *file;
177     char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = "";
178
179     file = fopen (path, "r");
180     if (file == NULL)
181         return NULL;
182
183     if (!fgets(uuid, sizeof(uuid), file)) {
184         fclose(file);
185         return NULL;
186     }
187     fclose(file);
188     strstripnewline (uuid);
189
190     return strdup (uuid);
191 }
192
193 static char *
194 uuid_get_local(void)
195 {
196     char *uuid;
197
198     /* Check /etc/uuid / UUIDFile before any other method. */
199     if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL){
200         return uuid;
201     }
202
203 #if HAVE_LIBHAL_H
204     if ((uuid = uuid_get_from_hal()) != NULL) {
205         return uuid;
206     }
207 #endif
208
209     if ((uuid = uuid_get_from_dmidecode()) != NULL) {
210         return uuid;
211     }
212
213     if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL) {
214         return uuid;
215     }
216
217     return NULL;
218 }
219
220 static int
221 uuid_config (const char *key, const char *value)
222 {
223     if (strcasecmp (key, "UUIDFile") == 0) {
224         char *tmp = strdup (value);
225         if (tmp == NULL)
226             return -1;
227         sfree (uuidfile);
228         uuidfile = tmp;
229     } else {
230         return 1;
231     }
232
233     return 0;
234 }
235
236 static int
237 uuid_init (void)
238 {
239     char *uuid = uuid_get_local ();
240
241     if (uuid) {
242         sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
243         sfree (uuid);
244         return 0;
245     }
246
247     WARNING ("uuid: could not read UUID using any known method");
248     return 0;
249 }
250
251 void module_register (void)
252 {
253     plugin_register_config ("uuid", uuid_config,
254             config_keys, STATIC_ARRAY_SIZE (config_keys));
255     plugin_register_init ("uuid", uuid_init);
256 }
257
258 /*
259  * vim: set tabstop=4:
260  * vim: set shiftwidth=4:
261  * vim: set expandtab:
262  */
263 /*
264  * Local variables:
265  *  indent-tabs-mode: nil
266  *  c-indent-level: 4
267  *  c-basic-offset: 4
268  *  tab-width: 4
269  * End:
270  */