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

Revision 4643, 17.2 KB (checked in by khali, 6 years ago)

The way we build the feature lists guarantees that subfeatures always
immediately follow their main feature. This makes it possible to simplify
sensors_get_all_features() quite a bit. We no longer need to maintain
separate pointers for the last main feature and the last subfeature,
we can simply walk the list linearly.

Note that I am still not entirely happy with this API. It was obviously
designed for debugging purposes (sensors -u) and without performance
concernes nor interface cleanliness in mind. I believe that we want to
tag main features and subfeatures as such, and let the application ask
specifically for the list of main features, and for each feature, for
its list of subfeatures (i.e. two functions instead of one.)

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