root/lm-sensors/trunk/lib/sysfs.c @ 5147

Revision 5147, 6.5 KB (checked in by khali, 6 years ago)

Don't choke on unrecognized devices, part 2. In case hwmon devices have
no underlying physical device, just ignore them. This happened in kernel
2.6.25-rc5-git4 with the newly added generic thermal zone device.

  • 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
37int sensors_found_sysfs = 0;
38
39char sensors_sysfs_mount[NAME_MAX];
40
41/* returns !0 if sysfs filesystem was found, 0 otherwise */
42int sensors_init_sysfs(void)
43{
44        struct stat statbuf;
45
46        /* libsysfs will return success even if sysfs is not mounted,
47           so we have to double-check */
48        if (sysfs_get_mnt_path(sensors_sysfs_mount, NAME_MAX) == 0
49         && stat(sensors_sysfs_mount, &statbuf) == 0
50         && statbuf.st_nlink > 2)
51                sensors_found_sysfs = 1;
52
53        return sensors_found_sysfs;
54}
55
56/* returns: 0 if successful, !0 otherwise */
57static int sensors_read_one_sysfs_chip(struct sysfs_device *dev)
58{
59        int domain, bus, slot, fn;
60        struct sysfs_attribute *attr, *bus_attr;
61        char bus_path[SYSFS_PATH_MAX];
62        sensors_proc_chips_entry entry;
63        int err = -SENSORS_ERR_PARSE;
64
65        /* ignore any device without name attribute */
66        if (!(attr = sysfs_get_device_attr(dev, "name")))
67                return 0;
68
69        /* ignore subclients */
70        if (attr->len >= 11 && !strcmp(attr->value + attr->len - 11,
71                        " subclient\n"))
72                return 0;
73
74        /* also ignore eeproms */
75        if (!strcmp(attr->value, "eeprom\n"))
76                return 0;
77
78        /* NB: attr->value[attr->len-1] == '\n'; chop that off */
79        entry.name.prefix = strndup(attr->value, attr->len - 1);
80        if (!entry.name.prefix)
81                sensors_fatal_error(__FUNCTION__, "out of memory");
82
83        entry.name.busname = strdup(dev->path);
84        if (!entry.name.busname)
85                sensors_fatal_error(__FUNCTION__, "out of memory");
86
87        if (sscanf(dev->name, "%d-%x", &entry.name.bus, &entry.name.addr) == 2) {
88                /* find out if legacy ISA or not */
89                if (entry.name.bus == 9191)
90                        entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA;
91                else {
92                        snprintf(bus_path, sizeof(bus_path),
93                                "%s/class/i2c-adapter/i2c-%d/device/name",
94                                sensors_sysfs_mount, entry.name.bus);
95
96                        if ((bus_attr = sysfs_open_attribute(bus_path))) {
97                                if (sysfs_read_attribute(bus_attr)) {
98                                        sysfs_close_attribute(bus_attr);
99                                        goto exit_free;
100                                }
101
102                                if (bus_attr->value
103                                 && !strncmp(bus_attr->value, "ISA ", 4))
104                                        entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA;
105
106                                sysfs_close_attribute(bus_attr);
107                        }
108                }
109        } else if (sscanf(dev->name, "%*[a-z0-9_].%d", &entry.name.addr) == 1) {
110                /* must be new ISA (platform driver) */
111                entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA;
112        } else if (sscanf(dev->name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
113                /* PCI */
114                entry.name.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
115                entry.name.bus = SENSORS_CHIP_NAME_BUS_PCI;
116        } else {
117                /* Ignore unknown devices */
118                err = 0;
119                goto exit_free;
120        }
121
122        sensors_add_proc_chips(&entry);
123
124        return 0;
125
126exit_free:
127        free(entry.name.prefix);
128        free(entry.name.busname);
129        return err;
130}
131
132/* returns 0 if successful, !0 otherwise */
133static int sensors_read_sysfs_chips_compat(void)
134{
135        struct sysfs_bus *bus;
136        struct dlist *devs;
137        struct sysfs_device *dev;
138        int ret = 0;
139
140        if (!(bus = sysfs_open_bus("i2c"))) {
141                if (errno && errno != ENOENT)
142                        ret = -SENSORS_ERR_PROC;
143                goto exit0;
144        }
145
146        if (!(devs = sysfs_get_bus_devices(bus))) {
147                if (errno && errno != ENOENT)
148                        ret = -SENSORS_ERR_PROC;
149                goto exit1;
150        }
151
152        dlist_for_each_data(devs, dev, struct sysfs_device)
153                if ((ret = sensors_read_one_sysfs_chip(dev)))
154                        goto exit1;
155
156exit1:
157        /* this frees bus and devs */
158        sysfs_close_bus(bus);
159
160exit0:
161        return ret;
162}
163
164/* returns 0 if successful, !0 otherwise */
165int sensors_read_sysfs_chips(void)
166{
167        struct sysfs_class *cls;
168        struct dlist *clsdevs;
169        struct sysfs_class_device *clsdev;
170        int ret = 0;
171
172        if (!(cls = sysfs_open_class("hwmon"))) {
173                /* compatibility function for kernel 2.6.n where n <= 13 */
174                return sensors_read_sysfs_chips_compat();
175        }
176
177        if (!(clsdevs = sysfs_get_class_devices(cls))) {
178                if (errno && errno != ENOENT)
179                        ret = -SENSORS_ERR_PROC;
180                goto exit;
181        }
182
183        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
184                struct sysfs_device *dev;
185                if (!(dev = sysfs_get_classdev_device(clsdev)))
186                        continue;
187                if ((ret = sensors_read_one_sysfs_chip(dev)))
188                        goto exit;
189        }
190
191exit:
192        /* this frees cls and clsdevs */
193        sysfs_close_class(cls);
194        return ret;
195}
196
197/* returns 0 if successful, !0 otherwise */
198int sensors_read_sysfs_bus(void)
199{
200        struct sysfs_class *cls;
201        struct dlist *clsdevs;
202        struct sysfs_class_device *clsdev;
203        sensors_bus entry;
204        int ret = 0;
205
206        if (!(cls = sysfs_open_class("i2c-adapter"))) {
207                if (errno && errno != ENOENT)
208                        ret = -SENSORS_ERR_PROC;
209                goto exit0;
210        }
211
212        if (!(clsdevs = sysfs_get_class_devices(cls))) {
213                if (errno && errno != ENOENT)
214                        ret = -SENSORS_ERR_PROC;
215                goto exit1;
216        }
217
218        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
219                struct sysfs_device *dev;
220                struct sysfs_attribute *attr;
221
222                /* Get the adapter name from the classdev "name" attribute
223                 * (Linux 2.6.20 and later). If it fails, fall back to
224                 * the device "name" attribute (for older kernels). */
225                if (!(attr = sysfs_get_classdev_attr(clsdev, "name"))
226                 && !((dev = sysfs_get_classdev_device(clsdev)) &&
227                      (attr = sysfs_get_device_attr(dev, "name"))))
228                        continue;
229
230                /* NB: attr->value[attr->len-1] == '\n'; chop that off */
231                entry.adapter = strndup(attr->value, attr->len - 1);
232                if (!entry.adapter)
233                        sensors_fatal_error(__FUNCTION__, "out of memory");
234
235                if (!strncmp(entry.adapter, "ISA ", 4)) {
236                        entry.number = SENSORS_CHIP_NAME_BUS_ISA;
237                } else if (sscanf(clsdev->name, "i2c-%d", &entry.number) != 1) {
238                        entry.number = SENSORS_CHIP_NAME_BUS_DUMMY;
239                }
240
241                sensors_add_proc_bus(&entry);
242        }
243
244exit1:
245        /* this frees *cls _and_ *clsdevs */
246        sysfs_close_class(cls);
247
248exit0:
249        return ret;
250}
251
Note: See TracBrowser for help on using the browser.