2 * get_device_by_label.h
4 * Copyright 1999 by Andries Brouwer
5 * Copyright 1999, 2000 by Theodore Ts'o
7 * This file may be redistributed under the terms of the GNU Public
10 * Taken from aeb's mount, 990619
11 * Updated from aeb's mount, 20000725
12 * Added call to ext2fs_find_block_device, so that we can find devices
13 * even if devfs (ugh) is compiled in, but not mounted, since
14 * this messes up /proc/partitions, by TYT.
23 #include <sys/types.h>
25 #ifdef HAVE_SYS_MKDEV_H
26 #include <sys/mkdev.h>
28 #ifdef HAVE_SYS_SYSMACROS_H
29 #include <sys/sysmacros.h>
32 #include "nls-enable.h"
34 #include "get_device_by_label.h"
36 /* function prototype from libext2 */
37 extern char *ext2fs_find_block_device(dev_t device);
39 #define PROC_PARTITIONS "/proc/partitions"
40 #define PROC_EVMS_VOLUMES "/proc/evms/volumes"
41 #define DEVLABELDIR "/dev"
42 #define VG_DIR "/proc/lvm/VGs"
44 #define EXT2_SUPER_MAGIC 0xEF53
45 struct ext2_super_block {
46 unsigned char s_dummy1[56];
47 unsigned char s_magic[2];
48 unsigned char s_dummy2[46];
49 unsigned char s_uuid[16];
50 unsigned char s_volume_name[16];
52 #define ext2magic(s) ((unsigned int) s.s_magic[0] + (((unsigned int) s.s_magic[1]) << 8))
54 #define XFS_SUPER_MAGIC "XFSB"
55 struct xfs_super_block {
56 unsigned char s_magic[4];
57 unsigned char s_dummy[28];
58 unsigned char s_uuid[16];
59 unsigned char s_dummy2[60];
60 unsigned char s_fname[12];
63 struct reiserfs_super_block
65 /* Following entries are based on reiserfsutils 3.6.3
66 * (Copyright Hans Reiser) since Linux kernel headers
67 * (2.4.18) seemed not up-to-date. */
68 unsigned char s_dummy1[52];
69 unsigned char s_magic[10];
70 unsigned char s_dummy2[10];
71 unsigned char s_version[2];
72 unsigned char s_dummy3[10];
73 unsigned char s_uuid[16];
74 unsigned char s_label[16];
75 unsigned char s_unused[88];
78 #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" /* v. 3.6 */
79 #define REISER3FS_SUPER_MAGIC_STRING "ReIsEr3Fs" /* Journal Relocation */
80 #define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
81 /* the spot for the super in versions 3.5 - 3.5.10 (inclusive) -
82 * We'll use it in case volume has been converted. */
83 #define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
84 #define reiserversion(s) ((unsigned) (s).s_version[0] + (((unsigned) (s).s_version[1]) << 8))
86 /* We're checking for ReiserFS v. 3.6 and RJ 3.6 SB */
88 reiser_supports_uuid (struct reiserfs_super_block *sb)
90 return (strncmp(sb->s_magic, REISER2FS_SUPER_MAGIC_STRING,
91 strlen (REISER2FS_SUPER_MAGIC_STRING)) == 0)
92 || (strncmp(sb->s_magic, REISER3FS_SUPER_MAGIC_STRING,
93 strlen (REISER3FS_SUPER_MAGIC_STRING)) == 0
94 && reiserversion(*sb) == 2);
97 static struct uuidCache_s {
98 struct uuidCache_s *next;
104 char *string_copy(const char *s)
108 ret = malloc(strlen(s)+1);
114 /* for now, only ext2, ext3, xfs and ReiserFS are supported */
116 get_label_uuid(const char *device, char **label, char *uuid) {
118 /* start with ext2/3, xfs and ReiserFS tests, taken from mount_guess_fstype */
119 /* should merge these later */
122 unsigned char *sb_uuid = 0, *sb_label = 0;
123 struct ext2_super_block e2sb;
124 struct xfs_super_block xfsb;
125 struct reiserfs_super_block rfsb;
127 fd = open(device, O_RDONLY);
131 if (lseek(fd, 1024, SEEK_SET) == 1024
132 && read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb)
133 && (ext2magic(e2sb) == EXT2_SUPER_MAGIC)) {
134 sb_uuid = e2sb.s_uuid;
135 sb_label = e2sb.s_volume_name;
136 label_size = sizeof(e2sb.s_volume_name);
137 } else if (lseek(fd, 0, SEEK_SET) == 0
138 && read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb)
139 && strncmp((char *) &xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0) {
140 sb_uuid = xfsb.s_uuid;
141 sb_label = xfsb.s_fname;
142 label_size = sizeof(xfsb.s_fname);
143 } else if ((lseek(fd, REISERFS_OLD_DISK_OFFSET_IN_BYTES, SEEK_SET)
144 == REISERFS_OLD_DISK_OFFSET_IN_BYTES
145 && read(fd, (char *) &rfsb, sizeof(rfsb)) == sizeof(rfsb)
146 && (reiser_supports_uuid(&rfsb)))
147 || (lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET)
148 == REISERFS_DISK_OFFSET_IN_BYTES
149 && read(fd, (char *) &rfsb, sizeof(rfsb)) == sizeof(rfsb)
150 && (reiser_supports_uuid(&rfsb)))) {
151 sb_uuid = rfsb.s_uuid;
152 sb_label = rfsb.s_label;
153 label_size = sizeof(rfsb.s_label);
161 memcpy(uuid, sb_uuid, sizeof(e2sb.s_uuid));
163 if ((*label = calloc(label_size + 1, 1)) != NULL)
164 memcpy(*label, sb_label, label_size);
169 #define CBBUF (16 * 1024)
172 uuidcache_addentry(char *device, char *label, char *uuid) {
173 struct uuidCache_s *last;
176 last = uuidCache = malloc(sizeof(*uuidCache));
178 for (last = uuidCache; last->next; last = last->next) ;
179 last->next = malloc(sizeof(*uuidCache));
183 last->device = device;
185 memcpy(last->uuid, uuid, sizeof(last->uuid));
189 * This function initializes the UUID cache with devices from the LVM
190 * proc hierarchy. We currently depend on the names of the LVM
191 * hierarchy giving us the device structure in /dev. (XXX is this a
195 static void init_lvm(void)
197 DIR *vg_dir, *lv_list;
198 char *vdirname, *lvm_device;
199 char uuid[16], *label, *vname, *lname;
200 struct dirent *vg_iter, *lv_iter;
202 if ((vg_dir = opendir(VG_DIR)) == NULL)
205 while ((vg_iter = readdir(vg_dir)) != 0) {
206 vname = vg_iter->d_name;
207 if (!strcmp(vname, ".") || !strcmp(vname, ".."))
209 vdirname = malloc(strlen(VG_DIR)+strlen(vname)+8);
214 sprintf(vdirname, "%s/%s/LVs", VG_DIR, vname);
216 lv_list = opendir(vdirname);
221 while ((lv_iter = readdir(lv_list)) != 0) {
222 lname = lv_iter->d_name;
223 if (!strcmp(lname, ".") || !strcmp(lname, ".."))
226 lvm_device = malloc(strlen(DEVLABELDIR) +
234 sprintf(lvm_device, "%s/%s/%s", DEVLABELDIR,
236 if (!get_label_uuid(lvm_device, &label, uuid)) {
237 uuidcache_addentry(string_copy(lvm_device),
249 read_partitions(void)
254 static char ptname[100];
256 char uuid[16], *label, *devname;
264 procpt = fopen(PROC_PARTITIONS, "r");
268 iobuf = (char *)malloc(CBBUF);
270 setvbuf(procpt, iobuf, _IOFBF, CBBUF);
272 for (firstPass = 1; firstPass >= 0; firstPass--) {
273 fseek(procpt, 0, SEEK_SET);
275 while (fgets(line, sizeof(line), procpt)) {
276 if (sscanf (line, " %d %d %d %[^\n ]",
277 &ma, &mi, &sz, ptname) != 4)
280 /* skip extended partitions (heuristic: size 1) */
284 /* look only at md devices on first pass */
285 handleOnFirst = !strncmp(ptname, "md", 2);
286 if (firstPass != handleOnFirst)
289 /* skip entire disk (minor 0, 64, ... on ide;
291 /* heuristic: partition name ends in a digit */
292 /* OR partition name starts with 'lvm' */
294 for(s = ptname; *s; s++);
295 if (isdigit(s[-1]) || !strncmp(ptname, "lvm", 3)) {
297 * We first look in /dev for the device, but
298 * if we don't find it, or if the stat
299 * information doesn't check out, we use
300 * ext2fs_find_block_device to find it.
302 sprintf(device, "%s/%s", DEVLABELDIR, ptname);
303 dev = makedev(ma, mi);
304 if ((stat(device, &statbuf) < 0) ||
305 (statbuf.st_rdev != dev)) {
306 devname = ext2fs_find_block_device(dev);
308 devname = string_copy(device);
312 printf("Checking partition %s (%d, %d)\n",
315 if (!get_label_uuid(devname, &label, uuid))
316 uuidcache_addentry(devname, label, uuid);
334 char uuid[16], *label, *devname;
339 procpt = fopen(PROC_EVMS_VOLUMES, "r");
342 while (fgets(line, sizeof(line), procpt)) {
343 if (sscanf (line, " %d %d %d %*s %*s %[^\n ]",
344 &ma, &mi, &sz, device) != 4)
348 * We first look for the device in the named location,
349 * but if we don't find it, or if the stat information
350 * doesn't check out, we use ext2fs_find_block_device
353 dev = makedev(ma, mi);
354 if ((stat(device, &statbuf) < 0) || (statbuf.st_rdev != dev)) {
355 devname = ext2fs_find_block_device(dev);
357 devname = string_copy(device);
361 printf("Checking partition %s (%d, %d)\n",
364 if (!get_label_uuid(devname, &label, uuid))
365 uuidcache_addentry(devname, label, uuid);
389 get_spec_by_x(int n, const char *t) {
390 struct uuidCache_s *uc;
401 if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
402 return string_copy(uc->device);
405 if (!strcmp(t, uc->label))
406 return string_copy(uc->device);
414 static char fromhex(char c)
419 return (c - 'a' + 10);
421 return (c - 'A' + 10);
425 get_spec_by_uuid(const char *s)
430 if (strlen(s) != 36 ||
431 s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
433 for (i=0; i<16; i++) {
435 if (!isxdigit(s[0]) || !isxdigit(s[1]))
437 uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
440 return get_spec_by_x(UUID, uuid);
443 fprintf(stderr, _("WARNING: %s: bad UUID\n"), s);
448 get_spec_by_volume_label(const char *s) {
449 return get_spec_by_x(VOL, s);
453 get_volume_label_by_spec(const char *spec) {
454 struct uuidCache_s *uc;
460 if (!strcmp(spec, uc->device))
468 * Interpret the device name if necessary.
469 * Frees the pointer passed to it if we return a different device string.
471 char *interpret_spec(char *spec)
478 if (!strncmp(spec, "UUID=", 5))
479 dev = get_spec_by_uuid(spec+5);
480 else if (!strncmp(spec, "LABEL=", 6))
481 dev = get_spec_by_volume_label(spec+6);
483 dev = string_copy(spec);
488 main(int argc, char **argv)