(root)/
util-linux-2.39/
libblkid/
src/
verify.c
       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  {
      28  	const char *data;
      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++) {
      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);
      43  
      44  		} else if (!strstr(name, "_ID")) {
      45  			/* superblock UUID, LABEL, ...
      46  			 * but not {SYSTEM,APPLICATION,..._ID} */
      47  			blkid_set_tag(dev, name, data, len);
      48  		}
      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   */
      61  blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
      62  {
      63  	blkid_tag_iterate iter;
      64  	const char *type, *value;
      65  	struct stat st;
      66  	time_t diff, now;
      67  	int fd;
      68  
      69  	if (!dev || !cache)
      70  		return NULL;
      71  
      72  	now = time(NULL);
      73  	diff = (uintmax_t)now - dev->bid_time;
      74  
      75  	if (stat(dev->bid_name, &st) < 0) {
      76  		DBG(PROBE, ul_debug("blkid_verify: error %s (%d) while "
      77  			   "trying to stat %s", strerror(errno), errno,
      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. */
      82  			DBG(PROBE, ul_debug("returning unverified data for %s",
      83  						dev->bid_name));
      84  			return dev;
      85  		}
      86  		blkid_free_dev(dev);
      87  		return NULL;
      88  	}
      89  
      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
      98  	    diff >= 0 && diff < BLKID_PROBE_MIN) {
      99  		dev->bid_flags |= BLKID_BID_FL_VERIFIED;
     100  		return dev;
     101  	}
     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  	DBG(PROBE, ul_debug("need to revalidate %s (cache time %lld.%lld, stat time %lld.%lld,\t"
     110  		   "time since last check %lld)",
     111  		   dev->bid_name,
     112  		   (long long)dev->bid_time, (long long)dev->bid_utime,
     113  		   (long long)st.st_mtime, (long long)st.st_mtim.tv_nsec / 1000,
     114  		   (long long)diff));
     115  #endif
     116  
     117  	if (sysfs_devno_is_dm_private(st.st_rdev, NULL)) {
     118  		blkid_free_dev(dev);
     119  		return NULL;
     120  	}
     121  	if (!cache->probe) {
     122  		cache->probe = blkid_new_probe();
     123  		if (!cache->probe) {
     124  			blkid_free_dev(dev);
     125  			return NULL;
     126  		}
     127  	}
     128  
     129  	fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
     130  	if (fd < 0) {
     131  		DBG(PROBE, ul_debug("blkid_verify: error %s (%d) while "
     132  					"opening %s", strerror(errno), errno,
     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  
     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);
     149  
     150  	/* enable superblocks probing */
     151  	blkid_probe_enable_superblocks(cache->probe, TRUE);
     152  	blkid_probe_set_superblocks_flags(cache->probe,
     153  		BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
     154  		BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE);
     155  
     156  	/* enable partitions probing */
     157  	blkid_probe_enable_partitions(cache->probe, TRUE);
     158  	blkid_probe_set_partitions_flags(cache->probe, BLKID_PARTS_ENTRY_DETAILS);
     159  
     160  	/* probe */
     161  	if (blkid_do_safeprobe(cache->probe)) {
     162  		/* found nothing or error */
     163  		blkid_free_dev(dev);
     164  		dev = NULL;
     165  	}
     166  
     167  	if (dev) {
     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
     175  			dev->bid_time = time(NULL);
     176  
     177  		dev->bid_devno = st.st_rdev;
     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  
     183  		DBG(PROBE, ul_debug("%s: devno 0x%04llx, type %s",
     184  			   dev->bid_name, (long long)st.st_rdev, dev->bid_type));
     185  	}
     186  
     187  	/* reset prober */
     188  	blkid_probe_reset_superblocks_filter(cache->probe);
     189  	blkid_probe_set_device(cache->probe, -1, 0, 0);
     190  	close(fd);
     191  
     192  	return dev;
     193  }
     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