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

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

We can plain skip the feature lookup and compute statement search for
subfeatures with no compute mapping.

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