LCOV - code coverage report
Current view: top level - misc/kabi/lvm2.git/lib/filters - filter-sysfs.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 81 118 68.6 %
Date: 2010-04-13 Functions: 12 12 100.0 %
Branches: 36 66 54.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
       3                 :            :  *
       4                 :            :  * This file is part of LVM2.
       5                 :            :  *
       6                 :            :  * This copyrighted material is made available to anyone wishing to use,
       7                 :            :  * modify, copy, or redistribute it subject to the terms and conditions
       8                 :            :  * of the GNU Lesser General Public License v.2.1.
       9                 :            :  *
      10                 :            :  * You should have received a copy of the GNU Lesser General Public License
      11                 :            :  * along with this program; if not, write to the Free Software Foundation,
      12                 :            :  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      13                 :            :  */
      14                 :            : 
      15                 :            : #include "lib.h"
      16                 :            : #include "filter-sysfs.h"
      17                 :            : #include "lvm-string.h"
      18                 :            : 
      19                 :            : #ifdef linux
      20                 :            : 
      21                 :            : #include <dirent.h>
      22                 :            : 
      23                 :          3 : static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len,
      24                 :            :                                 unsigned *sysfs_depth)
      25                 :            : {
      26                 :            :         struct stat info;
      27                 :            : 
      28                 :            :         /*
      29                 :            :          * unified classification directory for all kernel subsystems
      30                 :            :          *
      31                 :            :          * /sys/subsystem/block/devices
      32                 :            :          * |-- sda -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
      33                 :            :          * |-- sda1 -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
      34                 :            :          *  `-- sr0 -> ../../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
      35                 :            :          *
      36                 :            :          */
      37         [ +  - ]:          3 :         if (dm_snprintf(path, len, "%s/%s", sysfs_dir,
      38                 :            :                         "subsystem/block/devices") >= 0) {
      39         [ -  + ]:          3 :                 if (!stat(path, &info)) {
      40                 :          0 :                         *sysfs_depth = 0;
      41                 :          0 :                         return 1;
      42                 :            :                 }
      43                 :            :         }
      44                 :            : 
      45                 :            :         /*
      46                 :            :          * block subsystem as a class
      47                 :            :          *
      48                 :            :          * /sys/class/block
      49                 :            :          * |-- sda -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
      50                 :            :          * |-- sda1 -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
      51                 :            :          *  `-- sr0 -> ../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
      52                 :            :          *
      53                 :            :          */
      54         [ +  - ]:          3 :         if (dm_snprintf(path, len, "%s/%s", sysfs_dir, "class/block") >= 0) {
      55         [ +  - ]:          3 :                 if (!stat(path, &info)) {
      56                 :          3 :                         *sysfs_depth = 0;
      57                 :          3 :                         return 1;
      58                 :            :                 }
      59                 :            :         }
      60                 :            : 
      61                 :            :         /*
      62                 :            :          * old block subsystem layout with nested directories
      63                 :            :          *
      64                 :            :          * /sys/block/
      65                 :            :          * |-- sda
      66                 :            :          * |   |-- capability
      67                 :            :          * |   |-- dev
      68                 :            :          * ...
      69                 :            :          * |   |-- sda1
      70                 :            :          * |   |   |-- dev
      71                 :            :          * ...
      72                 :            :          * |
      73                 :            :          * `-- sr0
      74                 :            :          *     |-- capability
      75                 :            :          *     |-- dev
      76                 :            :          * ...
      77                 :            :          *
      78                 :            :          */
      79         [ #  # ]:          0 :         if (dm_snprintf(path, len, "%s/%s", sysfs_dir, "block") >= 0) {
      80         [ #  # ]:          0 :                 if (!stat(path, &info)) {
      81                 :          0 :                         *sysfs_depth = 1;
      82                 :          0 :                         return 1;
      83                 :            :                 }
      84                 :            :         }
      85                 :            : 
      86                 :          3 :         return 0;
      87                 :            : }
      88                 :            : 
      89                 :            : /*----------------------------------------------------------------
      90                 :            :  * We need to store a set of dev_t.
      91                 :            :  *--------------------------------------------------------------*/
      92                 :            : struct entry {
      93                 :            :         struct entry *next;
      94                 :            :         dev_t dev;
      95                 :            : };
      96                 :            : 
      97                 :            : #define SET_BUCKETS 64
      98                 :            : struct dev_set {
      99                 :            :         struct dm_pool *mem;
     100                 :            :         const char *sys_block;
     101                 :            :         unsigned sysfs_depth;
     102                 :            :         int initialised;
     103                 :            :         struct entry *slots[SET_BUCKETS];
     104                 :            : };
     105                 :            : 
     106                 :          3 : static struct dev_set *_dev_set_create(struct dm_pool *mem,
     107                 :            :                                        const char *sys_block,
     108                 :            :                                        unsigned sysfs_depth)
     109                 :            : {
     110                 :            :         struct dev_set *ds;
     111                 :            : 
     112         [ -  + ]:          3 :         if (!(ds = dm_pool_zalloc(mem, sizeof(*ds))))
     113                 :          0 :                 return NULL;
     114                 :            : 
     115                 :          3 :         ds->mem = mem;
     116                 :          3 :         ds->sys_block = dm_pool_strdup(mem, sys_block);
     117                 :          3 :         ds->sysfs_depth = sysfs_depth;
     118                 :          3 :         ds->initialised = 0;
     119                 :            : 
     120                 :          3 :         return ds;
     121                 :            : }
     122                 :            : 
     123                 :         78 : static unsigned _hash_dev(dev_t dev)
     124                 :            : {
     125                 :         78 :         return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1);
     126                 :            : }
     127                 :            : 
     128                 :            : /*
     129                 :            :  * Doesn't check that the set already contains dev.
     130                 :            :  */
     131                 :         39 : static int _set_insert(struct dev_set *ds, dev_t dev)
     132                 :            : {
     133                 :            :         struct entry *e;
     134                 :         39 :         unsigned h = _hash_dev(dev);
     135                 :            : 
     136         [ -  + ]:         39 :         if (!(e = dm_pool_alloc(ds->mem, sizeof(*e))))
     137                 :          0 :                 return 0;
     138                 :            : 
     139                 :         39 :         e->next = ds->slots[h];
     140                 :         39 :         e->dev = dev;
     141                 :         39 :         ds->slots[h] = e;
     142                 :            : 
     143                 :         39 :         return 1;
     144                 :            : }
     145                 :            : 
     146                 :         39 : static int _set_lookup(struct dev_set *ds, dev_t dev)
     147                 :            : {
     148                 :         39 :         unsigned h = _hash_dev(dev);
     149                 :            :         struct entry *e;
     150                 :            : 
     151         [ +  - ]:         49 :         for (e = ds->slots[h]; e; e = e->next)
     152         [ +  + ]:         49 :                 if (e->dev == dev)
     153                 :         39 :                         return 1;
     154                 :            : 
     155                 :         39 :         return 0;
     156                 :            : }
     157                 :            : 
     158                 :            : /*----------------------------------------------------------------
     159                 :            :  * filter methods
     160                 :            :  *--------------------------------------------------------------*/
     161                 :         39 : static int _parse_dev(const char *file, FILE *fp, dev_t *result)
     162                 :            : {
     163                 :            :         unsigned major, minor;
     164                 :            :         char buffer[64];
     165                 :            : 
     166         [ -  + ]:         39 :         if (!fgets(buffer, sizeof(buffer), fp)) {
     167                 :          0 :                 log_error("Empty sysfs device file: %s", file);
     168                 :          0 :                 return 0;
     169                 :            :         }
     170                 :            : 
     171         [ -  + ]:         39 :         if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
     172                 :          0 :                 log_info("sysfs device file not correct format");
     173                 :          0 :                 return 0;
     174                 :            :         }
     175                 :            : 
     176                 :         39 :         *result = makedev(major, minor);
     177                 :         39 :         return 1;
     178                 :            : }
     179                 :            : 
     180                 :         39 : static int _read_dev(const char *file, dev_t *result)
     181                 :            : {
     182                 :            :         int r;
     183                 :            :         FILE *fp;
     184                 :            : 
     185         [ -  + ]:         39 :         if (!(fp = fopen(file, "r"))) {
     186                 :          0 :                 log_sys_error("fopen", file);
     187                 :          0 :                 return 0;
     188                 :            :         }
     189                 :            : 
     190                 :         39 :         r = _parse_dev(file, fp, result);
     191                 :            : 
     192         [ -  + ]:         39 :         if (fclose(fp))
     193                 :          0 :                 log_sys_error("fclose", file);
     194                 :            : 
     195                 :         39 :         return r;
     196                 :            : }
     197                 :            : 
     198                 :            : /*
     199                 :            :  * Recurse through sysfs directories, inserting any devs found.
     200                 :            :  */
     201                 :          1 : static int _read_devs(struct dev_set *ds, const char *dir, unsigned sysfs_depth)
     202                 :            : {
     203                 :            :         struct dirent *d;
     204                 :            :         DIR *dr;
     205                 :            :         struct stat info;
     206                 :            :         char path[PATH_MAX];
     207                 :            :         char file[PATH_MAX];
     208                 :          1 :         dev_t dev = { 0 };
     209                 :          1 :         int r = 1;
     210                 :            : 
     211         [ -  + ]:          1 :         if (!(dr = opendir(dir))) {
     212                 :          0 :                 log_sys_error("opendir", dir);
     213                 :          0 :                 return 0;
     214                 :            :         }
     215                 :            : 
     216         [ +  + ]:         42 :         while ((d = readdir(dr))) {
     217 [ +  + ][ +  + ]:         41 :                 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
     218                 :          2 :                         continue;
     219                 :            : 
     220         [ -  + ]:         39 :                 if (dm_snprintf(path, sizeof(path), "%s/%s", dir,
     221                 :            :                                  d->d_name) < 0) {
     222                 :          0 :                         log_error("sysfs path name too long: %s in %s",
     223                 :            :                                   d->d_name, dir);
     224                 :          0 :                         continue;
     225                 :            :                 }
     226                 :            : 
     227                 :            :                 /* devices have a "dev" file */
     228         [ -  + ]:         39 :                 if (dm_snprintf(file, sizeof(file), "%s/dev", path) < 0) {
     229                 :          0 :                         log_error("sysfs path name too long: %s in %s",
     230                 :            :                                   d->d_name, dir);
     231                 :          0 :                         continue;
     232                 :            :                 }
     233                 :            : 
     234         [ +  - ]:         39 :                 if (!stat(file, &info)) {
     235                 :            :                         /* recurse if we found a device and expect subdirs */
     236         [ -  + ]:         39 :                         if (sysfs_depth)
     237                 :          0 :                                 _read_devs(ds, path, sysfs_depth - 1);
     238                 :            : 
     239                 :            :                         /* add the device we have found */
     240         [ +  - ]:         39 :                         if (_read_dev(file, &dev))
     241                 :         39 :                                 _set_insert(ds, dev);
     242                 :            :                 }
     243                 :            :         }
     244                 :            : 
     245         [ -  + ]:          1 :         if (closedir(dr))
     246                 :          0 :                 log_sys_error("closedir", dir);
     247                 :            : 
     248                 :          1 :         return r;
     249                 :            : }
     250                 :            : 
     251                 :          1 : static int _init_devs(struct dev_set *ds)
     252                 :            : {
     253         [ -  + ]:          1 :         if (!_read_devs(ds, ds->sys_block, ds->sysfs_depth)) {
     254                 :          0 :                 ds->initialised = -1;
     255                 :          0 :                 return 0;
     256                 :            :         }
     257                 :            : 
     258                 :          1 :         ds->initialised = 1;
     259                 :            : 
     260                 :          1 :         return 1;
     261                 :            : }
     262                 :            : 
     263                 :            : 
     264                 :         39 : static int _accept_p(struct dev_filter *f, struct device *dev)
     265                 :            : {
     266                 :         39 :         struct dev_set *ds = (struct dev_set *) f->private;
     267                 :            : 
     268         [ +  + ]:         39 :         if (!ds->initialised)
     269                 :          1 :                 _init_devs(ds);
     270                 :            : 
     271                 :            :         /* Pass through if initialisation failed */
     272         [ -  + ]:         39 :         if (ds->initialised != 1)
     273                 :          0 :                 return 1;
     274                 :            : 
     275         [ -  + ]:         39 :         if (!_set_lookup(ds, dev->dev)) {
     276                 :          0 :                 log_debug("%s: Skipping (sysfs)", dev_name(dev));
     277                 :          0 :                 return 0;
     278                 :            :         } else
     279                 :         39 :                 return 1;
     280                 :            : }
     281                 :            : 
     282                 :          3 : static void _destroy(struct dev_filter *f)
     283                 :            : {
     284                 :          3 :         struct dev_set *ds = (struct dev_set *) f->private;
     285                 :          3 :         dm_pool_destroy(ds->mem);
     286                 :          3 : }
     287                 :            : 
     288                 :          3 : struct dev_filter *sysfs_filter_create(const char *sysfs_dir)
     289                 :            : {
     290                 :            :         char sys_block[PATH_MAX];
     291                 :            :         unsigned sysfs_depth;
     292                 :            :         struct dm_pool *mem;
     293                 :            :         struct dev_set *ds;
     294                 :            :         struct dev_filter *f;
     295                 :            : 
     296         [ -  + ]:          3 :         if (!*sysfs_dir) {
     297                 :          0 :                 log_verbose("No proc filesystem found: skipping sysfs filter");
     298                 :          0 :                 return NULL;
     299                 :            :         }
     300                 :            : 
     301         [ -  + ]:          3 :         if (!_locate_sysfs_blocks(sysfs_dir, sys_block, sizeof(sys_block), &sysfs_depth))
     302                 :          0 :                 return NULL;
     303                 :            : 
     304         [ -  + ]:          3 :         if (!(mem = dm_pool_create("sysfs", 256))) {
     305                 :          0 :                 log_error("sysfs pool creation failed");
     306                 :          0 :                 return NULL;
     307                 :            :         }
     308                 :            : 
     309         [ -  + ]:          3 :         if (!(ds = _dev_set_create(mem, sys_block, sysfs_depth))) {
     310                 :          0 :                 log_error("sysfs dev_set creation failed");
     311                 :          0 :                 goto bad;
     312                 :            :         }
     313                 :            : 
     314         [ -  + ]:          3 :         if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
     315                 :          0 :                 goto_bad;
     316                 :            : 
     317                 :          3 :         f->passes_filter = _accept_p;
     318                 :          3 :         f->destroy = _destroy;
     319                 :          3 :         f->private = ds;
     320                 :          3 :         return f;
     321                 :            : 
     322                 :            :  bad:
     323                 :          0 :         dm_pool_destroy(mem);
     324                 :          3 :         return NULL;
     325                 :            : }
     326                 :            : 
     327                 :            : #else
     328                 :            : 
     329                 :            : struct dev_filter *sysfs_filter_create(const char *sysfs_dir __attribute((unused)))
     330                 :            : {
     331                 :            :         return NULL;
     332                 :            : }
     333                 :            : 
     334                 :            : #endif

Generated by: LCOV version 1.8