Show
Ignore:
Timestamp:
12/10/07 14:30:22 (4 years ago)
Author:
khali
Message:

libsensors: No longer depend on libsysfs.
Instead, access sysfs directly, using 3 embedded helper
functions. My motivations for doing this are:
* As far as I know, libsysfs is no longer maintained.
* libsysfs does much more than we need. For example, when asking for a
device attribute list, libsysfs will read the contents and permissions
of all attributes. Not only does this waste CPU cycles per se, but in
the case of hwmon driver it also triggers register reads, which can be
slow for SMBus chips.
* libsysfs enforces the difference between devices and class devices,
while future changes will be easier if we can handle both types alike.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • lm-sensors/branches/lm-sensors-3.0.0/lib/sysfs.c

    r4899 r5067  
    2929#include <limits.h> 
    3030#include <errno.h> 
    31 #include <sysfs/libsysfs.h> 
     31#include <dirent.h> 
    3232#include "data.h" 
    3333#include "error.h" 
     
    3535#include "general.h" 
    3636#include "sysfs.h" 
     37 
     38 
     39/****************************************************************************/ 
     40 
     41#define ATTR_MAX        128 
     42 
     43/* 
     44 * Read an attribute from sysfs 
     45 * Returns a pointer to a freshly allocated string; free it yourself. 
     46 * If the file doesn't exist or can't be read, NULL is returned. 
     47 */ 
     48static char *sysfs_read_attr(const char *device, const char *attr) 
     49{ 
     50        char path[NAME_MAX]; 
     51        char buf[ATTR_MAX], *p; 
     52        FILE *f; 
     53 
     54        snprintf(path, NAME_MAX, "%s/%s", device, attr); 
     55 
     56        if (!(f = fopen(path, "r"))) 
     57                return NULL; 
     58        p = fgets(buf, ATTR_MAX, f); 
     59        fclose(f); 
     60        if (!p) 
     61                return NULL; 
     62 
     63        /* Last byte is a '\n'; chop that off */ 
     64        p = strndup(buf, strlen(buf) - 1); 
     65        if (!p) 
     66                sensors_fatal_error(__FUNCTION__, "out of memory"); 
     67        return p; 
     68} 
     69 
     70/* 
     71 * Call an arbitrary function for each class device of the given class 
     72 * Returns 0 on success (all calls returned 0), a positive errno for 
     73 * local errors, or a negative error value if any call fails. 
     74 */ 
     75static int sysfs_foreach_classdev(const char *class_name, 
     76                                   int (*func)(char *, const char*)) 
     77{ 
     78        char path[NAME_MAX]; 
     79        int path_off, ret; 
     80        DIR *dir; 
     81        struct dirent *ent; 
     82 
     83        path_off = snprintf(path, NAME_MAX, "%s/class/%s", 
     84                            sensors_sysfs_mount, class_name); 
     85        if (!(dir = opendir(path))) 
     86                return errno; 
     87 
     88        ret = 0; 
     89        while (!ret && (ent = readdir(dir))) { 
     90                if (ent->d_name[0] == '.')      /* skip hidden entries */ 
     91                        continue; 
     92 
     93                snprintf(path + path_off, NAME_MAX - path_off, "/%s", 
     94                         ent->d_name); 
     95                ret = func(path, ent->d_name); 
     96        } 
     97 
     98        closedir(dir); 
     99        return ret; 
     100} 
     101 
     102/* 
     103 * Call an arbitrary function for each device of the given bus type 
     104 * Returns 0 on success (all calls returned 0), a positive errno for 
     105 * local errors, or a negative error value if any call fails. 
     106 */ 
     107static int sysfs_foreach_busdev(const char *bus_type, 
     108                                 int (*func)(char *, const char*)) 
     109{ 
     110        char path[NAME_MAX]; 
     111        int path_off, ret; 
     112        DIR *dir; 
     113        struct dirent *ent; 
     114 
     115        path_off = snprintf(path, NAME_MAX, "%s/bus/%s/devices", 
     116                            sensors_sysfs_mount, bus_type); 
     117        if (!(dir = opendir(path))) 
     118                return errno; 
     119 
     120        ret = 0; 
     121        while (!ret && (ent = readdir(dir))) { 
     122                if (ent->d_name[0] == '.')      /* skip hidden entries */ 
     123                        continue; 
     124 
     125                snprintf(path + path_off, NAME_MAX - path_off, "/%s", 
     126                         ent->d_name); 
     127                ret = func(path, ent->d_name); 
     128        } 
     129 
     130        closedir(dir); 
     131        return ret; 
     132} 
     133 
     134/****************************************************************************/ 
    37135 
    38136char sensors_sysfs_mount[NAME_MAX]; 
     
    177275} 
    178276 
     277static int sensors_get_attr_mode(const char *device, const char *attr) 
     278{ 
     279        char path[NAME_MAX]; 
     280        struct stat st; 
     281        int mode = 0; 
     282 
     283        snprintf(path, NAME_MAX, "%s/%s", device, attr); 
     284        if (!stat(path, &st)) { 
     285                if (st.st_mode & S_IRUSR) 
     286                        mode |= SENSORS_MODE_R; 
     287                if (st.st_mode & S_IWUSR) 
     288                        mode |= SENSORS_MODE_W; 
     289        } 
     290        return mode; 
     291} 
     292 
    179293static int sensors_read_dynamic_chip(sensors_chip_features *chip, 
    180                                      struct sysfs_device *sysdir) 
     294                                     const char *dev_path) 
    181295{ 
    182296        int i, fnum = 0, sfnum = 0, prev_slot; 
    183         struct sysfs_attribute *attr; 
    184         struct dlist *attrs; 
     297        DIR *dir; 
     298        struct dirent *ent; 
    185299        sensors_subfeature *all_subfeatures; 
    186300        sensors_subfeature *dyn_subfeatures; 
     
    189303        sensors_subfeature_type sftype; 
    190304 
    191         attrs = sysfs_get_device_attributes(sysdir); 
    192  
    193         if (attrs == NULL) 
    194                 return -ENOENT; 
     305        if (!(dir = opendir(dev_path))) 
     306                return -errno; 
    195307 
    196308        /* We use a large sparse table at first to store all found 
     
    202314                sensors_fatal_error(__FUNCTION__, "Out of memory"); 
    203315 
    204         dlist_for_each_data(attrs, attr, struct sysfs_attribute) { 
    205                 char *name = attr->name; 
     316        while ((ent = readdir(dir))) { 
     317                char *name = ent->d_name; 
    206318                int nr; 
     319 
     320                if (ent->d_name[0] == '.') 
     321                        continue; 
    207322 
    208323                sftype = sensors_subfeature_get_type(name, &nr); 
     
    258373                if (!(sftype & 0x80)) 
    259374                        all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING; 
    260                 if (attr->method & SYSFS_METHOD_SHOW) 
    261                         all_subfeatures[i].flags |= SENSORS_MODE_R; 
    262                 if (attr->method & SYSFS_METHOD_STORE) 
    263                         all_subfeatures[i].flags |= SENSORS_MODE_W; 
     375                all_subfeatures[i].flags |= sensors_get_attr_mode(dev_path, name); 
    264376 
    265377                sfnum++; 
    266378        } 
     379        closedir(dir); 
    267380 
    268381        if (!sfnum) { /* No subfeature */ 
     
    334447        struct stat statbuf; 
    335448 
    336         /* libsysfs will return success even if sysfs is not mounted, 
    337            so we have to double-check */ 
    338         if (sysfs_get_mnt_path(sensors_sysfs_mount, NAME_MAX) 
    339          || stat(sensors_sysfs_mount, &statbuf) < 0 
     449        snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys"); 
     450        if (stat(sensors_sysfs_mount, &statbuf) < 0 
    340451         || statbuf.st_nlink <= 2)      /* Empty directory */ 
    341452                return 0; 
     
    345456 
    346457/* returns: 0 if successful, !0 otherwise */ 
    347 static int sensors_read_one_sysfs_chip(struct sysfs_device *dev) 
     458static int sensors_read_one_sysfs_chip(char *dev_path, const char *dev_name) 
    348459{ 
    349460        int domain, bus, slot, fn; 
    350461        int err = -SENSORS_ERR_KERNEL; 
    351         struct sysfs_attribute *attr, *bus_attr; 
    352         char bus_path[SYSFS_PATH_MAX]; 
     462        char *bus_attr; 
     463        char bus_path[NAME_MAX]; 
    353464        sensors_chip_features entry; 
    354465 
    355466        /* ignore any device without name attribute */ 
    356         if (!(attr = sysfs_get_device_attr(dev, "name"))) 
     467        if (!(entry.chip.prefix = sysfs_read_attr(dev_path, "name"))) 
    357468                return 0; 
    358469 
    359         /* NB: attr->value[attr->len-1] == '\n'; chop that off */ 
    360         entry.chip.prefix = strndup(attr->value, attr->len - 1); 
    361         if (!entry.chip.prefix) 
    362                 sensors_fatal_error(__FUNCTION__, "out of memory"); 
    363  
    364         entry.chip.path = strdup(dev->path); 
     470        entry.chip.path = strdup(dev_path); 
    365471        if (!entry.chip.path) 
    366472                sensors_fatal_error(__FUNCTION__, "out of memory"); 
    367473 
    368         if (sscanf(dev->name, "%hd-%x", &entry.chip.bus.nr, &entry.chip.addr) == 2) { 
     474        if (sscanf(dev_name, "%hd-%x", &entry.chip.bus.nr, &entry.chip.addr) == 2) { 
    369475                /* find out if legacy ISA or not */ 
    370476                if (entry.chip.bus.nr == 9191) { 
     
    374480                        entry.chip.bus.type = SENSORS_BUS_TYPE_I2C; 
    375481                        snprintf(bus_path, sizeof(bus_path), 
    376                                 "%s/class/i2c-adapter/i2c-%d/device/name", 
     482                                "%s/class/i2c-adapter/i2c-%d/device", 
    377483                                sensors_sysfs_mount, entry.chip.bus.nr); 
    378484 
    379                         if ((bus_attr = sysfs_open_attribute(bus_path))) { 
    380                                 if (sysfs_read_attribute(bus_attr)) { 
    381                                         sysfs_close_attribute(bus_attr); 
    382                                         goto exit_free; 
    383                                 } 
    384  
    385                                 if (bus_attr->value 
    386                                  && !strncmp(bus_attr->value, "ISA ", 4)) { 
     485                        if ((bus_attr = sysfs_read_attr(bus_path, "name"))) { 
     486                                if (!strncmp(bus_attr, "ISA ", 4)) { 
    387487                                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA; 
    388488                                        entry.chip.bus.nr = 0; 
    389489                                } 
    390490 
    391                                 sysfs_close_attribute(bus_attr); 
     491                                free(bus_attr); 
    392492                        } 
    393493                } 
    394         } else if (sscanf(dev->name, "spi%hd.%d", &entry.chip.bus.nr, 
     494        } else if (sscanf(dev_name, "spi%hd.%d", &entry.chip.bus.nr, 
    395495                          &entry.chip.addr) == 2) { 
    396496                /* SPI */ 
    397497                entry.chip.bus.type = SENSORS_BUS_TYPE_SPI; 
    398         } else if (sscanf(dev->name, "%*[a-z0-9_].%d", &entry.chip.addr) == 1) { 
     498        } else if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry.chip.addr) == 1) { 
    399499                /* must be new ISA (platform driver) */ 
    400500                entry.chip.bus.type = SENSORS_BUS_TYPE_ISA; 
    401501                entry.chip.bus.nr = 0; 
    402         } else if (sscanf(dev->name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) { 
     502        } else if (sscanf(dev_name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) { 
    403503                /* PCI */ 
    404504                entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn; 
     
    412512        } 
    413513 
    414         if (sensors_read_dynamic_chip(&entry, dev) < 0) 
     514        if (sensors_read_dynamic_chip(&entry, dev_path) < 0) 
    415515                goto exit_free; 
    416516        if (!entry.subfeature) { /* No subfeature, discard chip */ 
     
    431531static int sensors_read_sysfs_chips_compat(void) 
    432532{ 
    433         struct sysfs_bus *bus; 
    434         struct dlist *devs; 
    435         struct sysfs_device *dev; 
    436         int ret = 0; 
    437  
    438         if (!(bus = sysfs_open_bus("i2c"))) { 
    439                 if (errno && errno != ENOENT) 
    440                         ret = -SENSORS_ERR_KERNEL; 
    441                 goto exit0; 
    442         } 
    443  
    444         if (!(devs = sysfs_get_bus_devices(bus))) { 
    445                 if (errno && errno != ENOENT) 
    446                         ret = -SENSORS_ERR_KERNEL; 
    447                 goto exit1; 
    448         } 
    449  
    450         dlist_for_each_data(devs, dev, struct sysfs_device) 
    451                 if ((ret = sensors_read_one_sysfs_chip(dev))) 
    452                         goto exit1; 
    453  
    454 exit1: 
    455         /* this frees bus and devs */ 
    456         sysfs_close_bus(bus); 
    457  
    458 exit0: 
    459         return ret; 
     533        int ret; 
     534 
     535        ret = sysfs_foreach_busdev("i2c", sensors_read_one_sysfs_chip); 
     536        if (ret && ret != ENOENT) 
     537                return -SENSORS_ERR_KERNEL; 
     538 
     539        return 0; 
     540} 
     541 
     542static int sensors_add_hwmon_device(char *path, const char *classdev) 
     543{ 
     544        char device[NAME_MAX]; 
     545        int path_off = strlen(path); 
     546        int dev_len; 
     547        (void)classdev; /* hide warning */ 
     548 
     549        snprintf(path + path_off, NAME_MAX - path_off, "/device"); 
     550        dev_len = readlink(path, device, NAME_MAX - 1); 
     551        if (dev_len < 0) 
     552                return -SENSORS_ERR_KERNEL; 
     553        device[dev_len] = '\0'; 
     554 
     555        return sensors_read_one_sysfs_chip(path, strrchr(device, '/') + 1); 
    460556} 
    461557 
     
    463559int sensors_read_sysfs_chips(void) 
    464560{ 
    465         struct sysfs_class *cls; 
    466         struct dlist *clsdevs; 
    467         struct sysfs_class_device *clsdev; 
    468         int ret = 0; 
    469  
    470         if (!(cls = sysfs_open_class("hwmon"))) { 
     561        int ret; 
     562 
     563        ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device); 
     564        if (ret == ENOENT) { 
    471565                /* compatibility function for kernel 2.6.n where n <= 13 */ 
    472566                return sensors_read_sysfs_chips_compat(); 
    473567        } 
    474568 
    475         if (!(clsdevs = sysfs_get_class_devices(cls))) { 
    476                 if (errno && errno != ENOENT) 
    477                         ret = -SENSORS_ERR_KERNEL; 
    478                 goto exit; 
    479         } 
    480  
    481         dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) { 
    482                 struct sysfs_device *dev; 
    483                 if (!(dev = sysfs_get_classdev_device(clsdev))) { 
    484                         ret = -SENSORS_ERR_KERNEL; 
    485                         goto exit; 
    486                 } 
    487                 if ((ret = sensors_read_one_sysfs_chip(dev))) 
    488                         goto exit; 
    489         } 
    490  
    491 exit: 
    492         /* this frees cls and clsdevs */ 
    493         sysfs_close_class(cls); 
     569        if (ret > 0) 
     570                ret = -SENSORS_ERR_KERNEL; 
    494571        return ret; 
     572} 
     573 
     574/* returns 0 if successful, !0 otherwise */ 
     575static int sensors_add_i2c_bus(char *path, const char *classdev) 
     576{ 
     577        sensors_bus entry; 
     578 
     579        if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 || 
     580            entry.bus.nr == 9191) /* legacy ISA */ 
     581                return 0; 
     582        entry.bus.type = SENSORS_BUS_TYPE_I2C; 
     583 
     584        /* Get the adapter name from the classdev "name" attribute 
     585         * (Linux 2.6.20 and later). If it fails, fall back to 
     586         * the device "name" attribute (for older kernels). */ 
     587        entry.adapter = sysfs_read_attr(path, "name"); 
     588        if (!entry.adapter) 
     589                entry.adapter = sysfs_read_attr(path, "device/name"); 
     590        if (entry.adapter) 
     591                sensors_add_proc_bus(&entry); 
     592 
     593        return 0; 
    495594} 
    496595 
     
    498597int sensors_read_sysfs_bus(void) 
    499598{ 
    500         struct sysfs_class *cls; 
    501         struct dlist *clsdevs; 
    502         struct sysfs_class_device *clsdev; 
    503         sensors_bus entry; 
    504         int ret = 0; 
    505  
    506         if (!(cls = sysfs_open_class("i2c-adapter"))) { 
    507                 if (errno && errno != ENOENT) 
    508                         ret = -SENSORS_ERR_KERNEL; 
    509                 goto exit0; 
    510         } 
    511  
    512         if (!(clsdevs = sysfs_get_class_devices(cls))) { 
    513                 if (errno && errno != ENOENT) 
    514                         ret = -SENSORS_ERR_KERNEL; 
    515                 goto exit1; 
    516         } 
    517  
    518         dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) { 
    519                 struct sysfs_device *dev; 
    520                 struct sysfs_attribute *attr; 
    521  
    522                 /* Get the adapter name from the classdev "name" attribute 
    523                  * (Linux 2.6.20 and later). If it fails, fall back to 
    524                  * the device "name" attribute (for older kernels). */ 
    525                 if (!(attr = sysfs_get_classdev_attr(clsdev, "name")) 
    526                  && !((dev = sysfs_get_classdev_device(clsdev)) && 
    527                       (attr = sysfs_get_device_attr(dev, "name")))) 
    528                         continue; 
    529  
    530                 if (sscanf(clsdev->name, "i2c-%hd", &entry.bus.nr) != 1 || 
    531                     entry.bus.nr == 9191) /* legacy ISA */ 
    532                         continue; 
    533                 entry.bus.type = SENSORS_BUS_TYPE_I2C; 
    534  
    535                 /* NB: attr->value[attr->len-1] == '\n'; chop that off */ 
    536                 entry.adapter = strndup(attr->value, attr->len - 1); 
    537                 if (!entry.adapter) 
    538                         sensors_fatal_error(__FUNCTION__, "out of memory"); 
    539  
    540                 sensors_add_proc_bus(&entry); 
    541         } 
    542  
    543 exit1: 
    544         /* this frees *cls _and_ *clsdevs */ 
    545         sysfs_close_class(cls); 
    546  
    547 exit0: 
    548         return ret; 
     599        int ret; 
     600 
     601        ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus); 
     602        if (ret && ret != ENOENT) 
     603                return -SENSORS_ERR_KERNEL; 
     604 
     605        return 0; 
    549606} 
    550607