root/lm-sensors/tags/V2-10-2/lib/proc.c

Revision 4287, 13.3 kB (checked in by mmh, 2 years ago)

The sensors library relied on one structure having an identical layout in
memory as part of another structure. This rather large patch fixes that by
making the smaller piece an explicit member of the larger.

I brought this patch into sync with the latest SVN, and tested it by comparing
objects files from the tree pre- and post- patch.

The remaining 99% of the credit goes to Bob Schlärmann <bob2@dsv.nl> for
creating the original patch... thanks Bob!

* Bob Schlärmann <bob2@dsv.nl> [2006-12-24 18:29:39 +0100]:

The following patch changes all of the lib/chips.c entries and any function
that uses sensors_chip_feature. Most of the conversion was done through a
perl script, so if you don't agree with the syntax it'll be easy to change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2     proc.c - Part of libsensors, a Linux library for reading sensor data.
3     Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <sys/types.h>
21 #include <sys/sysctl.h>
22 #include <stddef.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <dirent.h>
28
29 #include "kernel/include/sensors.h"
30 #include "data.h"
31 #include "error.h"
32 #include "access.h"
33 #include "general.h"
34 #include "sysfs.h"
35
36 /* OK, this proves one thing: if there are too many chips detected, we get in
37    trouble. The limit is around 4096/sizeof(struct sensors_chip_data), which
38    works out to about 100 entries right now. That seems sensible enough,
39    but if we ever get at the point where more chips can be detected, we must
40    enlarge buf, and check that sysctl can handle larger buffers. */
41
42 #define BUF_LEN 4096
43
44 static char buf[BUF_LEN];
45
46 static int getsysname(const sensors_chip_feature *feature, char *sysname,
47         int *sysmag, char *altsysname);
48
49 /* This reads /proc/sys/dev/sensors/chips into memory */
50 int sensors_read_proc_chips(void)
51 {
52   int res;
53
54   int name[3] = { CTL_DEV, DEV_SENSORS, SENSORS_CHIPS };
55   size_t buflen = BUF_LEN;
56   char *bufptr = buf;
57   sensors_proc_chips_entry entry;
58   int lineno;
59
60   if (sysctl(name, 3, bufptr, &buflen, NULL, 0))
61     return -SENSORS_ERR_PROC;
62
63   lineno = 1;
64   while (buflen >= sizeof(struct i2c_chips_data)) {
65     if ((res =
66           sensors_parse_chip_name(((struct i2c_chips_data *) bufptr)->name,
67                                    &entry.name))) {
68       sensors_parse_error("Parsing /proc/sys/dev/sensors/chips",lineno);
69       return res;
70     }
71     entry.sysctl = ((struct i2c_chips_data *) bufptr)->sysctl_id;
72     sensors_add_proc_chips(&entry);
73     bufptr += sizeof(struct i2c_chips_data);
74     buflen -= sizeof(struct i2c_chips_data);
75     lineno++;
76   }
77   return 0;
78 }
79
80 int sensors_read_proc_bus(void)
81 {
82   FILE *f;
83   char line[255];
84   char *border;
85   sensors_bus entry;
86   int lineno;
87
88   f = fopen("/proc/bus/i2c","r");
89   if (!f)
90     return -SENSORS_ERR_PROC;
91   lineno=1;
92   while (fgets(line,255,f)) {
93     if (strlen(line) > 0)
94       line[strlen(line)-1] = '\0';
95     if (! (border = rindex(line,'\t')))
96       goto ERROR;
97     /* Skip algorithm name */
98     *border='\0';
99     if (! (border = rindex(line,'\t')))
100       goto ERROR;
101     if (! (entry.adapter = strdup(border + 1)))
102       goto FAT_ERROR;
103     *border='\0';
104     if (! (border = rindex(line,'\t')))
105       goto ERROR;
106     *border='\0';
107     if (strncmp(line,"i2c-",4))
108       goto ERROR;
109     if (sensors_parse_i2cbus_name(line,&entry.number))
110       goto ERROR;
111     sensors_strip_of_spaces(entry.adapter);
112     sensors_add_proc_bus(&entry);
113     lineno++;
114   }
115   fclose(f);
116   return 0;
117 FAT_ERROR:
118   sensors_fatal_error("sensors_read_proc_bus","Allocating entry");
119 ERROR:
120   sensors_parse_error("Parsing /proc/bus/i2c",lineno);
121   fclose(f);
122   return -SENSORS_ERR_PROC;
123 }
124    
125
126 /* This returns the first detected chip which matches the name */
127 static int sensors_get_chip_id(sensors_chip_name name)
128 {
129   int i;
130   for (i = 0; i < sensors_proc_chips_count; i++)
131     if (sensors_match_chip(name, sensors_proc_chips[i].name))
132       return sensors_proc_chips[i].sysctl;
133   return -SENSORS_ERR_NO_ENTRY;
134 }
135  
136 /* This reads a feature /proc or /sys file.
137    Sysfs uses a one-value-per file system...
138 */
139 int sensors_read_proc(sensors_chip_name name, int feature, double *value)
140 {
141         int sysctl_name[4] = { CTL_DEV, DEV_SENSORS };
142         const sensors_chip_feature *the_feature;
143         size_t buflen = BUF_LEN;
144         int mag;
145
146         if (!sensors_found_sysfs)
147                 if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0)
148                         return sysctl_name[2];
149         if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature)))
150                 return -SENSORS_ERR_NO_ENTRY;
151         if (sensors_found_sysfs) {
152                 char n[NAME_MAX], altn[NAME_MAX];
153                 FILE *f;
154                 strcpy(n, name.busname);
155                 strcat(n, "/");
156                 strcpy(altn, n);
157                 /* use rindex to append sysname to n */
158                 getsysname(the_feature, rindex(n, '\0'), &mag, rindex(altn, '\0'));
159                 if ((f = fopen(n, "r")) != NULL
160                  || (f = fopen(altn, "r")) != NULL) {
161                         int res = fscanf(f, "%lf", value);
162                         fclose(f);
163                         if (res != 1)
164                                 return -SENSORS_ERR_PROC;
165                         for (; mag > 0; mag --)
166                                 *value /= 10.0;
167                 } else
168                         return -SENSORS_ERR_PROC;
169         } else {
170                 sysctl_name[3] = the_feature->sysctl;
171                 if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0))
172                         return -SENSORS_ERR_PROC;
173                 *value = *((long *) (buf + the_feature->offset));
174                 for (mag = the_feature->scaling; mag > 0; mag --)
175                         *value /= 10.0;
176                 for (; mag < 0; mag ++)
177                         *value *= 10.0;
178         }
179         return 0;
180 }
181  
182 int sensors_write_proc(sensors_chip_name name, int feature, double value)
183 {
184         int sysctl_name[4] = { CTL_DEV, DEV_SENSORS };
185         const sensors_chip_feature *the_feature;
186         size_t buflen = BUF_LEN;
187         int mag;
188  
189         if (!sensors_found_sysfs)
190                 if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0)
191                         return sysctl_name[2];
192         if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature)))
193                 return -SENSORS_ERR_NO_ENTRY;
194         if (sensors_found_sysfs) {
195                 char n[NAME_MAX], altn[NAME_MAX];
196                 FILE *f;
197                 strcpy(n, name.busname);
198                 strcat(n, "/");
199                 strcpy(altn, n);
200                 /* use rindex to append sysname to n */
201                 getsysname(the_feature, rindex(n, '\0'), &mag, rindex(altn, '\0'));
202                 if ((f = fopen(n, "w")) != NULL
203                  || (f = fopen(altn, "w")) != NULL) {
204                         for (; mag > 0; mag --)
205                                 value *= 10.0;
206                         fprintf(f, "%d", (int) value);
207                         fclose(f);
208                 } else
209                         return -SENSORS_ERR_PROC;
210         } else {
211                 sysctl_name[3] = the_feature->sysctl;
212                 if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0))
213                         return -SENSORS_ERR_PROC;
214                 /* The following line is known to solve random problems, still it
215                    can't be considered a definitive solution...
216                 if (sysctl_name[0] != CTL_DEV) { sysctl_name[0] = CTL_DEV ; } */
217                 for (mag = the_feature->scaling; mag > 0; mag --)
218                         value *= 10.0;
219                 for (; mag < 0; mag ++)
220                         value /= 10.0;
221                 * ((long *) (buf + the_feature->offset)) = (long) value;
222                 buflen = the_feature->offset + sizeof(long);
223 #ifdef DEBUG
224                 /* The following get* calls don't do anything, they are here
225                    for debugging purposes only. Strace will show the
226                    returned values. */
227                 getuid(); geteuid();
228                 getgid(); getegid();
229 #endif
230                 if (sysctl(sysctl_name, 4, NULL, 0, buf, buflen))
231                         return -SENSORS_ERR_PROC;
232         }
233         return 0;
234 }
235
236 #define CURRMAG 3
237 #define FANMAG 0
238 #define INMAG 3
239 #define TEMPMAG 3
240
241 /* The following are used in getsysname() below */
242 struct match {
243         const char * name, * sysname;
244         const int sysmag;
245         const char * altsysname;
246 };
247
248 static const struct match matches[] = {
249         { "beeps", "beep_mask", 0 },
250         { "pwm", "fan1_pwm", 0 },
251         { "vid", "cpu0_vid", INMAG, "in0_ref" },
252         { "remote_temp", "temp2_input", TEMPMAG },
253         { "remote_temp_hyst", "temp2_max_hyst", TEMPMAG },
254         { "remote_temp_low", "temp2_min", TEMPMAG },
255         { "remote_temp_over", "temp2_max", TEMPMAG },
256         { "temp", "temp1_input", TEMPMAG },
257         { "temp_hyst", "temp1_max_hyst", TEMPMAG },
258         { "temp_low", "temp1_min", TEMPMAG },
259         { "temp_over", "temp1_max", TEMPMAG },
260         { "temp_high", "temp1_max", TEMPMAG },
261         { "temp_crit", "temp1_crit", TEMPMAG },
262         { "pwm1", "pwm1", 0, "fan1_pwm" },
263         { "pwm2", "pwm2", 0, "fan2_pwm" },
264         { "pwm3", "pwm3", 0, "fan3_pwm" },
265         { "pwm4", "pwm4", 0, "fan4_pwm" },
266         { "pwm1_enable", "pwm1_enable", 0, "fan1_pwm_enable" },
267         { "pwm2_enable", "pwm2_enable", 0, "fan2_pwm_enable" },
268         { "pwm3_enable", "pwm3_enable", 0, "fan3_pwm_enable" },
269         { "pwm4_enable", "pwm4_enable", 0, "fan4_pwm_enable" },
270         { NULL, NULL }
271 };
272
273 /*
274         Returns the sysfs name and magnitude for a given feature.
275         First looks for a sysfs name and magnitude in the feature structure.
276         These should be added in chips.c for all non-standard feature names.
277         If that fails, converts common /proc feature names
278         to their sysfs equivalent, and uses common sysfs magnitude.
279         Common magnitudes are #defined above.
280         Common conversions are as follows:
281                 fan%d_min -> fan%d_min (for magnitude)
282                 fan%d_state -> fan%d_status
283                 fan%d -> fan_input%d
284                 pwm%d -> fan%d_pwm
285                 pwm%d_enable -> fan%d_pwm_enable
286                 in%d_max -> in%d_max (for magnitude)
287                 in%d_min -> in%d_min (for magnitude)
288                 in%d -> in%d_input
289                 vin%d_max -> in%d_max
290                 vin%d_min -> in%d_min
291                 vin%d -> in_input%d
292                 temp%d_over -> temp%d_max
293                 temp%d_hyst -> temp%d_max_hyst
294                 temp%d_max -> temp%d_max (for magnitude)
295                 temp%d_high -> temp%d_max
296                 temp%d_min -> temp%d_min (for magnitude)
297                 temp%d_low -> temp%d_min
298                 temp%d_state -> temp%d_status
299                 temp%d -> temp%d_input
300                 sensor%d -> temp%d_type
301         AND all conversions listed in the matches[] structure above.
302
303         If that fails, returns old /proc feature name and magnitude.
304
305         References: doc/developers/proc in the lm_sensors package;
306                     Documentation/i2c/sysfs_interface in the kernel
307 */
308 static int getsysname(const sensors_chip_feature *feature, char *sysname,
309         int *sysmag, char *altsysname)
310 {
311         const char * name = feature->data.name;
312         char last;
313         char check; /* used to verify end of string */
314         int num;
315         const struct match *m;
316
317 /* default to a non-existent alternate name (should rarely be tried) */
318         strcpy(altsysname, "_");
319
320 /* use override in feature structure if present */
321         if(feature->sysname != NULL) {
322                 strcpy(sysname, feature->sysname);
323                 if(feature->sysscaling)
324                         *sysmag = feature->sysscaling;
325                 else
326                         *sysmag = feature->scaling;
327                 if(feature->altsysname != NULL)
328                         strcpy(altsysname, feature->altsysname);
329                 return 0;
330         }
331
332 /* check for constant mappings */
333         for(m = matches; m->name != NULL; m++) {
334                 if(!strcmp(m->name, name)) {
335                         strcpy(sysname, m->sysname);
336                         if (m->altsysname != NULL)
337                                 strcpy(altsysname, m->altsysname);
338                         *sysmag = m->sysmag;
339                         return 0;
340                 }
341         }
342
343 /* convert common /proc names to common sysfs names */
344         if(sscanf(name, "fan%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') {
345                 strcpy(sysname, name);
346                 *sysmag = FANMAG;
347                 return 0;
348         }
349         if(sscanf(name, "fan%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') {
350                 sprintf(sysname, "fan%d_status", num);
351                 *sysmag = 0;
352                 return 0;
353         }
354         if(sscanf(name, "fan%d%c", &num, &check) == 1) {
355                 sprintf(sysname, "fan%d_input", num);
356                 *sysmag = FANMAG;
357                 return 0;
358         }
359         if(sscanf(name, "pwm%d%c", &num, &check) == 1) {
360                 sprintf(sysname, "fan%d_pwm", num);
361                 *sysmag = 0;
362                 return 0;
363         }
364         if(sscanf(name, "pwm%d_enabl%c%c", &num, &last, &check) == 2 && last == 'e') {
365                 sprintf(sysname, "fan%d_pwm_enable", num);
366                 *sysmag = 0;
367                 return 0;
368         }
369
370         if((sscanf(name, "in%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
371         || (sscanf(name, "in%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) {
372                 strcpy(sysname, name);
373                 *sysmag = INMAG;
374                 return 0;
375         }
376         if((sscanf(name, "in%d%c", &num, &check) == 1)
377         || (sscanf(name, "vin%d%c", &num, &check) == 1)) {
378                 sprintf(sysname, "in%d_input", num);
379                 *sysmag = INMAG;
380                 return 0;
381         }
382         if(sscanf(name, "vin%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') {
383                 sprintf(sysname, "in%d_min", num);
384                 *sysmag = INMAG;
385                 return 0;
386         }
387         if(sscanf(name, "vin%d_ma%c%c", &num, &last, &check) == 2 && last == 'x') {
388                 sprintf(sysname, "in%d_max", num);
389                 *sysmag = INMAG;
390                 return 0;
391         }
392
393         if(sscanf(name, "temp%d_hys%c%c", &num, &last, &check) == 2 && last == 't') {
394                 sprintf(sysname, "temp%d_max_hyst", num);
395                 *sysmag = TEMPMAG;
396                 return 0;
397         }
398         if((sscanf(name, "temp%d_ove%c%c", &num, &last, &check) == 2 && last == 'r')
399         || (sscanf(name, "temp%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')
400         || (sscanf(name, "temp%d_hig%c%c", &num, &last, &check) == 2 && last == 'h')) {
401                 sprintf(sysname, "temp%d_max", num);
402                 *sysmag = TEMPMAG;
403                 return 0;
404         }
405         if((sscanf(name, "temp%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
406         || (sscanf(name, "temp%d_lo%c%c", &num, &last, &check) == 2 && last == 'w')) {
407                 sprintf(sysname, "temp%d_min", num);
408                 *sysmag = TEMPMAG;
409                 return 0;
410         }
411         if(sscanf(name, "temp%d_cri%c%c", &num, &last, &check) == 2 && last == 't') {
412                 sprintf(sysname, "temp%d_crit", num);
413                 *sysmag = TEMPMAG;
414                 return 0;
415         }
416         if(sscanf(name, "temp%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') {
417                 sprintf(sysname, "temp%d_status", num);
418                 *sysmag = 0;
419                 return 0;
420         }
421         if(sscanf(name, "temp%d%c", &num, &check) == 1) {
422                 sprintf(sysname, "temp%d_input", num);
423                 *sysmag = TEMPMAG;
424                 return 0;
425         }
426         if(sscanf(name, "sensor%d%c", &num, &check) == 1) {
427                 sprintf(sysname, "temp%d_type", num);
428                 *sysmag = 0;
429                 return 0;
430         }
431
432 /* bmcsensors only, not yet in kernel */
433 /*
434         if((sscanf(name, "curr%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
435         || (sscanf(name, "curr%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) {
436                 strcpy(sysname, name);
437                 *sysmag = CURRMAG;
438                 return 0;
439         }
440         if(sscanf(name, "curr%d%c", &num, &check) == 1) {
441                 sprintf(sysname, "curr%d_input", num);
442                 *sysmag = CURRMAG;
443                 return 0;
444         }
445 */
446
447 /* give up, use old name (probably won't work though...) */
448 /* known to be the same:
449         "alarms", "beep_enable", "vrm", "fan%d_div"
450 */
451         strcpy(sysname, name);
452         *sysmag = feature->scaling;
453         return 0;
454 }
Note: See TracBrowser for help on using the browser.