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

Revision 5674, 15.8 KB (checked in by andy, 6 years ago)

Use func in sensors_fatal_error() to get function name.

  • 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-2009   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(__func__, "Allocating label text");
205        return label;
206}
207
208/* Looks up whether a feature should be ignored. Returns
209   1 if it should be ignored, 0 if not. */
210static int sensors_get_ignored(const sensors_chip_name *name,
211                               const sensors_feature *feature)
212{
213        const sensors_chip *chip;
214        int i;
215
216        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
217                for (i = 0; i < chip->ignores_count; i++)
218                        if (!strcmp(feature->name, chip->ignores[i].name))
219                                return 1;
220        return 0;
221}
222
223/* Read the value of a subfeature of a certain chip. Note that chip should not
224   contain wildcard values! This function will return 0 on success, and <0
225   on failure. */
226static int __sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
227                               int depth, double *result)
228{
229        const sensors_chip_features *chip_features;
230        const sensors_subfeature *subfeature;
231        const sensors_expr *expr = NULL;
232        double val;
233        int res, i;
234
235        if (depth >= DEPTH_MAX)
236                return -SENSORS_ERR_RECURSION;
237        if (sensors_chip_name_has_wildcards(name))
238                return -SENSORS_ERR_WILDCARDS;
239        if (!(chip_features = sensors_lookup_chip(name)))
240                return -SENSORS_ERR_NO_ENTRY;
241        if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
242                                                        subfeat_nr)))
243                return -SENSORS_ERR_NO_ENTRY;
244        if (!(subfeature->flags & SENSORS_MODE_R))
245                return -SENSORS_ERR_ACCESS_R;
246
247        /* Apply compute statement if it exists */
248        if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
249                const sensors_feature *feature;
250                const sensors_chip *chip;
251
252                feature = sensors_lookup_feature_nr(chip_features,
253                                        subfeature->mapping);
254
255                chip = NULL;
256                while (!expr &&
257                       (chip = sensors_for_all_config_chips(name, chip)))
258                        for (i = 0; i < chip->computes_count; i++) {
259                                if (!strcmp(feature->name,
260                                            chip->computes[i].name)) {
261                                        expr = chip->computes[i].from_proc;
262                                        break;
263                                }
264                        }
265        }
266
267        res = sensors_read_sysfs_attr(name, subfeature, &val);
268        if (res)
269                return res;
270        if (!expr)
271                *result = val;
272        else if ((res = sensors_eval_expr(chip_features, expr, val, depth,
273                                          result)))
274                return res;
275        return 0;
276}
277
278int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
279                      double *result)
280{
281        return __sensors_get_value(name, subfeat_nr, 0, result);
282}
283
284/* Set the value of a subfeature of a certain chip. Note that chip should not
285   contain wildcard values! This function will return 0 on success, and <0
286   on failure. */
287int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
288                      double value)
289{
290        const sensors_chip_features *chip_features;
291        const sensors_subfeature *subfeature;
292        const sensors_expr *expr = NULL;
293        int i, res;
294        double to_write;
295
296        if (sensors_chip_name_has_wildcards(name))
297                return -SENSORS_ERR_WILDCARDS;
298        if (!(chip_features = sensors_lookup_chip(name)))
299                return -SENSORS_ERR_NO_ENTRY;
300        if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
301                                                        subfeat_nr)))
302                return -SENSORS_ERR_NO_ENTRY;
303        if (!(subfeature->flags & SENSORS_MODE_W))
304                return -SENSORS_ERR_ACCESS_W;
305
306        /* Apply compute statement if it exists */
307        if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
308                const sensors_feature *feature;
309                const sensors_chip *chip;
310
311                feature = sensors_lookup_feature_nr(chip_features,
312                                        subfeature->mapping);
313
314                chip = NULL;
315                while (!expr &&
316                       (chip = sensors_for_all_config_chips(name, chip)))
317                        for (i = 0; i < chip->computes_count; i++) {
318                                if (!strcmp(feature->name,
319                                            chip->computes[i].name)) {
320                                        expr = chip->computes[i].to_proc;
321                                        break;
322                                }
323                        }
324        }
325
326        to_write = value;
327        if (expr)
328                if ((res = sensors_eval_expr(chip_features, expr,
329                                             value, 0, &to_write)))
330                        return res;
331        return sensors_write_sysfs_attr(name, subfeature, to_write);
332}
333
334const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
335                                                    *match, int *nr)
336{
337        const sensors_chip_name *res;
338
339        while (*nr < sensors_proc_chips_count) {
340                res = &sensors_proc_chips[(*nr)++].chip;
341                if (!match || sensors_match_chip(res, match))
342                        return res;
343        }
344        return NULL;
345}
346
347const char *sensors_get_adapter_name(const sensors_bus_id *bus)
348{
349        int i;
350
351        /* bus types with a single instance */
352        switch (bus->type) {
353        case SENSORS_BUS_TYPE_ISA:
354                return "ISA adapter";
355        case SENSORS_BUS_TYPE_PCI:
356                return "PCI adapter";
357        /* SPI should not be here, but for now SPI adapters have no name
358           so we don't have any custom string to return. */
359        case SENSORS_BUS_TYPE_SPI:
360                return "SPI adapter";
361        case SENSORS_BUS_TYPE_VIRTUAL:
362                return "Virtual device";
363        case SENSORS_BUS_TYPE_ACPI:
364                return "ACPI interface";
365        }
366
367        /* bus types with several instances */
368        for (i = 0; i < sensors_proc_bus_count; i++)
369                if (sensors_proc_bus[i].bus.type == bus->type &&
370                    sensors_proc_bus[i].bus.nr == bus->nr)
371                        return sensors_proc_bus[i].adapter;
372        return NULL;
373}
374
375const sensors_feature *
376sensors_get_features(const sensors_chip_name *name, int *nr)
377{
378        const sensors_chip_features *chip;
379
380        if (!(chip = sensors_lookup_chip(name)))
381                return NULL;    /* No such chip */
382
383        while (*nr < chip->feature_count
384            && sensors_get_ignored(name, &chip->feature[*nr]))
385                (*nr)++;
386        if (*nr >= chip->feature_count)
387                return NULL;
388        return &chip->feature[(*nr)++];
389}
390
391const sensors_subfeature *
392sensors_get_all_subfeatures(const sensors_chip_name *name,
393                        const sensors_feature *feature, int *nr)
394{
395        const sensors_chip_features *chip;
396        const sensors_subfeature *subfeature;
397
398        if (!(chip = sensors_lookup_chip(name)))
399                return NULL;    /* No such chip */
400
401        /* Seek directly to the first subfeature */
402        if (*nr < feature->first_subfeature)
403                *nr = feature->first_subfeature;
404
405        if (*nr >= chip->subfeature_count)
406                return NULL;    /* end of list */
407        subfeature = &chip->subfeature[(*nr)++];
408        if (subfeature->mapping == feature->number)
409                return subfeature;
410        return NULL;    /* end of subfeature list */
411}
412
413const sensors_subfeature *
414sensors_get_subfeature(const sensors_chip_name *name,
415                       const sensors_feature *feature,
416                       sensors_subfeature_type type)
417{
418        const sensors_chip_features *chip;
419        int i;
420
421        if (!(chip = sensors_lookup_chip(name)))
422                return NULL;    /* No such chip */
423
424        for (i = feature->first_subfeature; i < chip->subfeature_count &&
425             chip->subfeature[i].mapping == feature->number; i++) {
426                if (chip->subfeature[i].type == type)
427                        return &chip->subfeature[i];
428        }
429        return NULL;    /* No such subfeature */
430}
431
432/* Evaluate an expression */
433int sensors_eval_expr(const sensors_chip_features *chip_features,
434                      const sensors_expr *expr,
435                      double val, int depth, double *result)
436{
437        double res1, res2;
438        int res;
439        const sensors_subfeature *subfeature;
440
441        if (expr->kind == sensors_kind_val) {
442                *result = expr->data.val;
443                return 0;
444        }
445        if (expr->kind == sensors_kind_source) {
446                *result = val;
447                return 0;
448        }
449        if (expr->kind == sensors_kind_var) {
450                if (!(subfeature = sensors_lookup_subfeature_name(chip_features,
451                                                            expr->data.var)))
452                        return -SENSORS_ERR_NO_ENTRY;
453                return __sensors_get_value(&chip_features->chip,
454                                           subfeature->number, depth + 1,
455                                           result);
456        }
457        if ((res = sensors_eval_expr(chip_features, expr->data.subexpr.sub1,
458                                     val, depth, &res1)))
459                return res;
460        if (expr->data.subexpr.sub2 &&
461            (res = sensors_eval_expr(chip_features, expr->data.subexpr.sub2,
462                                     val, depth, &res2)))
463                return res;
464        switch (expr->data.subexpr.op) {
465        case sensors_add:
466                *result = res1 + res2;
467                return 0;
468        case sensors_sub:
469                *result = res1 - res2;
470                return 0;
471        case sensors_multiply:
472                *result = res1 * res2;
473                return 0;
474        case sensors_divide:
475                if (res2 == 0.0)
476                        return -SENSORS_ERR_DIV_ZERO;
477                *result = res1 / res2;
478                return 0;
479        case sensors_negate:
480                *result = -res1;
481                return 0;
482        case sensors_exp:
483                *result = exp(res1);
484                return 0;
485        case sensors_log:
486                if (res1 < 0.0)
487                        return -SENSORS_ERR_DIV_ZERO;
488                *result = log(res1);
489                return 0;
490        }
491        return 0;
492}
493
494/* Execute all set statements for this particular chip. The chip may not
495   contain wildcards!  This function will return 0 on success, and <0 on
496   failure. */
497static int sensors_do_this_chip_sets(const sensors_chip_name *name)
498{
499        const sensors_chip_features *chip_features;
500        sensors_chip *chip;
501        double value;
502        int i;
503        int err = 0, res;
504        const sensors_subfeature *subfeature;
505
506        chip_features = sensors_lookup_chip(name);      /* Can't fail */
507
508        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
509                for (i = 0; i < chip->sets_count; i++) {
510                        subfeature = sensors_lookup_subfeature_name(chip_features,
511                                                        chip->sets[i].name);
512                        if (!subfeature) {
513                                sensors_parse_error_wfn("Unknown feature name",
514                                                    chip->sets[i].line.filename,
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_wfn("Error parsing expression",
525                                                    chip->sets[i].line.filename,
526                                                    chip->sets[i].line.lineno);
527                                err = res;
528                                continue;
529                        }
530                        if ((res = sensors_set_value(name, subfeature->number,
531                                                     value))) {
532                                sensors_parse_error_wfn("Failed to set value",
533                                                chip->sets[i].line.filename,
534                                                chip->sets[i].line.lineno);
535                                err = res;
536                                continue;
537                        }
538                }
539        return err;
540}
541
542/* Execute all set statements for this particular chip. The chip may contain
543   wildcards!  This function will return 0 on success, and <0 on failure. */
544int sensors_do_chip_sets(const sensors_chip_name *name)
545{
546        int nr, this_res;
547        const sensors_chip_name *found_name;
548        int res = 0;
549
550        for (nr = 0; (found_name = sensors_get_detected_chips(name, &nr));) {
551                this_res = sensors_do_this_chip_sets(found_name);
552                if (this_res)
553                        res = this_res;
554        }
555        return res;
556}
Note: See TracBrowser for help on using the browser.