]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libblkid/src/cache.c
a60495aa50e3053f6147419cdc7f39177261419f
[thirdparty/util-linux.git] / 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 int blkid_debug_mask = 0;
28
29 /**
30 * SECTION:cache
31 * @title: Cache
32 * @short_description: basic routines to work with libblkid cache
33 *
34 * Block device information is normally kept in a cache file blkid.tab and is
35 * verified to still be valid before being returned to the user (if the user has
36 * read permission on the raw block device, otherwise not). The cache file also
37 * allows unprivileged users (normally anyone other than root, or those not in the
38 * "disk" group) to locate devices by label/id. The standard location of the
39 * cache file can be overridden by the environment variable BLKID_FILE.
40 *
41 * In situations where one is getting information about a single known device, it
42 * does not impact performance whether the cache is used or not (unless you are
43 * not able to read the block device directly). If you are dealing with multiple
44 * devices, use of the cache is highly recommended (even if empty) as devices will
45 * be scanned at most one time and the on-disk cache will be updated if possible.
46 * There is rarely a reason not to use the cache.
47 *
48 * In some cases (modular kernels), block devices are not even visible until after
49 * they are accessed the first time, so it is critical that there is some way to
50 * locate these devices without enumerating only visible devices, so the use of
51 * the cache file is required in this situation.
52 */
53
54 #if 0 /* ifdef CONFIG_BLKID_DEBUG */
55 static blkid_debug_dump_cache(int mask, blkid_cache cache)
56 {
57 struct list_head *p;
58
59 if (!cache) {
60 printf("cache: NULL\n");
61 return;
62 }
63
64 printf("cache: time = %lu\n", cache->bic_time);
65 printf("cache: flags = 0x%08X\n", cache->bic_flags);
66
67 list_for_each(p, &cache->bic_devs) {
68 blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
69 blkid_debug_dump_dev(dev);
70 }
71 }
72 #endif
73
74 #ifdef CONFIG_BLKID_DEBUG
75 void blkid_init_debug(int mask)
76 {
77 if (blkid_debug_mask & DEBUG_INIT)
78 return;
79
80 if (!mask)
81 {
82 char *dstr = getenv("LIBBLKID_DEBUG");
83
84 if (!dstr)
85 dstr = getenv("BLKID_DEBUG"); /* for backward compatibility */
86 if (dstr)
87 blkid_debug_mask = strtoul(dstr, 0, 0);
88 } else
89 blkid_debug_mask = mask;
90
91 if (blkid_debug_mask)
92 printf("libblkid: debug mask set to 0x%04x.\n", blkid_debug_mask);
93
94 blkid_debug_mask |= DEBUG_INIT;
95 }
96 #endif
97
98 static const char *get_default_cache_filename(void)
99 {
100 struct stat st;
101
102 if (stat(BLKID_RUNTIME_TOPDIR, &st) == 0 && S_ISDIR(st.st_mode))
103 return BLKID_CACHE_FILE; /* cache in /run */
104
105 return BLKID_CACHE_FILE_OLD; /* cache in /etc */
106 }
107
108 /* returns allocated path to cache */
109 char *blkid_get_cache_filename(struct blkid_config *conf)
110 {
111 char *filename;
112
113 filename = safe_getenv("BLKID_FILE");
114 if (filename)
115 filename = blkid_strdup(filename);
116 else if (conf)
117 filename = blkid_strdup(conf->cachefile);
118 else {
119 struct blkid_config *c = blkid_read_config(NULL);
120 if (!c)
121 filename = blkid_strdup(get_default_cache_filename());
122 else {
123 filename = c->cachefile; /* already allocated */
124 c->cachefile = NULL;
125 blkid_free_config(c);
126 }
127 }
128 return filename;
129 }
130
131 /**
132 * blkid_get_cache:
133 * @cache: pointer to return cache handler
134 * @filename: path to the cache file or NULL for the default path
135 *
136 * Allocates and initialize librray cache handler.
137 *
138 * Returns: 0 on success or number less than zero in case of error.
139 */
140 int blkid_get_cache(blkid_cache *ret_cache, const char *filename)
141 {
142 blkid_cache cache;
143
144 blkid_init_debug(0);
145
146 DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n",
147 filename ? filename : "default cache"));
148
149 if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache))))
150 return -BLKID_ERR_MEM;
151
152 INIT_LIST_HEAD(&cache->bic_devs);
153 INIT_LIST_HEAD(&cache->bic_tags);
154
155 if (filename && !*filename)
156 filename = NULL;
157 if (filename)
158 cache->bic_filename = blkid_strdup(filename);
159 else
160 cache->bic_filename = blkid_get_cache_filename(NULL);
161
162 blkid_read_cache(cache);
163 *ret_cache = cache;
164 return 0;
165 }
166
167 /**
168 * blkid_put_cache:
169 * @cache: cache handler
170 *
171 * Saves changes to cache file.
172 */
173 void blkid_put_cache(blkid_cache cache)
174 {
175 if (!cache)
176 return;
177
178 (void) blkid_flush_cache(cache);
179
180 DBG(DEBUG_CACHE, printf("freeing cache struct\n"));
181
182 /* DBG(DEBUG_CACHE, blkid_debug_dump_cache(cache)); */
183
184 while (!list_empty(&cache->bic_devs)) {
185 blkid_dev dev = list_entry(cache->bic_devs.next,
186 struct blkid_struct_dev,
187 bid_devs);
188 blkid_free_dev(dev);
189 }
190
191 while (!list_empty(&cache->bic_tags)) {
192 blkid_tag tag = list_entry(cache->bic_tags.next,
193 struct blkid_struct_tag,
194 bit_tags);
195
196 while (!list_empty(&tag->bit_names)) {
197 blkid_tag bad = list_entry(tag->bit_names.next,
198 struct blkid_struct_tag,
199 bit_names);
200
201 DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n",
202 bad->bit_name, bad->bit_val));
203 blkid_free_tag(bad);
204 }
205 blkid_free_tag(tag);
206 }
207
208 blkid_free_probe(cache->probe);
209
210 free(cache->bic_filename);
211 free(cache);
212 }
213
214 /**
215 * blkid_gc_cache:
216 * @cache: cache handler
217 *
218 * Removes garbage (non-existing devices) from the cache.
219 */
220 void blkid_gc_cache(blkid_cache cache)
221 {
222 struct list_head *p, *pnext;
223 struct stat st;
224
225 if (!cache)
226 return;
227
228 list_for_each_safe(p, pnext, &cache->bic_devs) {
229 blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
230 if (stat(dev->bid_name, &st) < 0) {
231 DBG(DEBUG_CACHE,
232 printf("freeing %s\n", dev->bid_name));
233 blkid_free_dev(dev);
234 cache->bic_flags |= BLKID_BIC_FL_CHANGED;
235 } else {
236 DBG(DEBUG_CACHE,
237 printf("Device %s exists\n", dev->bid_name));
238 }
239 }
240 }
241
242 #ifdef TEST_PROGRAM
243 int main(int argc, char** argv)
244 {
245 blkid_cache cache = NULL;
246 int ret;
247
248 blkid_init_debug(DEBUG_ALL);
249
250 if ((argc > 2)) {
251 fprintf(stderr, "Usage: %s [filename] \n", argv[0]);
252 exit(1);
253 }
254
255 if ((ret = blkid_get_cache(&cache, argv[1])) < 0) {
256 fprintf(stderr, "error %d parsing cache file %s\n", ret,
257 argv[1] ? argv[1] : blkid_get_cache_filename(NULL));
258 exit(1);
259 }
260 if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
261 fprintf(stderr, "%s: error creating cache (%d)\n",
262 argv[0], ret);
263 exit(1);
264 }
265 if ((ret = blkid_probe_all(cache)) < 0)
266 fprintf(stderr, "error probing devices\n");
267
268 blkid_put_cache(cache);
269
270 return ret;
271 }
272 #endif