223bfd544b8c680dd5c8722ba0dd484dcad07ec8
[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)
52         return (0);
53
54     len = strlen (uuid);
55
56     if (len < UUID_PRINTABLE_COMPACT_LENGTH)
57         return (0);
58
59     while (*uuid) {
60         if (!isxdigit ((int)*uuid) && *uuid != '-')
61             return (0);
62         uuid++;
63     }
64     return (1);
65 }
66
67 static char *
68 uuid_parse_dmidecode(FILE *file)
69 {
70     char line[1024];
71
72     while (fgets (line, sizeof (line), file) != NULL)
73     {
74         char *fields[4];
75         int fields_num;
76
77         strstripnewline (line);
78
79         /* Look for a line reading:
80          *   UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
81          */
82         fields_num = strsplit (line, fields, STATIC_ARRAY_SIZE (fields));
83         if (fields_num != 2)
84             continue;
85
86         if (strcmp("UUID:", fields[0]) != 0)
87             continue;
88
89         if (!looks_like_a_uuid (fields[1]))
90             continue;
91
92         return (strdup (fields[1]));
93     }
94     return (NULL);
95 }
96
97 static char *
98 uuid_get_from_dmidecode(void)
99 {
100     FILE *dmidecode = popen("dmidecode -t system 2>/dev/null", "r");
101     char *uuid;
102
103     if (!dmidecode)
104         return (NULL);
105
106     uuid = uuid_parse_dmidecode(dmidecode);
107
108     pclose(dmidecode);
109     return (uuid);
110 }
111
112 #if HAVE_LIBHAL_H
113
114 #define UUID_PATH "/org/freedesktop/Hal/devices/computer"
115 #define UUID_PROPERTY "smbios.system.uuid"
116
117 static char *
118 uuid_get_from_hal(void)
119 {
120     LibHalContext *ctx;
121
122     DBusError error;
123     DBusConnection *con;
124
125     dbus_error_init(&error);
126
127     if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)))
128         goto bailout_nobus;
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     if (!libhal_device_property_exists(ctx,
137                                        UUID_PATH,
138                                        UUID_PROPERTY,
139                                        &error))
140         goto bailout;
141
142     char *uuid  = libhal_device_get_property_string(ctx,
143                                                     UUID_PATH,
144                                                     UUID_PROPERTY,
145                                                     &error);
146     if (looks_like_a_uuid (uuid))
147         return (uuid);
148
149  bailout:
150     {
151         DBusError ctxerror;
152         dbus_error_init(&ctxerror);
153         if (!(libhal_ctx_shutdown(ctx, &ctxerror)))
154             dbus_error_free(&ctxerror);
155     }
156
157     libhal_ctx_free(ctx);
158
159  bailout_nobus:
160     if (dbus_error_is_set(&error))
161         dbus_error_free(&error);
162     return (NULL);
163 }
164 #endif
165
166 static char *
167 uuid_get_from_file(const char *path)
168 {
169     FILE *file;
170     char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = "";
171
172     file = fopen (path, "r");
173     if (file == NULL)
174         return (NULL);
175
176     if (!fgets(uuid, sizeof(uuid), file)) {
177         fclose(file);
178         return (NULL);
179     }
180     fclose(file);
181     strstripnewline (uuid);
182
183     return (strdup (uuid));
184 }
185
186 static char *
187 uuid_get_local(void)
188 {
189     char *uuid;
190
191     /* Check /etc/uuid / UUIDFile before any other method. */
192     if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL)
193         return (uuid);
194
195 #if HAVE_LIBHAL_H
196     if ((uuid = uuid_get_from_hal()) != NULL) {
197         return uuid;
198     }
199 #endif
200
201     if ((uuid = uuid_get_from_dmidecode()) != NULL)
202         return (uuid);
203
204 #if defined(__linux__)
205     if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL)
206         return (uuid);
207 #endif
208
209     return (NULL);
210 }
211
212 static int
213 uuid_config (const char *key, const char *value)
214 {
215     if (strcasecmp (key, "UUIDFile") == 0) {
216         char *tmp = strdup (value);
217         if (tmp == NULL)
218             return (-1);
219         sfree (uuidfile);
220         uuidfile = tmp;
221         return (0);
222     }
223
224     return (1);
225 }
226
227 static int
228 uuid_init (void)
229 {
230     char *uuid = uuid_get_local ();
231
232     if (uuid) {
233         sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
234         sfree (uuid);
235         return (0);
236     }
237
238     WARNING ("uuid: could not read UUID using any known method");
239     return (0);
240 }
241
242 void module_register (void)
243 {
244     plugin_register_config ("uuid", uuid_config,
245             config_keys, STATIC_ARRAY_SIZE (config_keys));
246     plugin_register_init ("uuid", uuid_init);
247 }
248
249 /*
250  * vim: set tabstop=4:
251  * vim: set shiftwidth=4:
252  * vim: set expandtab:
253  */
254 /*
255  * Local variables:
256  *  indent-tabs-mode: nil
257  *  c-indent-level: 4
258  *  c-basic-offset: 4
259  *  tab-width: 4
260  * End:
261  */