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

Revision 5147, 6.5 kB (checked in by khali, 9 months 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
37 int sensors_found_sysfs = 0;
38
39 char sensors_sysfs_mount[NAME_MAX];
40
41 /* returns !0 if sysfs filesystem was found, 0 otherwise */
42 int 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 */
57 static 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
126 exit_free:
127         free(entry.name.prefix);
128         free(entry.name.busname);
129         return err;
130 }
131
132 /* returns 0 if successful, !0 otherwise */
133 static 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
156 exit1:
157         /* this frees bus and devs */
158         sysfs_close_bus(bus);
159
160 exit0:
161         return ret;
162 }
163
164 /* returns 0 if successful, !0 otherwise */
165 int 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
191 exit:
192         /* this frees cls and clsdevs */
193         sysfs_close_class(cls);
194         return ret;
195 }
196
197 /* returns 0 if successful, !0 otherwise */
198 int 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
244 exit1:
245         /* this frees *cls _and_ *clsdevs */
246         sysfs_close_class(cls);
247
248 exit0:
249         return ret;
250 }
251
Note: See TracBrowser for help on using the browser.