root/lm-sensors/branches/lm-sensors-3.0.0/lib/proc.c @ 4357

Revision 4357, 13.0 KB (checked in by mmh, 6 years ago)

Merge from trunk (4303:4355) out to 3.0.0 branch.

  • 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
44static char buf[BUF_LEN];
45
46static 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 */
50int 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
80int 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;
117FAT_ERROR:
118  sensors_fatal_error("sensors_read_proc_bus","Allocating entry");
119ERROR:
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 */
127static 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*/
139int 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 
182int 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 */
242struct match {
243        const char * name, * sysname;
244        const int sysmag;
245        const char * altsysname;
246};
247
248static const struct match matches[] = {
249        { "beeps", "beep_mask", 0 },
250        { "pwm", "pwm1", 0, "fan1_pwm" },
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        { NULL, NULL }
263};
264
265/*
266        Returns the sysfs name and magnitude for a given feature.
267        First looks for a sysfs name and magnitude in the feature structure.
268        These should be added in chips.c for all non-standard feature names.
269        If that fails, converts common /proc feature names
270        to their sysfs equivalent, and uses common sysfs magnitude.
271        Common magnitudes are #defined above.
272        Common conversions are as follows:
273                fan%d_min -> fan%d_min (for magnitude)
274                fan%d_state -> fan%d_status
275                fan%d -> fan_input%d
276                pwm%d -> fan%d_pwm
277                pwm%d_enable -> fan%d_pwm_enable
278                in%d_max -> in%d_max (for magnitude)
279                in%d_min -> in%d_min (for magnitude)
280                in%d -> in%d_input
281                vin%d_max -> in%d_max
282                vin%d_min -> in%d_min
283                vin%d -> in_input%d
284                temp%d_over -> temp%d_max
285                temp%d_hyst -> temp%d_max_hyst
286                temp%d_max -> temp%d_max (for magnitude)
287                temp%d_high -> temp%d_max
288                temp%d_min -> temp%d_min (for magnitude)
289                temp%d_low -> temp%d_min
290                temp%d_state -> temp%d_status
291                temp%d -> temp%d_input
292                sensor%d -> temp%d_type
293        AND all conversions listed in the matches[] structure above.
294
295        If that fails, returns old /proc feature name and magnitude.
296
297        References: doc/developers/proc in the lm_sensors package;
298                    Documentation/i2c/sysfs_interface in the kernel
299*/
300static int getsysname(const sensors_chip_feature *feature, char *sysname,
301        int *sysmag, char *altsysname)
302{
303        const char * name = feature->data.name;
304        char last;
305        char check; /* used to verify end of string */
306        int num;
307        const struct match *m;
308
309/* default to a non-existent alternate name (should rarely be tried) */
310        strcpy(altsysname, "_");
311
312/* use override in feature structure if present */
313        if(feature->sysname != NULL) {
314                strcpy(sysname, feature->sysname);
315                if(feature->sysscaling)
316                        *sysmag = feature->sysscaling;
317                else
318                        *sysmag = feature->scaling;
319                if(feature->altsysname != NULL)
320                        strcpy(altsysname, feature->altsysname);
321                return 0;
322        }
323
324/* check for constant mappings */
325        for(m = matches; m->name != NULL; m++) {
326                if(!strcmp(m->name, name)) {
327                        strcpy(sysname, m->sysname);
328                        if (m->altsysname != NULL)
329                                strcpy(altsysname, m->altsysname);
330                        *sysmag = m->sysmag;
331                        return 0;
332                }
333        }
334
335/* convert common /proc names to common sysfs names */
336        if(sscanf(name, "fan%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') {
337                strcpy(sysname, name);
338                *sysmag = FANMAG;
339                return 0;
340        }
341        if(sscanf(name, "fan%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') {
342                sprintf(sysname, "fan%d_status", num);
343                *sysmag = 0;
344                return 0;
345        }
346        if(sscanf(name, "fan%d%c", &num, &check) == 1) {
347                sprintf(sysname, "fan%d_input", num);
348                *sysmag = FANMAG;
349                return 0;
350        }
351        if(sscanf(name, "pwm%d%c", &num, &check) == 1) {
352                strcpy(sysname, name);
353                *sysmag = 0;
354                sprintf(altsysname, "fan%d_pwm", num);
355                return 0;
356        }
357        if(sscanf(name, "pwm%d_enabl%c%c", &num, &last, &check) == 2 && last == 'e') {
358                strcpy(sysname, name);
359                *sysmag = 0;
360                sprintf(altsysname, "fan%d_pwm_enable", num);
361                return 0;
362        }
363
364        if((sscanf(name, "in%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
365        || (sscanf(name, "in%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) {
366                strcpy(sysname, name);
367                *sysmag = INMAG;
368                return 0;
369        }
370        if((sscanf(name, "in%d%c", &num, &check) == 1)
371        || (sscanf(name, "vin%d%c", &num, &check) == 1)) {
372                sprintf(sysname, "in%d_input", num);
373                *sysmag = INMAG;
374                return 0;
375        }
376        if(sscanf(name, "vin%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') {
377                sprintf(sysname, "in%d_min", num);
378                *sysmag = INMAG;
379                return 0;
380        }
381        if(sscanf(name, "vin%d_ma%c%c", &num, &last, &check) == 2 && last == 'x') {
382                sprintf(sysname, "in%d_max", num);
383                *sysmag = INMAG;
384                return 0;
385        }
386
387        if(sscanf(name, "temp%d_hys%c%c", &num, &last, &check) == 2 && last == 't') {
388                sprintf(sysname, "temp%d_max_hyst", num);
389                *sysmag = TEMPMAG;
390                return 0;
391        }
392        if((sscanf(name, "temp%d_ove%c%c", &num, &last, &check) == 2 && last == 'r')
393        || (sscanf(name, "temp%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')
394        || (sscanf(name, "temp%d_hig%c%c", &num, &last, &check) == 2 && last == 'h')) {
395                sprintf(sysname, "temp%d_max", num);
396                *sysmag = TEMPMAG;
397                return 0;
398        }
399        if((sscanf(name, "temp%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
400        || (sscanf(name, "temp%d_lo%c%c", &num, &last, &check) == 2 && last == 'w')) {
401                sprintf(sysname, "temp%d_min", num);
402                *sysmag = TEMPMAG;
403                return 0;
404        }
405        if(sscanf(name, "temp%d_cri%c%c", &num, &last, &check) == 2 && last == 't') {
406                sprintf(sysname, "temp%d_crit", num);
407                *sysmag = TEMPMAG;
408                return 0;
409        }
410        if(sscanf(name, "temp%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') {
411                sprintf(sysname, "temp%d_status", num);
412                *sysmag = 0;
413                return 0;
414        }
415        if(sscanf(name, "temp%d%c", &num, &check) == 1) {
416                sprintf(sysname, "temp%d_input", num);
417                *sysmag = TEMPMAG;
418                return 0;
419        }
420        if(sscanf(name, "sensor%d%c", &num, &check) == 1) {
421                sprintf(sysname, "temp%d_type", num);
422                *sysmag = 0;
423                return 0;
424        }
425
426/* bmcsensors only, not yet in kernel */
427/*
428        if((sscanf(name, "curr%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
429        || (sscanf(name, "curr%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) {
430                strcpy(sysname, name);
431                *sysmag = CURRMAG;
432                return 0;
433        }
434        if(sscanf(name, "curr%d%c", &num, &check) == 1) {
435                sprintf(sysname, "curr%d_input", num);
436                *sysmag = CURRMAG;
437                return 0;
438        }
439*/
440
441/* give up, use old name (probably won't work though...) */
442/* known to be the same:
443        "alarms", "beep_enable", "vrm", "fan%d_div"
444*/
445        strcpy(sysname, name);
446        *sysmag = feature->scaling;
447        return 0;
448}
Note: See TracBrowser for help on using the browser.