Merge branch 'collectd-5.5'
[collectd.git] / src / apple_sensors.c
1 /**
2  * collectd - src/apple_sensors.c
3  * Copyright (C) 2006,2007  Florian octo Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian octo Forster <octo at collectd.org>
25  **/
26
27 #include "collectd.h"
28 #include "common.h"
29 #include "plugin.h"
30
31 #if HAVE_CTYPE_H
32 #  include <ctype.h>
33 #endif
34
35 #if HAVE_MACH_MACH_TYPES_H
36 #  include <mach/mach_types.h>
37 #endif
38 #if HAVE_MACH_MACH_INIT_H
39 #  include <mach/mach_init.h>
40 #endif
41 #if HAVE_MACH_MACH_ERROR_H
42 #  include <mach/mach_error.h>
43 #endif
44 #if HAVE_MACH_MACH_PORT_H
45 #  include <mach/mach_port.h>
46 #endif
47 #if HAVE_COREFOUNDATION_COREFOUNDATION_H
48 #  include <CoreFoundation/CoreFoundation.h>
49 #endif
50 #if HAVE_IOKIT_IOKITLIB_H
51 #  include <IOKit/IOKitLib.h>
52 #endif
53 #if HAVE_IOKIT_IOTYPES_H
54 #  include <IOKit/IOTypes.h>
55 #endif
56
57 static mach_port_t io_master_port = MACH_PORT_NULL;
58
59 static int as_init (void)
60 {
61         kern_return_t status;
62         
63         if (io_master_port != MACH_PORT_NULL)
64         {
65                 mach_port_deallocate (mach_task_self (),
66                                 io_master_port);
67                 io_master_port = MACH_PORT_NULL;
68         }
69
70         status = IOMasterPort (MACH_PORT_NULL, &io_master_port);
71         if (status != kIOReturnSuccess)
72         {
73                 ERROR ("IOMasterPort failed: %s",
74                                 mach_error_string (status));
75                 io_master_port = MACH_PORT_NULL;
76                 return (-1);
77         }
78
79         return (0);
80 }
81
82 static void as_submit (const char *type, const char *type_instance,
83                 double val)
84 {
85         value_t values[1];
86         value_list_t vl = VALUE_LIST_INIT;
87
88         DEBUG ("type = %s; type_instance = %s; val = %f;",
89                         type, type_instance, val);
90
91         values[0].gauge = val;
92
93         vl.values = values;
94         vl.values_len = 1;
95         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
96         sstrncpy (vl.plugin, "apple_sensors", sizeof (vl.plugin));
97         sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
98         sstrncpy (vl.type, type, sizeof (vl.type));
99         sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
100
101         plugin_dispatch_values (&vl);
102 }
103
104 static int as_read (void)
105 {
106         kern_return_t   status;
107         io_iterator_t   iterator;
108         io_object_t     io_obj;
109         CFMutableDictionaryRef prop_dict;
110         CFTypeRef       property;
111
112         char   type[128];
113         char   inst[128];
114         int    value_int;
115         double value_double;
116         int    i;
117
118         if (!io_master_port || (io_master_port == MACH_PORT_NULL))
119                 return (-1);
120
121         status = IOServiceGetMatchingServices (io_master_port,
122                         IOServiceNameMatching("IOHWSensor"),
123                         &iterator);
124         if (status != kIOReturnSuccess)
125         {
126                 ERROR ("IOServiceGetMatchingServices failed: %s",
127                                 mach_error_string (status));
128                 return (-1);
129         }
130
131         while ((io_obj = IOIteratorNext (iterator)))
132         {
133                 prop_dict = NULL;
134                 status = IORegistryEntryCreateCFProperties (io_obj,
135                                 &prop_dict,
136                                 kCFAllocatorDefault,
137                                 kNilOptions);
138                 if (status != kIOReturnSuccess)
139                 {
140                         DEBUG ("IORegistryEntryCreateCFProperties failed: %s",
141                                         mach_error_string (status));
142                         continue;
143                 }
144
145                 /* Copy the sensor type. */
146                 property = NULL;
147                 if (!CFDictionaryGetValueIfPresent (prop_dict,
148                                         CFSTR ("type"),
149                                         &property))
150                         continue;
151                 if (CFGetTypeID (property) != CFStringGetTypeID ())
152                         continue;
153                 if (!CFStringGetCString (property,
154                                         type, sizeof (type),
155                                         kCFStringEncodingASCII))
156                         continue;
157                 type[sizeof (type) - 1] = '\0';
158
159                 /* Copy the sensor location. This will be used as `instance'. */
160                 property = NULL;
161                 if (!CFDictionaryGetValueIfPresent (prop_dict,
162                                         CFSTR ("location"),
163                                         &property))
164                         continue;
165                 if (CFGetTypeID (property) != CFStringGetTypeID ())
166                         continue;
167                 if (!CFStringGetCString (property,
168                                         inst, sizeof (inst),
169                                         kCFStringEncodingASCII))
170                         continue;
171                 inst[sizeof (inst) - 1] = '\0';
172                 for (i = 0; i < 128; i++)
173                 {
174                         if (inst[i] == '\0')
175                                 break;
176                         else if (isalnum (inst[i]))
177                                 inst[i] = (char) tolower (inst[i]);
178                         else
179                                 inst[i] = '_';
180                 }
181
182                 /* Get the actual value. Some computation, based on the `type'
183                  * is neccessary. */
184                 property = NULL;
185                 if (!CFDictionaryGetValueIfPresent (prop_dict,
186                                         CFSTR ("current-value"),
187                                         &property))
188                         continue;
189                 if (CFGetTypeID (property) != CFNumberGetTypeID ())
190                         continue;
191                 if (!CFNumberGetValue (property,
192                                         kCFNumberIntType,
193                                         &value_int))
194                         continue;
195
196                 /* Found e.g. in the 1.5GHz PowerBooks */
197                 if (strcmp (type, "temperature") == 0)
198                 {
199                         value_double = ((double) value_int) / 65536.0;
200                         sstrncpy (type, "temperature", sizeof (type));
201                 }
202                 else if (strcmp (type, "temp") == 0)
203                 {
204                         value_double = ((double) value_int) / 10.0;
205                         sstrncpy (type, "temperature", sizeof (type));
206                 }
207                 else if (strcmp (type, "fanspeed") == 0)
208                 {
209                         value_double = ((double) value_int) / 65536.0;
210                         sstrncpy (type, "fanspeed", sizeof (type));
211                 }
212                 else if (strcmp (type, "voltage") == 0)
213                 {
214                         /* Leave this to the battery plugin. */
215                         continue;
216                 }
217                 else if (strcmp (type, "adc") == 0)
218                 {
219                         value_double = ((double) value_int) / 10.0;
220                         sstrncpy (type, "fanspeed", sizeof (type));
221                 }
222                 else
223                 {
224                         DEBUG ("apple_sensors: Read unknown sensor type: %s",
225                                         type);
226                         value_double = (double) value_int;
227                 }
228
229                 as_submit (type, inst, value_double);
230
231                 CFRelease (prop_dict);
232                 IOObjectRelease (io_obj);
233         } /* while (iterator) */
234
235         IOObjectRelease (iterator);
236
237         return (0);
238 } /* int as_read */
239
240 void module_register (void)
241 {
242         plugin_register_init ("apple_sensors", as_init);
243         plugin_register_read ("apple_sensors", as_read);
244 } /* void module_register */