]>
Commit | Line | Data |
---|---|---|
e12f2ae7 TT |
1 | /* |
2 | * probe.c - identify a block device by its contents, and return a dev | |
3 | * struct with the details | |
4 | * | |
5 | * Copyright (C) 1999 by Andries Brouwer | |
50b380b4 | 6 | * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o |
e12f2ae7 | 7 | * Copyright (C) 2001 by Andreas Dilger |
2f79e519 | 8 | * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> |
e12f2ae7 TT |
9 | * |
10 | * %Begin-Header% | |
11 | * This file may be redistributed under the terms of the | |
12 | * GNU Lesser General Public License. | |
13 | * %End-Header% | |
14 | */ | |
15 | ||
16 | #include <stdio.h> | |
17 | #include <string.h> | |
18 | #include <stdlib.h> | |
19 | #include <unistd.h> | |
20 | #include <fcntl.h> | |
21 | #include <sys/types.h> | |
22 | #ifdef HAVE_SYS_STAT_H | |
23 | #include <sys/stat.h> | |
24 | #endif | |
25 | #ifdef HAVE_SYS_MKDEV_H | |
26 | #include <sys/mkdev.h> | |
27 | #endif | |
28 | #ifdef HAVE_ERRNO_H | |
29 | #include <errno.h> | |
30 | #endif | |
7a603aa8 | 31 | #include "blkidP.h" |
e12f2ae7 TT |
32 | #include "uuid/uuid.h" |
33 | #include "probe.h" | |
34 | ||
45a3fa87 TT |
35 | static int figure_label_len(const unsigned char *label, int len) |
36 | { | |
37 | const unsigned char *end = label + len - 1; | |
38 | ||
39 | while ((*end == ' ' || *end == 0) && end >= label) | |
40 | --end; | |
41 | if (end >= label) { | |
42 | label = label; | |
43 | return end - label + 1; | |
44 | } | |
45 | return 0; | |
46 | } | |
47 | ||
ca749859 TT |
48 | static unsigned char *get_buffer(struct blkid_probe *pr, |
49 | unsigned off, size_t len) | |
50 | { | |
51 | ssize_t ret_read; | |
52 | unsigned char *newbuf; | |
53 | ||
54 | if (off + len <= SB_BUFFER_SIZE) { | |
55 | if (!pr->sbbuf) { | |
56 | pr->sbbuf = malloc(SB_BUFFER_SIZE); | |
57 | if (!pr->sbbuf) | |
58 | return NULL; | |
59 | if (lseek(pr->fd, 0, SEEK_SET) < 0) | |
60 | return NULL; | |
61 | ret_read = read(pr->fd, pr->sbbuf, SB_BUFFER_SIZE); | |
62 | if (ret_read < 0) | |
63 | ret_read = 0; | |
64 | pr->sb_valid = ret_read; | |
65 | } | |
66 | if (off+len > pr->sb_valid) | |
67 | return NULL; | |
68 | return pr->sbbuf + off; | |
69 | } else { | |
70 | if (len > pr->buf_max) { | |
71 | newbuf = realloc(pr->buf, len); | |
72 | if (newbuf == NULL) | |
73 | return NULL; | |
74 | pr->buf = newbuf; | |
75 | pr->buf_max = len; | |
76 | } | |
77 | if (lseek(pr->fd, off, SEEK_SET) < 0) | |
78 | return NULL; | |
79 | ret_read = read(pr->fd, pr->buf, len); | |
80 | if (ret_read != (ssize_t) len) | |
81 | return NULL; | |
82 | return pr->buf; | |
83 | } | |
84 | } | |
85 | ||
86 | ||
e12f2ae7 | 87 | /* |
50b380b4 TT |
88 | * This is a special case code to check for an MDRAID device. We do |
89 | * this special since it requires checking for a superblock at the end | |
90 | * of the device. | |
e12f2ae7 | 91 | */ |
50b380b4 | 92 | static int check_mdraid(int fd, unsigned char *ret_uuid) |
e12f2ae7 | 93 | { |
50b380b4 TT |
94 | struct mdp_superblock_s *md; |
95 | blkid_loff_t offset; | |
96 | char buf[4096]; | |
97 | ||
98 | if (fd < 0) | |
e12f2ae7 TT |
99 | return -BLKID_ERR_PARAM; |
100 | ||
50b380b4 | 101 | offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536; |
e12f2ae7 TT |
102 | |
103 | if (blkid_llseek(fd, offset, 0) < 0 || | |
50b380b4 | 104 | read(fd, buf, 4096) != 4096) |
e12f2ae7 TT |
105 | return -BLKID_ERR_IO; |
106 | ||
50b380b4 TT |
107 | /* Check for magic number */ |
108 | if (memcmp("\251+N\374", buf, 4)) | |
e12f2ae7 TT |
109 | return -BLKID_ERR_PARAM; |
110 | ||
50b380b4 TT |
111 | if (!ret_uuid) |
112 | return 0; | |
113 | *ret_uuid = 0; | |
e12f2ae7 | 114 | |
50b380b4 TT |
115 | /* The MD UUID is not contiguous in the superblock, make it so */ |
116 | md = (struct mdp_superblock_s *)buf; | |
117 | if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) { | |
118 | memcpy(ret_uuid, &md->set_uuid0, 4); | |
119 | memcpy(ret_uuid, &md->set_uuid1, 12); | |
e12f2ae7 | 120 | } |
50b380b4 TT |
121 | return 0; |
122 | } | |
e12f2ae7 | 123 | |
ba5e3849 | 124 | static void set_uuid(blkid_dev dev, uuid_t uuid, char *tag) |
50b380b4 TT |
125 | { |
126 | char str[37]; | |
e12f2ae7 | 127 | |
50b380b4 TT |
128 | if (!uuid_is_null(uuid)) { |
129 | uuid_unparse(uuid, str); | |
ba5e3849 | 130 | blkid_set_tag(dev, tag ? tag : "UUID", str, sizeof(str)); |
50b380b4 | 131 | } |
e12f2ae7 TT |
132 | } |
133 | ||
2e6a9feb TT |
134 | static void get_ext2_info(blkid_dev dev, unsigned char *buf) |
135 | { | |
136 | struct ext2_super_block *es = (struct ext2_super_block *) buf; | |
137 | const char *label = 0; | |
138 | ||
139 | DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n", | |
140 | blkid_le32(es->s_feature_compat), | |
141 | blkid_le32(es->s_feature_incompat), | |
142 | blkid_le32(es->s_feature_ro_compat))); | |
143 | ||
7369f0ce | 144 | if (strlen(es->s_volume_name)) |
2e6a9feb | 145 | label = es->s_volume_name; |
7369f0ce | 146 | blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name)); |
2e6a9feb | 147 | |
ba5e3849 | 148 | set_uuid(dev, es->s_uuid, 0); |
2e6a9feb TT |
149 | } |
150 | ||
ca749859 | 151 | static int probe_ext3(struct blkid_probe *probe, |
12b3c8ec TT |
152 | struct blkid_magic *id __BLKID_ATTR((unused)), |
153 | unsigned char *buf) | |
e12f2ae7 | 154 | { |
e12f2ae7 | 155 | struct ext2_super_block *es; |
ba5e3849 | 156 | char uuid[37]; |
e12f2ae7 TT |
157 | es = (struct ext2_super_block *)buf; |
158 | ||
79dd234a | 159 | /* Distinguish between jbd and ext2/3 fs */ |
2e6a9feb TT |
160 | if (blkid_le32(es->s_feature_incompat) & |
161 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) | |
e12f2ae7 | 162 | return -BLKID_ERR_PARAM; |
e12f2ae7 | 163 | |
2e6a9feb TT |
164 | /* Distinguish between ext3 and ext2 */ |
165 | if (!(blkid_le32(es->s_feature_compat) & | |
166 | EXT3_FEATURE_COMPAT_HAS_JOURNAL)) | |
167 | return -BLKID_ERR_PARAM; | |
e12f2ae7 | 168 | |
ca749859 | 169 | get_ext2_info(probe->dev, buf); |
e12f2ae7 | 170 | |
ba5e3849 TT |
171 | if ((es->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && |
172 | !uuid_is_null(es->s_journal_uuid)) | |
173 | set_uuid(probe->dev, es->s_journal_uuid, "EXT_JOURNAL"); | |
174 | ||
ca749859 | 175 | blkid_set_tag(probe->dev, "SEC_TYPE", "ext2", sizeof("ext2")); |
2e6a9feb TT |
176 | |
177 | return 0; | |
178 | } | |
179 | ||
ca749859 | 180 | static int probe_ext2(struct blkid_probe *probe, |
12b3c8ec TT |
181 | struct blkid_magic *id __BLKID_ATTR((unused)), |
182 | unsigned char *buf) | |
2e6a9feb TT |
183 | { |
184 | struct ext2_super_block *es; | |
2e6a9feb TT |
185 | |
186 | es = (struct ext2_super_block *)buf; | |
187 | ||
188 | /* Distinguish between jbd and ext2/3 fs */ | |
189 | if (blkid_le32(es->s_feature_incompat) & | |
190 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) | |
191 | return -BLKID_ERR_PARAM; | |
05a6edf4 KZ |
192 | |
193 | /* Distinguish between ext3 and ext2 */ | |
194 | if ((blkid_le32(es->s_feature_compat) & | |
195 | EXT3_FEATURE_COMPAT_HAS_JOURNAL)) | |
196 | return -BLKID_ERR_PARAM; | |
2e6a9feb | 197 | |
ca749859 | 198 | get_ext2_info(probe->dev, buf); |
79dd234a | 199 | |
e12f2ae7 TT |
200 | return 0; |
201 | } | |
202 | ||
ca749859 | 203 | static int probe_jbd(struct blkid_probe *probe, |
54434927 TT |
204 | struct blkid_magic *id __BLKID_ATTR((unused)), |
205 | unsigned char *buf) | |
e12f2ae7 | 206 | { |
50b380b4 | 207 | struct ext2_super_block *es = (struct ext2_super_block *) buf; |
e12f2ae7 | 208 | |
76b07bb1 | 209 | if (!(blkid_le32(es->s_feature_incompat) & |
50b380b4 | 210 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) |
e12f2ae7 | 211 | return -BLKID_ERR_PARAM; |
e12f2ae7 | 212 | |
ca749859 | 213 | get_ext2_info(probe->dev, buf); |
2e6a9feb TT |
214 | |
215 | return 0; | |
e12f2ae7 TT |
216 | } |
217 | ||
2f79e519 TT |
218 | #define FAT_ATTR_VOLUME_ID 0x08 |
219 | #define FAT_ATTR_DIR 0x10 | |
220 | #define FAT_ATTR_LONG_NAME 0x0f | |
221 | #define FAT_ATTR_MASK 0x3f | |
222 | #define FAT_ENTRY_FREE 0xe5 | |
223 | ||
224 | static char *no_name = "NO NAME "; | |
225 | ||
226 | static unsigned char *search_fat_label(struct vfat_dir_entry *dir, int count) | |
227 | { | |
228 | unsigned int i; | |
229 | ||
230 | for (i = 0; i < count; i++) { | |
231 | if (dir[i].name[0] == 0x00) | |
232 | break; | |
233 | ||
234 | if ((dir[i].name[0] == FAT_ENTRY_FREE) || | |
235 | (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) || | |
236 | ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)) | |
237 | continue; | |
238 | ||
239 | if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == | |
240 | FAT_ATTR_VOLUME_ID) { | |
241 | return dir[i].name; | |
242 | } | |
243 | } | |
244 | return 0; | |
245 | } | |
246 | ||
247 | /* FAT label extraction from the root directory taken from Kay | |
248 | * Sievers's volume_id library */ | |
ca749859 | 249 | static int probe_fat(struct blkid_probe *probe, |
54434927 TT |
250 | struct blkid_magic *id __BLKID_ATTR((unused)), |
251 | unsigned char *buf) | |
e12f2ae7 | 252 | { |
038d2bed TT |
253 | struct vfat_super_block *vs = (struct vfat_super_block *) buf; |
254 | struct msdos_super_block *ms = (struct msdos_super_block *) buf; | |
2f79e519 | 255 | struct vfat_dir_entry *dir; |
e12f2ae7 | 256 | char serno[10]; |
ca749859 | 257 | const unsigned char *label = 0, *vol_label = 0; |
038d2bed | 258 | unsigned char *vol_serno; |
2f79e519 TT |
259 | int label_len = 0, maxloop = 100; |
260 | __u16 sector_size, dir_entries, reserved; | |
261 | __u32 sect_count, fat_size, dir_size, cluster_count, fat_length; | |
262 | __u32 buf_size, start_data_sect, next, root_start, root_dir_entries; | |
e12f2ae7 | 263 | |
038d2bed TT |
264 | /* sector size check */ |
265 | sector_size = blkid_le16(*((__u16 *) &ms->ms_sector_size)); | |
266 | if (sector_size != 0x200 && sector_size != 0x400 && | |
267 | sector_size != 0x800 && sector_size != 0x1000) | |
268 | return 1; | |
e12f2ae7 | 269 | |
038d2bed TT |
270 | dir_entries = blkid_le16(*((__u16 *) &ms->ms_dir_entries)); |
271 | reserved = blkid_le16(ms->ms_reserved); | |
272 | sect_count = blkid_le16(*((__u16 *) &ms->ms_sectors)); | |
273 | if (sect_count == 0) | |
274 | sect_count = blkid_le32(ms->ms_total_sect); | |
e12f2ae7 | 275 | |
038d2bed TT |
276 | fat_length = blkid_le16(ms->ms_fat_length); |
277 | if (fat_length == 0) | |
278 | fat_length = blkid_le32(vs->vs_fat32_length); | |
e12f2ae7 | 279 | |
038d2bed TT |
280 | fat_size = fat_length * ms->ms_fats; |
281 | dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + | |
282 | (sector_size-1)) / sector_size; | |
e12f2ae7 | 283 | |
038d2bed TT |
284 | cluster_count = sect_count - (reserved + fat_size + dir_size); |
285 | cluster_count /= ms->ms_cluster_size; | |
e12f2ae7 | 286 | |
038d2bed TT |
287 | if (cluster_count > FAT32_MAX) |
288 | return 1; | |
289 | ||
290 | if (ms->ms_fat_length) { | |
2f79e519 TT |
291 | /* the label may be an attribute in the root directory */ |
292 | root_start = (reserved + fat_size) * sector_size; | |
293 | root_dir_entries = vs->vs_dir_entries[0] + | |
294 | (vs->vs_dir_entries[1] << 8); | |
295 | ||
296 | buf_size = root_dir_entries * sizeof(struct vfat_dir_entry); | |
297 | dir = (struct vfat_dir_entry *) get_buffer(probe, root_start, | |
298 | buf_size); | |
299 | if (dir) | |
300 | vol_label = search_fat_label(dir, root_dir_entries); | |
301 | ||
302 | if (!vol_label || !memcmp(vol_label, no_name, 11)) | |
303 | vol_label = ms->ms_label; | |
038d2bed TT |
304 | vol_serno = ms->ms_serno; |
305 | ||
2f79e519 TT |
306 | blkid_set_tag(probe->dev, "SEC_TYPE", "msdos", |
307 | sizeof("msdos")); | |
038d2bed | 308 | } else { |
2f79e519 TT |
309 | /* Search the FAT32 root dir for the label attribute */ |
310 | buf_size = vs->vs_cluster_size * sector_size; | |
311 | start_data_sect = reserved + fat_size; | |
312 | ||
313 | next = blkid_le32(vs->vs_root_cluster); | |
314 | while (next && --maxloop) { | |
315 | __u32 next_sect_off; | |
316 | __u64 next_off, fat_entry_off; | |
317 | int count; | |
318 | ||
319 | next_sect_off = (next - 2) * vs->vs_cluster_size; | |
320 | next_off = (start_data_sect + next_sect_off) * | |
321 | sector_size; | |
322 | ||
323 | dir = (struct vfat_dir_entry *) | |
324 | get_buffer(probe, next_off, buf_size); | |
325 | if (dir == NULL) | |
326 | break; | |
327 | ||
328 | count = buf_size / sizeof(struct vfat_dir_entry); | |
329 | ||
330 | vol_label = search_fat_label(dir, count); | |
331 | if (vol_label) | |
332 | break; | |
333 | ||
334 | /* get FAT entry */ | |
335 | fat_entry_off = (reserved * sector_size) + | |
336 | (next * sizeof(__u32)); | |
337 | buf = get_buffer(probe, fat_entry_off, buf_size); | |
338 | if (buf == NULL) | |
339 | break; | |
340 | ||
341 | /* set next cluster */ | |
342 | next = blkid_le32(*((__u32 *) buf) & 0x0fffffff); | |
343 | } | |
344 | ||
345 | if (!vol_label || !memcmp(vol_label, no_name, 11)) | |
346 | vol_label = vs->vs_label; | |
038d2bed TT |
347 | vol_serno = vs->vs_serno; |
348 | } | |
e12f2ae7 | 349 | |
2f79e519 | 350 | if (vol_label && memcmp(vol_label, no_name, 11)) { |
45a3fa87 TT |
351 | label = vol_label; |
352 | label_len = figure_label_len(vol_label, 11); | |
e12f2ae7 TT |
353 | } |
354 | ||
355 | /* We can't just print them as %04X, because they are unaligned */ | |
038d2bed TT |
356 | sprintf(serno, "%02X%02X-%02X%02X", vol_serno[3], vol_serno[2], |
357 | vol_serno[1], vol_serno[0]); | |
358 | ||
ca749859 TT |
359 | blkid_set_tag(probe->dev, "LABEL", (const char *) label, label_len); |
360 | blkid_set_tag(probe->dev, "UUID", serno, sizeof(serno)-1); | |
e12f2ae7 TT |
361 | |
362 | return 0; | |
363 | } | |
364 | ||
c4c740ff KZ |
365 | /* |
366 | * The FAT filesystem could be without a magic string in superblock | |
367 | * (e.g. old floppies). This heuristic for FAT detection is inspired | |
368 | * by http://vrfy.org/projects/volume_id/ and Linux kernel. | |
369 | * [7-Jul-2005, Karel Zak <kzak@redhat.com>] | |
370 | */ | |
ca749859 | 371 | static int probe_fat_nomagic(struct blkid_probe *probe, |
038d2bed TT |
372 | struct blkid_magic *id __BLKID_ATTR((unused)), |
373 | unsigned char *buf) | |
c4c740ff KZ |
374 | { |
375 | struct vfat_super_block *vs; | |
c4c740ff KZ |
376 | |
377 | vs = (struct vfat_super_block *)buf; | |
378 | ||
c4c740ff KZ |
379 | /* heads check */ |
380 | if (vs->vs_heads == 0) | |
381 | return 1; | |
382 | ||
383 | /* cluster size check*/ | |
384 | if (vs->vs_cluster_size == 0 || | |
385 | (vs->vs_cluster_size & (vs->vs_cluster_size-1))) | |
386 | return 1; | |
387 | ||
388 | /* media check */ | |
389 | if (vs->vs_media < 0xf8 && vs->vs_media != 0xf0) | |
390 | return 1; | |
391 | ||
392 | /* fat counts(Linux kernel expects at least 1 FAT table) */ | |
393 | if (!vs->vs_fats) | |
394 | return 1; | |
395 | ||
ca749859 | 396 | return probe_fat(probe, id, buf); |
c4c740ff KZ |
397 | } |
398 | ||
ca749859 | 399 | static int probe_xfs(struct blkid_probe *probe, |
54434927 TT |
400 | struct blkid_magic *id __BLKID_ATTR((unused)), |
401 | unsigned char *buf) | |
e12f2ae7 | 402 | { |
e12f2ae7 | 403 | struct xfs_super_block *xs; |
a30b9446 | 404 | const char *label = 0; |
e12f2ae7 TT |
405 | |
406 | xs = (struct xfs_super_block *)buf; | |
407 | ||
e12f2ae7 | 408 | if (strlen(xs->xs_fname)) |
a30b9446 | 409 | label = xs->xs_fname; |
ca749859 | 410 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(xs->xs_fname)); |
ba5e3849 | 411 | set_uuid(probe->dev, xs->xs_uuid, 0); |
e12f2ae7 TT |
412 | return 0; |
413 | } | |
414 | ||
ca749859 | 415 | static int probe_reiserfs(struct blkid_probe *probe, |
79dd234a | 416 | struct blkid_magic *id, unsigned char *buf) |
e12f2ae7 | 417 | { |
50b380b4 | 418 | struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf; |
e12f2ae7 | 419 | unsigned int blocksize; |
a30b9446 | 420 | const char *label = 0; |
e12f2ae7 | 421 | |
76b07bb1 | 422 | blocksize = blkid_le16(rs->rs_blocksize); |
e12f2ae7 TT |
423 | |
424 | /* If the superblock is inside the journal, we have the wrong one */ | |
50b380b4 | 425 | if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block)) |
e12f2ae7 | 426 | return -BLKID_ERR_BIG; |
e12f2ae7 TT |
427 | |
428 | /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ | |
ca749859 | 429 | if (id->bim_magic[6] == '2' || id->bim_magic[6] == '3') { |
a30b9446 TT |
430 | if (strlen(rs->rs_label)) |
431 | label = rs->rs_label; | |
ba5e3849 | 432 | set_uuid(probe->dev, rs->rs_uuid, 0); |
e12f2ae7 | 433 | } |
ca749859 | 434 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(rs->rs_label)); |
e12f2ae7 TT |
435 | |
436 | return 0; | |
437 | } | |
438 | ||
ca749859 TT |
439 | static int probe_reiserfs4(struct blkid_probe *probe, |
440 | struct blkid_magic *id __BLKID_ATTR((unused)), | |
441 | unsigned char *buf) | |
bb626bcd TT |
442 | { |
443 | struct reiser4_super_block *rs4 = (struct reiser4_super_block *) buf; | |
ca749859 | 444 | const unsigned char *label = 0; |
bb626bcd | 445 | |
ca749859 | 446 | if (strlen((char *) rs4->rs4_label)) |
bb626bcd | 447 | label = rs4->rs4_label; |
ba5e3849 | 448 | set_uuid(probe->dev, rs4->rs4_uuid, 0); |
ca749859 TT |
449 | blkid_set_tag(probe->dev, "LABEL", (const char *) label, |
450 | sizeof(rs4->rs4_label)); | |
bb626bcd TT |
451 | |
452 | return 0; | |
453 | } | |
454 | ||
ca749859 | 455 | static int probe_jfs(struct blkid_probe *probe, |
54434927 TT |
456 | struct blkid_magic *id __BLKID_ATTR((unused)), |
457 | unsigned char *buf) | |
09a2ef8d TT |
458 | { |
459 | struct jfs_super_block *js; | |
a30b9446 | 460 | const char *label = 0; |
09a2ef8d TT |
461 | |
462 | js = (struct jfs_super_block *)buf; | |
463 | ||
48e6e813 | 464 | if (strlen((char *) js->js_label)) |
a30b9446 | 465 | label = (char *) js->js_label; |
ca749859 | 466 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(js->js_label)); |
ba5e3849 | 467 | set_uuid(probe->dev, js->js_uuid, 0); |
09a2ef8d TT |
468 | return 0; |
469 | } | |
470 | ||
ca749859 | 471 | static int probe_romfs(struct blkid_probe *probe, |
54434927 TT |
472 | struct blkid_magic *id __BLKID_ATTR((unused)), |
473 | unsigned char *buf) | |
09a2ef8d TT |
474 | { |
475 | struct romfs_super_block *ros; | |
a30b9446 | 476 | const char *label = 0; |
09a2ef8d TT |
477 | |
478 | ros = (struct romfs_super_block *)buf; | |
479 | ||
a30b9446 TT |
480 | if (strlen((char *) ros->ros_volume)) |
481 | label = (char *) ros->ros_volume; | |
ca749859 | 482 | blkid_set_tag(probe->dev, "LABEL", label, 0); |
7369f0ce TT |
483 | return 0; |
484 | } | |
485 | ||
ca749859 TT |
486 | static int probe_cramfs(struct blkid_probe *probe, |
487 | struct blkid_magic *id __BLKID_ATTR((unused)), | |
488 | unsigned char *buf) | |
4c4e3f78 TT |
489 | { |
490 | struct cramfs_super_block *csb; | |
491 | const char *label = 0; | |
492 | ||
493 | csb = (struct cramfs_super_block *)buf; | |
494 | ||
495 | if (strlen((char *) csb->name)) | |
496 | label = (char *) csb->name; | |
ca749859 | 497 | blkid_set_tag(probe->dev, "LABEL", label, 0); |
4c4e3f78 TT |
498 | return 0; |
499 | } | |
500 | ||
ca749859 | 501 | static int probe_swap0(struct blkid_probe *probe, |
7369f0ce TT |
502 | struct blkid_magic *id __BLKID_ATTR((unused)), |
503 | unsigned char *buf __BLKID_ATTR((unused))) | |
504 | { | |
ca749859 TT |
505 | blkid_set_tag(probe->dev, "UUID", 0, 0); |
506 | blkid_set_tag(probe->dev, "LABEL", 0, 0); | |
7369f0ce TT |
507 | return 0; |
508 | } | |
509 | ||
ca749859 | 510 | static int probe_swap1(struct blkid_probe *probe, |
7369f0ce TT |
511 | struct blkid_magic *id __BLKID_ATTR((unused)), |
512 | unsigned char *buf __BLKID_ATTR((unused))) | |
513 | { | |
514 | struct swap_id_block *sws; | |
7369f0ce | 515 | |
ca749859 | 516 | probe_swap0(probe, id, buf); |
7369f0ce TT |
517 | /* |
518 | * Version 1 swap headers are always located at offset of 1024 | |
519 | * bytes, although the swap signature itself is located at the | |
520 | * end of the page (which may vary depending on hardware | |
521 | * pagesize). | |
522 | */ | |
ca749859 TT |
523 | sws = (struct swap_id_block *) get_buffer(probe, 1024, 1024); |
524 | if (!sws) | |
7369f0ce | 525 | return 1; |
7369f0ce TT |
526 | |
527 | /* arbitrary sanity check.. is there any garbage down there? */ | |
528 | if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0) { | |
529 | if (sws->sws_volume[0]) | |
ca749859 | 530 | blkid_set_tag(probe->dev, "LABEL", sws->sws_volume, |
7369f0ce TT |
531 | sizeof(sws->sws_volume)); |
532 | if (sws->sws_uuid[0]) | |
ba5e3849 | 533 | set_uuid(probe->dev, sws->sws_uuid, 0); |
7369f0ce | 534 | } |
09a2ef8d TT |
535 | return 0; |
536 | } | |
537 | ||
ca749859 | 538 | static int probe_iso9660(struct blkid_probe *probe, |
45a3fa87 TT |
539 | struct blkid_magic *id __BLKID_ATTR((unused)), |
540 | unsigned char *buf) | |
541 | { | |
542 | struct iso_volume_descriptor *iso; | |
543 | const unsigned char *label; | |
544 | ||
545 | iso = (struct iso_volume_descriptor *) buf; | |
45a3fa87 TT |
546 | label = iso->volume_id; |
547 | ||
ca749859 TT |
548 | blkid_set_tag(probe->dev, "LABEL", (const char *) label, |
549 | figure_label_len(label, 32)); | |
45a3fa87 TT |
550 | return 0; |
551 | } | |
552 | ||
553 | ||
54434927 | 554 | static const char |
3de5bf61 TT |
555 | *udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02", |
556 | "NSR03", "TEA01", 0 }; | |
557 | ||
ca749859 TT |
558 | static int probe_udf(struct blkid_probe *probe, |
559 | struct blkid_magic *id __BLKID_ATTR((unused)), | |
54434927 | 560 | unsigned char *buf __BLKID_ATTR((unused))) |
3de5bf61 TT |
561 | { |
562 | int j, bs; | |
ca749859 | 563 | struct iso_volume_descriptor *isosb; |
54434927 | 564 | const char ** m; |
3de5bf61 TT |
565 | |
566 | /* determine the block size by scanning in 2K increments | |
567 | (block sizes larger than 2K will be null padded) */ | |
568 | for (bs = 1; bs < 16; bs++) { | |
ca749859 TT |
569 | isosb = (struct iso_volume_descriptor *) |
570 | get_buffer(probe, bs*2048+32768, sizeof(isosb)); | |
571 | if (!isosb) | |
3de5bf61 | 572 | return 1; |
ca749859 | 573 | if (isosb->vd_id[0]) |
3de5bf61 TT |
574 | break; |
575 | } | |
576 | ||
577 | /* Scan up to another 64 blocks looking for additional VSD's */ | |
578 | for (j = 1; j < 64; j++) { | |
579 | if (j > 1) { | |
ca749859 TT |
580 | isosb = (struct iso_volume_descriptor *) |
581 | get_buffer(probe, j*bs*2048+32768, | |
582 | sizeof(isosb)); | |
583 | if (!isosb) | |
3de5bf61 TT |
584 | return 1; |
585 | } | |
586 | /* If we find NSR0x then call it udf: | |
587 | NSR01 for UDF 1.00 | |
588 | NSR02 for UDF 1.50 | |
589 | NSR03 for UDF 2.00 */ | |
ca749859 | 590 | if (!strncmp(isosb->vd_id, "NSR0", 4)) |
3de5bf61 TT |
591 | return 0; |
592 | for (m = udf_magic; *m; m++) | |
ca749859 | 593 | if (!strncmp(*m, isosb->vd_id, 5)) |
3de5bf61 TT |
594 | break; |
595 | if (*m == 0) | |
596 | return 1; | |
597 | } | |
598 | return 1; | |
599 | } | |
600 | ||
ca749859 | 601 | static int probe_ocfs(struct blkid_probe *probe, |
9387c281 TT |
602 | struct blkid_magic *id __BLKID_ATTR((unused)), |
603 | unsigned char *buf) | |
604 | { | |
605 | struct ocfs_volume_header ovh; | |
606 | struct ocfs_volume_label ovl; | |
3838f7df | 607 | __u32 major; |
9387c281 TT |
608 | |
609 | memcpy(&ovh, buf, sizeof(ovh)); | |
610 | memcpy(&ovl, buf+512, sizeof(ovl)); | |
611 | ||
612 | major = ocfsmajor(ovh); | |
613 | if (major == 1) | |
ca749859 | 614 | blkid_set_tag(probe->dev,"SEC_TYPE","ocfs1",sizeof("ocfs1")); |
9387c281 | 615 | else if (major >= 9) |
ca749859 | 616 | blkid_set_tag(probe->dev,"SEC_TYPE","ntocfs",sizeof("ntocfs")); |
9387c281 | 617 | |
ca749859 TT |
618 | blkid_set_tag(probe->dev, "LABEL", ovl.label, ocfslabellen(ovl)); |
619 | blkid_set_tag(probe->dev, "MOUNT", ovh.mount, ocfsmountlen(ovh)); | |
ba5e3849 | 620 | set_uuid(probe->dev, ovl.vol_id, 0); |
9387c281 TT |
621 | return 0; |
622 | } | |
623 | ||
ca749859 | 624 | static int probe_ocfs2(struct blkid_probe *probe, |
2c92375e TT |
625 | struct blkid_magic *id __BLKID_ATTR((unused)), |
626 | unsigned char *buf) | |
414846b1 TT |
627 | { |
628 | struct ocfs2_super_block *osb; | |
629 | ||
630 | osb = (struct ocfs2_super_block *)buf; | |
631 | ||
ca749859 | 632 | blkid_set_tag(probe->dev, "LABEL", osb->s_label, sizeof(osb->s_label)); |
ba5e3849 | 633 | set_uuid(probe->dev, osb->s_uuid, 0); |
414846b1 TT |
634 | return 0; |
635 | } | |
636 | ||
ca749859 | 637 | static int probe_oracleasm(struct blkid_probe *probe, |
2c92375e TT |
638 | struct blkid_magic *id __BLKID_ATTR((unused)), |
639 | unsigned char *buf) | |
640 | { | |
641 | struct oracle_asm_disk_label *dl; | |
642 | ||
643 | dl = (struct oracle_asm_disk_label *)buf; | |
644 | ||
ca749859 | 645 | blkid_set_tag(probe->dev, "LABEL", dl->dl_id, sizeof(dl->dl_id)); |
2c92375e TT |
646 | return 0; |
647 | } | |
648 | ||
e12f2ae7 TT |
649 | /* |
650 | * BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined | |
50b380b4 TT |
651 | * in the type_array table below + bim_kbalign. |
652 | * | |
653 | * When probing for a lot of magics, we handle everything in 1kB buffers so | |
654 | * that we don't have to worry about reading each combination of block sizes. | |
e12f2ae7 | 655 | */ |
50b380b4 | 656 | #define BLKID_BLK_OFFS 64 /* currently reiserfs */ |
e12f2ae7 TT |
657 | |
658 | /* | |
659 | * Various filesystem magics that we can check for. Note that kboff and | |
660 | * sboff are in kilobytes and bytes respectively. All magics are in | |
661 | * byte strings so we don't worry about endian issues. | |
662 | */ | |
50b380b4 TT |
663 | static struct blkid_magic type_array[] = { |
664 | /* type kboff sboff len magic probe */ | |
2c92375e | 665 | { "oracleasm", 0, 32, 8, "ORCLDISK", probe_oracleasm }, |
9d0f4616 | 666 | { "ntfs", 0, 3, 8, "NTFS ", 0 }, |
50b380b4 | 667 | { "jbd", 1, 0x38, 2, "\123\357", probe_jbd }, |
2e6a9feb | 668 | { "ext3", 1, 0x38, 2, "\123\357", probe_ext3 }, |
50b380b4 TT |
669 | { "ext2", 1, 0x38, 2, "\123\357", probe_ext2 }, |
670 | { "reiserfs", 8, 0x34, 8, "ReIsErFs", probe_reiserfs }, | |
671 | { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", probe_reiserfs }, | |
672 | { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", probe_reiserfs }, | |
673 | { "reiserfs", 64, 0x34, 8, "ReIsErFs", probe_reiserfs }, | |
674 | { "reiserfs", 8, 20, 8, "ReIsErFs", probe_reiserfs }, | |
bb626bcd | 675 | { "reiser4", 64, 0, 7, "ReIsEr4", probe_reiserfs4 }, |
038d2bed TT |
676 | { "vfat", 0, 0x52, 5, "MSWIN", probe_fat }, |
677 | { "vfat", 0, 0x52, 8, "FAT32 ", probe_fat }, | |
678 | { "vfat", 0, 0x36, 5, "MSDOS", probe_fat }, | |
679 | { "vfat", 0, 0x36, 8, "FAT16 ", probe_fat }, | |
680 | { "vfat", 0, 0x36, 8, "FAT12 ", probe_fat }, | |
681 | { "vfat", 0, 0, 2, "\353\220", probe_fat_nomagic }, | |
682 | { "vfat", 0, 0, 1, "\351", probe_fat_nomagic }, | |
50b380b4 TT |
683 | { "minix", 1, 0x10, 2, "\177\023", 0 }, |
684 | { "minix", 1, 0x10, 2, "\217\023", 0 }, | |
685 | { "minix", 1, 0x10, 2, "\150\044", 0 }, | |
686 | { "minix", 1, 0x10, 2, "\170\044", 0 }, | |
687 | { "vxfs", 1, 0, 4, "\365\374\001\245", 0 }, | |
688 | { "xfs", 0, 0, 4, "XFSB", probe_xfs }, | |
09a2ef8d | 689 | { "romfs", 0, 0, 8, "-rom1fs-", probe_romfs }, |
50b380b4 | 690 | { "bfs", 0, 0, 4, "\316\372\173\033", 0 }, |
4c4e3f78 | 691 | { "cramfs", 0, 0, 4, "E=\315\050", probe_cramfs }, |
50b380b4 | 692 | { "qnx4", 0, 4, 6, "QNX4FS", 0 }, |
3de5bf61 TT |
693 | { "udf", 32, 1, 5, "BEA01", probe_udf }, |
694 | { "udf", 32, 1, 5, "BOOT2", probe_udf }, | |
695 | { "udf", 32, 1, 5, "CD001", probe_udf }, | |
696 | { "udf", 32, 1, 5, "CDW02", probe_udf }, | |
697 | { "udf", 32, 1, 5, "NSR02", probe_udf }, | |
698 | { "udf", 32, 1, 5, "NSR03", probe_udf }, | |
699 | { "udf", 32, 1, 5, "TEA01", probe_udf }, | |
45a3fa87 TT |
700 | { "iso9660", 32, 1, 5, "CD001", probe_iso9660 }, |
701 | { "iso9660", 32, 9, 5, "CDROM", probe_iso9660 }, | |
09a2ef8d | 702 | { "jfs", 32, 0, 4, "JFS1", probe_jfs }, |
50b380b4 TT |
703 | { "hfs", 1, 0, 2, "BD", 0 }, |
704 | { "ufs", 8, 0x55c, 4, "T\031\001\000", 0 }, | |
705 | { "hpfs", 8, 0, 4, "I\350\225\371", 0 }, | |
706 | { "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 }, | |
7369f0ce TT |
707 | { "swap", 0, 0xff6, 10, "SWAP-SPACE", probe_swap0 }, |
708 | { "swap", 0, 0xff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
709 | { "swsuspend", 0, 0xff6, 9, "S1SUSPEND", probe_swap1 }, |
710 | { "swsuspend", 0, 0xff6, 9, "S2SUSPEND", probe_swap1 }, | |
7369f0ce TT |
711 | { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", probe_swap0 }, |
712 | { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
713 | { "swsuspend", 0, 0x1ff6, 9, "S1SUSPEND", probe_swap1 }, |
714 | { "swsuspend", 0, 0x1ff6, 9, "S2SUSPEND", probe_swap1 }, | |
7369f0ce TT |
715 | { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", probe_swap0 }, |
716 | { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
717 | { "swsuspend", 0, 0x3ff6, 9, "S1SUSPEND", probe_swap1 }, |
718 | { "swsuspend", 0, 0x3ff6, 9, "S2SUSPEND", probe_swap1 }, | |
7369f0ce TT |
719 | { "swap", 0, 0x7ff6, 10, "SWAP-SPACE", probe_swap0 }, |
720 | { "swap", 0, 0x7ff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
721 | { "swsuspend", 0, 0x7ff6, 9, "S1SUSPEND", probe_swap1 }, |
722 | { "swsuspend", 0, 0x7ff6, 9, "S2SUSPEND", probe_swap1 }, | |
7369f0ce TT |
723 | { "swap", 0, 0xfff6, 10, "SWAP-SPACE", probe_swap0 }, |
724 | { "swap", 0, 0xfff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
725 | { "swsuspend", 0, 0xfff6, 9, "S1SUSPEND", probe_swap1 }, |
726 | { "swsuspend", 0, 0xfff6, 9, "S2SUSPEND", probe_swap1 }, | |
2c92375e TT |
727 | { "ocfs", 0, 8, 9, "OracleCFS", probe_ocfs }, |
728 | { "ocfs2", 1, 0, 6, "OCFSV2", probe_ocfs2 }, | |
729 | { "ocfs2", 2, 0, 6, "OCFSV2", probe_ocfs2 }, | |
730 | { "ocfs2", 4, 0, 6, "OCFSV2", probe_ocfs2 }, | |
731 | { "ocfs2", 8, 0, 6, "OCFSV2", probe_ocfs2 }, | |
50b380b4 | 732 | { NULL, 0, 0, 0, NULL, NULL } |
e12f2ae7 TT |
733 | }; |
734 | ||
e12f2ae7 TT |
735 | /* |
736 | * Verify that the data in dev is consistent with what is on the actual | |
737 | * block device (using the devname field only). Normally this will be | |
738 | * called when finding items in the cache, but for long running processes | |
739 | * is also desirable to revalidate an item before use. | |
740 | * | |
741 | * If we are unable to revalidate the data, we return the old data and | |
742 | * do not set the BLKID_BID_FL_VERIFIED flag on it. | |
743 | */ | |
18d12963 | 744 | blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) |
e12f2ae7 | 745 | { |
e12f2ae7 | 746 | struct blkid_magic *id; |
ca749859 | 747 | struct blkid_probe probe; |
ba5e3849 | 748 | blkid_tag_iterate iter; |
ca749859 | 749 | unsigned char *buf; |
ba5e3849 | 750 | const char *type, *value; |
50b380b4 | 751 | struct stat st; |
7ce08064 | 752 | time_t diff, now; |
ca749859 | 753 | int idx; |
e12f2ae7 TT |
754 | |
755 | if (!dev) | |
756 | return NULL; | |
757 | ||
7ce08064 TT |
758 | now = time(0); |
759 | diff = now - dev->bid_time; | |
e12f2ae7 | 760 | |
e324b250 TT |
761 | if ((now > dev->bid_time) && (diff > 0) && |
762 | ((diff < BLKID_PROBE_MIN) || | |
763 | (dev->bid_flags & BLKID_BID_FL_VERIFIED && | |
764 | diff < BLKID_PROBE_INTERVAL))) | |
e12f2ae7 TT |
765 | return dev; |
766 | ||
f0a22d0f TT |
767 | DBG(DEBUG_PROBE, |
768 | printf("need to revalidate %s (time since last check %lu)\n", | |
ce72b862 | 769 | dev->bid_name, diff)); |
e12f2ae7 | 770 | |
ca749859 TT |
771 | if (((probe.fd = open(dev->bid_name, O_RDONLY)) < 0) || |
772 | (fstat(probe.fd, &st) < 0)) { | |
ce72b862 | 773 | if (errno == ENXIO || errno == ENODEV || errno == ENOENT) { |
e12f2ae7 TT |
774 | blkid_free_dev(dev); |
775 | return NULL; | |
776 | } | |
777 | /* We don't have read permission, just return cache data. */ | |
f0a22d0f TT |
778 | DBG(DEBUG_PROBE, |
779 | printf("returning unverified data for %s\n", | |
780 | dev->bid_name)); | |
e12f2ae7 TT |
781 | return dev; |
782 | } | |
783 | ||
ca749859 TT |
784 | probe.cache = cache; |
785 | probe.dev = dev; | |
786 | probe.sbbuf = 0; | |
787 | probe.buf = 0; | |
788 | probe.buf_max = 0; | |
50b380b4 TT |
789 | |
790 | /* | |
791 | * Iterate over the type array. If we already know the type, | |
792 | * then try that first. If it doesn't work, then blow away | |
793 | * the type information, and try again. | |
794 | * | |
795 | */ | |
796 | try_again: | |
797 | type = 0; | |
50b380b4 TT |
798 | if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) { |
799 | uuid_t uuid; | |
800 | ||
ca749859 | 801 | if (check_mdraid(probe.fd, uuid) == 0) { |
ba5e3849 | 802 | set_uuid(dev, uuid, 0); |
50b380b4 TT |
803 | type = "mdraid"; |
804 | goto found_type; | |
805 | } | |
806 | } | |
e12f2ae7 | 807 | for (id = type_array; id->bim_type; id++) { |
50b380b4 TT |
808 | if (dev->bid_type && |
809 | strcmp(id->bim_type, dev->bid_type)) | |
810 | continue; | |
811 | ||
812 | idx = id->bim_kboff + (id->bim_sboff >> 10); | |
ca749859 TT |
813 | buf = get_buffer(&probe, idx << 10, 1024); |
814 | if (!buf) | |
50b380b4 | 815 | continue; |
e12f2ae7 | 816 | |
50b380b4 TT |
817 | if (memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ff), |
818 | id->bim_len)) | |
819 | continue; | |
820 | ||
821 | if ((id->bim_probe == NULL) || | |
ca749859 | 822 | (id->bim_probe(&probe, id, buf) == 0)) { |
50b380b4 TT |
823 | type = id->bim_type; |
824 | goto found_type; | |
e12f2ae7 TT |
825 | } |
826 | } | |
827 | ||
50b380b4 TT |
828 | if (!id->bim_type && dev->bid_type) { |
829 | /* | |
ba5e3849 | 830 | * Zap the device filesystem information and try again |
50b380b4 | 831 | */ |
ba5e3849 TT |
832 | iter = blkid_tag_iterate_begin(dev); |
833 | while (blkid_tag_next(iter, &type, &value) == 0) | |
834 | blkid_set_tag(dev, type, 0, 0); | |
835 | blkid_tag_iterate_end(iter); | |
50b380b4 TT |
836 | goto try_again; |
837 | } | |
e12f2ae7 | 838 | |
50b380b4 | 839 | if (!dev->bid_type) { |
e12f2ae7 | 840 | blkid_free_dev(dev); |
50b380b4 TT |
841 | return NULL; |
842 | } | |
843 | ||
844 | found_type: | |
845 | if (dev && type) { | |
846 | dev->bid_devno = st.st_rdev; | |
847 | dev->bid_time = time(0); | |
848 | dev->bid_flags |= BLKID_BID_FL_VERIFIED; | |
ce72b862 | 849 | cache->bic_flags |= BLKID_BIC_FL_CHANGED; |
50b380b4 | 850 | |
79dd234a | 851 | blkid_set_tag(dev, "TYPE", type, 0); |
50b380b4 | 852 | |
12b3c8ec | 853 | DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n", |
50b380b4 | 854 | dev->bid_name, st.st_rdev, type)); |
e12f2ae7 TT |
855 | } |
856 | ||
ca749859 TT |
857 | if (probe.sbbuf) |
858 | free(probe.sbbuf); | |
859 | if (probe.buf) | |
860 | free(probe.buf); | |
861 | close(probe.fd); | |
e12f2ae7 | 862 | |
e12f2ae7 | 863 | return dev; |
e12f2ae7 TT |
864 | } |
865 | ||
78e2edf7 TT |
866 | int blkid_known_fstype(const char *fstype) |
867 | { | |
868 | struct blkid_magic *id; | |
869 | ||
870 | for (id = type_array; id->bim_type; id++) { | |
871 | if (strcmp(fstype, id->bim_type) == 0) | |
872 | return 1; | |
873 | } | |
874 | return 0; | |
875 | } | |
876 | ||
e12f2ae7 TT |
877 | #ifdef TEST_PROGRAM |
878 | int main(int argc, char **argv) | |
879 | { | |
7a603aa8 | 880 | blkid_dev dev; |
50b380b4 | 881 | blkid_cache cache; |
79dd234a | 882 | int ret; |
e12f2ae7 TT |
883 | |
884 | if (argc != 2) { | |
885 | fprintf(stderr, "Usage: %s device\n" | |
886 | "Probe a single device to determine type\n", argv[0]); | |
887 | exit(1); | |
888 | } | |
79dd234a TT |
889 | if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { |
890 | fprintf(stderr, "%s: error creating cache (%d)\n", | |
891 | argv[0], ret); | |
892 | exit(1); | |
893 | } | |
98999c39 | 894 | dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL); |
50b380b4 | 895 | if (!dev) { |
e12f2ae7 | 896 | printf("%s: %s has an unsupported type\n", argv[0], argv[1]); |
50b380b4 TT |
897 | return (1); |
898 | } | |
1e5630ab | 899 | printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)"); |
50b380b4 | 900 | if (dev->bid_label) |
1e5630ab | 901 | printf("LABEL='%s'\n", dev->bid_label); |
50b380b4 | 902 | if (dev->bid_uuid) |
1e5630ab | 903 | printf("UUID='%s'\n", dev->bid_uuid); |
50b380b4 TT |
904 | |
905 | blkid_free_dev(dev); | |
e12f2ae7 TT |
906 | return (0); |
907 | } | |
908 | #endif |