(root)/
util-linux-2.39/
libblkid/
src/
cache.c
       1  /*
       2   * cache.c - allocation/initialization/free routines for cache
       3   *
       4   * Copyright (C) 2001 Andreas Dilger
       5   * Copyright (C) 2003 Theodore Ts'o
       6   *
       7   * %Begin-Header%
       8   * This file may be redistributed under the terms of the
       9   * GNU Lesser General Public License.
      10   * %End-Header%
      11   */
      12  
      13  #ifdef HAVE_UNISTD_H
      14  #include <unistd.h>
      15  #endif
      16  #ifdef HAVE_ERRNO_H
      17  #include <errno.h>
      18  #endif
      19  #include <stdlib.h>
      20  #include <string.h>
      21  #ifdef HAVE_SYS_STAT_H
      22  #include <sys/stat.h>
      23  #endif
      24  #include "blkidP.h"
      25  #include "env.h"
      26  
      27  /**
      28   * SECTION:cache
      29   * @title: Cache
      30   * @short_description: basic routines to work with libblkid cache
      31   *
      32   * Block device information is normally kept in a cache file blkid.tab and is
      33   * verified to still be valid before being returned to the user (if the user has
      34   * read permission on the raw block device, otherwise not).  The cache file also
      35   * allows unprivileged users (normally anyone other than root, or those not in the
      36   * "disk" group) to locate devices by label/id.  The standard location of the
      37   * cache file can be overridden by the environment variable BLKID_FILE.
      38   *
      39   * In situations where one is getting information about a single known device, it
      40   * does not impact performance whether the cache is used or not (unless you are
      41   * not able to read the block device directly).  If you are dealing with multiple
      42   * devices, use of the cache is highly recommended (even if empty) as devices will
      43   * be scanned at most one time and the on-disk cache will be updated if possible.
      44   * There is rarely a reason not to use the cache.
      45   *
      46   * In some cases (modular kernels), block devices are not even visible until after
      47   * they are accessed the first time, so it is critical that there is some way to
      48   * locate these devices without enumerating only visible devices, so the use of
      49   * the cache file is required in this situation.
      50   */
      51  static const char *get_default_cache_filename(void)
      52  {
      53  	struct stat st;
      54  
      55  	if (stat(BLKID_RUNTIME_TOPDIR, &st) == 0 && S_ISDIR(st.st_mode))
      56  		return BLKID_CACHE_FILE;	/* cache in /run */
      57  
      58  	return BLKID_CACHE_FILE_OLD;	/* cache in /etc */
      59  }
      60  
      61  /* returns allocated path to cache */
      62  char *blkid_get_cache_filename(struct blkid_config *conf)
      63  {
      64  	char *filename;
      65  
      66  	filename = safe_getenv("BLKID_FILE");
      67  	if (filename)
      68  		filename = strdup(filename);
      69  	else if (conf)
      70  		filename = conf->cachefile ? strdup(conf->cachefile) : NULL;
      71  	else {
      72  		struct blkid_config *c = blkid_read_config(NULL);
      73  		if (!c)
      74  			filename = strdup(get_default_cache_filename());
      75  		else {
      76  			filename = c->cachefile;  /* already allocated */
      77  			c->cachefile = NULL;
      78  			blkid_free_config(c);
      79  		}
      80  	}
      81  	return filename;
      82  }
      83  
      84  /**
      85   * blkid_get_cache:
      86   * @cache: pointer to return cache handler
      87   * @filename: path to the cache file or NULL for the default path
      88   *
      89   * Allocates and initializes library cache handler.
      90   *
      91   * Returns: 0 on success or number less than zero in case of error.
      92   */
      93  int blkid_get_cache(blkid_cache *ret_cache, const char *filename)
      94  {
      95  	blkid_cache cache;
      96  
      97  	if (!ret_cache)
      98  		return -BLKID_ERR_PARAM;
      99  
     100  	if (!(cache = calloc(1, sizeof(struct blkid_struct_cache))))
     101  		return -BLKID_ERR_MEM;
     102  
     103  	DBG(CACHE, ul_debugobj(cache, "alloc (from %s)", filename ? filename : "default cache"));
     104  	INIT_LIST_HEAD(&cache->bic_devs);
     105  	INIT_LIST_HEAD(&cache->bic_tags);
     106  
     107  	if (filename && !*filename)
     108  		filename = NULL;
     109  	if (filename)
     110  		cache->bic_filename = strdup(filename);
     111  	else
     112  		cache->bic_filename = blkid_get_cache_filename(NULL);
     113  
     114  	blkid_read_cache(cache);
     115  	*ret_cache = cache;
     116  	return 0;
     117  }
     118  
     119  /**
     120   * blkid_put_cache:
     121   * @cache: cache handler
     122   *
     123   * Saves changes to cache file.
     124   */
     125  void blkid_put_cache(blkid_cache cache)
     126  {
     127  	if (!cache)
     128  		return;
     129  
     130  	(void) blkid_flush_cache(cache);
     131  
     132  	DBG(CACHE, ul_debugobj(cache, "freeing cache struct"));
     133  
     134  	/* DBG(CACHE, ul_debug_dump_cache(cache)); */
     135  
     136  	while (!list_empty(&cache->bic_devs)) {
     137  		blkid_dev dev = list_entry(cache->bic_devs.next,
     138  					   struct blkid_struct_dev,
     139  					    bid_devs);
     140  		blkid_free_dev(dev);
     141  	}
     142  
     143  	DBG(CACHE, ul_debugobj(cache, "freeing cache tag heads"));
     144  	while (!list_empty(&cache->bic_tags)) {
     145  		blkid_tag tag = list_entry(cache->bic_tags.next,
     146  					   struct blkid_struct_tag,
     147  					   bit_tags);
     148  
     149  		while (!list_empty(&tag->bit_names)) {
     150  			blkid_tag bad = list_entry(tag->bit_names.next,
     151  						   struct blkid_struct_tag,
     152  						   bit_names);
     153  
     154  			DBG(CACHE, ul_debugobj(cache, "warning: unfreed tag %s=%s",
     155  						bad->bit_name, bad->bit_val));
     156  			blkid_free_tag(bad);
     157  		}
     158  		blkid_free_tag(tag);
     159  	}
     160  
     161  	blkid_free_probe(cache->probe);
     162  
     163  	free(cache->bic_filename);
     164  	free(cache);
     165  }
     166  
     167  /**
     168   * blkid_gc_cache:
     169   * @cache: cache handler
     170   *
     171   * Removes garbage (non-existing devices) from the cache.
     172   */
     173  void blkid_gc_cache(blkid_cache cache)
     174  {
     175  	struct list_head *p, *pnext;
     176  	struct stat st;
     177  
     178  	if (!cache)
     179  		return;
     180  
     181  	list_for_each_safe(p, pnext, &cache->bic_devs) {
     182  		blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
     183  		if (stat(dev->bid_name, &st) < 0) {
     184  			DBG(CACHE, ul_debugobj(cache, "freeing non-existing %s", dev->bid_name));
     185  			blkid_free_dev(dev);
     186  			cache->bic_flags |= BLKID_BIC_FL_CHANGED;
     187  		} else {
     188  			DBG(CACHE, ul_debug("Device %s exists", dev->bid_name));
     189  		}
     190  	}
     191  }
     192  
     193  #ifdef TEST_PROGRAM
     194  int main(int argc, char** argv)
     195  {
     196  	blkid_cache cache = NULL;
     197  	int ret;
     198  
     199  	blkid_init_debug(BLKID_DEBUG_ALL);
     200  
     201  	if ((argc > 2)) {
     202  		fprintf(stderr, "Usage: %s [filename] \n", argv[0]);
     203  		exit(1);
     204  	}
     205  
     206  	if ((ret = blkid_get_cache(&cache, argv[1])) < 0) {
     207  		fprintf(stderr, "error %d parsing cache file %s\n", ret,
     208  			argv[1] ? argv[1] : blkid_get_cache_filename(NULL));
     209  		exit(1);
     210  	}
     211  	if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
     212  		fprintf(stderr, "%s: error creating cache (%d)\n",
     213  			argv[0], ret);
     214  		exit(1);
     215  	}
     216  	if ((ret = blkid_probe_all(cache)) < 0)
     217  		fprintf(stderr, "error probing devices\n");
     218  
     219  	blkid_put_cache(cache);
     220  
     221  	return ret;
     222  }
     223  #endif