2 * Derived from the util-linux/mount/mount_by_label.c source,
3 * currently maintained by Andries Brouwer <aeb@cwi.nl>.
5 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
6 * - added Native Language Support
7 * 2000-01-20 James Antill <james@and.org>
8 * - Added error message if /proc/partitions cannot be opened
9 * 2000-05-09 Erik Troan <ewt@redhat.com>
10 * - Added cache for UUID and disk labels
11 * 2000-11-07 Nathan Scott <nathans@sgi.com>
18 #include <sys/param.h>
28 #define PROC_PARTITIONS "/proc/partitions"
29 #define DEVLABELDIR "/dev"
31 static struct uuidCache_s {
32 struct uuidCache_s *next;
38 #define EXT2_SUPER_MAGIC 0xEF53
39 struct ext2_super_block {
44 u_char s_volume_name[16];
47 #define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8))
49 #define XFS_SUPER_MAGIC "XFSB"
50 #define XFS_SUPER_MAGIC2 "BSFX"
51 struct xfs_super_block {
59 #define REISER_SUPER_MAGIC "ReIsEr2Fs"
60 struct reiserfs_super_block {
65 u_char s_volume_name[16];
68 static inline unsigned short swapped(unsigned short a)
70 return (a >> 8) | (a << 8);
73 /* for now, only ext2 and xfs are supported */
74 static int get_label_uuid(const char *device, char **label, char *uuid)
77 /* start with ext2 and xfs tests, taken from mount_guess_fstype */
78 /* should merge these later */
81 struct ext2_super_block e2sb;
82 struct xfs_super_block xfsb;
83 struct reiserfs_super_block reisersb;
85 fd = open(device, O_RDONLY);
89 if (lseek(fd, 1024, SEEK_SET) == 1024
90 && read(fd, (char *)&e2sb, sizeof(e2sb)) == sizeof(e2sb)
91 && ext2magic(e2sb) == EXT2_SUPER_MAGIC) {
92 memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
93 namesize = sizeof(e2sb.s_volume_name);
94 *label = smalloc(namesize + 1);
95 sstrncpy(*label, (char *)e2sb.s_volume_name, namesize);
98 else if (lseek(fd, 0, SEEK_SET) == 0
99 && read(fd, (char *)&xfsb, sizeof(xfsb)) == sizeof(xfsb)
100 && (strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0 ||
101 strncmp((char *)&xfsb.s_magic, XFS_SUPER_MAGIC2, 4) == 0)) {
102 memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid));
103 namesize = sizeof(xfsb.s_fsname);
104 *label = smalloc(namesize + 1);
105 sstrncpy(*label, (char *)xfsb.s_fsname, namesize);
108 else if (lseek(fd, 65536, SEEK_SET) == 65536
109 && read(fd, (char *)&reisersb, sizeof(reisersb)) == sizeof(reisersb)
110 && !strncmp((char *)&reisersb.s_magic, REISER_SUPER_MAGIC, 9)) {
111 memcpy(uuid, reisersb.s_uuid, sizeof(reisersb.s_uuid));
112 namesize = sizeof(reisersb.s_volume_name);
113 *label = smalloc(namesize + 1);
114 sstrncpy(*label, (char *)reisersb.s_volume_name, namesize);
121 static void uuidcache_addentry(char *device, char *label, char *uuid)
123 struct uuidCache_s *last;
126 last = uuidCache = smalloc(sizeof(*uuidCache));
129 for (last = uuidCache; last->next; last = last->next);
130 last->next = smalloc(sizeof(*uuidCache));
134 last->device = device;
136 memcpy(last->uuid, uuid, sizeof(last->uuid));
139 static void uuidcache_init(void)
144 static char ptname[100];
146 char uuid[16], *label;
154 procpt = fopen(PROC_PARTITIONS, "r");
158 for (firstPass = 1; firstPass >= 0; firstPass--) {
159 fseek(procpt, 0, SEEK_SET);
161 while (fgets(line, sizeof(line), procpt)) {
162 if (sscanf(line, " %d %d %d %[^\n ]", &ma, &mi, &sz, ptname) != 4)
165 /* skip extended partitions (heuristic: size 1) */
169 /* look only at md devices on first pass */
170 handleOnFirst = !strncmp(ptname, "md", 2);
171 if (firstPass != handleOnFirst)
174 /* skip entire disk (minor 0, 64, ... on ide;
176 /* heuristic: partition name ends in a digit */
178 for (s = ptname; *s; s++);
179 if (isdigit(s[-1])) {
181 * Note: this is a heuristic only - there is no reason
182 * why these devices should live in /dev.
183 * Perhaps this directory should be specifiable by option.
184 * One might for example have /devlabel with links to /dev
185 * for the devices that may be accessed in this way.
186 * (This is useful, if the cdrom on /dev/hdc must not
189 snprintf(device, sizeof(device), "%s/%s", DEVLABELDIR, ptname);
190 if (!get_label_uuid(device, &label, uuid))
191 uuidcache_addentry(sstrdup(device), label, uuid);
202 static char *get_spec_by_x(int n, const char *t)
204 struct uuidCache_s *uc;
212 if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
213 return sstrdup(uc->device);
216 if (!strcmp(t, uc->label))
217 return sstrdup(uc->device);
225 static u_char fromhex(char c)
230 return (c - 'a' + 10);
232 return (c - 'A' + 10);
235 static char *get_spec_by_uuid(const char *s)
240 if (strlen(s) != 36 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
242 for (i = 0; i < 16; i++) {
245 if (!isxdigit(s[0]) || !isxdigit(s[1]))
247 uuid[i] = ((fromhex(s[0]) << 4) | fromhex(s[1]));
250 return get_spec_by_x(UUID, (char *)uuid);
253 errstr(_("Found an invalid UUID: %s\n"), s);
257 static char *get_spec_by_volume_label(const char *s)
259 return get_spec_by_x(VOL, s);
262 const char *get_device_name(const char *item)
266 if (!strncmp(item, "UUID=", 5))
267 rc = get_spec_by_uuid(item + 5);
268 else if (!strncmp(item, "LABEL=", 6))
269 rc = get_spec_by_volume_label(item + 6);
273 errstr(_("Error checking device name: %s\n"), item);