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

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

Fix error propagation during expression evaluation.

  • 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., 51 Franklin Street, Fifth Floor, Boston,
19    MA 02110-1301 USA.
20*/
21
22#include <stdlib.h>
23#include <string.h>
24#include <math.h>
25#include "access.h"
26#include "sensors.h"
27#include "data.h"
28#include "error.h"
29#include "sysfs.h"
30#include "general.h"
31
32static int sensors_eval_expr(const sensors_chip_features *chip_features,
33                             const sensors_expr *expr,
34                             double val, double *result);
35
36/* Compare two chips name descriptions, to see whether they could match.
37   Return 0 if it does not match, return 1 if it does match. */
38static int sensors_match_chip(const sensors_chip_name *chip1,
39                       const sensors_chip_name *chip2)
40{
41        if ((chip1->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
42            (chip2->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
43            strcmp(chip1->prefix, chip2->prefix))
44                return 0;
45
46        if ((chip1->bus.type != SENSORS_BUS_TYPE_ANY) &&
47            (chip2->bus.type != SENSORS_BUS_TYPE_ANY) &&
48            (chip1->bus.type != chip2->bus.type))
49                return 0;
50
51        if ((chip1->bus.nr != SENSORS_BUS_NR_ANY) &&
52            (chip2->bus.nr != SENSORS_BUS_NR_ANY) &&
53            (chip1->bus.nr != chip2->bus.nr))
54                return 0;
55
56        if ((chip1->addr != chip2->addr) &&
57            (chip1->addr != SENSORS_CHIP_NAME_ADDR_ANY) &&
58            (chip2->addr != SENSORS_CHIP_NAME_ADDR_ANY))
59                return 0;
60
61        return 1;
62}
63
64/* Returns, one by one, a pointer to all sensor_chip structs of the
65   config file which match with the given chip name. Last should be
66   the value returned by the last call, or NULL if this is the first
67   call. Returns NULL if no more matches are found. Do not modify
68   the struct the return value points to!
69   Note that this visits the list of chips from last to first. Usually,
70   you want the match that was latest in the config file. */
71static sensors_chip *
72sensors_for_all_config_chips(const sensors_chip_name *name,
73                             const sensors_chip *last)
74{
75        int nr, i;
76        sensors_chip_name_list chips;
77
78        for (nr = last ? last - sensors_config_chips - 1 :
79                         sensors_config_chips_count - 1; nr >= 0; nr--) {
80
81                chips = sensors_config_chips[nr].chips;
82                for (i = 0; i < chips.fits_count; i++) {
83                        if (sensors_match_chip(&chips.fits[i], name))
84                                return sensors_config_chips + nr;
85                }
86        }
87        return NULL;
88}
89
90/* Look up a chip in the intern chip list, and return a pointer to it.
91   Do not modify the struct the return value points to! Returns NULL if
92   not found.*/
93static const sensors_chip_features *
94sensors_lookup_chip(const sensors_chip_name *name)
95{
96        int i;
97
98        for (i = 0; i < sensors_proc_chips_count; i++)
99                if (sensors_match_chip(&sensors_proc_chips[i].chip, name))
100                        return &sensors_proc_chips[i];
101
102        return NULL;
103}
104
105/* Look up a subfeature of the given chip, and return a pointer to it.
106   Do not modify the struct the return value points to! Returns NULL if
107   not found.*/
108static const sensors_subfeature *
109sensors_lookup_subfeature_nr(const sensors_chip_features *chip,
110                             int subfeat_nr)
111{
112        if (subfeat_nr < 0 ||
113            subfeat_nr >= chip->subfeature_count)
114                return NULL;
115        return chip->subfeature + subfeat_nr;
116}
117
118/* Look up a feature of the given chip, and return a pointer to it.
119   Do not modify the struct the return value points to! Returns NULL if
120   not found.*/
121static const sensors_feature *
122sensors_lookup_feature_nr(const sensors_chip_features *chip, int feat_nr)
123{
124        if (feat_nr < 0 ||
125            feat_nr >= chip->feature_count)
126                return NULL;
127        return chip->feature + feat_nr;
128}
129
130/* Look up a subfeature by name, and return a pointer to it.
131   Do not modify the struct the return value points to! Returns NULL if
132   not found.*/
133static const sensors_subfeature *
134sensors_lookup_subfeature_name(const sensors_chip_features *chip,
135                               const char *name)
136{
137        int j;
138
139        for (j = 0; j < chip->subfeature_count; j++)
140                if (!strcmp(chip->subfeature[j].name, name))
141                        return chip->subfeature + j;
142        return NULL;
143}
144
145/* Check whether the chip name is an 'absolute' name, which can only match
146   one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
147   if there are wildcards. */
148int sensors_chip_name_has_wildcards(const sensors_chip_name *chip)
149{
150        if ((chip->prefix == SENSORS_CHIP_NAME_PREFIX_ANY) ||
151            (chip->bus.type == SENSORS_BUS_TYPE_ANY) ||
152            (chip->bus.nr == SENSORS_BUS_NR_ANY) ||
153            (chip->addr == SENSORS_CHIP_NAME_ADDR_ANY))
154                return 1;
155        else
156                return 0;
157}
158
159/* Look up the label for a given feature. Note that chip should not
160   contain wildcard values! The returned string is newly allocated (free it
161   yourself). On failure, NULL is returned.
162   If no label exists for this feature, its name is returned itself. */
163char *sensors_get_label(const sensors_chip_name *name,
164                        const sensors_feature *feature)
165{
166        char *label;
167        const sensors_chip *chip;
168        char buf[128], path[PATH_MAX];
169        FILE *f;
170        int i;
171
172        if (sensors_chip_name_has_wildcards(name))
173                return NULL;
174
175        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
176                for (i = 0; i < chip->labels_count; i++)
177                        if (!strcmp(feature->name, chip->labels[i].name)) {
178                                label = strdup(chip->labels[i].value);
179                                goto sensors_get_label_exit;
180                        }
181
182        /* No user specified label, check for a _label sysfs file */
183        snprintf(path, PATH_MAX, "%s/%s_label", name->path, feature->name);
184       
185        if ((f = fopen(path, "r"))) {
186                i = fread(buf, 1, sizeof(buf) - 1, f);
187                fclose(f);
188                if (i > 0) {
189                        /* i - 1 to strip the '\n' at the end */
190                        buf[i - 1] = 0;
191                        label = strdup(buf);
192                        goto sensors_get_label_exit;
193                }
194        }
195
196        /* No label, return the feature name instead */
197        label = strdup(feature->name);
198       
199sensors_get_label_exit:
200        if (!label)
201                sensors_fatal_error("sensors_get_label",
202                                    "Allocating label text");
203        return label;
204}
205
206/* Looks up whether a feature should be ignored. Returns
207   1 if it should be ignored, 0 if not. */
208static int sensors_get_ignored(const sensors_chip_name *name,
209                               const sensors_feature *feature)
210{
211        const sensors_chip *chip;
212        int i;
213
214        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
215                for (i = 0; i < chip->ignores_count; i++)
216                        if (!strcmp(feature->name, chip->ignores[i].name))
217                                return 1;
218        return 0;
219}
220
221/* Read the value of a subfeature of a certain chip. Note that chip should not
222   contain wildcard values! This function will return 0 on success, and <0
223   on failure. */
224int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
225                      double *result)
226{
227        const sensors_chip_features *chip_features;
228        const sensors_subfeature *subfeature;
229        const sensors_expr *expr = NULL;
230        double val;
231        int res, i;
232
233        if (sensors_chip_name_has_wildcards(name))
234                return -SENSORS_ERR_WILDCARDS;
235        if (!(chip_features = sensors_lookup_chip(name)))
236                return -SENSORS_ERR_NO_ENTRY;
237        if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
238                                                        subfeat_nr)))
239                return -SENSORS_ERR_NO_ENTRY;
240        if (!(subfeature->flags & SENSORS_MODE_R))
241                return -SENSORS_ERR_ACCESS_R;
242
243        /* Apply compute statement if it exists */
244        if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
245                const sensors_feature *feature;
246                const sensors_chip *chip;
247
248                feature = sensors_lookup_feature_nr(chip_features,
249                                        subfeature->mapping);
250
251                chip = NULL;
252                while (!expr &&
253                       (chip = sensors_for_all_config_chips(name, chip)))
254                        for (i = 0; i < chip->computes_count; i++) {
255                                if (!strcmp(feature->name,
256                                            chip->computes[i].name)) {
257                                        expr = chip->computes[i].from_proc;
258                                        break;
259                                }
260                        }
261        }
262
263        res = sensors_read_sysfs_attr(name, subfeature, &val);
264        if (res)
265                return res;
266        if (!expr)
267                *result = val;
268        else if ((res = sensors_eval_expr(chip_features, expr, val, result)))
269                return res;
270        return 0;
271}
272
273/* Set the value of a subfeature of a certain chip. Note that chip should not
274   contain wildcard values! This function will return 0 on success, and <0
275   on failure. */
276int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
277                      double value)
278{
279        const sensors_chip_features *chip_features;
280        const sensors_subfeature *subfeature;
281        const sensors_expr *expr = NULL;
282        int i, res;
283        double to_write;
284
285        if (sensors_chip_name_has_wildcards(name))
286                return -SENSORS_ERR_WILDCARDS;
287        if (!(chip_features = sensors_lookup_chip(name)))
288                return -SENSORS_ERR_NO_ENTRY;
289        if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
290                                                        subfeat_nr)))
291                return -SENSORS_ERR_NO_ENTRY;
292        if (!(subfeature->flags & SENSORS_MODE_W))
293                return -SENSORS_ERR_ACCESS_W;
294
295        /* Apply compute statement if it exists */
296        if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
297                const sensors_feature *feature;
298                const sensors_chip *chip;
299
300                feature = sensors_lookup_feature_nr(chip_features,
301                                        subfeature->mapping);
302
303                chip = NULL;
304                while (!expr &&
305                       (chip = sensors_for_all_config_chips(name, chip)))
306                        for (i = 0; i < chip->computes_count; i++) {
307                                if (!strcmp(feature->name,
308                                            chip->computes[i].name)) {
309                                        expr = chip->computes[i].to_proc;
310                                        break;
311                                }
312                        }
313        }
314
315        to_write = value;
316        if (expr)
317                if ((res = sensors_eval_expr(chip_features, expr,
318                                             value, &to_write)))
319                        return res;
320        return sensors_write_sysfs_attr(name, subfeature, to_write);
321}
322
323const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
324                                                    *match, int *nr)
325{
326        const sensors_chip_name *res;
327
328        while (*nr < sensors_proc_chips_count) {
329                res = &sensors_proc_chips[(*nr)++].chip;
330                if (!match || sensors_match_chip(res, match))
331                        return res;
332        }
333        return NULL;
334}
335
336const char *sensors_get_adapter_name(const sensors_bus_id *bus)
337{
338        int i;
339
340        /* bus types with a single instance */
341        switch (bus->type) {
342        case SENSORS_BUS_TYPE_ISA:
343                return "ISA adapter";
344        case SENSORS_BUS_TYPE_PCI:
345                return "PCI adapter";
346        /* SPI should not be here, but for now SPI adapters have no name
347           so we don't have any custom string to return. */
348        case SENSORS_BUS_TYPE_SPI:
349                return "SPI adapter";
350        case SENSORS_BUS_TYPE_VIRTUAL:
351                return "Virtual device";
352        }
353
354        /* bus types with several instances */
355        for (i = 0; i < sensors_proc_bus_count; i++)
356                if (sensors_proc_bus[i].bus.type == bus->type &&
357                    sensors_proc_bus[i].bus.nr == bus->nr)
358                        return sensors_proc_bus[i].adapter;
359        return NULL;
360}
361
362const sensors_feature *
363sensors_get_features(const sensors_chip_name *name, int *nr)
364{
365        const sensors_chip_features *chip;
366
367        if (!(chip = sensors_lookup_chip(name)))
368                return NULL;    /* No such chip */
369
370        while (*nr < chip->feature_count
371            && sensors_get_ignored(name, &chip->feature[*nr]))
372                (*nr)++;
373        if (*nr >= chip->feature_count)
374                return NULL;
375        return &chip->feature[(*nr)++];
376}
377
378const sensors_subfeature *
379sensors_get_all_subfeatures(const sensors_chip_name *name,
380                        const sensors_feature *feature, int *nr)
381{
382        const sensors_chip_features *chip;
383        const sensors_subfeature *subfeature;
384
385        if (!(chip = sensors_lookup_chip(name)))
386                return NULL;    /* No such chip */
387
388        /* Seek directly to the first subfeature */
389        if (*nr < feature->first_subfeature)
390                *nr = feature->first_subfeature;
391
392        if (*nr >= chip->subfeature_count)
393                return NULL;    /* end of list */
394        subfeature = &chip->subfeature[(*nr)++];
395        if (subfeature->mapping == feature->number)
396                return subfeature;
397        return NULL;    /* end of subfeature list */
398}
399
400const sensors_subfeature *
401sensors_get_subfeature(const sensors_chip_name *name,
402                       const sensors_feature *feature,
403                       sensors_subfeature_type type)
404{
405        const sensors_chip_features *chip;
406        int i;
407
408        if (!(chip = sensors_lookup_chip(name)))
409                return NULL;    /* No such chip */
410
411        for (i = feature->first_subfeature; i < chip->subfeature_count &&
412             chip->subfeature[i].mapping == feature->number; i++) {
413                if (chip->subfeature[i].type == type)
414                        return &chip->subfeature[i];
415        }
416        return NULL;    /* No such subfeature */
417}
418
419/* Evaluate an expression */
420int sensors_eval_expr(const sensors_chip_features *chip_features,
421                      const sensors_expr *expr,
422                      double val, double *result)
423{
424        double res1, res2;
425        int res;
426        const sensors_subfeature *subfeature;
427
428        if (expr->kind == sensors_kind_val) {
429                *result = expr->data.val;
430                return 0;
431        }
432        if (expr->kind == sensors_kind_source) {
433                *result = val;
434                return 0;
435        }
436        if (expr->kind == sensors_kind_var) {
437                if (!(subfeature = sensors_lookup_subfeature_name(chip_features,
438                                                            expr->data.var)))
439                        return -SENSORS_ERR_NO_ENTRY;
440                return sensors_get_value(&chip_features->chip,
441                                         subfeature->number, result);
442        }
443        if ((res = sensors_eval_expr(chip_features, expr->data.subexpr.sub1,
444                                     val, &res1)))
445                return res;
446        if (expr->data.subexpr.sub2 &&
447            (res = sensors_eval_expr(chip_features, expr->data.subexpr.sub2,
448                                     val, &res2)))
449                return res;
450        switch (expr->data.subexpr.op) {
451        case sensors_add:
452                *result = res1 + res2;
453                return 0;
454        case sensors_sub:
455                *result = res1 - res2;
456                return 0;
457        case sensors_multiply:
458                *result = res1 * res2;
459                return 0;
460        case sensors_divide:
461                if (res2 == 0.0)
462                        return -SENSORS_ERR_DIV_ZERO;
463                *result = res1 / res2;
464                return 0;
465        case sensors_negate:
466                *result = -res1;
467                return 0;
468        case sensors_exp:
469                *result = exp(res1);
470                return 0;
471        case sensors_log:
472                if (res1 < 0.0)
473                        return -SENSORS_ERR_DIV_ZERO;
474                *result = log(res1);
475                return 0;
476        }
477        return 0;
478}
479
480/* Execute all set statements for this particular chip. The chip may not
481   contain wildcards!  This function will return 0 on success, and <0 on
482   failure. */
483static int sensors_do_this_chip_sets(const sensors_chip_name *name)
484{
485        const sensors_chip_features *chip_features;
486        sensors_chip *chip;
487        double value;
488        int i;
489        int err = 0, res;
490        const sensors_subfeature *subfeature;
491
492        chip_features = sensors_lookup_chip(name);      /* Can't fail */
493
494        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
495                for (i = 0; i < chip->sets_count; i++) {
496                        subfeature = sensors_lookup_subfeature_name(chip_features,
497                                                        chip->sets[i].name);
498                        if (!subfeature) {
499                                sensors_parse_error("Unknown feature name",
500                                                    chip->sets[i].lineno);
501                                err = -SENSORS_ERR_NO_ENTRY;
502                                continue;
503                        }
504
505                        res = sensors_eval_expr(chip_features,
506                                                chip->sets[i].value, 0,
507                                                &value);
508                        if (res) {
509                                sensors_parse_error("Error parsing expression",
510                                                    chip->sets[i].lineno);
511                                err = res;
512                                continue;
513                        }
514                        if ((res = sensors_set_value(name, subfeature->number,
515                                                     value))) {
516                                sensors_parse_error("Failed to set value",
517                                                chip->sets[i].lineno);
518                                err = res;
519                                continue;
520                        }
521                }
522        return err;
523}
524
525/* Execute all set statements for this particular chip. The chip may contain
526   wildcards!  This function will return 0 on success, and <0 on failure. */
527int sensors_do_chip_sets(const sensors_chip_name *name)
528{
529        int nr, this_res;
530        const sensors_chip_name *found_name;
531        int res = 0;
532
533        for (nr = 0; (found_name = sensors_get_detected_chips(name, &nr));) {
534                this_res = sensors_do_this_chip_sets(found_name);
535                if (this_res)
536                        res = this_res;
537        }
538        return res;
539}
Note: See TracBrowser for help on using the browser.