]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libblkid/src/verify.c
libblkid: fix file descriptor leak in blkid_verify()
[thirdparty/util-linux.git] / libblkid / src / verify.c
CommitLineData
51410fc6
KZ
1/*
2 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
3 *
51410fc6
KZ
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
51410fc6
KZ
6 */
7
8#include <stdio.h>
9#include <string.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <fcntl.h>
13#include <time.h>
6c2f2b9d 14#include <sys/time.h>
51410fc6
KZ
15#include <sys/types.h>
16#ifdef HAVE_SYS_STAT_H
17#include <sys/stat.h>
18#endif
19#ifdef HAVE_ERRNO_H
20#include <errno.h>
21#endif
25472aaf 22
51410fc6 23#include "blkidP.h"
25472aaf 24#include "sysfs.h"
51410fc6
KZ
25
26static void blkid_probe_to_tags(blkid_probe pr, blkid_dev dev)
27{
6d042d0d 28 const char *data;
51410fc6
KZ
29 const char *name;
30 int nvals, n;
31 size_t len;
32
33 nvals = blkid_probe_numof_values(pr);
34
35 for (n = 0; n < nvals; n++) {
fc387ee1
KZ
36 if (blkid_probe_get_value(pr, n, &name, &data, &len) != 0)
37 continue;
38 if (strncmp(name, "PART_ENTRY_", 11) == 0) {
39 if (strcmp(name, "PART_ENTRY_UUID") == 0)
40 blkid_set_tag(dev, "PARTUUID", data, len);
41 else if (strcmp(name, "PART_ENTRY_NAME") == 0)
42 blkid_set_tag(dev, "PARTLABEL", data, len);
fafe46bc
ZAK
43
44 } else if (!strstr(name, "_ID")) {
45 /* superblock UUID, LABEL, ...
46 * but not {SYSTEM,APPLICATION,..._ID} */
6d042d0d 47 blkid_set_tag(dev, name, data, len);
fc387ee1 48 }
51410fc6
KZ
49 }
50}
51
52/*
53 * Verify that the data in dev is consistent with what is on the actual
54 * block device (using the devname field only). Normally this will be
55 * called when finding items in the cache, but for long running processes
56 * is also desirable to revalidate an item before use.
57 *
58 * If we are unable to revalidate the data, we return the old data and
59 * do not set the BLKID_BID_FL_VERIFIED flag on it.
60 */
61blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
62{
6a076644
KZ
63 blkid_tag_iterate iter;
64 const char *type, *value;
51410fc6
KZ
65 struct stat st;
66 time_t diff, now;
51410fc6
KZ
67 int fd;
68
e3436956 69 if (!dev || !cache)
51410fc6
KZ
70 return NULL;
71
87918040 72 now = time(NULL);
51410fc6
KZ
73 diff = now - dev->bid_time;
74
75 if (stat(dev->bid_name, &st) < 0) {
c62a6311 76 DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while "
0540ea54 77 "trying to stat %s", errno,
51410fc6
KZ
78 dev->bid_name));
79 open_err:
80 if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) {
81 /* We don't have read permission, just return cache data. */
c62a6311 82 DBG(PROBE, ul_debug("returning unverified data for %s",
51410fc6
KZ
83 dev->bid_name));
84 return dev;
85 }
86 blkid_free_dev(dev);
87 return NULL;
88 }
89
6c2f2b9d
KZ
90 if (now >= dev->bid_time &&
91#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
92 (st.st_mtime < dev->bid_time ||
93 (st.st_mtime == dev->bid_time &&
94 st.st_mtim.tv_nsec / 1000 <= dev->bid_utime)) &&
95#else
96 st.st_mtime <= dev->bid_time &&
97#endif
99878f5d
NB
98 diff < BLKID_PROBE_MIN) {
99 dev->bid_flags |= BLKID_BID_FL_VERIFIED;
51410fc6 100 return dev;
99878f5d 101 }
51410fc6 102
6c2f2b9d 103#ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
c62a6311 104 DBG(PROBE, ul_debug("need to revalidate %s (cache time %lu, stat time %lu,\t"
0540ea54 105 "time since last check %lu)",
51410fc6
KZ
106 dev->bid_name, (unsigned long)dev->bid_time,
107 (unsigned long)st.st_mtime, (unsigned long)diff));
6c2f2b9d 108#else
c62a6311 109 DBG(PROBE, ul_debug("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\t"
0540ea54 110 "time since last check %lu)",
6c2f2b9d
KZ
111 dev->bid_name,
112 (unsigned long)dev->bid_time, (unsigned long)dev->bid_utime,
113 (unsigned long)st.st_mtime, (unsigned long)st.st_mtim.tv_nsec / 1000,
114 (unsigned long)diff));
115#endif
51410fc6 116
80ec018c 117 if (sysfs_devno_is_dm_private(st.st_rdev, NULL)) {
20e1c3dc
KZ
118 blkid_free_dev(dev);
119 return NULL;
120 }
ebeafc50 121 if (!cache->probe) {
51410fc6 122 cache->probe = blkid_new_probe();
ebeafc50
KZ
123 if (!cache->probe) {
124 blkid_free_dev(dev);
125 return NULL;
126 }
127 }
51410fc6 128
49a8f58e 129 fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC);
51410fc6 130 if (fd < 0) {
c62a6311 131 DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while "
0540ea54 132 "opening %s", errno,
51410fc6
KZ
133 dev->bid_name));
134 goto open_err;
135 }
136
137 if (blkid_probe_set_device(cache->probe, fd, 0, 0)) {
138 /* failed to read the device */
139 close(fd);
140 blkid_free_dev(dev);
141 return NULL;
142 }
143
6a076644
KZ
144 /* remove old cache info */
145 iter = blkid_tag_iterate_begin(dev);
146 while (blkid_tag_next(iter, &type, &value) == 0)
147 blkid_set_tag(dev, type, NULL, 0);
148 blkid_tag_iterate_end(iter);
1b780848 149
6a076644
KZ
150 /* enable superblocks probing */
151 blkid_probe_enable_superblocks(cache->probe, TRUE);
1b780848
KZ
152 blkid_probe_set_superblocks_flags(cache->probe,
153 BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
154 BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE);
51410fc6 155
6a076644 156 /* enable partitions probing */
f4388dea
KZ
157 blkid_probe_enable_partitions(cache->probe, TRUE);
158 blkid_probe_set_partitions_flags(cache->probe, BLKID_PARTS_ENTRY_DETAILS);
159
6a076644 160 /* probe */
a2f01a1c
KZ
161 if (blkid_do_safeprobe(cache->probe)) {
162 /* found nothing or error */
51410fc6
KZ
163 blkid_free_dev(dev);
164 dev = NULL;
165 }
166
51410fc6 167 if (dev) {
6c2f2b9d
KZ
168#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
169 struct timeval tv;
170 if (!gettimeofday(&tv, NULL)) {
171 dev->bid_time = tv.tv_sec;
172 dev->bid_utime = tv.tv_usec;
173 } else
174#endif
87918040 175 dev->bid_time = time(NULL);
6c2f2b9d 176
51410fc6 177 dev->bid_devno = st.st_rdev;
51410fc6
KZ
178 dev->bid_flags |= BLKID_BID_FL_VERIFIED;
179 cache->bic_flags |= BLKID_BIC_FL_CHANGED;
180
181 blkid_probe_to_tags(cache->probe, dev);
182
c62a6311 183 DBG(PROBE, ul_debug("%s: devno 0x%04llx, type %s",
6644688a 184 dev->bid_name, (long long)st.st_rdev, dev->bid_type));
51410fc6
KZ
185 }
186
c4d6d1c5 187 /* reset prober */
1b780848 188 blkid_probe_reset_superblocks_filter(cache->probe);
c4d6d1c5 189 blkid_probe_set_device(cache->probe, -1, 0, 0);
51410fc6 190 close(fd);
c4d6d1c5 191
51410fc6
KZ
192 return dev;
193}
194
195#ifdef TEST_PROGRAM
196int main(int argc, char **argv)
197{
198 blkid_dev dev;
199 blkid_cache cache;
200 int ret;
201
202 if (argc != 2) {
203 fprintf(stderr, "Usage: %s device\n"
204 "Probe a single device to determine type\n", argv[0]);
205 exit(1);
206 }
207 if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
208 fprintf(stderr, "%s: error creating cache (%d)\n",
209 argv[0], ret);
210 exit(1);
211 }
212 dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL);
213 if (!dev) {
214 printf("%s: %s has an unsupported type\n", argv[0], argv[1]);
215 return (1);
216 }
217 printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)");
218 if (dev->bid_label)
219 printf("LABEL='%s'\n", dev->bid_label);
220 if (dev->bid_uuid)
221 printf("UUID='%s'\n", dev->bid_uuid);
222
223 blkid_free_dev(dev);
224 return (0);
225}
226#endif