37bd5c3965284f9e32ce39dc3cedda131d3f60c4
1 /**
2 * collectd - src/apple_sensors.c
3 * Copyright (C) 2006 Florian octo Forster
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; either version 2 of the License, or (at your
8 * option) any later version.
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 * Florian octo Forster <octo at verplant.org>
21 **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "utils_debug.h"
28 #define MODULE_NAME "apple_sensors"
30 #if HAVE_CTYPE_H
31 # include <ctype.h>
32 #endif
34 #if HAVE_MACH_MACH_TYPES_H
35 # include <mach/mach_types.h>
36 #endif
37 #if HAVE_MACH_MACH_INIT_H
38 # include <mach/mach_init.h>
39 #endif
40 #if HAVE_MACH_MACH_ERROR_H
41 # include <mach/mach_error.h>
42 #endif
43 #if HAVE_MACH_MACH_PORT_H
44 # include <mach/mach_port.h>
45 #endif
46 #if HAVE_COREFOUNDATION_COREFOUNDATION_H
47 # include <CoreFoundation/CoreFoundation.h>
48 #endif
49 #if HAVE_IOKIT_IOKITLIB_H
50 # include <IOKit/IOKitLib.h>
51 #endif
52 #if HAVE_IOKIT_IOTYPES_H
53 # include <IOKit/IOTypes.h>
54 #endif
56 #if HAVE_IOKIT_IOKITLIB_H
57 # define IOKIT_HAVE_READ 1
58 #else
59 # define IOKIT_HAVE_READ 0
60 #endif
62 #if HAVE_IOKIT_IOKITLIB_H
63 static mach_port_t io_master_port = MACH_PORT_NULL;
64 #endif
66 static char *temperature_file = "apple_sensors/temperature-%s.rrd";
67 static char *fanspeed_file = "apple_sensors/fanspeed-%s.rrd";
69 static char *ds_def[] =
70 {
71 "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U",
72 NULL
73 };
74 static int ds_num = 1;
76 static void as_init (void)
77 {
78 #if IOKIT_HAVE_READ
79 kern_return_t status;
81 if (io_master_port != MACH_PORT_NULL)
82 {
83 mach_port_deallocate (mach_task_self (),
84 io_master_port);
85 io_master_port = MACH_PORT_NULL;
86 }
88 status = IOMasterPort (MACH_PORT_NULL, &io_master_port);
89 if (status != kIOReturnSuccess)
90 {
91 syslog (LOG_ERR, "IOMasterPort failed: %s",
92 mach_error_string (status));
93 io_master_port = MACH_PORT_NULL;
94 return;
95 }
96 #endif /* IOKIT_HAVE_READ */
98 return;
99 }
101 static void as_write (char *host, char *inst, char *val, const char *template)
102 {
103 char filename[256];
104 int status;
106 status = snprintf (filename, 256, template, inst);
107 if ((status < 1) || (status >= 256))
108 return;
110 rrd_update_file (host, filename, val, ds_def, ds_num);
111 }
113 static void temperature_write (char *host, char *inst, char *val)
114 {
115 as_write (host, inst, val, temperature_file);
116 }
118 static void fanspeed_write (char *host, char *inst, char *val)
119 {
120 as_write (host, inst, val, fanspeed_file);
121 }
123 #if IOKIT_HAVE_READ
124 static void as_submit (char *type, char *inst, double value)
125 {
126 char buf[128];
128 if (snprintf (buf, 1024, "%u:%f", (unsigned int) curtime,
129 value) >= 128)
130 return;
132 plugin_submit (type, inst, buf);
133 }
135 static void as_read (void)
136 {
137 kern_return_t status;
138 io_iterator_t iterator;
139 io_object_t io_obj;
140 CFMutableDictionaryRef prop_dict;
141 CFTypeRef property;
143 char type[128];
144 char inst[128];
145 int value_int;
146 double value_double;
147 int i;
149 if (!io_master_port || (io_master_port == MACH_PORT_NULL))
150 return;
152 status = IOServiceGetMatchingServices (io_master_port,
153 IOServiceNameMatching("IOHWSensor"),
154 &iterator);
155 if (status != kIOReturnSuccess)
156 {
157 syslog (LOG_ERR, "IOServiceGetMatchingServices failed: %s",
158 mach_error_string (status));
159 return;
160 }
162 while ((io_obj = IOIteratorNext (iterator)))
163 {
164 prop_dict = NULL;
165 status = IORegistryEntryCreateCFProperties (io_obj,
166 &prop_dict,
167 kCFAllocatorDefault,
168 kNilOptions);
169 if (status != kIOReturnSuccess)
170 {
171 DBG ("IORegistryEntryCreateCFProperties failed: %s",
172 mach_error_string (status));
173 continue;
174 }
176 /* Copy the sensor type. */
177 property = NULL;
178 if (!CFDictionaryGetValueIfPresent (prop_dict,
179 CFSTR ("type"),
180 &property))
181 continue;
182 if (CFGetTypeID (property) != CFStringGetTypeID ())
183 continue;
184 if (!CFStringGetCString (property,
185 type, 128,
186 kCFStringEncodingASCII))
187 continue;
188 type[127] = '\0';
190 /* Copy the sensor location. This will be used as `instance'. */
191 property = NULL;
192 if (!CFDictionaryGetValueIfPresent (prop_dict,
193 CFSTR ("location"),
194 &property))
195 continue;
196 if (CFGetTypeID (property) != CFStringGetTypeID ())
197 continue;
198 if (!CFStringGetCString (property,
199 inst, 128,
200 kCFStringEncodingASCII))
201 continue;
202 inst[127] = '\0';
203 for (i = 0; i < 128; i++)
204 {
205 if (inst[i] == '\0')
206 break;
207 else if (isalnum (inst[i]))
208 inst[i] = (char) tolower (inst[i]);
209 else
210 inst[i] = '_';
211 }
213 /* Get the actual value. Some computation, based on the `type'
214 * is neccessary. */
215 property = NULL;
216 if (!CFDictionaryGetValueIfPresent (prop_dict,
217 CFSTR ("current-value"),
218 &property))
219 continue;
220 if (CFGetTypeID (property) != CFNumberGetTypeID ())
221 continue;
222 if (!CFNumberGetValue (property,
223 kCFNumberIntType,
224 &value_int))
225 continue;
227 /* Found e.g. in the 1.5GHz PowerBooks */
228 if (strcmp (type, "temperature") == 0)
229 {
230 value_double = ((double) value_int) / 65536.0;
231 strncpy (type, "apple_temperature", 128);
232 }
233 else if (strcmp (type, "temp") == 0)
234 {
235 value_double = ((double) value_int) / 10.0;
236 strncpy (type, "apple_temperature", 128);
237 }
238 else if (strcmp (type, "fanspeed") == 0)
239 {
240 value_double = ((double) value_int) / 65536.0;
241 strncpy (type, "apple_fanspeed", 128);
242 }
243 else if (strcmp (type, "voltage") == 0)
244 {
245 /* Leave this to the battery plugin. */
246 continue;
247 }
248 else if (strcmp (type, "adc") == 0)
249 {
250 value_double = ((double) value_int) / 10.0;
251 strncpy (type, "apple_temperature", 128);
252 }
253 else
254 {
255 DBG ("apple_sensors: Read unknown sensor type: %s",
256 type);
257 value_double = (double) value_int;
258 }
260 as_submit (type, inst, value_double);
262 CFRelease (prop_dict);
263 IOObjectRelease (io_obj);
264 } /* while (iterator) */
266 IOObjectRelease (iterator);
267 }
268 #else
269 # define as_read NULL
270 #endif /* IOKIT_HAVE_READ */
272 void module_register (void)
273 {
274 plugin_register (MODULE_NAME, as_init, as_read, NULL);
275 plugin_register ("apple_temperature", NULL, NULL, temperature_write);
276 plugin_register ("apple_fanspeed", NULL, NULL, fanspeed_write);
277 }
279 #undef MODULE_NAME