Coverage Report

Created: 2025-12-10 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libblkid/src/cache.c
Line
Count
Source
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
0
{
53
0
  struct stat st;
54
55
0
  if (stat(BLKID_RUNTIME_TOPDIR, &st) == 0 && S_ISDIR(st.st_mode))
56
0
    return BLKID_CACHE_FILE; /* cache in /run */
57
58
0
  return BLKID_CACHE_FILE_OLD; /* cache in /etc */
59
0
}
60
61
/* returns allocated path to cache */
62
char *blkid_get_cache_filename(struct blkid_config *conf)
63
0
{
64
0
  char *filename;
65
66
0
  filename = safe_getenv("BLKID_FILE");
67
0
  if (filename)
68
0
    filename = strdup(filename);
69
0
  else if (conf)
70
0
    filename = conf->cachefile ? strdup(conf->cachefile) : NULL;
71
0
  else {
72
0
    struct blkid_config *c = blkid_read_config(NULL);
73
0
    if (!c)
74
0
      filename = strdup(get_default_cache_filename());
75
0
    else {
76
0
      filename = c->cachefile;  /* already allocated */
77
0
      c->cachefile = NULL;
78
0
      blkid_free_config(c);
79
0
    }
80
0
  }
81
0
  return filename;
82
0
}
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
0
{
95
0
  blkid_cache cache;
96
97
0
  if (!ret_cache)
98
0
    return -BLKID_ERR_PARAM;
99
100
0
  if (!(cache = calloc(1, sizeof(struct blkid_struct_cache))))
101
0
    return -BLKID_ERR_MEM;
102
103
0
  DBG(CACHE, ul_debugobj(cache, "alloc (from %s)", filename ? filename : "default cache"));
104
0
  INIT_LIST_HEAD(&cache->bic_devs);
105
0
  INIT_LIST_HEAD(&cache->bic_tags);
106
107
0
  if (filename && !*filename)
108
0
    filename = NULL;
109
0
  if (filename)
110
0
    cache->bic_filename = strdup(filename);
111
0
  else
112
0
    cache->bic_filename = blkid_get_cache_filename(NULL);
113
114
0
  blkid_read_cache(cache);
115
0
  *ret_cache = cache;
116
0
  return 0;
117
0
}
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
0
{
127
0
  if (!cache)
128
0
    return;
129
130
0
  (void) blkid_flush_cache(cache);
131
132
0
  DBG(CACHE, ul_debugobj(cache, "freeing cache struct"));
133
134
  /* DBG(CACHE, ul_debug_dump_cache(cache)); */
135
136
0
  while (!list_empty(&cache->bic_devs)) {
137
0
    blkid_dev dev = list_entry(cache->bic_devs.next,
138
0
             struct blkid_struct_dev,
139
0
              bid_devs);
140
0
    blkid_free_dev(dev);
141
0
  }
142
143
0
  DBG(CACHE, ul_debugobj(cache, "freeing cache tag heads"));
144
0
  while (!list_empty(&cache->bic_tags)) {
145
0
    blkid_tag tag = list_entry(cache->bic_tags.next,
146
0
             struct blkid_struct_tag,
147
0
             bit_tags);
148
149
0
    while (!list_empty(&tag->bit_names)) {
150
0
      blkid_tag bad = list_entry(tag->bit_names.next,
151
0
               struct blkid_struct_tag,
152
0
               bit_names);
153
154
0
      DBG(CACHE, ul_debugobj(cache, "warning: unfreed tag %s=%s",
155
0
            bad->bit_name, bad->bit_val));
156
0
      blkid_free_tag(bad);
157
0
    }
158
0
    blkid_free_tag(tag);
159
0
  }
160
161
0
  blkid_free_probe(cache->probe);
162
163
0
  free(cache->bic_filename);
164
0
  free(cache);
165
0
}
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
0
{
175
0
  struct list_head *p, *pnext;
176
0
  struct stat st;
177
178
0
  if (!cache)
179
0
    return;
180
181
0
  list_for_each_safe(p, pnext, &cache->bic_devs) {
182
0
    blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
183
0
    if (stat(dev->bid_name, &st) < 0) {
184
0
      DBG(CACHE, ul_debugobj(cache, "freeing non-existing %s", dev->bid_name));
185
0
      blkid_free_dev(dev);
186
0
      cache->bic_flags |= BLKID_BIC_FL_CHANGED;
187
0
    } else {
188
      DBG(CACHE, ul_debug("Device %s exists", dev->bid_name));
189
0
    }
190
0
  }
191
0
}
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