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

Revision 4834, 15.0 KB (checked in by khali, 6 years ago)

Define a separate structure to represent main features. This allows
for faster main features lookup. One side effect of this change is
that subfeatures can no longer have labels nor be ignored. I do not
think that this is a problem in practice, and actually this makes a
lot of sense.

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