root/lm-sensors/branches/lm-sensors-3.0.0/lib/access.c @ 4766

Revision 4766, 17.0 KB (checked in by khali, 7 years ago)

Add support for the standard beep_enable attribute (#2248).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    access.c - Part of libsensors, a Linux library for reading sensor data.
3    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
4    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include <stdlib.h>
22#include <string.h>
23#include <math.h>
24#include "access.h"
25#include "sensors.h"
26#include "data.h"
27#include "error.h"
28#include "sysfs.h"
29#include "general.h"
30
31static int sensors_eval_expr(const sensors_chip_name *name,
32                             const sensors_expr *expr,
33                             double val, double *result);
34
35/* Compare two chips name descriptions, to see whether they could match.
36   Return 0 if it does not match, return 1 if it does match. */
37static int sensors_match_chip(const sensors_chip_name *chip1,
38                       const sensors_chip_name *chip2)
39{
40        if ((chip1->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
41            (chip2->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
42            strcasecmp(chip1->prefix, chip2->prefix))
43                return 0;
44
45        if ((chip1->bus.type != SENSORS_BUS_TYPE_ANY) &&
46            (chip2->bus.type != SENSORS_BUS_TYPE_ANY) &&
47            (chip1->bus.type != chip2->bus.type))
48                return 0;
49
50        if ((chip1->bus.nr != SENSORS_BUS_NR_ANY) &&
51            (chip2->bus.nr != SENSORS_BUS_NR_ANY) &&
52            (chip1->bus.nr != chip2->bus.nr))
53                return 0;
54
55        if ((chip1->addr != chip2->addr) &&
56            (chip1->addr != SENSORS_CHIP_NAME_ADDR_ANY) &&
57            (chip2->addr != SENSORS_CHIP_NAME_ADDR_ANY))
58                return 0;
59
60        return 1;
61}
62
63/* Returns, one by one, a pointer to all sensor_chip structs of the
64   config file which match with the given chip name. Last should be
65   the value returned by the last call, or NULL if this is the first
66   call. Returns NULL if no more matches are found. Do not modify
67   the struct the return value points to!
68   Note that this visits the list of chips from last to first. Usually,
69   you want the match that was latest in the config file. */
70static sensors_chip *
71sensors_for_all_config_chips(const sensors_chip_name *name,
72                             const sensors_chip *last)
73{
74        int nr, i;
75        sensors_chip_name_list chips;
76
77        for (nr = last ? last - sensors_config_chips - 1 :
78                         sensors_config_chips_count - 1; nr >= 0; nr--) {
79
80                chips = sensors_config_chips[nr].chips;
81                for (i = 0; i < chips.fits_count; i++) {
82                        if (sensors_match_chip(&chips.fits[i], name))
83                                return sensors_config_chips + nr;
84                }
85        }
86        return NULL;
87}
88
89/* Look up a resource in the intern chip list, and return a pointer to it.
90   Do not modify the struct the return value points to! Returns NULL if
91   not found.*/
92const sensors_chip_feature *sensors_lookup_feature_nr(const sensors_chip_name *chip,
93                                                      int feature)
94{
95        int i;
96
97        for (i = 0; i < sensors_proc_chips_count; i++)
98                if (sensors_match_chip(&sensors_proc_chips[i].chip, chip)) {
99                        if (feature < 0 ||
100                            feature >= sensors_proc_chips[i].feature_count)
101                                return NULL;
102                        return sensors_proc_chips[i].feature + feature;
103                }
104        return NULL;
105}
106
107/* Look up a resource in the intern chip list, and return a pointer to it.
108   Do not modify the struct the return value points to! Returns NULL if
109   not found.*/
110static const sensors_chip_feature *
111sensors_lookup_feature_name(const sensors_chip_name *chip, const char *feature)
112{
113        int i, j;
114        const sensors_chip_feature *features;
115
116        for (i = 0; i < sensors_proc_chips_count; i++)
117                if (sensors_match_chip(&sensors_proc_chips[i].chip, chip)) {
118                        features = sensors_proc_chips[i].feature;
119                        for (j = 0; j < sensors_proc_chips[i].feature_count; j++)
120                                if (!strcasecmp(features[j].data.name, feature))
121                                        return features + j;
122                }
123        return NULL;
124}
125
126/* Check whether the chip name is an 'absolute' name, which can only match
127   one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
128   if there are wildcards. */
129int sensors_chip_name_has_wildcards(const sensors_chip_name *chip)
130{
131        if ((chip->prefix == SENSORS_CHIP_NAME_PREFIX_ANY) ||
132            (chip->bus.type == SENSORS_BUS_TYPE_ANY) ||
133            (chip->bus.nr == SENSORS_BUS_NR_ANY) ||
134            (chip->addr == SENSORS_CHIP_NAME_ADDR_ANY))
135                return 1;
136        else
137                return 0;
138}
139
140/* Look up the label which belongs to this chip. Note that chip should not
141   contain wildcard values! The returned string is newly allocated (free it
142   yourself). On failure, NULL is returned.
143   If no label exists for this feature, its name is returned itself. */
144char *sensors_get_label(const sensors_chip_name *name, int feature)
145{
146        char *label;
147        const sensors_chip *chip;
148        const sensors_chip_feature *featureptr;
149        char buf[128], path[PATH_MAX];
150        FILE *f;
151        int i;
152
153        if (sensors_chip_name_has_wildcards(name))
154                return NULL;
155        if (!(featureptr = sensors_lookup_feature_nr(name, feature)))
156                return NULL;
157
158        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
159                for (i = 0; i < chip->labels_count; i++)
160                        if (!strcasecmp(featureptr->data.name, chip->labels[i].name)) {
161                                label = strdup(chip->labels[i].value);
162                                goto sensors_get_label_exit;
163                        }
164
165        /* No user specified label, check for a _label sysfs file */
166        snprintf(path, PATH_MAX, "%s/%s_label", name->path,
167                featureptr->data.name);
168       
169        if ((f = fopen(path, "r"))) {
170                i = fread(buf, 1, sizeof(buf) - 1, f);
171                fclose(f);
172                if (i > 0) {
173                        /* i - 1 to strip the '\n' at the end */
174                        buf[i - 1] = 0;
175                        label = strdup(buf);
176                        goto sensors_get_label_exit;
177                }
178        }
179
180        /* No label, return the feature name instead */
181        label = strdup(featureptr->data.name);
182       
183sensors_get_label_exit:
184        if (!label)
185                sensors_fatal_error("sensors_get_label",
186                                    "Allocating label text");
187        return label;
188}
189
190/* Looks up whether a feature should be ignored. Returns
191   1 if it should be ignored, 0 if not. This function takes
192   mappings into account. */
193static int sensors_get_ignored(const sensors_chip_name *name,
194                               const sensors_chip_feature *feature)
195{
196        const sensors_chip *chip;
197        const char *main_feature_name;
198        int i;
199
200        if (feature->data.mapping == SENSORS_NO_MAPPING)
201                main_feature_name = NULL;
202        else
203                main_feature_name = sensors_lookup_feature_nr(name,
204                                        feature->data.mapping)->data.name;
205
206        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
207                for (i = 0; i < chip->ignores_count; i++)
208                        if (!strcasecmp(feature->data.name, chip->ignores[i].name) ||
209                            (main_feature_name &&
210                             !strcasecmp(main_feature_name, chip->ignores[i].name)))
211                                return 1;
212        return 0;
213}
214
215/* Read the value of a feature of a certain chip. Note that chip should not
216   contain wildcard values! This function will return 0 on success, and <0
217   on failure. */
218int sensors_get_value(const sensors_chip_name *name, int feature,
219                      double *result)
220{
221        const sensors_chip_feature *main_feature;
222        const sensors_chip_feature *alt_feature;
223        const sensors_chip *chip;
224        const sensors_expr *expr = NULL;
225        double val;
226        int res, i;
227        int final_expr = 0;
228
229        if (sensors_chip_name_has_wildcards(name))
230                return -SENSORS_ERR_WILDCARDS;
231        if (!(main_feature = sensors_lookup_feature_nr(name, feature)))
232                return -SENSORS_ERR_NO_ENTRY;
233
234        if (main_feature->data.flags & SENSORS_COMPUTE_MAPPING)
235                alt_feature = sensors_lookup_feature_nr(name,
236                                        main_feature->data.mapping);
237        else
238                alt_feature = NULL;
239
240        if (!(main_feature->data.flags & SENSORS_MODE_R))
241                return -SENSORS_ERR_ACCESS_R;
242        for (chip = NULL;
243             !expr && (chip = sensors_for_all_config_chips(name, chip));)
244                for (i = 0; !final_expr && (i < chip->computes_count); i++) {
245                        if (!strcasecmp(main_feature->data.name, chip->computes[i].name)) {
246                                expr = chip->computes[i].from_proc;
247                                final_expr = 1;
248                        } else if (alt_feature && !strcasecmp(alt_feature->data.name,
249                                               chip->computes[i].name)) {
250                                expr = chip->computes[i].from_proc;
251                        }
252                }
253        if (sensors_read_sysfs_attr(name, feature, &val))
254                return -SENSORS_ERR_PROC;
255        if (!expr)
256                *result = val;
257        else if ((res = sensors_eval_expr(name, expr, val, result)))
258                return res;
259        return 0;
260}
261
262/* Set the value of a feature of a certain chip. Note that chip should not
263   contain wildcard values! This function will return 0 on success, and <0
264   on failure. */
265int sensors_set_value(const sensors_chip_name *name, int feature,
266                      double value)
267{
268        const sensors_chip_feature *main_feature;
269        const sensors_chip_feature *alt_feature;
270        const sensors_chip *chip;
271        const sensors_expr *expr = NULL;
272        int i, res;
273        int final_expr = 0;
274        double to_write;
275
276        if (sensors_chip_name_has_wildcards(name))
277                return -SENSORS_ERR_WILDCARDS;
278        if (!(main_feature = sensors_lookup_feature_nr(name, feature)))
279                return -SENSORS_ERR_NO_ENTRY;
280
281        if (main_feature->data.flags & SENSORS_COMPUTE_MAPPING)
282                alt_feature = sensors_lookup_feature_nr(name,
283                                        main_feature->data.mapping);
284        else
285                alt_feature = NULL;
286
287        if (!(main_feature->data.flags & SENSORS_MODE_W))
288                return -SENSORS_ERR_ACCESS_W;
289        for (chip = NULL;
290             !expr && (chip = sensors_for_all_config_chips(name, chip));)
291                for (i = 0; !final_expr && (i < chip->computes_count); i++)
292                        if (!strcasecmp(main_feature->data.name, chip->computes[i].name)) {
293                                expr = chip->computes->to_proc;
294                                final_expr = 1;
295                        } else if (alt_feature && !strcasecmp(alt_feature->data.name,
296                                               chip->computes[i].name)) {
297                                expr = chip->computes[i].to_proc;
298                        }
299
300        to_write = value;
301        if (expr)
302                if ((res = sensors_eval_expr(name, expr, value, &to_write)))
303                        return res;
304        if (sensors_write_sysfs_attr(name, feature, to_write))
305                return -SENSORS_ERR_PROC;
306        return 0;
307}
308
309const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
310                                                    *match, int *nr)
311{
312        const sensors_chip_name *res;
313
314        while (*nr < sensors_proc_chips_count) {
315                res = &sensors_proc_chips[(*nr)++].chip;
316                if (!match || sensors_match_chip(res, match))
317                        return res;
318        }
319        return NULL;
320}
321
322const char *sensors_get_adapter_name(const sensors_bus_id *bus)
323{
324        int i;
325
326        /* bus types with a single instance */
327        switch (bus->type) {
328        case SENSORS_BUS_TYPE_ISA:
329                return "ISA adapter";
330        case SENSORS_BUS_TYPE_PCI:
331                return "PCI adapter";
332        /* SPI should not be here, but for now SPI adapters have no name
333           so we don't have any custom string to return. */
334        case SENSORS_BUS_TYPE_SPI:
335                return "SPI adapter";
336        }
337
338        /* bus types with several instances */
339        for (i = 0; i < sensors_proc_bus_count; i++)
340                if (sensors_proc_bus[i].bus.type == bus->type &&
341                    sensors_proc_bus[i].bus.nr == bus->nr)
342                        return sensors_proc_bus[i].adapter;
343        return NULL;
344}
345
346/* nr-1 is the last feature returned */
347const sensors_feature_data *sensors_get_all_features(const sensors_chip_name *name,
348                                                     int *nr)
349{
350        sensors_chip_feature *feature_list;
351        int i;
352
353        for (i = 0; i < sensors_proc_chips_count; i++)
354                if (sensors_match_chip(&sensors_proc_chips[i].chip, name)) {
355                        feature_list = sensors_proc_chips[i].feature;
356                        while (*nr < sensors_proc_chips[i].feature_count
357                            && sensors_get_ignored(name, &feature_list[*nr]))
358                                (*nr)++;
359                        if (*nr == sensors_proc_chips[i].feature_count)
360                                return NULL;
361                        return &feature_list[(*nr)++].data;
362                }
363        return NULL;
364}
365
366/* Evaluate an expression */
367int sensors_eval_expr(const sensors_chip_name *name,
368                      const sensors_expr *expr,
369                      double val, double *result)
370{
371        double res1, res2;
372        int res;
373        const sensors_chip_feature *feature;
374
375        if (expr->kind == sensors_kind_val) {
376                *result = expr->data.val;
377                return 0;
378        }
379        if (expr->kind == sensors_kind_source) {
380                *result = val;
381                return 0;
382        }
383        if (expr->kind == sensors_kind_var) {
384                if (!(feature = sensors_lookup_feature_name(name,
385                                                            expr->data.var)))
386                        return SENSORS_ERR_NO_ENTRY;
387                if (!(res = sensors_get_value(name, feature->data.number, result)))
388                        return res;
389                return 0;
390        }
391        if ((res = sensors_eval_expr(name, expr->data.subexpr.sub1, val, &res1)))
392                return res;
393        if (expr->data.subexpr.sub2 &&
394            (res = sensors_eval_expr(name, expr->data.subexpr.sub2, val, &res2)))
395                return res;
396        switch (expr->data.subexpr.op) {
397        case sensors_add:
398                *result = res1 + res2;
399                return 0;
400        case sensors_sub:
401                *result = res1 - res2;
402                return 0;
403        case sensors_multiply:
404                *result = res1 * res2;
405                return 0;
406        case sensors_divide:
407                if (res2 == 0.0)
408                        return -SENSORS_ERR_DIV_ZERO;
409                *result = res1 / res2;
410                return 0;
411        case sensors_negate:
412                *result = -res1;
413                return 0;
414        case sensors_exp:
415                *result = exp(res1);
416                return 0;
417        case sensors_log:
418                if (res1 < 0.0)
419                        return -SENSORS_ERR_DIV_ZERO;
420                *result = log(res1);
421                return 0;
422        }
423        return 0;
424}
425
426/* Execute all set statements for this particular chip. The chip may not
427   contain wildcards!  This function will return 0 on success, and <0 on
428   failure. */
429static int sensors_do_this_chip_sets(const sensors_chip_name *name)
430{
431        sensors_chip *chip;
432        double value;
433        int i, j;
434        int err = 0, res;
435        const sensors_chip_feature *feature;
436        int *feature_list = NULL;
437        int feature_count = 0;
438        int feature_max = 0;
439        int feature_nr;
440
441        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
442                for (i = 0; i < chip->sets_count; i++) {
443                        feature = sensors_lookup_feature_name(name,
444                                                        chip->sets[i].name);
445                        if (!feature) {
446                                sensors_parse_error("Unknown feature name",
447                                                    chip->sets[i].lineno);
448                                err = SENSORS_ERR_NO_ENTRY;
449                                continue;
450                        }
451                        feature_nr = feature->data.number;
452
453                        /* Check whether we already set this feature */
454                        for (j = 0; j < feature_count; j++)
455                                if (feature_list[j] == feature_nr)
456                                        break;
457                        if (j != feature_count)
458                                continue;
459                        sensors_add_array_el(&feature_nr, &feature_list,
460                                             &feature_count, &feature_max,
461                                             sizeof(int));
462
463                        res = sensors_eval_expr(name, chip->sets[i].value, 0,
464                                              &value);
465                        if (res) {
466                                sensors_parse_error("Error parsing expression",
467                                                    chip->sets[i].lineno);
468                                err = res;
469                                continue;
470                        }
471                        if ((res = sensors_set_value(name, feature_nr, value))) {
472                                sensors_parse_error("Failed to set feature",
473                                                chip->sets[i].lineno);
474                                err = res;
475                                continue;
476                        }
477                }
478        free(feature_list);
479        return err;
480}
481
482/* Execute all set statements for this particular chip. The chip may contain
483   wildcards!  This function will return 0 on success, and <0 on failure. */
484int sensors_do_chip_sets(const sensors_chip_name *name)
485{
486        int nr, this_res;
487        const sensors_chip_name *found_name;
488        int res = 0;
489
490        for (nr = 0; (found_name = sensors_get_detected_chips(name, &nr));) {
491                this_res = sensors_do_this_chip_sets(found_name);
492                if (this_res)
493                        res = this_res;
494        }
495        return res;
496}
497
498/* Static mappings for use by sensors_feature_get_type() */
499struct feature_subtype_match
500{
501        const char *name;
502        sensors_feature_type type;
503};
504
505struct feature_type_match
506{
507        const char *name;
508        const struct feature_subtype_match *submatches;
509};
510
511static const struct feature_subtype_match temp_matches[] = {
512        { "input", SENSORS_FEATURE_TEMP },
513        { "max", SENSORS_FEATURE_TEMP_MAX },
514        { "max_hyst", SENSORS_FEATURE_TEMP_MAX_HYST },
515        { "min", SENSORS_FEATURE_TEMP_MIN },
516        { "crit", SENSORS_FEATURE_TEMP_CRIT },
517        { "crit_hyst", SENSORS_FEATURE_TEMP_CRIT_HYST },
518        { "alarm", SENSORS_FEATURE_TEMP_ALARM },
519        { "min_alarm", SENSORS_FEATURE_TEMP_MIN_ALARM },
520        { "max_alarm", SENSORS_FEATURE_TEMP_MAX_ALARM },
521        { "crit_alarm", SENSORS_FEATURE_TEMP_CRIT_ALARM },
522        { "fault", SENSORS_FEATURE_TEMP_FAULT },
523        { "type", SENSORS_FEATURE_TEMP_TYPE },
524        { NULL, 0 }
525};
526
527static const struct feature_subtype_match in_matches[] = {
528        { "input", SENSORS_FEATURE_IN },
529        { "min", SENSORS_FEATURE_IN_MIN },
530        { "max", SENSORS_FEATURE_IN_MAX },
531        { "alarm", SENSORS_FEATURE_IN_ALARM },
532        { "min_alarm", SENSORS_FEATURE_IN_MIN_ALARM },
533        { "max_alarm", SENSORS_FEATURE_IN_MAX_ALARM },
534        { NULL, 0 }
535};
536
537static const struct feature_subtype_match fan_matches[] = {
538        { "input", SENSORS_FEATURE_FAN },
539        { "min", SENSORS_FEATURE_FAN_MIN },
540        { "div", SENSORS_FEATURE_FAN_DIV },
541        { "alarm", SENSORS_FEATURE_FAN_ALARM },
542        { "fault", SENSORS_FEATURE_FAN_FAULT },
543        { NULL, 0 }
544};
545
546static const struct feature_subtype_match cpu_matches[] = {
547        { "vid", SENSORS_FEATURE_VID },
548        { NULL, 0 }
549};
550
551static struct feature_type_match matches[] = { 
552        { "temp%d%c", temp_matches },
553        { "in%d%c", in_matches },
554        { "fan%d%c", fan_matches },
555        { "cpu%d%c", cpu_matches },
556};
557
558/* Return the feature type and channel number based on the feature name */
559sensors_feature_type sensors_feature_get_type(const char *name, int *nr)
560{
561        char c;
562        int i, count;
563        const struct feature_subtype_match *submatches;
564       
565        /* Special case */
566        if (!strcmp(name, "beep_enable")) {
567                *nr = 0;
568                return SENSORS_FEATURE_BEEP_ENABLE;
569        }
570
571        for (i = 0; i < ARRAY_SIZE(matches); i++)
572                if ((count = sscanf(name, matches[i].name, nr, &c)))
573                        break;
574       
575        if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
576                return SENSORS_FEATURE_UNKNOWN;  /* no match */
577
578        submatches = matches[i].submatches;
579        name = strchr(name + 3, '_') + 1;
580        for (i = 0; submatches[i].name != NULL; i++)
581                if (!strcmp(name, submatches[i].name))
582                        return submatches[i].type;
583       
584        return SENSORS_FEATURE_UNKNOWN;
585}
Note: See TracBrowser for help on using the browser.