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
48typedef 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
60static CONTAINER LmSensors;
61static int LmSensorsOk = -1;
62
63static int sensorCmp( void* s1, void* s2 )
64{
65 return strcmp( ((LMSENSOR*)s1)->fullName, ((LMSENSOR*)s2)->fullName );
66}
67
68static 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
90static 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
106void 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 */
185void 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
247void exitLmSensors( void )
248{
249 destr_ctnr( LmSensors, free );
250}
251
252void 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
269void 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
304void initLmSensors( struct SensorModul* sm )
305{
306 (void)sm;
307}
308
309void exitLmSensors( void )
310{
311}
312
313#endif
314