]>
Commit | Line | Data |
---|---|---|
a0948ffe KZ |
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 | ||
fbc333fe | 13 | #ifdef HAVE_UNISTD_H |
a0948ffe KZ |
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> | |
a0948ffe KZ |
21 | #ifdef HAVE_SYS_STAT_H |
22 | #include <sys/stat.h> | |
23 | #endif | |
24 | #include "blkidP.h" | |
035507c8 | 25 | #include "env.h" |
a0948ffe | 26 | |
488e52be KZ |
27 | /** |
28 | * SECTION:cache | |
29 | * @title: Cache | |
30 | * @short_description: basic routines to work with libblkid cache | |
31 | * | |
b82590ad | 32 | * Block device information is normally kept in a cache file blkid.tab and is |
488e52be KZ |
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 | */ | |
b82590ad KZ |
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 | ||
bb5f2876 KZ |
61 | /* returns allocated path to cache */ |
62 | char *blkid_get_cache_filename(struct blkid_config *conf) | |
63 | { | |
64 | char *filename; | |
65 | ||
035507c8 | 66 | filename = safe_getenv("BLKID_FILE"); |
bb5f2876 | 67 | if (filename) |
e0a9b8cf | 68 | filename = strdup(filename); |
bb5f2876 | 69 | else if (conf) |
e0a9b8cf | 70 | filename = conf->cachefile ? strdup(conf->cachefile) : NULL; |
bb5f2876 KZ |
71 | else { |
72 | struct blkid_config *c = blkid_read_config(NULL); | |
73 | if (!c) | |
e0a9b8cf | 74 | filename = strdup(get_default_cache_filename()); |
30fce928 KZ |
75 | else { |
76 | filename = c->cachefile; /* already allocated */ | |
77 | c->cachefile = NULL; | |
78 | blkid_free_config(c); | |
79 | } | |
bb5f2876 KZ |
80 | } |
81 | return filename; | |
82 | } | |
83 | ||
488e52be KZ |
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 | * | |
9e930041 | 89 | * Allocates and initialize library cache handler. |
488e52be KZ |
90 | * |
91 | * Returns: 0 on success or number less than zero in case of error. | |
92 | */ | |
6644688a KZ |
93 | int blkid_get_cache(blkid_cache *ret_cache, const char *filename) |
94 | { | |
95 | blkid_cache cache; | |
96 | ||
e3436956 KZ |
97 | if (!ret_cache) |
98 | return -BLKID_ERR_PARAM; | |
99 | ||
7a458332 | 100 | blkid_init_debug(0); |
6644688a | 101 | |
fea1cbf7 | 102 | if (!(cache = calloc(1, sizeof(struct blkid_struct_cache)))) |
a0948ffe KZ |
103 | return -BLKID_ERR_MEM; |
104 | ||
14308bc3 | 105 | DBG(CACHE, ul_debugobj(cache, "alloc (from %s)", filename ? filename : "default cache")); |
a0948ffe KZ |
106 | INIT_LIST_HEAD(&cache->bic_devs); |
107 | INIT_LIST_HEAD(&cache->bic_tags); | |
108 | ||
568871ae KZ |
109 | if (filename && !*filename) |
110 | filename = NULL; | |
568871ae | 111 | if (filename) |
e0a9b8cf | 112 | cache->bic_filename = strdup(filename); |
bb5f2876 KZ |
113 | else |
114 | cache->bic_filename = blkid_get_cache_filename(NULL); | |
a0948ffe KZ |
115 | |
116 | blkid_read_cache(cache); | |
a0948ffe KZ |
117 | *ret_cache = cache; |
118 | return 0; | |
119 | } | |
120 | ||
488e52be KZ |
121 | /** |
122 | * blkid_put_cache: | |
123 | * @cache: cache handler | |
124 | * | |
125 | * Saves changes to cache file. | |
126 | */ | |
a0948ffe KZ |
127 | void blkid_put_cache(blkid_cache cache) |
128 | { | |
129 | if (!cache) | |
130 | return; | |
131 | ||
132 | (void) blkid_flush_cache(cache); | |
133 | ||
14308bc3 | 134 | DBG(CACHE, ul_debugobj(cache, "freeing cache struct")); |
a0948ffe | 135 | |
c62a6311 | 136 | /* DBG(CACHE, ul_debug_dump_cache(cache)); */ |
a0948ffe KZ |
137 | |
138 | while (!list_empty(&cache->bic_devs)) { | |
139 | blkid_dev dev = list_entry(cache->bic_devs.next, | |
140 | struct blkid_struct_dev, | |
141 | bid_devs); | |
142 | blkid_free_dev(dev); | |
143 | } | |
144 | ||
14308bc3 | 145 | DBG(CACHE, ul_debugobj(cache, "freeing cache tag heads")); |
a0948ffe KZ |
146 | while (!list_empty(&cache->bic_tags)) { |
147 | blkid_tag tag = list_entry(cache->bic_tags.next, | |
148 | struct blkid_struct_tag, | |
149 | bit_tags); | |
150 | ||
151 | while (!list_empty(&tag->bit_names)) { | |
152 | blkid_tag bad = list_entry(tag->bit_names.next, | |
153 | struct blkid_struct_tag, | |
154 | bit_names); | |
155 | ||
14308bc3 | 156 | DBG(CACHE, ul_debugobj(cache, "warning: unfreed tag %s=%s", |
a0948ffe KZ |
157 | bad->bit_name, bad->bit_val)); |
158 | blkid_free_tag(bad); | |
159 | } | |
160 | blkid_free_tag(tag); | |
161 | } | |
a0948ffe | 162 | |
ebeafc50 KZ |
163 | blkid_free_probe(cache->probe); |
164 | ||
165 | free(cache->bic_filename); | |
a0948ffe KZ |
166 | free(cache); |
167 | } | |
168 | ||
488e52be KZ |
169 | /** |
170 | * blkid_gc_cache: | |
171 | * @cache: cache handler | |
172 | * | |
173 | * Removes garbage (non-existing devices) from the cache. | |
174 | */ | |
a0948ffe KZ |
175 | void blkid_gc_cache(blkid_cache cache) |
176 | { | |
177 | struct list_head *p, *pnext; | |
178 | struct stat st; | |
179 | ||
180 | if (!cache) | |
181 | return; | |
182 | ||
183 | list_for_each_safe(p, pnext, &cache->bic_devs) { | |
184 | blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); | |
a0948ffe | 185 | if (stat(dev->bid_name, &st) < 0) { |
14308bc3 | 186 | DBG(CACHE, ul_debugobj(cache, "freeing non-exiting %s", dev->bid_name)); |
a0948ffe KZ |
187 | blkid_free_dev(dev); |
188 | cache->bic_flags |= BLKID_BIC_FL_CHANGED; | |
189 | } else { | |
c62a6311 | 190 | DBG(CACHE, ul_debug("Device %s exists", dev->bid_name)); |
a0948ffe KZ |
191 | } |
192 | } | |
193 | } | |
194 | ||
a0948ffe KZ |
195 | #ifdef TEST_PROGRAM |
196 | int main(int argc, char** argv) | |
197 | { | |
198 | blkid_cache cache = NULL; | |
199 | int ret; | |
200 | ||
0540ea54 | 201 | blkid_init_debug(BLKID_DEBUG_ALL); |
6644688a | 202 | |
a0948ffe KZ |
203 | if ((argc > 2)) { |
204 | fprintf(stderr, "Usage: %s [filename] \n", argv[0]); | |
205 | exit(1); | |
206 | } | |
207 | ||
208 | if ((ret = blkid_get_cache(&cache, argv[1])) < 0) { | |
209 | fprintf(stderr, "error %d parsing cache file %s\n", ret, | |
b82590ad | 210 | argv[1] ? argv[1] : blkid_get_cache_filename(NULL)); |
a0948ffe KZ |
211 | exit(1); |
212 | } | |
213 | if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { | |
214 | fprintf(stderr, "%s: error creating cache (%d)\n", | |
215 | argv[0], ret); | |
216 | exit(1); | |
217 | } | |
07023b07 | 218 | if ((ret = blkid_probe_all(cache)) < 0) |
a0948ffe KZ |
219 | fprintf(stderr, "error probing devices\n"); |
220 | ||
221 | blkid_put_cache(cache); | |
222 | ||
223 | return ret; | |
224 | } | |
225 | #endif |