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 **/
26 #include "collectd.h"
27 #include "common.h"
28 #include "configfile.h"
29 #include "plugin.h"
31 #if HAVE_LIBHAL
32 #include <libhal.h>
33 #endif
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)
39 static char *uuidfile = NULL;
41 static const char *config_keys[] = {
42 "UUIDFile"
43 };
45 static int
46 looks_like_a_uuid (const char *uuid)
47 {
48 int len;
50 if (!uuid) return 0;
52 len = strlen (uuid);
54 if (len < UUID_PRINTABLE_COMPACT_LENGTH)
55 return 0;
57 while (*uuid) {
58 if (!isxdigit ((int)*uuid) && *uuid != '-') return 0;
59 uuid++;
60 }
61 return 1;
62 }
64 static char *
65 uuid_parse_dmidecode(FILE *file)
66 {
67 char line[1024];
69 while (fgets (line, sizeof (line), file) != NULL)
70 {
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 *
95 uuid_get_from_dmidecode(void)
96 {
97 FILE *dmidecode = popen("dmidecode 2>/dev/null", "r");
98 char *uuid;
100 if (!dmidecode) {
101 return NULL;
102 }
104 uuid = uuid_parse_dmidecode(dmidecode);
106 pclose(dmidecode);
107 return uuid;
108 }
110 #if HAVE_LIBHAL
112 #define UUID_PATH "/org/freedesktop/Hal/devices/computer"
113 #define UUID_PROPERTY "smbios.system.uuid"
115 static char *
116 uuid_get_from_hal(void)
117 {
118 LibHalContext *ctx;
120 DBusError error;
121 DBusConnection *con;
123 dbus_error_init(&error);
125 if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) ) {
126 goto bailout_nobus;
127 }
129 ctx = libhal_ctx_new();
130 libhal_ctx_set_dbus_connection(ctx, con);
132 if (!libhal_ctx_init(ctx, &error)) {
133 goto bailout;
134 }
136 if (!libhal_device_property_exists(ctx,
137 UUID_PATH,
138 UUID_PROPERTY,
139 &error)) {
140 goto bailout;
141 }
143 char *uuid = libhal_device_get_property_string(ctx,
144 UUID_PATH,
145 UUID_PROPERTY,
146 &error);
147 if (looks_like_a_uuid (uuid)) {
148 return uuid;
149 }
151 bailout:
152 {
153 DBusError ctxerror;
154 dbus_error_init(&ctxerror);
155 if (!(libhal_ctx_shutdown(ctx, &ctxerror))) {
156 dbus_error_free(&ctxerror);
157 }
158 }
160 libhal_ctx_free(ctx);
161 //dbus_connection_unref(con);
163 bailout_nobus:
164 if (dbus_error_is_set(&error)) {
165 /*printf("Error %s\n", error.name);*/
166 dbus_error_free(&error);
167 }
168 return NULL;
169 }
170 #endif
172 static char *
173 uuid_get_from_file(const char *path)
174 {
175 FILE *file;
176 char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = "";
178 file = fopen (path, "r");
179 if (file == NULL)
180 return NULL;
182 if (!fgets(uuid, sizeof(uuid), file)) {
183 fclose(file);
184 return NULL;
185 }
186 fclose(file);
187 strstripnewline (uuid);
189 return strdup (uuid);
190 }
192 static char *
193 uuid_get_local(void)
194 {
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;
200 }
202 #if HAVE_LIBHAL
203 if ((uuid = uuid_get_from_hal()) != NULL) {
204 return uuid;
205 }
206 #endif
208 if ((uuid = uuid_get_from_dmidecode()) != NULL) {
209 return uuid;
210 }
212 if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL) {
213 return uuid;
214 }
216 return NULL;
217 }
219 static int
220 uuid_config (const char *key, const char *value)
221 {
222 if (strcasecmp (key, "UUIDFile") == 0) {
223 char *tmp = strdup (value);
224 if (tmp == NULL)
225 return -1;
226 sfree (uuidfile);
227 uuidfile = tmp;
228 } else {
229 return 1;
230 }
232 return 0;
233 }
235 static int
236 uuid_init (void)
237 {
238 char *uuid = uuid_get_local ();
240 if (uuid) {
241 sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
242 sfree (uuid);
243 return 0;
244 }
246 WARNING ("uuid: could not read UUID using any known method");
247 return 0;
248 }
250 void module_register (void)
251 {
252 plugin_register_config ("uuid", uuid_config,
253 config_keys, STATIC_ARRAY_SIZE (config_keys));
254 plugin_register_init ("uuid", uuid_init);
255 }
257 /*
258 * vim: set tabstop=4:
259 * vim: set shiftwidth=4:
260 * vim: set expandtab:
261 */
262 /*
263 * Local variables:
264 * indent-tabs-mode: nil
265 * c-indent-level: 4
266 * c-basic-offset: 4
267 * tab-width: 4
268 * End:
269 */