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 #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:"
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];
68 int inSysInfo = 0;
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 }
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 }
108 static char *
109 uuid_get_from_dmidecode(void)
110 {
111 FILE *dmidecode = popen("dmidecode 2>/dev/null", "r");
112 char *uuid;
114 if (!dmidecode) {
115 return NULL;
116 }
118 uuid = uuid_parse_dmidecode(dmidecode);
120 pclose(dmidecode);
121 return uuid;
122 }
124 #if HAVE_LIBHAL
126 #define UUID_PATH "/org/freedesktop/Hal/devices/computer"
127 #define UUID_PROPERTY "smbios.system.uuid"
129 static char *
130 uuid_get_from_hal(void)
131 {
132 LibHalContext *ctx;
134 DBusError error;
135 DBusConnection *con;
137 dbus_error_init(&error);
139 if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) ) {
140 goto bailout_nobus;
141 }
143 ctx = libhal_ctx_new();
144 libhal_ctx_set_dbus_connection(ctx, con);
146 if (!libhal_ctx_init(ctx, &error)) {
147 goto bailout;
148 }
150 if (!libhal_device_property_exists(ctx,
151 UUID_PATH,
152 UUID_PROPERTY,
153 &error)) {
154 goto bailout;
155 }
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 }
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 }
174 libhal_ctx_free(ctx);
175 //dbus_connection_unref(con);
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
186 static char *
187 uuid_get_from_file(const char *path)
188 {
189 FILE *file;
190 char uuid[UUID_PRINTABLE_NORMAL_LENGTH+1];
192 if (!(file = fopen(path, "r"))) {
193 return NULL;
194 }
196 if (!fgets(uuid, sizeof(uuid), file)) {
197 fclose(file);
198 return NULL;
199 }
200 fclose(file);
202 return strdup (uuid);
203 }
205 static char *uuidfile = NULL;
207 static char *
208 uuid_get_local(void)
209 {
210 char *uuid;
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 }
217 #if HAVE_LIBHAL
218 if ((uuid = uuid_get_from_hal()) != NULL) {
219 return uuid;
220 }
221 #endif
223 if ((uuid = uuid_get_from_dmidecode()) != NULL) {
224 return uuid;
225 }
227 if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL) {
228 return uuid;
229 }
231 return NULL;
232 }
234 static const char *config_keys[] = {
235 "UUIDFile",
236 NULL
237 };
238 #define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1)
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 }
254 static int
255 uuid_init (void)
256 {
257 char *uuid = uuid_get_local ();
259 if (uuid) {
260 sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
261 sfree (uuid);
262 return 0;
263 }
265 WARNING ("uuid: could not read UUID using any known method");
266 return 0;
267 }
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 }
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 */