222 lines
5.6 KiB
C
222 lines
5.6 KiB
C
/*
|
|
* Copyright (C) 2008 Karel Zak <kzak@redhat.com>
|
|
*
|
|
* This file may be redistributed under the terms of the
|
|
* GNU Lesser General Public License.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#ifdef HAVE_SYS_STAT_H
|
|
#include <sys/stat.h>
|
|
#endif
|
|
#ifdef HAVE_ERRNO_H
|
|
#include <errno.h>
|
|
#endif
|
|
#include "blkidP.h"
|
|
|
|
static void blkid_probe_to_tags(blkid_probe pr, blkid_dev dev)
|
|
{
|
|
const char *data;
|
|
const char *name;
|
|
int nvals, n;
|
|
size_t len;
|
|
|
|
nvals = blkid_probe_numof_values(pr);
|
|
|
|
for (n = 0; n < nvals; n++) {
|
|
if (blkid_probe_get_value(pr, n, &name, &data, &len) != 0)
|
|
continue;
|
|
if (strncmp(name, "PART_ENTRY_", 11) == 0) {
|
|
if (strcmp(name, "PART_ENTRY_UUID") == 0)
|
|
blkid_set_tag(dev, "PARTUUID", data, len);
|
|
else if (strcmp(name, "PART_ENTRY_NAME") == 0)
|
|
blkid_set_tag(dev, "PARTLABEL", data, len);
|
|
|
|
} else if (!strstr(name, "_ID")) {
|
|
/* superblock UUID, LABEL, ...
|
|
* but not {SYSTEM,APPLICATION,..._ID} */
|
|
blkid_set_tag(dev, name, data, len);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Verify that the data in dev is consistent with what is on the actual
|
|
* block device (using the devname field only). Normally this will be
|
|
* called when finding items in the cache, but for long running processes
|
|
* is also desirable to revalidate an item before use.
|
|
*
|
|
* If we are unable to revalidate the data, we return the old data and
|
|
* do not set the BLKID_BID_FL_VERIFIED flag on it.
|
|
*/
|
|
blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
|
|
{
|
|
blkid_tag_iterate iter;
|
|
const char *type, *value;
|
|
struct stat st;
|
|
time_t diff, now;
|
|
int fd;
|
|
|
|
if (!dev || !cache)
|
|
return NULL;
|
|
|
|
now = time(0);
|
|
diff = now - dev->bid_time;
|
|
|
|
if (stat(dev->bid_name, &st) < 0) {
|
|
DBG(DEBUG_PROBE,
|
|
printf("blkid_verify: error %m (%d) while "
|
|
"trying to stat %s\n", errno,
|
|
dev->bid_name));
|
|
open_err:
|
|
if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) {
|
|
/* We don't have read permission, just return cache data. */
|
|
DBG(DEBUG_PROBE, printf("returning unverified data for %s\n",
|
|
dev->bid_name));
|
|
return dev;
|
|
}
|
|
blkid_free_dev(dev);
|
|
return NULL;
|
|
}
|
|
|
|
if (now >= dev->bid_time &&
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
|
(st.st_mtime < dev->bid_time ||
|
|
(st.st_mtime == dev->bid_time &&
|
|
st.st_mtim.tv_nsec / 1000 <= dev->bid_utime)) &&
|
|
#else
|
|
st.st_mtime <= dev->bid_time &&
|
|
#endif
|
|
(diff < BLKID_PROBE_MIN ||
|
|
(dev->bid_flags & BLKID_BID_FL_VERIFIED &&
|
|
diff < BLKID_PROBE_INTERVAL)))
|
|
return dev;
|
|
|
|
#ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
|
DBG(DEBUG_PROBE,
|
|
printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t"
|
|
"time since last check %lu)\n",
|
|
dev->bid_name, (unsigned long)dev->bid_time,
|
|
(unsigned long)st.st_mtime, (unsigned long)diff));
|
|
#else
|
|
DBG(DEBUG_PROBE,
|
|
printf("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\n\t"
|
|
"time since last check %lu)\n",
|
|
dev->bid_name,
|
|
(unsigned long)dev->bid_time, (unsigned long)dev->bid_utime,
|
|
(unsigned long)st.st_mtime, (unsigned long)st.st_mtim.tv_nsec / 1000,
|
|
(unsigned long)diff));
|
|
#endif
|
|
|
|
if (!cache->probe) {
|
|
cache->probe = blkid_new_probe();
|
|
if (!cache->probe) {
|
|
blkid_free_dev(dev);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC);
|
|
if (fd < 0) {
|
|
DBG(DEBUG_PROBE, printf("blkid_verify: error %m (%d) while "
|
|
"opening %s\n", errno,
|
|
dev->bid_name));
|
|
goto open_err;
|
|
}
|
|
|
|
if (blkid_probe_set_device(cache->probe, fd, 0, 0)) {
|
|
/* failed to read the device */
|
|
close(fd);
|
|
blkid_free_dev(dev);
|
|
return NULL;
|
|
}
|
|
|
|
/* remove old cache info */
|
|
iter = blkid_tag_iterate_begin(dev);
|
|
while (blkid_tag_next(iter, &type, &value) == 0)
|
|
blkid_set_tag(dev, type, NULL, 0);
|
|
blkid_tag_iterate_end(iter);
|
|
|
|
/* enable superblocks probing */
|
|
blkid_probe_enable_superblocks(cache->probe, TRUE);
|
|
blkid_probe_set_superblocks_flags(cache->probe,
|
|
BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
|
|
BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE);
|
|
|
|
/* enable partitions probing */
|
|
blkid_probe_enable_partitions(cache->probe, TRUE);
|
|
blkid_probe_set_partitions_flags(cache->probe, BLKID_PARTS_ENTRY_DETAILS);
|
|
|
|
/* probe */
|
|
if (blkid_do_safeprobe(cache->probe)) {
|
|
/* found nothing or error */
|
|
blkid_free_dev(dev);
|
|
dev = NULL;
|
|
}
|
|
|
|
if (dev) {
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
|
struct timeval tv;
|
|
if (!gettimeofday(&tv, NULL)) {
|
|
dev->bid_time = tv.tv_sec;
|
|
dev->bid_utime = tv.tv_usec;
|
|
} else
|
|
#endif
|
|
dev->bid_time = time(0);
|
|
|
|
dev->bid_devno = st.st_rdev;
|
|
dev->bid_flags |= BLKID_BID_FL_VERIFIED;
|
|
cache->bic_flags |= BLKID_BIC_FL_CHANGED;
|
|
|
|
blkid_probe_to_tags(cache->probe, dev);
|
|
|
|
DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n",
|
|
dev->bid_name, (long long)st.st_rdev, dev->bid_type));
|
|
}
|
|
|
|
blkid_reset_probe(cache->probe);
|
|
blkid_probe_reset_superblocks_filter(cache->probe);
|
|
close(fd);
|
|
return dev;
|
|
}
|
|
|
|
#ifdef TEST_PROGRAM
|
|
int main(int argc, char **argv)
|
|
{
|
|
blkid_dev dev;
|
|
blkid_cache cache;
|
|
int ret;
|
|
|
|
if (argc != 2) {
|
|
fprintf(stderr, "Usage: %s device\n"
|
|
"Probe a single device to determine type\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
|
|
fprintf(stderr, "%s: error creating cache (%d)\n",
|
|
argv[0], ret);
|
|
exit(1);
|
|
}
|
|
dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL);
|
|
if (!dev) {
|
|
printf("%s: %s has an unsupported type\n", argv[0], argv[1]);
|
|
return (1);
|
|
}
|
|
printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)");
|
|
if (dev->bid_label)
|
|
printf("LABEL='%s'\n", dev->bid_label);
|
|
if (dev->bid_uuid)
|
|
printf("UUID='%s'\n", dev->bid_uuid);
|
|
|
|
blkid_free_dev(dev);
|
|
return (0);
|
|
}
|
|
#endif
|