root/lm-sensors/tags/V3-0-1/lib/access.c

Revision 5077, 15.1 kB (checked in by khali, 1 year ago)

Returned error values are supposed to be negative.

  • 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
31 static 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. */
37 static 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. */
70 static sensors_chip *
71 sensors_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.*/
92 static const sensors_chip_features *
93 sensors_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.*/
107 static const sensors_subfeature *
108 sensors_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.*/
120 static const sensors_feature *
121 sensors_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.*/
132 static const sensors_subfeature *
133 sensors_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. */
147 int 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. */
162 char *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        
198 sensors_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. */
207 static 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. */
223 int 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. */
274 int 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
320 const 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
333 const 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
357 const sensors_feature *
358 sensors_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
373 const sensors_subfeature *
374 sensors_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
395 const sensors_subfeature *
396 sensors_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 */
415 int 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. */
480 static 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. */
524 int 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.