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

Revision 4835, 14.8 KB (checked in by khali, 6 years ago)

sensors_get_all_features has a single caller now, so fold
it thereinto.

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