root/lm-sensors/trunk/lib/proc.c

Revision 5059, 13.5 kB (checked in by khali, 1 year ago)

Fix broken reference.

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