LCOV - code coverage report
Current view: top level - misc/kabi/lvm2.git/lib/device - dev-cache.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 232 399 58.1 %
Date: 2010-04-13 Functions: 24 29 82.8 %
Branches: 106 246 43.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
       3                 :            :  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
       4                 :            :  *
       5                 :            :  * This file is part of LVM2.
       6                 :            :  *
       7                 :            :  * This copyrighted material is made available to anyone wishing to use,
       8                 :            :  * modify, copy, or redistribute it subject to the terms and conditions
       9                 :            :  * of the GNU Lesser General Public License v.2.1.
      10                 :            :  *
      11                 :            :  * You should have received a copy of the GNU Lesser General Public License
      12                 :            :  * along with this program; if not, write to the Free Software Foundation,
      13                 :            :  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "lib.h"
      17                 :            : #include "dev-cache.h"
      18                 :            : #include "lvm-types.h"
      19                 :            : #include "btree.h"
      20                 :            : #include "filter.h"
      21                 :            : #include "filter-persistent.h"
      22                 :            : #include "toolcontext.h"
      23                 :            : 
      24                 :            : #include <unistd.h>
      25                 :            : #include <sys/param.h>
      26                 :            : #include <dirent.h>
      27                 :            : 
      28                 :            : struct dev_iter {
      29                 :            :         struct btree_iter *current;
      30                 :            :         struct dev_filter *filter;
      31                 :            : };
      32                 :            : 
      33                 :            : struct dir_list {
      34                 :            :         struct dm_list list;
      35                 :            :         char dir[0];
      36                 :            : };
      37                 :            : 
      38                 :            : static struct {
      39                 :            :         struct dm_pool *mem;
      40                 :            :         struct dm_hash_table *names;
      41                 :            :         struct btree *devices;
      42                 :            :         struct dm_regex *preferred_names_matcher;
      43                 :            : 
      44                 :            :         int has_scanned;
      45                 :            :         struct dm_list dirs;
      46                 :            :         struct dm_list files;
      47                 :            : 
      48                 :            : } _cache;
      49                 :            : 
      50                 :            : #define _alloc(x) dm_pool_zalloc(_cache.mem, (x))
      51                 :            : #define _free(x) dm_pool_free(_cache.mem, (x))
      52                 :            : #define _strdup(x) dm_pool_strdup(_cache.mem, (x))
      53                 :            : 
      54                 :            : static int _insert(const char *path, int rec);
      55                 :            : 
      56                 :          4 : struct device *dev_create_file(const char *filename, struct device *dev,
      57                 :            :                                struct str_list *alias, int use_malloc)
      58                 :            : {
      59                 :          4 :         int allocate = !dev;
      60                 :            : 
      61         [ +  - ]:          4 :         if (allocate) {
      62         [ +  - ]:          4 :                 if (use_malloc) {
      63         [ -  + ]:          4 :                         if (!(dev = dm_malloc(sizeof(*dev)))) {
      64                 :          0 :                                 log_error("struct device allocation failed");
      65                 :          0 :                                 return NULL;
      66                 :            :                         }
      67         [ -  + ]:          4 :                         if (!(alias = dm_malloc(sizeof(*alias)))) {
      68                 :          0 :                                 log_error("struct str_list allocation failed");
      69                 :          0 :                                 dm_free(dev);
      70                 :          0 :                                 return NULL;
      71                 :            :                         }
      72         [ -  + ]:          4 :                         if (!(alias->str = dm_strdup(filename))) {
      73                 :          0 :                                 log_error("filename strdup failed");
      74                 :          0 :                                 dm_free(dev);
      75                 :          0 :                                 dm_free(alias);
      76                 :          0 :                                 return NULL;
      77                 :            :                         }
      78                 :          4 :                         dev->flags = DEV_ALLOCED;
      79                 :            :                 } else {
      80         [ #  # ]:          0 :                         if (!(dev = _alloc(sizeof(*dev)))) {
      81                 :          0 :                                 log_error("struct device allocation failed");
      82                 :          0 :                                 return NULL;
      83                 :            :                         }
      84         [ #  # ]:          0 :                         if (!(alias = _alloc(sizeof(*alias)))) {
      85                 :          0 :                                 log_error("struct str_list allocation failed");
      86                 :          0 :                                 _free(dev);
      87                 :          0 :                                 return NULL;
      88                 :            :                         }
      89         [ #  # ]:          0 :                         if (!(alias->str = _strdup(filename))) {
      90                 :          0 :                                 log_error("filename strdup failed");
      91                 :          4 :                                 return NULL;
      92                 :            :                         }
      93                 :            :                 }
      94         [ #  # ]:          0 :         } else if (!(alias->str = dm_strdup(filename))) {
      95                 :          0 :                 log_error("filename strdup failed");
      96                 :          0 :                 return NULL;
      97                 :            :         }
      98                 :            : 
      99                 :          4 :         dev->flags |= DEV_REGULAR;
     100                 :          4 :         dm_list_init(&dev->aliases);
     101                 :          4 :         dm_list_add(&dev->aliases, &alias->list);
     102                 :          4 :         dev->end = UINT64_C(0);
     103                 :          4 :         dev->dev = 0;
     104                 :          4 :         dev->fd = -1;
     105                 :          4 :         dev->open_count = 0;
     106                 :          4 :         dev->block_size = -1;
     107                 :          4 :         dev->read_ahead = -1;
     108                 :          4 :         memset(dev->pvid, 0, sizeof(dev->pvid));
     109                 :          4 :         dm_list_init(&dev->open_list);
     110                 :            : 
     111                 :          4 :         return dev;
     112                 :            : }
     113                 :            : 
     114                 :         44 : static struct device *_dev_create(dev_t d)
     115                 :            : {
     116                 :            :         struct device *dev;
     117                 :            : 
     118         [ -  + ]:         44 :         if (!(dev = _alloc(sizeof(*dev)))) {
     119                 :          0 :                 log_error("struct device allocation failed");
     120                 :          0 :                 return NULL;
     121                 :            :         }
     122                 :         44 :         dev->flags = 0;
     123                 :         44 :         dm_list_init(&dev->aliases);
     124                 :         44 :         dev->dev = d;
     125                 :         44 :         dev->fd = -1;
     126                 :         44 :         dev->open_count = 0;
     127                 :         44 :         dev->block_size = -1;
     128                 :         44 :         dev->read_ahead = -1;
     129                 :         44 :         dev->end = UINT64_C(0);
     130                 :         44 :         memset(dev->pvid, 0, sizeof(dev->pvid));
     131                 :         44 :         dm_list_init(&dev->open_list);
     132                 :            : 
     133                 :         44 :         return dev;
     134                 :            : }
     135                 :            : 
     136                 :          0 : void dev_set_preferred_name(struct str_list *sl, struct device *dev)
     137                 :            : {
     138                 :            :         /*
     139                 :            :          * Don't interfere with ordering specified in config file.
     140                 :            :          */
     141         [ #  # ]:          0 :         if (_cache.preferred_names_matcher)
     142                 :          0 :                 return;
     143                 :            : 
     144                 :          0 :         log_debug("%s: New preferred name", sl->str);
     145                 :          0 :         dm_list_del(&sl->list);
     146                 :          0 :         dm_list_add_h(&dev->aliases, &sl->list);
     147                 :            : }
     148                 :            : 
     149                 :            : /* Return 1 if we prefer path1 else return 0 */
     150                 :         93 : static int _compare_paths(const char *path0, const char *path1)
     151                 :            : {
     152                 :         93 :         int slash0 = 0, slash1 = 0;
     153                 :            :         int m0, m1;
     154                 :            :         const char *p;
     155                 :            :         char p0[PATH_MAX], p1[PATH_MAX];
     156                 :            :         char *s0, *s1;
     157                 :            :         struct stat stat0, stat1;
     158                 :            : 
     159                 :            :         /*
     160                 :            :          * FIXME Better to compare patterns one-at-a-time against all names.
     161                 :            :          */
     162         [ -  + ]:         93 :         if (_cache.preferred_names_matcher) {
     163                 :          0 :                 m0 = dm_regex_match(_cache.preferred_names_matcher, path0);
     164                 :          0 :                 m1 = dm_regex_match(_cache.preferred_names_matcher, path1);
     165                 :            : 
     166         [ #  # ]:          0 :                 if (m0 != m1) {
     167         [ #  # ]:          0 :                         if (m0 < 0)
     168                 :          0 :                                 return 1;
     169         [ #  # ]:          0 :                         if (m1 < 0)
     170                 :          0 :                                 return 0;
     171         [ #  # ]:          0 :                         if (m0 < m1)
     172                 :          0 :                                 return 1;
     173         [ #  # ]:          0 :                         if (m1 < m0)
     174                 :          0 :                                 return 0;
     175                 :            :                 }
     176                 :            :         }
     177                 :            : 
     178                 :            :         /*
     179                 :            :          * Built-in rules.
     180                 :            :          */
     181                 :            : 
     182                 :            :         /* Return the path with fewer slashes */
     183         [ +  + ]:        384 :         for (p = path0; p++; p = (const char *) strchr(p, '/'))
     184                 :        291 :                 slash0++;
     185                 :            : 
     186         [ +  + ]:        367 :         for (p = path1; p++; p = (const char *) strchr(p, '/'))
     187                 :        274 :                 slash1++;
     188                 :            : 
     189         [ +  + ]:         93 :         if (slash0 < slash1)
     190                 :         31 :                 return 0;
     191         [ +  + ]:         62 :         if (slash1 < slash0)
     192                 :         47 :                 return 1;
     193                 :            : 
     194                 :         15 :         strncpy(p0, path0, PATH_MAX);
     195                 :         15 :         strncpy(p1, path1, PATH_MAX);
     196                 :         15 :         s0 = &p0[0] + 1;
     197                 :         15 :         s1 = &p1[0] + 1;
     198                 :            : 
     199                 :            :         /* We prefer symlinks - they exist for a reason!
     200                 :            :          * So we prefer a shorter path before the first symlink in the name.
     201                 :            :          * FIXME Configuration option to invert this? */
     202         [ +  + ]:         48 :         while (s0) {
     203                 :         44 :                 s0 = strchr(s0, '/');
     204                 :         44 :                 s1 = strchr(s1, '/');
     205         [ +  + ]:         44 :                 if (s0) {
     206                 :         29 :                         *s0 = '\0';
     207                 :         29 :                         *s1 = '\0';
     208                 :            :                 }
     209         [ -  + ]:         44 :                 if (lstat(p0, &stat0)) {
     210                 :          0 :                         log_sys_very_verbose("lstat", p0);
     211                 :          0 :                         return 1;
     212                 :            :                 }
     213         [ -  + ]:         44 :                 if (lstat(p1, &stat1)) {
     214                 :          0 :                         log_sys_very_verbose("lstat", p1);
     215                 :          0 :                         return 0;
     216                 :            :                 }
     217 [ +  + ][ -  + ]:         44 :                 if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode))
     218                 :          0 :                         return 0;
     219 [ +  + ][ +  + ]:         44 :                 if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode))
     220                 :         11 :                         return 1;
     221         [ +  + ]:         33 :                 if (s0) {
     222                 :         29 :                         *s0++ = '/';
     223                 :         29 :                         *s1++ = '/';
     224                 :            :                 }
     225                 :            :         }
     226                 :            : 
     227                 :            :         /* ASCII comparison */
     228         [ -  + ]:          4 :         if (strcmp(path0, path1) < 0)
     229                 :          0 :                 return 0;
     230                 :            :         else
     231                 :         93 :                 return 1;
     232                 :            : }
     233                 :            : 
     234                 :        137 : static int _add_alias(struct device *dev, const char *path)
     235                 :            : {
     236                 :        137 :         struct str_list *sl = _alloc(sizeof(*sl));
     237                 :            :         struct str_list *strl;
     238                 :            :         const char *oldpath;
     239                 :        137 :         int prefer_old = 1;
     240                 :            : 
     241         [ -  + ]:        137 :         if (!sl)
     242                 :          0 :                 return_0;
     243                 :            : 
     244                 :            :         /* Is name already there? */
     245         [ +  + ]:        333 :         dm_list_iterate_items(strl, &dev->aliases) {
     246         [ -  + ]:        196 :                 if (!strcmp(strl->str, path)) {
     247                 :          0 :                         log_debug("%s: Already in device cache", path);
     248                 :          0 :                         return 1;
     249                 :            :                 }
     250                 :            :         }
     251                 :            : 
     252         [ -  + ]:        137 :         if (!(sl->str = dm_pool_strdup(_cache.mem, path)))
     253                 :          0 :                 return_0;
     254                 :            : 
     255         [ +  + ]:        137 :         if (!dm_list_empty(&dev->aliases)) {
     256                 :         93 :                 oldpath = dm_list_item(dev->aliases.n, struct str_list)->str;
     257                 :         93 :                 prefer_old = _compare_paths(path, oldpath);
     258         [ +  + ]:         93 :                 log_debug("%s: Aliased to %s in device cache%s",
     259                 :            :                           path, oldpath, prefer_old ? "" : " (preferred name)");
     260                 :            : 
     261                 :            :         } else
     262                 :         44 :                 log_debug("%s: Added to device cache", path);
     263                 :            : 
     264         [ +  + ]:        137 :         if (prefer_old)
     265                 :        106 :                 dm_list_add(&dev->aliases, &sl->list);
     266                 :            :         else
     267                 :         31 :                 dm_list_add_h(&dev->aliases, &sl->list);
     268                 :            : 
     269                 :        137 :         return 1;
     270                 :            : }
     271                 :            : 
     272                 :            : /*
     273                 :            :  * Either creates a new dev, or adds an alias to
     274                 :            :  * an existing dev.
     275                 :            :  */
     276                 :        137 : static int _insert_dev(const char *path, dev_t d)
     277                 :            : {
     278                 :            :         struct device *dev;
     279                 :            :         static dev_t loopfile_count = 0;
     280                 :        137 :         int loopfile = 0;
     281                 :            : 
     282                 :            :         /* Generate pretend device numbers for loopfiles */
     283         [ -  + ]:        137 :         if (!d) {
     284         [ #  # ]:          0 :                 if (dm_hash_lookup(_cache.names, path))
     285                 :          0 :                         return 1;
     286                 :          0 :                 d = ++loopfile_count;
     287                 :          0 :                 loopfile = 1;
     288                 :            :         }
     289                 :            : 
     290                 :            :         /* is this device already registered ? */
     291         [ +  + ]:        137 :         if (!(dev = (struct device *) btree_lookup(_cache.devices,
     292                 :            :                                                    (uint32_t) d))) {
     293                 :            :                 /* create new device */
     294         [ -  + ]:         44 :                 if (loopfile) {
     295         [ #  # ]:          0 :                         if (!(dev = dev_create_file(path, NULL, NULL, 0)))
     296                 :          0 :                                 return_0;
     297         [ -  + ]:         44 :                 } else if (!(dev = _dev_create(d)))
     298                 :          0 :                         return_0;
     299                 :            : 
     300         [ -  + ]:         44 :                 if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
     301                 :          0 :                         log_error("Couldn't insert device into binary tree.");
     302                 :          0 :                         _free(dev);
     303                 :          0 :                         return 0;
     304                 :            :                 }
     305                 :            :         }
     306                 :            : 
     307 [ +  - ][ -  + ]:        137 :         if (!loopfile && !_add_alias(dev, path)) {
     308                 :          0 :                 log_error("Couldn't add alias to dev cache.");
     309                 :          0 :                 return 0;
     310                 :            :         }
     311                 :            : 
     312         [ -  + ]:        137 :         if (!dm_hash_insert(_cache.names, path, dev)) {
     313                 :          0 :                 log_error("Couldn't add name to hash in dev cache.");
     314                 :          0 :                 return 0;
     315                 :            :         }
     316                 :            : 
     317                 :        137 :         return 1;
     318                 :            : }
     319                 :            : 
     320                 :        386 : static char *_join(const char *dir, const char *name)
     321                 :            : {
     322                 :        386 :         size_t len = strlen(dir) + strlen(name) + 2;
     323                 :        386 :         char *r = dm_malloc(len);
     324         [ +  - ]:        386 :         if (r)
     325                 :        386 :                 snprintf(r, len, "%s/%s", dir, name);
     326                 :            : 
     327                 :        386 :         return r;
     328                 :            : }
     329                 :            : 
     330                 :            : /*
     331                 :            :  * Get rid of extra slashes in the path string.
     332                 :            :  */
     333                 :        386 : static void _collapse_slashes(char *str)
     334                 :            : {
     335                 :            :         char *ptr;
     336                 :        386 :         int was_slash = 0;
     337                 :            : 
     338         [ +  + ]:       7014 :         for (ptr = str; *ptr; ptr++) {
     339         [ +  + ]:       6628 :                 if (*ptr == '/') {
     340         [ -  + ]:       1041 :                         if (was_slash)
     341                 :          0 :                                 continue;
     342                 :            : 
     343                 :       1041 :                         was_slash = 1;
     344                 :            :                 } else
     345                 :       5587 :                         was_slash = 0;
     346                 :       6628 :                 *str++ = *ptr;
     347                 :            :         }
     348                 :            : 
     349                 :        386 :         *str = *ptr;
     350                 :        386 : }
     351                 :            : 
     352                 :         19 : static int _insert_dir(const char *dir)
     353                 :            : {
     354                 :         19 :         int n, dirent_count, r = 1;
     355                 :            :         struct dirent **dirent;
     356                 :            :         char *path;
     357                 :            : 
     358                 :         19 :         dirent_count = scandir(dir, &dirent, NULL, alphasort);
     359         [ +  - ]:         19 :         if (dirent_count > 0) {
     360         [ +  + ]:        444 :                 for (n = 0; n < dirent_count; n++) {
     361         [ +  + ]:        425 :                         if (dirent[n]->d_name[0] == '.') {
     362                 :         39 :                                 free(dirent[n]);
     363                 :         39 :                                 continue;
     364                 :            :                         }
     365                 :            : 
     366         [ -  + ]:        386 :                         if (!(path = _join(dir, dirent[n]->d_name)))
     367                 :          0 :                                 return_0;
     368                 :            : 
     369                 :        386 :                         _collapse_slashes(path);
     370                 :        386 :                         r &= _insert(path, 1);
     371                 :        386 :                         dm_free(path);
     372                 :            : 
     373                 :        386 :                         free(dirent[n]);
     374                 :            :                 }
     375                 :         19 :                 free(dirent);
     376                 :            :         }
     377                 :            : 
     378                 :         19 :         return r;
     379                 :            : }
     380                 :            : 
     381                 :          0 : static int _insert_file(const char *path)
     382                 :            : {
     383                 :            :         struct stat info;
     384                 :            : 
     385         [ #  # ]:          0 :         if (stat(path, &info) < 0) {
     386                 :          0 :                 log_sys_very_verbose("stat", path);
     387                 :          0 :                 return 0;
     388                 :            :         }
     389                 :            : 
     390         [ #  # ]:          0 :         if (!S_ISREG(info.st_mode)) {
     391                 :          0 :                 log_debug("%s: Not a regular file", path);
     392                 :          0 :                 return 0;
     393                 :            :         }
     394                 :            : 
     395         [ #  # ]:          0 :         if (!_insert_dev(path, 0))
     396                 :          0 :                 return_0;
     397                 :            : 
     398                 :          0 :         return 1;
     399                 :            : }
     400                 :            : 
     401                 :        402 : static int _insert(const char *path, int rec)
     402                 :            : {
     403                 :            :         struct stat info;
     404                 :        402 :         int r = 0;
     405                 :            : 
     406         [ -  + ]:        402 :         if (stat(path, &info) < 0) {
     407                 :          0 :                 log_sys_very_verbose("stat", path);
     408                 :          0 :                 return 0;
     409                 :            :         }
     410                 :            : 
     411         [ +  + ]:        402 :         if (S_ISDIR(info.st_mode)) {    /* add a directory */
     412                 :            :                 /* check it's not a symbolic link */
     413         [ -  + ]:         19 :                 if (lstat(path, &info) < 0) {
     414                 :          0 :                         log_sys_very_verbose("lstat", path);
     415                 :          0 :                         return 0;
     416                 :            :                 }
     417                 :            : 
     418         [ +  + ]:         19 :                 if (S_ISLNK(info.st_mode)) {
     419                 :          1 :                         log_debug("%s: Symbolic link to directory", path);
     420                 :          1 :                         return 0;
     421                 :            :                 }
     422                 :            : 
     423         [ +  - ]:         18 :                 if (rec)
     424                 :         18 :                         r = _insert_dir(path);
     425                 :            : 
     426                 :            :         } else {                /* add a device */
     427         [ +  + ]:        383 :                 if (!S_ISBLK(info.st_mode)) {
     428                 :        246 :                         log_debug("%s: Not a block device", path);
     429                 :        246 :                         return 0;
     430                 :            :                 }
     431                 :            : 
     432         [ -  + ]:        137 :                 if (!_insert_dev(path, info.st_rdev))
     433                 :          0 :                         return_0;
     434                 :            : 
     435                 :        137 :                 r = 1;
     436                 :            :         }
     437                 :            : 
     438                 :        402 :         return r;
     439                 :            : }
     440                 :            : 
     441                 :          1 : static void _full_scan(int dev_scan)
     442                 :            : {
     443                 :            :         struct dir_list *dl;
     444                 :            : 
     445 [ -  + ][ #  # ]:          1 :         if (_cache.has_scanned && !dev_scan)
     446                 :          0 :                 return;
     447                 :            : 
     448         [ +  + ]:          2 :         dm_list_iterate_items(dl, &_cache.dirs)
     449                 :          1 :                 _insert_dir(dl->dir);
     450                 :            : 
     451         [ -  + ]:          1 :         dm_list_iterate_items(dl, &_cache.files)
     452                 :          0 :                 _insert_file(dl->dir);
     453                 :            : 
     454                 :          1 :         _cache.has_scanned = 1;
     455                 :          1 :         init_full_scan_done(1);
     456                 :            : }
     457                 :            : 
     458                 :          0 : int dev_cache_has_scanned(void)
     459                 :            : {
     460                 :          0 :         return _cache.has_scanned;
     461                 :            : }
     462                 :            : 
     463                 :          1 : void dev_cache_scan(int do_scan)
     464                 :            : {
     465         [ +  - ]:          1 :         if (!do_scan)
     466                 :          1 :                 _cache.has_scanned = 1;
     467                 :            :         else
     468                 :          0 :                 _full_scan(1);
     469                 :          1 : }
     470                 :            : 
     471                 :          3 : static int _init_preferred_names(struct cmd_context *cmd)
     472                 :            : {
     473                 :            :         const struct config_node *cn;
     474                 :            :         struct config_value *v;
     475                 :          3 :         struct dm_pool *scratch = NULL;
     476                 :            :         char **regex;
     477                 :          3 :         unsigned count = 0;
     478                 :          3 :         int i, r = 0;
     479                 :            : 
     480                 :          3 :         _cache.preferred_names_matcher = NULL;
     481                 :            : 
     482 [ +  - ][ +  - ]:          3 :         if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
     483                 :          3 :             cn->v->type == CFG_EMPTY_ARRAY) {
     484                 :          3 :                 log_very_verbose("devices/preferred_names not found in config file: "
     485                 :            :                                  "using built-in preferences");
     486                 :          3 :                 return 1;
     487                 :            :         }
     488                 :            : 
     489         [ #  # ]:          0 :         for (v = cn->v; v; v = v->next) {
     490         [ #  # ]:          0 :                 if (v->type != CFG_STRING) {
     491                 :          0 :                         log_error("preferred_names patterns must be enclosed in quotes");
     492                 :          0 :                         return 0;
     493                 :            :                 }
     494                 :            : 
     495                 :          0 :                 count++;
     496                 :            :         }
     497                 :            : 
     498         [ #  # ]:          0 :         if (!(scratch = dm_pool_create("preferred device name matcher", 1024)))
     499                 :          0 :                 return_0;
     500                 :            : 
     501         [ #  # ]:          0 :         if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
     502                 :          0 :                 log_error("Failed to allocate preferred device name "
     503                 :            :                           "pattern list.");
     504                 :          0 :                 goto out;
     505                 :            :         }
     506                 :            : 
     507         [ #  # ]:          0 :         for (v = cn->v, i = count - 1; v; v = v->next, i--) {
     508         [ #  # ]:          0 :                 if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) {
     509                 :          0 :                         log_error("Failed to allocate a preferred device name "
     510                 :            :                                   "pattern.");
     511                 :          0 :                         goto out;
     512                 :            :                 }
     513                 :            :         }
     514                 :            : 
     515         [ #  # ]:          0 :         if (!(_cache.preferred_names_matcher =
     516                 :          0 :                 dm_regex_create(_cache.mem,(const char **) regex, count))) {
     517                 :          0 :                 log_error("Preferred device name pattern matcher creation failed.");
     518                 :          0 :                 goto out;
     519                 :            :         }
     520                 :            : 
     521                 :          0 :         r = 1;
     522                 :            : 
     523                 :            : out:
     524                 :          0 :         dm_pool_destroy(scratch);
     525                 :            : 
     526                 :          3 :         return r;
     527                 :            : }
     528                 :            : 
     529                 :          3 : int dev_cache_init(struct cmd_context *cmd)
     530                 :            : {
     531                 :          3 :         _cache.names = NULL;
     532                 :          3 :         _cache.has_scanned = 0;
     533                 :            : 
     534         [ -  + ]:          3 :         if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
     535                 :          0 :                 return_0;
     536                 :            : 
     537         [ -  + ]:          3 :         if (!(_cache.names = dm_hash_create(128))) {
     538                 :          0 :                 dm_pool_destroy(_cache.mem);
     539                 :          0 :                 _cache.mem = 0;
     540                 :          0 :                 return_0;
     541                 :            :         }
     542                 :            : 
     543         [ -  + ]:          3 :         if (!(_cache.devices = btree_create(_cache.mem))) {
     544                 :          0 :                 log_error("Couldn't create binary tree for dev-cache.");
     545                 :          0 :                 goto bad;
     546                 :            :         }
     547                 :            : 
     548                 :          3 :         dm_list_init(&_cache.dirs);
     549                 :          3 :         dm_list_init(&_cache.files);
     550                 :            : 
     551         [ -  + ]:          3 :         if (!_init_preferred_names(cmd))
     552                 :          0 :                 goto_bad;
     553                 :            : 
     554                 :          3 :         return 1;
     555                 :            : 
     556                 :            :       bad:
     557                 :          0 :         dev_cache_exit();
     558                 :          3 :         return 0;
     559                 :            : }
     560                 :            : 
     561                 :        137 : static void _check_closed(struct device *dev)
     562                 :            : {
     563         [ -  + ]:        137 :         if (dev->fd >= 0)
     564                 :          0 :                 log_error("Device '%s' has been left open.", dev_name(dev));
     565                 :        137 : }
     566                 :            : 
     567                 :          3 : static void _check_for_open_devices(void)
     568                 :            : {
     569                 :          3 :         dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed);
     570                 :          3 : }
     571                 :            : 
     572                 :          3 : void dev_cache_exit(void)
     573                 :            : {
     574         [ +  - ]:          3 :         if (_cache.names)
     575                 :          3 :                 _check_for_open_devices();
     576                 :            : 
     577         [ -  + ]:          3 :         if (_cache.preferred_names_matcher)
     578                 :          0 :                 _cache.preferred_names_matcher = NULL;
     579                 :            : 
     580         [ +  - ]:          3 :         if (_cache.mem) {
     581                 :          3 :                 dm_pool_destroy(_cache.mem);
     582                 :          3 :                 _cache.mem = NULL;
     583                 :            :         }
     584                 :            : 
     585         [ +  - ]:          3 :         if (_cache.names) {
     586                 :          3 :                 dm_hash_destroy(_cache.names);
     587                 :          3 :                 _cache.names = NULL;
     588                 :            :         }
     589                 :            : 
     590                 :          3 :         _cache.devices = NULL;
     591                 :          3 :         _cache.has_scanned = 0;
     592                 :          3 :         dm_list_init(&_cache.dirs);
     593                 :          3 :         dm_list_init(&_cache.files);
     594                 :          3 : }
     595                 :            : 
     596                 :          3 : int dev_cache_add_dir(const char *path)
     597                 :            : {
     598                 :            :         struct dir_list *dl;
     599                 :            :         struct stat st;
     600                 :            : 
     601         [ -  + ]:          3 :         if (stat(path, &st)) {
     602                 :          0 :                 log_error("Ignoring %s: %s", path, strerror(errno));
     603                 :            :                 /* But don't fail */
     604                 :          0 :                 return 1;
     605                 :            :         }
     606                 :            : 
     607         [ -  + ]:          3 :         if (!S_ISDIR(st.st_mode)) {
     608                 :          0 :                 log_error("Ignoring %s: Not a directory", path);
     609                 :          0 :                 return 1;
     610                 :            :         }
     611                 :            : 
     612         [ -  + ]:          3 :         if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
     613                 :          0 :                 log_error("dir_list allocation failed");
     614                 :          0 :                 return 0;
     615                 :            :         }
     616                 :            : 
     617                 :          3 :         strcpy(dl->dir, path);
     618                 :          3 :         dm_list_add(&_cache.dirs, &dl->list);
     619                 :          3 :         return 1;
     620                 :            : }
     621                 :            : 
     622                 :          0 : int dev_cache_add_loopfile(const char *path)
     623                 :            : {
     624                 :            :         struct dir_list *dl;
     625                 :            :         struct stat st;
     626                 :            : 
     627         [ #  # ]:          0 :         if (stat(path, &st)) {
     628                 :          0 :                 log_error("Ignoring %s: %s", path, strerror(errno));
     629                 :            :                 /* But don't fail */
     630                 :          0 :                 return 1;
     631                 :            :         }
     632                 :            : 
     633         [ #  # ]:          0 :         if (!S_ISREG(st.st_mode)) {
     634                 :          0 :                 log_error("Ignoring %s: Not a regular file", path);
     635                 :          0 :                 return 1;
     636                 :            :         }
     637                 :            : 
     638         [ #  # ]:          0 :         if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
     639                 :          0 :                 log_error("dir_list allocation failed for file");
     640                 :          0 :                 return 0;
     641                 :            :         }
     642                 :            : 
     643                 :          0 :         strcpy(dl->dir, path);
     644                 :          0 :         dm_list_add(&_cache.files, &dl->list);
     645                 :          0 :         return 1;
     646                 :            : }
     647                 :            : 
     648                 :            : /* Check cached device name is still valid before returning it */
     649                 :            : /* This should be a rare occurrence */
     650                 :            : /* set quiet if the cache is expected to be out-of-date */
     651                 :            : /* FIXME Make rest of code pass/cache struct device instead of dev_name */
     652                 :          0 : const char *dev_name_confirmed(struct device *dev, int quiet)
     653                 :            : {
     654                 :            :         struct stat buf;
     655                 :            :         const char *name;
     656                 :            :         int r;
     657                 :            : 
     658         [ #  # ]:          0 :         if ((dev->flags & DEV_REGULAR))
     659                 :          0 :                 return dev_name(dev);
     660                 :            : 
     661 [ #  # ][ #  # ]:          0 :         while ((r = stat(name = dm_list_item(dev->aliases.n,
     662                 :            :                                           struct str_list)->str, &buf)) ||
     663                 :          0 :                (buf.st_rdev != dev->dev)) {
     664         [ #  # ]:          0 :                 if (r < 0) {
     665         [ #  # ]:          0 :                         if (quiet)
     666                 :          0 :                                 log_sys_debug("stat", name);
     667                 :            :                         else
     668                 :          0 :                                 log_sys_error("stat", name);
     669                 :            :                 }
     670         [ #  # ]:          0 :                 if (quiet)
     671                 :          0 :                         log_debug("Path %s no longer valid for device(%d,%d)",
     672                 :            :                                   name, (int) MAJOR(dev->dev),
     673                 :            :                                   (int) MINOR(dev->dev));
     674                 :            :                 else
     675                 :          0 :                         log_error("Path %s no longer valid for device(%d,%d)",
     676                 :            :                                   name, (int) MAJOR(dev->dev),
     677                 :            :                                   (int) MINOR(dev->dev));
     678                 :            : 
     679                 :            :                 /* Remove the incorrect hash entry */
     680                 :          0 :                 dm_hash_remove(_cache.names, name);
     681                 :            : 
     682                 :            :                 /* Leave list alone if there isn't an alternative name */
     683                 :            :                 /* so dev_name will always find something to return. */
     684                 :            :                 /* Otherwise add the name to the correct device. */
     685         [ #  # ]:          0 :                 if (dm_list_size(&dev->aliases) > 1) {
     686                 :          0 :                         dm_list_del(dev->aliases.n);
     687         [ #  # ]:          0 :                         if (!r)
     688                 :          0 :                                 _insert(name, 0);
     689                 :          0 :                         continue;
     690                 :            :                 }
     691                 :            : 
     692                 :            :                 /* Scanning issues this inappropriately sometimes. */
     693                 :          0 :                 log_debug("Aborting - please provide new pathname for what "
     694                 :            :                           "used to be %s", name);
     695                 :          0 :                 return NULL;
     696                 :            :         }
     697                 :            : 
     698                 :          0 :         return dev_name(dev);
     699                 :            : }
     700                 :            : 
     701                 :         16 : struct device *dev_cache_get(const char *name, struct dev_filter *f)
     702                 :            : {
     703                 :            :         struct stat buf;
     704                 :         16 :         struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
     705                 :            : 
     706   [ -  +  #  # ]:         16 :         if (d && (d->flags & DEV_REGULAR))
     707                 :          0 :                 return d;
     708                 :            : 
     709                 :            :         /* If the entry's wrong, remove it */
     710 [ -  + ][ #  # ]:         16 :         if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
                 [ #  # ]
     711                 :          0 :                 dm_hash_remove(_cache.names, name);
     712                 :          0 :                 d = NULL;
     713                 :            :         }
     714                 :            : 
     715         [ +  - ]:         16 :         if (!d) {
     716                 :         16 :                 _insert(name, 0);
     717                 :         16 :                 d = (struct device *) dm_hash_lookup(_cache.names, name);
     718         [ -  + ]:         16 :                 if (!d) {
     719                 :          0 :                         _full_scan(0);
     720                 :          0 :                         d = (struct device *) dm_hash_lookup(_cache.names, name);
     721                 :            :                 }
     722                 :            :         }
     723                 :            : 
     724 [ +  - ][ -  + ]:         16 :         return (d && (!f || (d->flags & DEV_REGULAR) ||
           [ #  #  #  # ]
     725                 :          0 :                       f->passes_filter(f, d))) ? d : NULL;
     726                 :            : }
     727                 :            : 
     728                 :          1 : struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
     729                 :            : {
     730                 :          1 :         struct dev_iter *di = dm_malloc(sizeof(*di));
     731                 :            : 
     732         [ -  + ]:          1 :         if (!di) {
     733                 :          0 :                 log_error("dev_iter allocation failed");
     734                 :          0 :                 return NULL;
     735                 :            :         }
     736                 :            : 
     737 [ -  + ][ #  # ]:          1 :         if (dev_scan && !trust_cache()) {
     738                 :            :                 /* Flag gets reset between each command */
     739         [ #  # ]:          0 :                 if (!full_scan_done())
     740                 :          0 :                         persistent_filter_wipe(f); /* Calls _full_scan(1) */
     741                 :            :         } else
     742                 :          1 :                 _full_scan(0);
     743                 :            : 
     744                 :          1 :         di->current = btree_first(_cache.devices);
     745                 :          1 :         di->filter = f;
     746                 :            : 
     747                 :          1 :         return di;
     748                 :            : }
     749                 :            : 
     750                 :          1 : void dev_iter_destroy(struct dev_iter *iter)
     751                 :            : {
     752                 :          1 :         dm_free(iter);
     753                 :          1 : }
     754                 :            : 
     755                 :         39 : static struct device *_iter_next(struct dev_iter *iter)
     756                 :            : {
     757                 :         39 :         struct device *d = btree_get_data(iter->current);
     758                 :         39 :         iter->current = btree_next(iter->current);
     759                 :         39 :         return d;
     760                 :            : }
     761                 :            : 
     762                 :          1 : struct device *dev_iter_get(struct dev_iter *iter)
     763                 :            : {
     764         [ +  + ]:         40 :         while (iter->current) {
     765                 :         39 :                 struct device *d = _iter_next(iter);
     766 [ +  -  +  -  - :         78 :                 if (!iter->filter || (d->flags & DEV_REGULAR) ||
                      + ]
     767                 :         39 :                     iter->filter->passes_filter(iter->filter, d))
     768                 :          0 :                         return d;
     769                 :            :         }
     770                 :            : 
     771                 :          1 :         return NULL;
     772                 :            : }
     773                 :            : 
     774                 :          4 : int dev_fd(struct device *dev)
     775                 :            : {
     776                 :          4 :         return dev->fd;
     777                 :            : }
     778                 :            : 
     779                 :         90 : const char *dev_name(const struct device *dev)
     780                 :            : {
     781         [ +  - ]:         90 :         return (dev) ? dm_list_item(dev->aliases.n, struct str_list)->str :
     782                 :            :             "unknown device";
     783                 :            : }

Generated by: LCOV version 1.8