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