1 | /* |
2 | KSysGuard, the KDE System Guard |
3 | |
4 | Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> |
5 | |
6 | This program is free software; you can redistribute it and/or |
7 | modify it under the terms of version 2 of the GNU General Public |
8 | License as published by the Free Software Foundation. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | |
19 | */ |
20 | |
21 | #include "config-ksysguardd.h" |
22 | |
23 | #include <config-workspace.h> |
24 | #include <stdio.h> |
25 | #include <stdlib.h> |
26 | #include <string.h> |
27 | |
28 | #include "Command.h" |
29 | #include "ccont.h" |
30 | #include "ksysguardd.h" |
31 | |
32 | #include "lmsensors.h" |
33 | |
34 | #ifdef HAVE_LMSENSORS |
35 | #include <sensors/sensors.h> |
36 | |
37 | #ifndef SENSORS_API_VERSION |
38 | #define SENSORS_API_VERSION 0x000 |
39 | #endif |
40 | #ifndef SENSORS_CHIP_NAME_BUS_PCI |
41 | #define SENSORS_CHIP_NAME_BUS_PCI -5 |
42 | #endif |
43 | #ifndef SENSORS_CHIP_NAME_BUS_ISA |
44 | #define SENSORS_CHIP_NAME_BUS_ISA -1 |
45 | #endif |
46 | |
47 | #define BUFFER_SIZE_LMSEN 300 |
48 | typedef struct |
49 | { |
50 | char* fullName; |
51 | const sensors_chip_name* scn; |
52 | #if SENSORS_API_VERSION & 0x400 |
53 | const sensors_feature *sf; |
54 | const sensors_subfeature *sfd; |
55 | #else |
56 | const sensors_feature_data* sfd; |
57 | #endif |
58 | } LMSENSOR; |
59 | |
60 | static CONTAINER LmSensors; |
61 | static int LmSensorsOk = -1; |
62 | |
63 | static int sensorCmp( void* s1, void* s2 ) |
64 | { |
65 | return strcmp( ((LMSENSOR*)s1)->fullName, ((LMSENSOR*)s2)->fullName ); |
66 | } |
67 | |
68 | static LMSENSOR* findMatchingSensor( const char* name ) |
69 | { |
70 | INDEX idx; |
71 | LMSENSOR key; |
72 | LMSENSOR* s; |
73 | |
74 | if(name == NULL || name[0] == '\0') return 0; |
75 | key.fullName = strdup( name ); |
76 | int end = strlen(key.fullName)-1; |
77 | if(key.fullName[end] == '?') |
78 | key.fullName[end] = '\0'; |
79 | if ( ( idx = search_ctnr( LmSensors, sensorCmp, &key ) ) < 0 ) { |
80 | free( key.fullName ); |
81 | return 0; |
82 | } |
83 | |
84 | free( key.fullName ); |
85 | s = get_ctnr( LmSensors, idx ); |
86 | |
87 | return s; |
88 | } |
89 | |
90 | static const char *chipName(const sensors_chip_name *chip) { |
91 | static char buffer[256]; |
92 | #if SENSORS_API_VERSION & 0x400 |
93 | sensors_snprintf_chip_name(buffer, sizeof(buffer), chip); |
94 | #else /* SENSORS_API_VERSION & 0x400 */ |
95 | if (chip->bus == SENSORS_CHIP_NAME_BUS_ISA) |
96 | snprintf (buffer, sizeof(buffer), "%s-isa-%04x" , chip->prefix, chip->addr); |
97 | else if (chip->bus == SENSORS_CHIP_NAME_BUS_PCI) |
98 | snprintf (buffer, sizeof(buffer), "%s-pci-%04x" , chip->prefix, chip->addr); |
99 | else |
100 | snprintf (buffer, sizeof(buffer), "%s-i2c-%d-%02x" , chip->prefix, chip->bus, chip->addr); |
101 | #endif /* SENSORS_API_VERSION & 0x400 */ |
102 | return buffer; |
103 | } |
104 | |
105 | #if SENSORS_API_VERSION & 0x400 |
106 | void initLmSensors( struct SensorModul* sm ) |
107 | { |
108 | const sensors_chip_name* scn; |
109 | int nr = 0; |
110 | |
111 | if ( sensors_init( NULL ) ) { |
112 | LmSensorsOk = -1; |
113 | return; |
114 | } |
115 | |
116 | LmSensors = new_ctnr(); |
117 | while ( ( scn = sensors_get_detected_chips( NULL, &nr ) ) != NULL ) { |
118 | int nr1 = 0; |
119 | const sensors_feature* sf; |
120 | |
121 | while ( ( sf = sensors_get_features( scn, &nr1 ) ) != 0 ) { |
122 | const sensors_subfeature *ssubf; |
123 | LMSENSOR *p; |
124 | char *s, *label; |
125 | char scnbuf[BUFFER_SIZE_LMSEN]; |
126 | |
127 | switch( sf->type ) |
128 | { |
129 | case SENSORS_FEATURE_IN: |
130 | ssubf = sensors_get_subfeature( scn, sf, |
131 | SENSORS_SUBFEATURE_IN_INPUT ); |
132 | break; |
133 | |
134 | case SENSORS_FEATURE_FAN: |
135 | ssubf = sensors_get_subfeature( scn, sf, |
136 | SENSORS_SUBFEATURE_FAN_INPUT ); |
137 | break; |
138 | |
139 | case SENSORS_FEATURE_TEMP: |
140 | ssubf = sensors_get_subfeature( scn, sf, |
141 | SENSORS_SUBFEATURE_TEMP_INPUT ); |
142 | break; |
143 | default: |
144 | ssubf = NULL; |
145 | } |
146 | |
147 | if ( !ssubf ) |
148 | continue; |
149 | |
150 | label = sensors_get_label( scn, sf ); |
151 | sensors_snprintf_chip_name(scnbuf, BUFFER_SIZE_LMSEN, scn); |
152 | p = (LMSENSOR*)malloc( sizeof( LMSENSOR ) ); |
153 | p->fullName = (char*)malloc( strlen( "lmsensors/" ) + |
154 | strlen( scnbuf ) + 1 + |
155 | strlen( label ) + 1 ); |
156 | snprintf( p->fullName, BUFFER_SIZE_LMSEN, "lmsensors/%s/%s" , scnbuf, label ); |
157 | |
158 | /* Make sure that name contains only proper characters. */ |
159 | for ( s = p->fullName; *s; s++ ) |
160 | if ( *s == ' ' ) |
161 | *s = '_'; |
162 | |
163 | p->scn = scn; |
164 | p->sf = sf; |
165 | p->sfd = ssubf; |
166 | |
167 | /* Note a name collision should never happen with the lm_sensors-3x code, |
168 | but it does in the case of k8temp, when there are 2 identical labeled |
169 | sensors per CPU. This are really 2 distinct sensors measuring the |
170 | same thing, but fullName must be unique so we just drop the second |
171 | sensor */ |
172 | if ( search_ctnr( LmSensors, sensorCmp, p ) < 0 ) { |
173 | push_ctnr( LmSensors, p ); |
174 | registerMonitor( p->fullName, "float" , printLmSensor, printLmSensorInfo, sm ); |
175 | } else { |
176 | free( p->fullName ); |
177 | free( p ); |
178 | } |
179 | free( label ); |
180 | } |
181 | } |
182 | bsort_ctnr( LmSensors, sensorCmp ); |
183 | } |
184 | #else /* SENSORS_API_VERSION & 0x400 */ |
185 | void initLmSensors( struct SensorModul* sm ) |
186 | { |
187 | const sensors_chip_name* scn; |
188 | char buffer[BUFFER_SIZE_LMSEN]; |
189 | int nr = 0; |
190 | |
191 | FILE* input; |
192 | if ( ( input = fopen( "/etc/sensors.conf" , "r" ) ) == NULL ) { |
193 | LmSensorsOk = -1; |
194 | return; |
195 | } |
196 | |
197 | if ( sensors_init( input ) ) { |
198 | LmSensorsOk = -1; |
199 | fclose( input ); |
200 | return; |
201 | } |
202 | |
203 | fclose( input ); |
204 | |
205 | LmSensors = new_ctnr(); |
206 | while ( ( scn = sensors_get_detected_chips( &nr ) ) != NULL ) { |
207 | int nr1, nr2; |
208 | const sensors_feature_data* sfd; |
209 | nr1 = nr2 = 0; |
210 | while ( ( sfd = sensors_get_all_features( *scn, &nr1, &nr2 ) ) != 0 ) { |
211 | if ( sfd->mapping == SENSORS_NO_MAPPING && sfd->mode & SENSORS_MODE_R /* readable feature */) { |
212 | LMSENSOR* p; |
213 | char* label=NULL; |
214 | |
215 | if(sensors_get_label( *scn, sfd->number, &label ) != 0) |
216 | continue; /*error*/ |
217 | else |
218 | free( label ); |
219 | if(sensors_get_ignored( *scn, sfd->number) != 1 ) |
220 | continue; /* 1 for not ignored, 0 for ignore, <0 for error */ |
221 | double result; |
222 | if(sensors_get_feature( *scn, sfd->number, &result) != 0 ) |
223 | continue; /* Make sure this feature actually works. 0 for success, <0 for fail */ |
224 | |
225 | p = (LMSENSOR*)malloc( sizeof( LMSENSOR ) ); |
226 | |
227 | snprintf( buffer, BUFFER_SIZE_LMSEN, "lmsensors/%s/%s" , chipName(scn), sfd->name ); |
228 | |
229 | p->fullName = strndup(buffer, BUFFER_SIZE_LMSEN); |
230 | |
231 | p->scn = scn; |
232 | p->sfd = sfd; |
233 | if ( search_ctnr( LmSensors, sensorCmp, p ) < 0 ) { |
234 | push_ctnr( LmSensors, p ); |
235 | registerMonitor( p->fullName, "float" , printLmSensor, printLmSensorInfo, sm ); |
236 | } else { |
237 | free( p->fullName ); |
238 | free( p ); |
239 | } |
240 | } |
241 | } |
242 | } |
243 | bsort_ctnr( LmSensors, sensorCmp ); |
244 | } |
245 | #endif /* SENSORS_API_VERSION & 0x400 */ |
246 | |
247 | void exitLmSensors( void ) |
248 | { |
249 | destr_ctnr( LmSensors, free ); |
250 | } |
251 | |
252 | void printLmSensor( const char* cmd ) |
253 | { |
254 | double value; |
255 | LMSENSOR* s; |
256 | |
257 | if ( ( s = findMatchingSensor( cmd ) ) == 0 ) { /* should never happen */ |
258 | output( "0\n" ); |
259 | return; |
260 | } |
261 | #if SENSORS_API_VERSION & 0x400 |
262 | sensors_get_value( s->scn, s->sfd->number, &value ); |
263 | #else |
264 | sensors_get_feature( *(s->scn), s->sfd->number, &value ); |
265 | #endif |
266 | output( "%f\n" , value ); |
267 | } |
268 | |
269 | void printLmSensorInfo( const char* cmd ) |
270 | { |
271 | LMSENSOR* s; |
272 | |
273 | if ( ( s = findMatchingSensor( cmd ) ) == 0 ) { /* should never happen */ |
274 | output( "0\n" ); |
275 | return; |
276 | } |
277 | |
278 | /* TODO: print real name here */ |
279 | char *label; |
280 | #if SENSORS_API_VERSION & 0x400 |
281 | label = sensors_get_label( s->scn, s->sf ); |
282 | if (label == NULL) { |
283 | #else |
284 | if(sensors_get_label( *s->scn, s->sfd->number, &label ) != 0) { /*error*/ |
285 | #endif |
286 | output( "0\n" ); |
287 | return; |
288 | } |
289 | if( strncmp(s->sfd->name, "temp" , sizeof("temp" )-1) == 0) |
290 | output( "%s\t0\t0\t°C\n" , label ); |
291 | else if( strncmp(s->sfd->name, "fan" , sizeof("fan" )-1) == 0) |
292 | output( "%s\t0\t0\trpm\n" , label ); |
293 | else |
294 | output( "%s\t0\t0\tV\n" , label ); /* For everything else, say it's in volts. */ |
295 | #if SENSORS_API_VERSION & 0x400 |
296 | free(label); |
297 | #endif |
298 | } |
299 | |
300 | #else /* HAVE_LMSENSORS */ |
301 | |
302 | /* dummy version for systems that have no lmsensors support */ |
303 | |
304 | void initLmSensors( struct SensorModul* sm ) |
305 | { |
306 | (void)sm; |
307 | } |
308 | |
309 | void exitLmSensors( void ) |
310 | { |
311 | } |
312 | |
313 | #endif |
314 | |