Update to upstream util-linux 2.20.1
[framework/base/util-linux-ng.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 #if 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 /etc/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 /* returns allocated path to cache */
99 char *blkid_get_cache_filename(struct blkid_config *conf)
100 {
101         char *filename;
102
103         filename = safe_getenv("BLKID_FILE");
104         if (filename)
105                 filename = blkid_strdup(filename);
106         else if (conf)
107                 filename = blkid_strdup(conf->cachefile);
108         else {
109                 struct blkid_config *c = blkid_read_config(NULL);
110                 if (!c)
111                         filename = blkid_strdup(BLKID_CACHE_FILE);
112                 else {
113                         filename = c->cachefile;  /* already allocated */
114                         c->cachefile = NULL;
115                         blkid_free_config(c);
116                 }
117         }
118         return filename;
119 }
120
121 /**
122  * blkid_get_cache:
123  * @cache: pointer to return cache handler
124  * @filename: path to the cache file or NULL for the default path
125  *
126  * Allocates and initialize librray cache handler.
127  *
128  * Returns: 0 on success or number less than zero in case of error.
129  */
130 int blkid_get_cache(blkid_cache *ret_cache, const char *filename)
131 {
132         blkid_cache cache;
133
134         blkid_init_debug(0);
135
136         DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n",
137                                 filename ? filename : "default cache"));
138
139         if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache))))
140                 return -BLKID_ERR_MEM;
141
142         INIT_LIST_HEAD(&cache->bic_devs);
143         INIT_LIST_HEAD(&cache->bic_tags);
144
145         if (filename && !*filename)
146                 filename = NULL;
147         if (filename)
148                 cache->bic_filename = blkid_strdup(filename);
149         else
150                 cache->bic_filename = blkid_get_cache_filename(NULL);
151
152         blkid_read_cache(cache);
153         *ret_cache = cache;
154         return 0;
155 }
156
157 /**
158  * blkid_put_cache:
159  * @cache: cache handler
160  *
161  * Saves changes to cache file.
162  */
163 void blkid_put_cache(blkid_cache cache)
164 {
165         if (!cache)
166                 return;
167
168         (void) blkid_flush_cache(cache);
169
170         DBG(DEBUG_CACHE, printf("freeing cache struct\n"));
171
172         /* DBG(DEBUG_CACHE, blkid_debug_dump_cache(cache)); */
173
174         while (!list_empty(&cache->bic_devs)) {
175                 blkid_dev dev = list_entry(cache->bic_devs.next,
176                                            struct blkid_struct_dev,
177                                             bid_devs);
178                 blkid_free_dev(dev);
179         }
180
181         while (!list_empty(&cache->bic_tags)) {
182                 blkid_tag tag = list_entry(cache->bic_tags.next,
183                                            struct blkid_struct_tag,
184                                            bit_tags);
185
186                 while (!list_empty(&tag->bit_names)) {
187                         blkid_tag bad = list_entry(tag->bit_names.next,
188                                                    struct blkid_struct_tag,
189                                                    bit_names);
190
191                         DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n",
192                                                 bad->bit_name, bad->bit_val));
193                         blkid_free_tag(bad);
194                 }
195                 blkid_free_tag(tag);
196         }
197
198         blkid_free_probe(cache->probe);
199
200         free(cache->bic_filename);
201         free(cache);
202 }
203
204 /**
205  * blkid_gc_cache:
206  * @cache: cache handler
207  *
208  * Removes garbage (non-existing devices) from the cache.
209  */
210 void blkid_gc_cache(blkid_cache cache)
211 {
212         struct list_head *p, *pnext;
213         struct stat st;
214
215         if (!cache)
216                 return;
217
218         list_for_each_safe(p, pnext, &cache->bic_devs) {
219                 blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
220                 if (!p)
221                         break;
222                 if (stat(dev->bid_name, &st) < 0) {
223                         DBG(DEBUG_CACHE,
224                             printf("freeing %s\n", dev->bid_name));
225                         blkid_free_dev(dev);
226                         cache->bic_flags |= BLKID_BIC_FL_CHANGED;
227                 } else {
228                         DBG(DEBUG_CACHE,
229                             printf("Device %s exists\n", dev->bid_name));
230                 }
231         }
232 }
233
234 #ifdef TEST_PROGRAM
235 int main(int argc, char** argv)
236 {
237         blkid_cache cache = NULL;
238         int ret;
239
240         blkid_init_debug(DEBUG_ALL);
241
242         if ((argc > 2)) {
243                 fprintf(stderr, "Usage: %s [filename] \n", argv[0]);
244                 exit(1);
245         }
246
247         if ((ret = blkid_get_cache(&cache, argv[1])) < 0) {
248                 fprintf(stderr, "error %d parsing cache file %s\n", ret,
249                         argv[1] ? argv[1] : BLKID_CACHE_FILE);
250                 exit(1);
251         }
252         if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
253                 fprintf(stderr, "%s: error creating cache (%d)\n",
254                         argv[0], ret);
255                 exit(1);
256         }
257         if ((ret = blkid_probe_all(cache) < 0))
258                 fprintf(stderr, "error probing devices\n");
259
260         blkid_put_cache(cache);
261
262         return ret;
263 }
264 #endif