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

Revision 5036, 6.5 KB (checked in by khali, 5 years ago)

Fix sysfs presence detection. Since sysfsutils 2.0.0, libsysfs will
return success even if sysfs isn't mounted. We have to check by ourselves
if it is mounted or not, so that we can fallback to procfs on Linux 2.4
systems.

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