Coverage Report

Created: 2025-10-10 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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