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

Revision 4547, 13.0 kB (checked in by khali, 1 year ago)

Add missing include.

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