Merge pull request #2618 from ajssmith/amqp1_dev1_branch
[collectd.git] / src / uuid.c
1 /**
2  * collectd - src/uuid.c
3  * Copyright (C) 2007  Red Hat Inc.
4  * Copyright (C) 2015  Ruben Kerkhof
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; only version 2 of the License is applicable.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Dan Berrange <berrange@redhat.com>
21  *   Richard W.M. Jones <rjones@redhat.com>
22  *
23  * Derived from UUID detection code by Dan Berrange <berrange@redhat.com>
24  * http://hg.et.redhat.com/virt/daemons/spectre--devel?f=f6e3a1b06433;file=lib/uuid.c
25  **/
26
27 #include "collectd.h"
28
29 #include "common.h"
30 #include "plugin.h"
31
32 #if HAVE_SYS_SYSCTL_H
33 #include <sys/sysctl.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;
41
42 static const char *config_keys[] = {"UUIDFile"};
43
44 static int looks_like_a_uuid(const char *uuid) {
45   int len;
46
47   if (!uuid)
48     return 0;
49
50   len = strlen(uuid);
51
52   if (len < UUID_PRINTABLE_COMPACT_LENGTH)
53     return 0;
54
55   while (*uuid) {
56     if (!isxdigit((int)*uuid) && *uuid != '-')
57       return 0;
58     uuid++;
59   }
60   return 1;
61 }
62
63 static char *uuid_parse_dmidecode(FILE *file) {
64   char line[1024];
65
66   while (fgets(line, sizeof(line), file) != NULL) {
67     char *fields[4];
68     int fields_num;
69
70     strstripnewline(line);
71
72     /* Look for a line reading:
73      *   UUID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
74      */
75     fields_num = strsplit(line, fields, STATIC_ARRAY_SIZE(fields));
76     if (fields_num != 2)
77       continue;
78
79     if (strcmp("UUID:", fields[0]) != 0)
80       continue;
81
82     if (!looks_like_a_uuid(fields[1]))
83       continue;
84
85     return strdup(fields[1]);
86   }
87   return NULL;
88 }
89
90 static char *uuid_get_from_dmidecode(void) {
91   FILE *dmidecode = popen("dmidecode -t system 2>/dev/null", "r");
92   char *uuid;
93
94   if (!dmidecode)
95     return NULL;
96
97   uuid = uuid_parse_dmidecode(dmidecode);
98
99   pclose(dmidecode);
100   return uuid;
101 }
102
103 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
104 static char *uuid_get_from_sysctlbyname(const char *name) {
105   char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
106   size_t len = sizeof(uuid);
107   if (sysctlbyname(name, &uuid, &len, NULL, 0) == -1)
108     return NULL;
109   return strdup(uuid);
110 }
111 #elif defined(__OpenBSD__)
112 static char *uuid_get_from_sysctl(void) {
113   char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1];
114   size_t len = sizeof(uuid);
115   int mib[2];
116
117   mib[0] = CTL_HW;
118   mib[1] = HW_UUID;
119
120   if (sysctl(mib, 2, uuid, &len, NULL, 0) == -1)
121     return NULL;
122   return strdup(uuid);
123 }
124 #endif
125
126 static char *uuid_get_from_file(const char *path) {
127   FILE *file;
128   char uuid[UUID_PRINTABLE_NORMAL_LENGTH + 1] = "";
129
130   file = fopen(path, "r");
131   if (file == NULL)
132     return NULL;
133
134   if (!fgets(uuid, sizeof(uuid), file)) {
135     fclose(file);
136     return NULL;
137   }
138   fclose(file);
139   strstripnewline(uuid);
140
141   return strdup(uuid);
142 }
143
144 static char *uuid_get_local(void) {
145   char *uuid;
146
147   /* Check /etc/uuid / UUIDFile before any other method. */
148   if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL)
149     return uuid;
150
151 #if defined(__APPLE__)
152   if ((uuid = uuid_get_from_sysctlbyname("kern.uuid")) != NULL)
153     return uuid;
154 #elif defined(__FreeBSD__)
155   if ((uuid = uuid_get_from_sysctlbyname("kern.hostuuid")) != NULL)
156     return uuid;
157 #elif defined(__NetBSD__)
158   if ((uuid = uuid_get_from_sysctlbyname("machdep.dmi.system-uuid")) != NULL)
159     return uuid;
160 #elif defined(__OpenBSD__)
161   if ((uuid = uuid_get_from_sysctl()) != NULL)
162     return uuid;
163 #elif defined(__linux__)
164   if ((uuid = uuid_get_from_file("/sys/class/dmi/id/product_uuid")) != NULL)
165     return uuid;
166 #endif
167
168   if ((uuid = uuid_get_from_dmidecode()) != NULL)
169     return uuid;
170
171 #if defined(__linux__)
172   if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL)
173     return uuid;
174 #endif
175
176   return NULL;
177 }
178
179 static int uuid_config(const char *key, const char *value) {
180   if (strcasecmp(key, "UUIDFile") == 0) {
181     char *tmp = strdup(value);
182     if (tmp == NULL)
183       return -1;
184     sfree(uuidfile);
185     uuidfile = tmp;
186     return 0;
187   }
188
189   return 1;
190 }
191
192 static int uuid_init(void) {
193   char *uuid = uuid_get_local();
194
195   if (uuid) {
196     hostname_set(uuid);
197     sfree(uuid);
198     return 0;
199   }
200
201   WARNING("uuid: could not read UUID using any known method");
202   return 0;
203 }
204
205 void module_register(void) {
206   plugin_register_config("uuid", uuid_config, config_keys,
207                          STATIC_ARRAY_SIZE(config_keys));
208   plugin_register_init("uuid", uuid_init);
209 }