/src/util-linux/libblkid/src/verify.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2008 Karel Zak <kzak@redhat.com> |
3 | | * |
4 | | * This file may be redistributed under the terms of the |
5 | | * GNU Lesser General Public License. |
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> |
14 | | #include <sys/time.h> |
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 |
22 | | |
23 | | #include "blkidP.h" |
24 | | #include "sysfs.h" |
25 | | |
26 | | static void blkid_probe_to_tags(blkid_probe pr, blkid_dev dev) |
27 | 3 | { |
28 | 3 | const char *data; |
29 | 3 | const char *name; |
30 | 3 | int nvals, n; |
31 | 3 | size_t len; |
32 | | |
33 | 3 | nvals = blkid_probe_numof_values(pr); |
34 | | |
35 | 31 | for (n = 0; n < nvals; n++) { |
36 | 28 | if (blkid_probe_get_value(pr, n, &name, &data, &len) != 0) |
37 | 0 | continue; |
38 | 28 | if (strncmp(name, "PART_ENTRY_", 11) == 0) { |
39 | 21 | if (strcmp(name, "PART_ENTRY_UUID") == 0) |
40 | 3 | blkid_set_tag(dev, "PARTUUID", data, len); |
41 | 18 | else if (strcmp(name, "PART_ENTRY_NAME") == 0) |
42 | 0 | blkid_set_tag(dev, "PARTLABEL", data, len); |
43 | | |
44 | 21 | } else if (!strstr(name, "_ID")) { |
45 | | /* superblock UUID, LABEL, ... |
46 | | * but not {SYSTEM,APPLICATION,..._ID} */ |
47 | 7 | blkid_set_tag(dev, name, data, len); |
48 | 7 | } |
49 | 28 | } |
50 | 3 | } |
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 | | */ |
61 | | blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) |
62 | 46 | { |
63 | 46 | blkid_tag_iterate iter; |
64 | 46 | const char *type, *value; |
65 | 46 | struct stat st; |
66 | 46 | time_t diff, now; |
67 | 46 | int fd; |
68 | | |
69 | 46 | if (!dev || !cache) |
70 | 0 | return NULL; |
71 | | |
72 | 46 | now = time(NULL); |
73 | 46 | diff = (uintmax_t)now - dev->bid_time; |
74 | | |
75 | 46 | if (stat(dev->bid_name, &st) < 0) { |
76 | 0 | DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while " |
77 | 0 | "trying to stat %s", errno, |
78 | 0 | dev->bid_name)); |
79 | 0 | open_err: |
80 | 0 | if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) { |
81 | | /* We don't have read permission, just return cache data. */ |
82 | 0 | DBG(PROBE, ul_debug("returning unverified data for %s", |
83 | 0 | dev->bid_name)); |
84 | 0 | return dev; |
85 | 0 | } |
86 | 0 | blkid_free_dev(dev); |
87 | 0 | return NULL; |
88 | 0 | } |
89 | | |
90 | 46 | if (now >= dev->bid_time && |
91 | 46 | #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC |
92 | 46 | (st.st_mtime < dev->bid_time || |
93 | 3 | (st.st_mtime == dev->bid_time && |
94 | 0 | st.st_mtim.tv_nsec / 1000 <= dev->bid_utime)) && |
95 | | #else |
96 | | st.st_mtime <= dev->bid_time && |
97 | | #endif |
98 | 43 | diff >= 0 && diff < BLKID_PROBE_MIN) { |
99 | 43 | dev->bid_flags |= BLKID_BID_FL_VERIFIED; |
100 | 43 | return dev; |
101 | 43 | } |
102 | | |
103 | | #ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC |
104 | | DBG(PROBE, ul_debug("need to revalidate %s (cache time %lld, stat time %lld,\t" |
105 | | "time since last check %lld)", |
106 | | dev->bid_name, (long long)dev->bid_time, |
107 | | (long long)st.st_mtime, (long long)diff)); |
108 | | #else |
109 | 3 | DBG(PROBE, ul_debug("need to revalidate %s (cache time %lld.%lld, stat time %lld.%lld,\t" |
110 | 3 | "time since last check %lld)", |
111 | 3 | dev->bid_name, |
112 | 3 | (long long)dev->bid_time, (long long)dev->bid_utime, |
113 | 3 | (long long)st.st_mtime, (long long)st.st_mtim.tv_nsec / 1000, |
114 | 3 | (long long)diff)); |
115 | 3 | #endif |
116 | | |
117 | 3 | if (sysfs_devno_is_dm_private(st.st_rdev, NULL)) { |
118 | 0 | blkid_free_dev(dev); |
119 | 0 | return NULL; |
120 | 0 | } |
121 | 3 | if (!cache->probe) { |
122 | 1 | cache->probe = blkid_new_probe(); |
123 | 1 | if (!cache->probe) { |
124 | 0 | blkid_free_dev(dev); |
125 | 0 | return NULL; |
126 | 0 | } |
127 | 1 | } |
128 | | |
129 | 3 | fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC|O_NONBLOCK); |
130 | 3 | if (fd < 0) { |
131 | 0 | DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while " |
132 | 0 | "opening %s", errno, |
133 | 0 | dev->bid_name)); |
134 | 0 | goto open_err; |
135 | 0 | } |
136 | | |
137 | 3 | if (blkid_probe_set_device(cache->probe, fd, 0, 0)) { |
138 | | /* failed to read the device */ |
139 | 0 | close(fd); |
140 | 0 | blkid_free_dev(dev); |
141 | 0 | return NULL; |
142 | 0 | } |
143 | | |
144 | | /* remove old cache info */ |
145 | 3 | iter = blkid_tag_iterate_begin(dev); |
146 | 3 | while (blkid_tag_next(iter, &type, &value) == 0) |
147 | 0 | blkid_set_tag(dev, type, NULL, 0); |
148 | 3 | blkid_tag_iterate_end(iter); |
149 | | |
150 | | /* enable superblocks probing */ |
151 | 3 | blkid_probe_enable_superblocks(cache->probe, TRUE); |
152 | 3 | blkid_probe_set_superblocks_flags(cache->probe, |
153 | 3 | BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | |
154 | 3 | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE); |
155 | | |
156 | | /* enable partitions probing */ |
157 | 3 | blkid_probe_enable_partitions(cache->probe, TRUE); |
158 | 3 | blkid_probe_set_partitions_flags(cache->probe, BLKID_PARTS_ENTRY_DETAILS); |
159 | | |
160 | | /* probe */ |
161 | 3 | if (blkid_do_safeprobe(cache->probe)) { |
162 | | /* found nothing or error */ |
163 | 0 | blkid_free_dev(dev); |
164 | 0 | dev = NULL; |
165 | 0 | } |
166 | | |
167 | 3 | if (dev) { |
168 | 3 | #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC |
169 | 3 | struct timeval tv; |
170 | 3 | if (!gettimeofday(&tv, NULL)) { |
171 | 3 | dev->bid_time = tv.tv_sec; |
172 | 3 | dev->bid_utime = tv.tv_usec; |
173 | 3 | } else |
174 | 0 | #endif |
175 | 0 | dev->bid_time = time(NULL); |
176 | | |
177 | 3 | dev->bid_devno = st.st_rdev; |
178 | 3 | dev->bid_flags |= BLKID_BID_FL_VERIFIED; |
179 | 3 | cache->bic_flags |= BLKID_BIC_FL_CHANGED; |
180 | | |
181 | 3 | blkid_probe_to_tags(cache->probe, dev); |
182 | | |
183 | 3 | DBG(PROBE, ul_debug("%s: devno 0x%04llx, type %s", |
184 | 3 | dev->bid_name, (long long)st.st_rdev, dev->bid_type)); |
185 | 3 | } |
186 | | |
187 | | /* reset prober */ |
188 | 3 | blkid_probe_reset_superblocks_filter(cache->probe); |
189 | 3 | blkid_probe_set_device(cache->probe, -1, 0, 0); |
190 | 3 | close(fd); |
191 | | |
192 | 3 | return dev; |
193 | 3 | } |
194 | | |
195 | | #ifdef TEST_PROGRAM |
196 | | int 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 |