root/lm-sensors/trunk/lib/access.c @ 5648

Revision 5648, 15.7 KB (checked in by khali, 5 years ago)

Keep track of configuration file names so that we can later generate
better error reports.

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