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

Revision 4831, 15.2 KB (checked in by khali, 6 years ago)

Split sensors_get_all_features() into two distinct functions, one to
get the list of all main features, and one to get the list of all the
subfeatures of a given main feature. This is a more logical interface for
applications to use. The current implementation is admittedly less than
optimal, because the storage structures weren't meant for it, but this
issue can (and will) be addressed later.

  • 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            strcmp(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_feature_data *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_feature_data *
111sensors_lookup_feature_name(const sensors_chip_name *chip, const char *feature)
112{
113        int i, j;
114        const sensors_feature_data *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 (!strcmp(features[j].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_feature_data *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 (!strcmp(featureptr->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->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->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_feature_data *feature)
195{
196        const sensors_chip *chip;
197        const char *main_feature_name;
198        int i;
199
200        if (feature->mapping == SENSORS_NO_MAPPING)
201                main_feature_name = NULL;
202        else
203                main_feature_name = sensors_lookup_feature_nr(name,
204                                        feature->mapping)->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 (!strcmp(feature->name, chip->ignores[i].name) ||
209                            (main_feature_name &&
210                             !strcmp(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_feature_data *main_feature;
222        const sensors_feature_data *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->flags & SENSORS_COMPUTE_MAPPING)
235                alt_feature = sensors_lookup_feature_nr(name,
236                                        main_feature->mapping);
237        else
238                alt_feature = NULL;
239
240        if (!(main_feature->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 (!strcmp(main_feature->name, chip->computes[i].name)) {
246                                expr = chip->computes[i].from_proc;
247                                final_expr = 1;
248                        } else if (alt_feature && !strcmp(alt_feature->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_feature_data *main_feature;
269        const sensors_feature_data *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->flags & SENSORS_COMPUTE_MAPPING)
282                alt_feature = sensors_lookup_feature_nr(name,
283                                        main_feature->mapping);
284        else
285                alt_feature = NULL;
286
287        if (!(main_feature->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 (!strcmp(main_feature->name, chip->computes[i].name)) {
293                                expr = chip->computes->to_proc;
294                                final_expr = 1;
295                        } else if (alt_feature && !strcmp(alt_feature->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
346static const sensors_feature_data *
347sensors_get_all_features(const sensors_chip_name *name, int *nr)
348{
349        sensors_feature_data *feature_list;
350        int i;
351
352        for (i = 0; i < sensors_proc_chips_count; i++)
353                if (sensors_match_chip(&sensors_proc_chips[i].chip, name)) {
354                        feature_list = sensors_proc_chips[i].feature;
355                        while (*nr < sensors_proc_chips[i].feature_count
356                            && sensors_get_ignored(name, &feature_list[*nr]))
357                                (*nr)++;
358                        if (*nr == sensors_proc_chips[i].feature_count)
359                                return NULL;
360                        return &feature_list[(*nr)++];
361                }
362        return NULL;
363}
364
365const sensors_feature_data *
366sensors_get_features(const sensors_chip_name *name, int *nr)
367{
368        const sensors_feature_data *feature;
369
370        while ((feature = sensors_get_all_features(name, nr))) {
371                if (feature->mapping == SENSORS_NO_MAPPING)
372                        return feature;
373        }
374        return NULL;    /* end of list */
375}
376
377const sensors_feature_data *
378sensors_get_all_subfeatures(const sensors_chip_name *name, int feature, int *nr)
379{
380        const sensors_feature_data *subfeature;
381
382        /* Seek directly to the first subfeature */
383        if (*nr < feature)
384                *nr = feature;
385
386        subfeature = sensors_get_all_features(name, nr);
387        if (!subfeature)
388                return NULL;    /* end of list */
389        if (subfeature->number == feature ||
390            subfeature->mapping == feature)
391                return subfeature;
392        return NULL;            /* end of subfeature list */
393}
394
395/* Evaluate an expression */
396int sensors_eval_expr(const sensors_chip_name *name,
397                      const sensors_expr *expr,
398                      double val, double *result)
399{
400        double res1, res2;
401        int res;
402        const sensors_feature_data *feature;
403
404        if (expr->kind == sensors_kind_val) {
405                *result = expr->data.val;
406                return 0;
407        }
408        if (expr->kind == sensors_kind_source) {
409                *result = val;
410                return 0;
411        }
412        if (expr->kind == sensors_kind_var) {
413                if (!(feature = sensors_lookup_feature_name(name,
414                                                            expr->data.var)))
415                        return SENSORS_ERR_NO_ENTRY;
416                if (!(res = sensors_get_value(name, feature->number, result)))
417                        return res;
418                return 0;
419        }
420        if ((res = sensors_eval_expr(name, expr->data.subexpr.sub1, val, &res1)))
421                return res;
422        if (expr->data.subexpr.sub2 &&
423            (res = sensors_eval_expr(name, expr->data.subexpr.sub2, val, &res2)))
424                return res;
425        switch (expr->data.subexpr.op) {
426        case sensors_add:
427                *result = res1 + res2;
428                return 0;
429        case sensors_sub:
430                *result = res1 - res2;
431                return 0;
432        case sensors_multiply:
433                *result = res1 * res2;
434                return 0;
435        case sensors_divide:
436                if (res2 == 0.0)
437                        return -SENSORS_ERR_DIV_ZERO;
438                *result = res1 / res2;
439                return 0;
440        case sensors_negate:
441                *result = -res1;
442                return 0;
443        case sensors_exp:
444                *result = exp(res1);
445                return 0;
446        case sensors_log:
447                if (res1 < 0.0)
448                        return -SENSORS_ERR_DIV_ZERO;
449                *result = log(res1);
450                return 0;
451        }
452        return 0;
453}
454
455/* Execute all set statements for this particular chip. The chip may not
456   contain wildcards!  This function will return 0 on success, and <0 on
457   failure. */
458static int sensors_do_this_chip_sets(const sensors_chip_name *name)
459{
460        sensors_chip *chip;
461        double value;
462        int i, j;
463        int err = 0, res;
464        const sensors_feature_data *feature;
465        int *feature_list = NULL;
466        int feature_count = 0;
467        int feature_max = 0;
468        int feature_nr;
469
470        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
471                for (i = 0; i < chip->sets_count; i++) {
472                        feature = sensors_lookup_feature_name(name,
473                                                        chip->sets[i].name);
474                        if (!feature) {
475                                sensors_parse_error("Unknown feature name",
476                                                    chip->sets[i].lineno);
477                                err = SENSORS_ERR_NO_ENTRY;
478                                continue;
479                        }
480                        feature_nr = feature->number;
481
482                        /* Check whether we already set this feature */
483                        for (j = 0; j < feature_count; j++)
484                                if (feature_list[j] == feature_nr)
485                                        break;
486                        if (j != feature_count)
487                                continue;
488                        sensors_add_array_el(&feature_nr, &feature_list,
489                                             &feature_count, &feature_max,
490                                             sizeof(int));
491
492                        res = sensors_eval_expr(name, chip->sets[i].value, 0,
493                                              &value);
494                        if (res) {
495                                sensors_parse_error("Error parsing expression",
496                                                    chip->sets[i].lineno);
497                                err = res;
498                                continue;
499                        }
500                        if ((res = sensors_set_value(name, feature_nr, value))) {
501                                sensors_parse_error("Failed to set feature",
502                                                chip->sets[i].lineno);
503                                err = res;
504                                continue;
505                        }
506                }
507        free(feature_list);
508        return err;
509}
510
511/* Execute all set statements for this particular chip. The chip may contain
512   wildcards!  This function will return 0 on success, and <0 on failure. */
513int sensors_do_chip_sets(const sensors_chip_name *name)
514{
515        int nr, this_res;
516        const sensors_chip_name *found_name;
517        int res = 0;
518
519        for (nr = 0; (found_name = sensors_get_detected_chips(name, &nr));) {
520                this_res = sensors_do_this_chip_sets(found_name);
521                if (this_res)
522                        res = this_res;
523        }
524        return res;
525}
Note: See TracBrowser for help on using the browser.