AUTHORS: Added Marco.
[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 #include "common.h"
28 #include "configfile.h"
29 #include "plugin.h"
30
31 #if HAVE_LIBHAL
32 #include <libhal.h>
33 #endif
34
35 #define UUID_RAW_LENGTH 16
36 #define UUID_PRINTABLE_COMPACT_LENGTH  (UUID_RAW_LENGTH * 2)
37 #define UUID_PRINTABLE_NORMAL_LENGTH  (UUID_PRINTABLE_COMPACT_LENGTH + 4)
38
39 #define HANDLE_PREFIX "Handle"
40 #define SYSINFO_PREFIX "System Information"
41 #define ALT_SYSINFO_PREFIX "\tSystem Information"
42 #define UUID_PREFIX "\tUUID:"
43 #define ALT_UUID_PREFIX "\t\tUUID:"
44
45 static int
46 looks_like_a_uuid (const char *uuid)
47 {
48     int len;
49
50     if (!uuid) return 0;
51
52     len = strlen (uuid);
53
54     if (len < UUID_PRINTABLE_COMPACT_LENGTH)
55         return 0;
56
57     while (*uuid) {
58         if (!isxdigit (*uuid) && *uuid != '-') return 0;
59         uuid++;
60     }
61     return 1;
62 }
63
64 static char *
65 uuid_parse_dmidecode(FILE *file)
66 {
67     char line[1024];
68     int inSysInfo = 0;
69
70     for (;;) {
71         if (!fgets(line, sizeof(line)/sizeof(char), file)) {
72             return NULL;
73         }
74         if (strncmp(line, HANDLE_PREFIX,
75                     (sizeof(HANDLE_PREFIX)/sizeof(char))-1) == 0) {
76             /*printf("Got handle %s\n", line);*/
77             inSysInfo = 0;
78         } else if (strncmp(line, SYSINFO_PREFIX,
79                            (sizeof(SYSINFO_PREFIX)/sizeof(char))-1) == 0) {
80             /*printf("Got system info %s\n", line);*/
81             inSysInfo = 1;
82         } else if (strncmp(line, ALT_SYSINFO_PREFIX,
83                            (sizeof(ALT_SYSINFO_PREFIX)/sizeof(char))-1) == 0) {
84             /*printf("Got alt system info %s\n", line);*/
85             inSysInfo = 1;
86         }
87         
88         if (inSysInfo) {
89             if (strncmp(line, UUID_PREFIX,
90                         (sizeof(UUID_PREFIX)/sizeof(char))-1) == 0) {
91                 char *uuid = line + (sizeof(UUID_PREFIX)/sizeof(char));
92                 /*printf("Got uuid [%s]\n", uuid);*/
93                 if (looks_like_a_uuid (uuid))
94                     return strdup (uuid);
95             }
96             if (strncmp(line, ALT_UUID_PREFIX,
97                         (sizeof(ALT_UUID_PREFIX)/sizeof(char))-1) == 0) {
98                 char *uuid = line + (sizeof(ALT_UUID_PREFIX)/sizeof(char));
99                 /*printf("Got alt uuid [%s]\n", uuid);*/
100                 if (looks_like_a_uuid (uuid))
101                     return strdup (uuid);
102             }
103         }
104     }
105     return NULL;
106 }
107
108 static char *
109 uuid_get_from_dmidecode(void)
110 {
111     FILE *dmidecode = popen("dmidecode 2>/dev/null", "r");
112     char *uuid;
113
114     if (!dmidecode) {
115         return NULL;
116     }
117     
118     uuid = uuid_parse_dmidecode(dmidecode);
119
120     pclose(dmidecode);
121     return uuid;
122 }
123
124 #if HAVE_LIBHAL
125
126 #define UUID_PATH "/org/freedesktop/Hal/devices/computer"
127 #define UUID_PROPERTY "smbios.system.uuid"
128
129 static char *
130 uuid_get_from_hal(void)
131 {
132     LibHalContext *ctx;
133
134     DBusError error;
135     DBusConnection *con;
136
137     dbus_error_init(&error);
138
139     if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) ) {
140         goto bailout_nobus;
141     }
142
143     ctx = libhal_ctx_new();
144     libhal_ctx_set_dbus_connection(ctx, con);
145
146     if (!libhal_ctx_init(ctx, &error)) {
147         goto bailout;
148     }
149
150     if (!libhal_device_property_exists(ctx,
151                                        UUID_PATH,
152                                        UUID_PROPERTY,
153                                        &error)) {
154         goto bailout;
155     }
156
157     char *uuid  = libhal_device_get_property_string(ctx,
158                                                     UUID_PATH,
159                                                     UUID_PROPERTY,
160                                                     &error);
161     if (looks_like_a_uuid (uuid)) {
162         return uuid;
163     }
164
165  bailout:
166     {
167         DBusError ctxerror;
168         dbus_error_init(&ctxerror);
169         if (!(libhal_ctx_shutdown(ctx, &ctxerror))) {
170             dbus_error_free(&ctxerror);
171         }
172     }
173
174     libhal_ctx_free(ctx);
175     //dbus_connection_unref(con);
176
177  bailout_nobus:
178     if (dbus_error_is_set(&error)) {
179         /*printf("Error %s\n", error.name);*/
180         dbus_error_free(&error);
181     }
182     return NULL;
183 }
184 #endif
185
186 static char *
187 uuid_get_from_file(const char *path)
188 {
189     FILE *file;
190     char uuid[UUID_PRINTABLE_NORMAL_LENGTH+1];
191
192     if (!(file = fopen(path, "r"))) {
193         return NULL;
194     }
195
196     if (!fgets(uuid, sizeof(uuid), file)) {
197         fclose(file);
198         return NULL;
199     }
200     fclose(file);
201
202     return strdup (uuid);
203 }
204
205 static char *uuidfile = NULL;
206
207 static char *
208 uuid_get_local(void)
209 {
210     char *uuid;
211
212     /* Check /etc/uuid / UUIDFile before any other method. */
213     if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL){
214         return uuid;
215     }
216
217 #if HAVE_LIBHAL
218     if ((uuid = uuid_get_from_hal()) != NULL) {
219         return uuid;
220     }
221 #endif
222
223     if ((uuid = uuid_get_from_dmidecode()) != NULL) {
224         return uuid;
225     }
226
227     if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL) {
228         return uuid;
229     }
230
231     return NULL;
232 }
233
234 static const char *config_keys[] = {
235     "UUIDFile",
236     NULL
237 };
238 #define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1)
239
240 static int
241 uuid_config (const char *key, const char *value)
242 {
243     if (strcasecmp (key, "UUIDFile") == 0) {
244         if (uuidfile) {
245             ERROR ("UUIDFile given twice in configuration file");
246             return 1;
247         }
248         uuidfile = strdup (value);
249         return 0;
250     }
251     return 0;
252 }
253
254 static int
255 uuid_init (void)
256 {
257     char *uuid = uuid_get_local ();
258
259     if (uuid) {
260         sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
261         sfree (uuid);
262         return 0;
263     }
264
265     WARNING ("uuid: could not read UUID using any known method");
266     return 0;
267 }
268
269 void module_register (void)
270 {
271         plugin_register_config ("uuid", uuid_config,
272                             config_keys, NR_CONFIG_KEYS);
273         plugin_register_init ("uuid", uuid_init);
274 }
275
276 /*
277  * vim: set tabstop=4:
278  * vim: set shiftwidth=4:
279  * vim: set expandtab:
280  */
281 /*
282  * Local variables:
283  *  indent-tabs-mode: nil
284  *  c-indent-level: 4
285  *  c-basic-offset: 4
286  *  tab-width: 4
287  * End:
288  */