637c8086083ad0107224e85c5c847bbfc7840c0b
[collectd.git] / src / iokit.c
1 /**
2  * collectd - src/iokit.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 "iokit"
29
30 #if HAVE_MACH_MACH_TYPES_H
31 #  include <mach/mach_types.h>
32 #endif
33 #if HAVE_MACH_MACH_INIT_H
34 #  include <mach/mach_init.h>
35 #endif
36 #if HAVE_MACH_MACH_ERROR_H
37 #  include <mach/mach_error.h>
38 #endif
39 #if HAVE_COREFOUNDATION_COREFOUNDATION_H
40 #  include <CoreFoundation/CoreFoundation.h>
41 #endif
42 #if HAVE_IOKIT_IOKITLIB_H
43 #  include <IOKit/IOKitLib.h>
44 #endif
45 #if HAVE_IOKIT_IOTYPES_H
46 #  include <IOKit/IOTypes.h>
47 #endif
48
49 #if HAVE_IOKIT_IOKITLIB_H
50 # define IOKIT_HAVE_READ 1
51 #else
52 # define IOKIT_HAVE_READ 0
53 #endif
54
55 #if IOKIT_HAVE_READ
56 static mach_port_t io_master_port;
57 #endif
58
59 static char *temperature_file = "temperature-%s.rrd";
60
61 static char *ds_def[] =
62 {
63         "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U",
64         NULL
65 };
66 static int ds_num = 1;
67
68 static void iokit_init (void)
69 {
70 #if IOKIT_HAVE_READ
71         kern_return_t status;
72         
73         /* FIXME: de-allocate port if it's defined */
74
75         status = IOMasterPort (MACH_PORT_NULL, &io_master_port);
76         if (status != kIOReturnSuccess)
77         {
78                 syslog (LOG_ERR, "IOMasterPort failed: %s",
79                                 mach_error_string (status));
80                 io_master_port = MACH_PORT_NULL;
81                 return;
82         }
83 #endif
84
85         return;
86 }
87
88 static void temperature_write (char *host, char *inst, char *val)
89 {
90         rrd_update_file (host, temperature_file, val, ds_def, ds_num);
91 }
92
93 #if IOKIT_HAVE_READ
94 static void iokit_submit (char *type, char *inst, int value)
95 {
96         char buf[128];
97
98         if (snprintf (buf, 1024, "%u:%i", (unsigned int) curtime,
99                                 value) >= 128)
100                 return;
101
102         plugin_submit (type, inst, buf);
103 }
104
105 static void iokit_read (void)
106 {
107         kern_return_t   status;
108         io_iterator_t   iterator;
109         io_object_t     io_obj;
110         CFMutableDictionaryRef prop_dict;
111         CFTypeRef       property;
112
113         char type[128];
114         char inst[128];
115         int   value;
116
117         if (!io_master_port || (io_master_port == MACH_PORT_NULL))
118                 return;
119
120         status = IOServiceGetMatchingServices (io_master_port,
121                         IOServiceNameMatching("IOHWSensor"),
122                         &iterator);
123         if (status != kIOReturnSuccess)
124         {
125                 syslog (LOG_ERR, "IOServiceGetMatchingServices failed: %s",
126                                 mach_error_string (status));
127                 return;
128         }
129
130         while ((io_obj = IOIteratorNext (iterator)))
131         {
132                 prop_dict = NULL;
133                 status = IORegistryEntryCreateCFProperties (io_obj,
134                                 &prop_dict,
135                                 kCFAllocatorDefault,
136                                 kNilOptions);
137                 if (status != kIOReturnSuccess)
138                 {
139                         DBG ("IORegistryEntryCreateCFProperties failed: %s",
140                                         mach_error_string (status));
141                         continue;
142                 }
143
144                 /* Copy the sensor type. */
145                 property = NULL;
146                 if (!CFDictionaryGetValueIfPresent (prop_dict,
147                                         CFSTR ("type"),
148                                         &property))
149                         continue;
150                 if (CFGetTypeID (property) != CFStringGetTypeID ())
151                         continue;
152                 if (!CFStringGetCString (property,
153                                         type, 128,
154                                         kCFStringEncodingASCII))
155                         continue;
156                 type[127] = '\0';
157
158                 /* Copy the sensor location. This will be used as `instance'. */
159                 property = NULL;
160                 if (!CFDictionaryGetValueIfPresent (prop_dict,
161                                         CFSTR ("location"),
162                                         &property))
163                         continue;
164                 if (CFGetTypeID (property) != CFStringGetTypeID ())
165                         continue;
166                 if (!CFStringGetCString (property,
167                                         inst, 128,
168                                         kCFStringEncodingASCII))
169                         continue;
170                 inst[127] = '\0';
171
172                 /* Get the actual value. Some computation, based on the `type'
173                  * is neccessary. */
174                 property = NULL;
175                 if (!CFDictionaryGetValueIfPresent (prop_dict,
176                                         CFSTR ("current-value"),
177                                         &property))
178                         continue;
179                 if (CFGetTypeID (property) != CFNumberGetTypeID ())
180                         continue;
181                 if (!CFNumberGetValue (property,
182                                         kCFNumberIntType,
183                                         &value))
184                         continue;
185
186                 /* Do stuff */
187                 DBG ("type = %s, inst = %s, value = %i",
188                                 type, inst, value);
189                 iokit_submit (type, inst, value);
190
191                 CFRelease (prop_dict);
192                 IOObjectRelease (io_obj);
193         } /* while (iterator) */
194
195         IOObjectRelease (iterator);
196 }
197 #else
198 # define iokit_read NULL
199 #endif /* IOKIT_HAVE_READ */
200
201 void module_register (void)
202 {
203         DBG ("IOKIT_HAVE_READ = %i", IOKIT_HAVE_READ);
204
205         plugin_register (MODULE_NAME, iokit_init, iokit_read, NULL);
206         plugin_register ("iokit-temperature", NULL, NULL, temperature_write);
207 }
208
209 #undef MODULE_NAME