root/lm-sensors/branches/lm-sensors-3.0.0/lib/sysfs.c @ 4464

Revision 4464, 10.9 KB (checked in by khali, 7 years ago)

Return with an explicit error code/message if sysfs isn't mounted.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    sysfs.c - Part of libsensors, a library for reading Linux sensor data
3    Copyright (c) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20/* this define needed for strndup() */
21#define _GNU_SOURCE
22
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
26#include <string.h>
27#include <stdlib.h>
28#include <limits.h>
29#include <errno.h>
30#include <sysfs/libsysfs.h>
31#include "data.h"
32#include "error.h"
33#include "access.h"
34#include "general.h"
35#include "sysfs.h"
36
37char sensors_sysfs_mount[NAME_MAX];
38
39#define MAX_SENSORS_PER_TYPE 16
40
41static
42int get_type_scaling(int type)
43{
44        switch (type & 0xFF10) {
45        case SENSORS_FEATURE_IN:
46        case SENSORS_FEATURE_TEMP:
47                return 3;
48        case SENSORS_FEATURE_FAN:
49                return 0;
50        }
51
52        switch (type) {
53        case SENSORS_FEATURE_VID:
54                return 3;
55        case SENSORS_FEATURE_VRM:
56                return 1;
57        default:
58                return 0;
59        }
60
61        return 0;
62}
63
64static 
65sensors_chip_features sensors_read_dynamic_chip(struct sysfs_device *sysdir)
66{
67        int i, type, fnum = 1;
68        struct sysfs_attribute *attr;
69        struct dlist *attrs;
70        sensors_chip_features ret = {0, 0};
71        /* room for all 3  (in, fan, temp) types, with all their subfeatures
72           + misc features. We use a large sparse table at first to store all
73           found features, so that we can store them sorted at type and index
74           and then later create a dense sorted table */
75        sensors_chip_feature features[MAX_SENSORS_PER_TYPE *
76                SENSORS_FEATURE_MAX_SUB_FEATURES * 3 +
77                SENSORS_FEATURE_MAX_SUB_FEATURES];
78        sensors_chip_feature *dyn_features;
79        char *name;
80               
81        attrs = sysfs_get_device_attributes(sysdir);
82       
83        if (attrs == NULL)
84                return ret;
85               
86        memset(features, 0, sizeof(features));
87       
88        dlist_for_each_data(attrs, attr, struct sysfs_attribute) {
89                sensors_chip_feature feature = { { 0, }, 0, };
90                name = attr->name;
91               
92                if (!strcmp(name, "name")) {
93                        ret.prefix = strndup(attr->value, strlen(attr->value) - 1);
94                        continue;
95                } 
96               
97                /* check for _input extension and remove */
98                i = strlen(name);
99                if (i > 6 && !strcmp(name + i - 6, "_input"))
100                        feature.data.name = strndup(name, i-6);
101                else
102                        feature.data.name = strdup(name);
103
104                type = sensors_feature_get_type(&feature.data);
105                if (type == SENSORS_FEATURE_UNKNOWN) {
106                        free((char *)feature.data.name);
107                        continue;
108                }
109                       
110                /* Get N as in this is the N-th in / fan / temp sensor */
111                switch (type & 0xFF00) {
112                        case SENSORS_FEATURE_IN:
113                                i = strtol(name + 2, NULL, 10);
114                                break;
115                        case SENSORS_FEATURE_FAN:
116                                i = strtol(name + 3, NULL, 10);
117                                if (i) i--;
118                                break;
119                        case SENSORS_FEATURE_TEMP:
120                                i = strtol(name + 4, NULL, 10);
121                                if (i) i--;
122                                break;
123                        case SENSORS_FEATURE_VID: /* first misc feature */
124                                i = 0;
125                                break;
126                }
127               
128                if (i >= MAX_SENSORS_PER_TYPE) {
129                        fprintf(stderr, "libsensors error, more sensors of one"
130                                " type then MAX_SENSORS_PER_TYPE, ignoring "
131                                "feature: %s\n", name);
132                        free((char *)feature.data.name);
133                        continue;
134                }
135               
136                /* "calculate" a place to store the feature in our sparse,
137                   sorted table */
138                i = (type >> 8) * MAX_SENSORS_PER_TYPE *
139                        SENSORS_FEATURE_MAX_SUB_FEATURES +
140                        i * SENSORS_FEATURE_MAX_SUB_FEATURES + (type & 0xFF);
141               
142                if (features[i].data.name) {                   
143                        fprintf(stderr, "libsensors error, trying to add dupli"
144                                "cate feature: %s to dynamic feature table\n",
145                                name);
146                        free((char *)feature.data.name);
147                        continue;
148                }
149               
150                /* fill in the other feature members */
151                feature.data.number = i + 1;
152                       
153                if ( (type & 0xFF00) == SENSORS_FEATURE_VID ||
154                                (type & 0x00FF) == 0) {
155                        /* misc sensor or main feature */
156                        feature.data.mapping = SENSORS_NO_MAPPING;
157                        feature.data.compute_mapping = SENSORS_NO_MAPPING;
158                } else if (type & 0x10) {
159                        /* sub feature without compute mapping */
160                        feature.data.mapping = i -
161                                i % SENSORS_FEATURE_MAX_SUB_FEATURES + 1;
162                        feature.data.compute_mapping = SENSORS_NO_MAPPING;
163                } else {
164                        feature.data.mapping = i -
165                                i % SENSORS_FEATURE_MAX_SUB_FEATURES + 1;
166                        feature.data.compute_mapping = feature.data.mapping;
167                }
168               
169                feature.data.mode =
170                        (attr->method & (SYSFS_METHOD_SHOW|SYSFS_METHOD_STORE))
171                         == (SYSFS_METHOD_SHOW|SYSFS_METHOD_STORE) ?
172                        SENSORS_MODE_RW : (attr->method & SYSFS_METHOD_SHOW) ?
173                        SENSORS_MODE_R : (attr->method & SYSFS_METHOD_STORE) ?
174                        SENSORS_MODE_W : SENSORS_MODE_NO_RW;
175
176                feature.scaling = get_type_scaling(type);
177
178                features[i] = feature;
179                fnum++;
180        }
181
182        dyn_features = calloc(fnum, sizeof(sensors_chip_feature));
183        if (dyn_features == NULL) {
184                sensors_fatal_error(__FUNCTION__,"Out of memory");
185        }
186       
187        fnum = 0;
188        for(i = 0; i < sizeof(features)/sizeof(sensors_chip_feature); i++) {
189                if (features[i].data.name) {
190                        dyn_features[fnum] = features[i];
191                        fnum++;
192                }
193        }
194       
195        ret.feature = dyn_features;
196       
197        return ret;
198}
199
200/* returns !0 if sysfs filesystem was found, 0 otherwise */
201int sensors_init_sysfs(void)
202{
203        struct stat statbuf;
204
205        /* libsysfs will return success even if sysfs is not mounted,
206           so we have to double-check */
207        if (sysfs_get_mnt_path(sensors_sysfs_mount, NAME_MAX)
208         || stat(sensors_sysfs_mount, &statbuf) < 0
209         || statbuf.st_nlink <= 2)      /* Empty directory */
210                return 0;
211
212        return 1;
213}
214
215/* returns: 0 if successful, !0 otherwise */
216static int sensors_read_one_sysfs_chip(struct sysfs_device *dev)
217{
218        static int total_dynamic = 0;
219        int domain, bus, slot, fn, i;
220        struct sysfs_attribute *attr, *bus_attr;
221        char bus_path[SYSFS_PATH_MAX];
222        sensors_proc_chips_entry entry;
223
224        /* ignore any device without name attribute */
225        if (!(attr = sysfs_get_device_attr(dev, "name")))
226                return 0;
227
228        /* ignore subclients */
229        if (attr->len >= 11 && !strcmp(attr->value + attr->len - 11,
230                        " subclient\n"))
231                return 0;
232
233        /* NB: attr->value[attr->len-1] == '\n'; chop that off */
234        entry.name.prefix = strndup(attr->value, attr->len - 1);
235        if (!entry.name.prefix)
236                sensors_fatal_error(__FUNCTION__, "out of memory");
237
238        entry.name.busname = strdup(dev->path);
239        if (!entry.name.busname)
240                sensors_fatal_error(__FUNCTION__, "out of memory");
241
242        if (sscanf(dev->name, "%d-%x", &entry.name.bus, &entry.name.addr) == 2) {
243                /* find out if legacy ISA or not */
244                if (entry.name.bus == 9191)
245                        entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA;
246                else {
247                        snprintf(bus_path, sizeof(bus_path),
248                                "%s/class/i2c-adapter/i2c-%d/device/name",
249                                sensors_sysfs_mount, entry.name.bus);
250
251                        if ((bus_attr = sysfs_open_attribute(bus_path))) {
252                                if (sysfs_read_attribute(bus_attr))
253                                        return -SENSORS_ERR_PARSE;
254
255                                if (bus_attr->value
256                                 && !strncmp(bus_attr->value, "ISA ", 4))
257                                        entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA;
258
259                                sysfs_close_attribute(bus_attr);
260                        }
261                }
262        } else if (sscanf(dev->name, "%*[a-z0-9_].%d", &entry.name.addr) == 1) {
263                /* must be new ISA (platform driver) */
264                entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA;
265        } else if (sscanf(dev->name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
266                /* PCI */
267                entry.name.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
268                entry.name.bus = SENSORS_CHIP_NAME_BUS_PCI;
269        } else
270                return -SENSORS_ERR_PARSE;
271       
272        /* check whether this chip is known in the static list */ 
273        for (i = 0; sensors_chip_features_list[i].prefix; i++)
274                if (!strcasecmp(sensors_chip_features_list[i].prefix, entry.name.prefix))
275                        break;
276
277        /* if no chip definition matches */
278        if (!sensors_chip_features_list[i].prefix && 
279                total_dynamic < N_PLACEHOLDER_ELEMENTS) {
280                sensors_chip_features n_entry = sensors_read_dynamic_chip(dev);
281
282                /* skip to end of list */
283                for(i = 0; sensors_chip_features_list[i].prefix; i++);
284
285                sensors_chip_features_list[i] = n_entry;       
286
287                total_dynamic++;
288        }
289               
290        sensors_add_proc_chips(&entry);
291
292        return 0;
293}
294
295/* returns 0 if successful, !0 otherwise */
296static int sensors_read_sysfs_chips_compat(void)
297{
298        struct sysfs_bus *bus;
299        struct dlist *devs;
300        struct sysfs_device *dev;
301        int ret = 0;
302
303        if (!(bus = sysfs_open_bus("i2c"))) {
304                if (errno && errno != ENOENT)
305                        ret = -SENSORS_ERR_PROC;
306                goto exit0;
307        }
308
309        if (!(devs = sysfs_get_bus_devices(bus))) {
310                if (errno && errno != ENOENT)
311                        ret = -SENSORS_ERR_PROC;
312                goto exit1;
313        }
314
315        dlist_for_each_data(devs, dev, struct sysfs_device)
316                if ((ret = sensors_read_one_sysfs_chip(dev)))
317                        goto exit1;
318
319exit1:
320        /* this frees bus and devs */
321        sysfs_close_bus(bus);
322
323exit0:
324        return ret;
325}
326
327/* returns 0 if successful, !0 otherwise */
328int sensors_read_sysfs_chips(void)
329{
330        struct sysfs_class *cls;
331        struct dlist *clsdevs;
332        struct sysfs_class_device *clsdev;
333        int ret = 0;
334
335        if (!(cls = sysfs_open_class("hwmon"))) {
336                /* compatibility function for kernel 2.6.n where n <= 13 */
337                return sensors_read_sysfs_chips_compat();
338        }
339
340        if (!(clsdevs = sysfs_get_class_devices(cls))) {
341                if (errno && errno != ENOENT)
342                        ret = -SENSORS_ERR_PROC;
343                goto exit;
344        }
345
346        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
347                struct sysfs_device *dev;
348                if (!(dev = sysfs_get_classdev_device(clsdev))) {
349                        ret = -SENSORS_ERR_PROC;
350                        goto exit;
351                }
352                if ((ret = sensors_read_one_sysfs_chip(dev)))
353                        goto exit;
354        }
355
356exit:
357        /* this frees cls and clsdevs */
358        sysfs_close_class(cls);
359        return ret;
360}
361
362/* returns 0 if successful, !0 otherwise */
363int sensors_read_sysfs_bus(void)
364{
365        struct sysfs_class *cls;
366        struct dlist *clsdevs;
367        struct sysfs_class_device *clsdev;
368        sensors_bus entry;
369        int ret = 0;
370
371        if (!(cls = sysfs_open_class("i2c-adapter"))) {
372                if (errno && errno != ENOENT)
373                        ret = -SENSORS_ERR_PROC;
374                goto exit0;
375        }
376
377        if (!(clsdevs = sysfs_get_class_devices(cls))) {
378                if (errno && errno != ENOENT)
379                        ret = -SENSORS_ERR_PROC;
380                goto exit1;
381        }
382
383        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
384                struct sysfs_device *dev;
385                struct sysfs_attribute *attr;
386
387                /* Get the adapter name from the classdev "name" attribute
388                 * (Linux 2.6.20 and later). If it fails, fall back to
389                 * the device "name" attribute (for older kernels). */
390                if (!(attr = sysfs_get_classdev_attr(clsdev, "name"))
391                 && !((dev = sysfs_get_classdev_device(clsdev)) &&
392                      (attr = sysfs_get_device_attr(dev, "name"))))
393                        continue;
394
395                /* NB: attr->value[attr->len-1] == '\n'; chop that off */
396                entry.adapter = strndup(attr->value, attr->len - 1);
397                if (!entry.adapter)
398                        sensors_fatal_error(__FUNCTION__, "out of memory");
399
400                if (!strncmp(entry.adapter, "ISA ", 4)) {
401                        entry.number = SENSORS_CHIP_NAME_BUS_ISA;
402                } else if (sscanf(clsdev->name, "i2c-%d", &entry.number) != 1) {
403                        entry.number = SENSORS_CHIP_NAME_BUS_DUMMY;
404                }
405
406                sensors_add_proc_bus(&entry);
407        }
408
409exit1:
410        /* this frees *cls _and_ *clsdevs */
411        sysfs_close_class(cls);
412
413exit0:
414        return ret;
415}
416
Note: See TracBrowser for help on using the browser.