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