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

Revision 4851, 15.1 KB (checked in by khali, 7 years ago)

Preserve error values returned by sensors_read_sysfs_attr() and
sensors_write_sysfs_attr().

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