apple_sensors plugin: Converted to the new plugin interface.
[collectd.git] / src / apple_sensors.c
1 /**
2  * collectd - src/apple_sensors.c
3  * Copyright (C) 2006,2007  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; 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  *   Florian octo Forster <octo at verplant.org>
20  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "utils_debug.h"
26
27 #if HAVE_CTYPE_H
28 #  include <ctype.h>
29 #endif
30
31 #if HAVE_MACH_MACH_TYPES_H
32 #  include <mach/mach_types.h>
33 #endif
34 #if HAVE_MACH_MACH_INIT_H
35 #  include <mach/mach_init.h>
36 #endif
37 #if HAVE_MACH_MACH_ERROR_H
38 #  include <mach/mach_error.h>
39 #endif
40 #if HAVE_MACH_MACH_PORT_H
41 #  include <mach/mach_port.h>
42 #endif
43 #if HAVE_COREFOUNDATION_COREFOUNDATION_H
44 #  include <CoreFoundation/CoreFoundation.h>
45 #endif
46 #if HAVE_IOKIT_IOKITLIB_H
47 #  include <IOKit/IOKitLib.h>
48 #endif
49 #if HAVE_IOKIT_IOTYPES_H
50 #  include <IOKit/IOTypes.h>
51 #endif
52
53 #if HAVE_IOKIT_IOKITLIB_H
54 # define IOKIT_HAVE_READ 1
55 #else
56 # define IOKIT_HAVE_READ 0
57 #endif
58
59 #if HAVE_IOKIT_IOKITLIB_H
60 static mach_port_t io_master_port = MACH_PORT_NULL;
61 #endif
62
63 static data_source_t data_source_fanspeed[1] =
64 {
65         {"value", DS_TYPE_GAUGE, 0, NAN}
66 };
67
68 static data_set_t fanspeed_ds =
69 {
70         "fanspeed", 1, data_source_fanspeed
71 };
72
73 static data_source_t data_source_temperature[1] =
74 {
75         {"value", DS_TYPE_GAUGE, -273.15, NAN}
76 };
77
78 static data_set_t temperature_ds =
79 {
80         "temperature", 1, data_source_temperature
81 };
82
83 #if IOKIT_HAVE_READ
84 static int as_init (void)
85 {
86         kern_return_t status;
87         
88         if (io_master_port != MACH_PORT_NULL)
89         {
90                 mach_port_deallocate (mach_task_self (),
91                                 io_master_port);
92                 io_master_port = MACH_PORT_NULL;
93         }
94
95         status = IOMasterPort (MACH_PORT_NULL, &io_master_port);
96         if (status != kIOReturnSuccess)
97         {
98                 syslog (LOG_ERR, "IOMasterPort failed: %s",
99                                 mach_error_string (status));
100                 io_master_port = MACH_PORT_NULL;
101                 return (-1);
102         }
103
104         return (0);
105 }
106
107 static void as_submit (const char *type, const char *type_instance,
108                 double val)
109 {
110         value_t values[1];
111         value_list_t vl = VALUE_LIST_INIT;
112
113         DBG ("type = %s; type_instance = %s; val = %f;",
114                         type, type_instance, val);
115
116         values[0].gauge = val;
117
118         vl.values = values;
119         vl.values_len = 1;
120         vl.time = time (NULL);
121         strcpy (vl.host, hostname);
122         strcpy (vl.plugin, "apple_sensors");
123         strcpy (vl.plugin_instance, "");
124         strcpy (vl.type_instance, type_instance);
125
126         plugin_dispatch_values (type, &vl);
127 }
128
129 static int as_read (void)
130 {
131         kern_return_t   status;
132         io_iterator_t   iterator;
133         io_object_t     io_obj;
134         CFMutableDictionaryRef prop_dict;
135         CFTypeRef       property;
136
137         char   type[128];
138         char   inst[128];
139         int    value_int;
140         double value_double;
141         int    i;
142
143         if (!io_master_port || (io_master_port == MACH_PORT_NULL))
144                 return (-1);
145
146         status = IOServiceGetMatchingServices (io_master_port,
147                         IOServiceNameMatching("IOHWSensor"),
148                         &iterator);
149         if (status != kIOReturnSuccess)
150         {
151                 syslog (LOG_ERR, "IOServiceGetMatchingServices failed: %s",
152                                 mach_error_string (status));
153                 return (-1);
154         }
155
156         while ((io_obj = IOIteratorNext (iterator)))
157         {
158                 prop_dict = NULL;
159                 status = IORegistryEntryCreateCFProperties (io_obj,
160                                 &prop_dict,
161                                 kCFAllocatorDefault,
162                                 kNilOptions);
163                 if (status != kIOReturnSuccess)
164                 {
165                         DBG ("IORegistryEntryCreateCFProperties failed: %s",
166                                         mach_error_string (status));
167                         continue;
168                 }
169
170                 /* Copy the sensor type. */
171                 property = NULL;
172                 if (!CFDictionaryGetValueIfPresent (prop_dict,
173                                         CFSTR ("type"),
174                                         &property))
175                         continue;
176                 if (CFGetTypeID (property) != CFStringGetTypeID ())
177                         continue;
178                 if (!CFStringGetCString (property,
179                                         type, 128,
180                                         kCFStringEncodingASCII))
181                         continue;
182                 type[127] = '\0';
183
184                 /* Copy the sensor location. This will be used as `instance'. */
185                 property = NULL;
186                 if (!CFDictionaryGetValueIfPresent (prop_dict,
187                                         CFSTR ("location"),
188                                         &property))
189                         continue;
190                 if (CFGetTypeID (property) != CFStringGetTypeID ())
191                         continue;
192                 if (!CFStringGetCString (property,
193                                         inst, 128,
194                                         kCFStringEncodingASCII))
195                         continue;
196                 inst[127] = '\0';
197                 for (i = 0; i < 128; i++)
198                 {
199                         if (inst[i] == '\0')
200                                 break;
201                         else if (isalnum (inst[i]))
202                                 inst[i] = (char) tolower (inst[i]);
203                         else
204                                 inst[i] = '_';
205                 }
206
207                 /* Get the actual value. Some computation, based on the `type'
208                  * is neccessary. */
209                 property = NULL;
210                 if (!CFDictionaryGetValueIfPresent (prop_dict,
211                                         CFSTR ("current-value"),
212                                         &property))
213                         continue;
214                 if (CFGetTypeID (property) != CFNumberGetTypeID ())
215                         continue;
216                 if (!CFNumberGetValue (property,
217                                         kCFNumberIntType,
218                                         &value_int))
219                         continue;
220
221                 /* Found e.g. in the 1.5GHz PowerBooks */
222                 if (strcmp (type, "temperature") == 0)
223                 {
224                         value_double = ((double) value_int) / 65536.0;
225                         strcpy (type, "temperature");
226                 }
227                 else if (strcmp (type, "temp") == 0)
228                 {
229                         value_double = ((double) value_int) / 10.0;
230                         strcpy (type, "temperature");
231                 }
232                 else if (strcmp (type, "fanspeed") == 0)
233                 {
234                         value_double = ((double) value_int) / 65536.0;
235                         strcpy (type, "fanspeed");
236                 }
237                 else if (strcmp (type, "voltage") == 0)
238                 {
239                         /* Leave this to the battery plugin. */
240                         continue;
241                 }
242                 else if (strcmp (type, "adc") == 0)
243                 {
244                         value_double = ((double) value_int) / 10.0;
245                         strcpy (type, "fanspeed");
246                 }
247                 else
248                 {
249                         DBG ("apple_sensors: Read unknown sensor type: %s",
250                                         type);
251                         value_double = (double) value_int;
252                 }
253
254                 as_submit (type, inst, value_double);
255
256                 CFRelease (prop_dict);
257                 IOObjectRelease (io_obj);
258         } /* while (iterator) */
259
260         IOObjectRelease (iterator);
261
262         return (0);
263 } /* int as_read */
264 #endif /* IOKIT_HAVE_READ */
265
266 void module_register (void)
267 {
268         plugin_register_data_set (&fanspeed_ds);
269         plugin_register_data_set (&temperature_ds);
270
271 #if IOKIT_HAVE_READ
272         plugin_register_init ("apple_sensors", as_init);
273         plugin_register_read ("apple_sensors", as_read);
274 #endif /* IOKIT_HAVE_READ */
275 }