blob: ee5070dbc48c8e45732313b8d381bcb1daa0d622 [file] [log] [blame]
Theodore Ts'o2d8defd1999-07-03 01:59:42 +00001/*
2 * get_device_by_label.h
3 *
Theodore Ts'o556ccbd2000-08-20 19:11:05 +00004 * Copyright 1999 by Andries Brouwer
5 * Copyright 1999, 2000 by Theodore Ts'o
Theodore Ts'o2d8defd1999-07-03 01:59:42 +00006 *
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 *
10 * Taken from aeb's mount, 990619
Theodore Ts'o28412de2000-07-27 02:45:55 +000011 * Updated from aeb's mount, 20000725
Theodore Ts'o556ccbd2000-08-20 19:11:05 +000012 * 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.
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000015 */
16
17#include <stdio.h>
18#include <string.h>
Theodore Ts'o556ccbd2000-08-20 19:11:05 +000019#include <stdlib.h>
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000020#include <ctype.h>
21#include <fcntl.h>
22#include <unistd.h>
Theodore Ts'o556ccbd2000-08-20 19:11:05 +000023#include <sys/types.h>
24#include <sys/stat.h>
25#ifdef HAVE_SYS_MKDEV_H
26#include <sys/mkdev.h>
27#endif
Theodore Ts'o8820c792001-01-06 04:20:03 +000028#ifdef HAVE_SYS_SYSMACROS_H
29#include <sys/sysmacros.h>
30#endif
Theodore Ts'od9c56d32000-02-08 00:47:55 +000031#include "nls-enable.h"
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000032#include "get_device_by_label.h"
Theodore Ts'o8820c792001-01-06 04:20:03 +000033#include "fsck.h"
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000034
Theodore Ts'o556ccbd2000-08-20 19:11:05 +000035/* function prototype from libext2 */
36extern char *ext2fs_find_block_device(dev_t device);
37
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000038#define PROC_PARTITIONS "/proc/partitions"
39#define DEVLABELDIR "/dev"
40
41#define EXT2_SUPER_MAGIC 0xEF53
42struct ext2_super_block {
Theodore Ts'o36b01301999-10-26 14:38:36 +000043 unsigned char s_dummy1[56];
44 unsigned char s_magic[2];
45 unsigned char s_dummy2[46];
46 unsigned char s_uuid[16];
47 unsigned char s_volume_name[16];
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000048};
Theodore Ts'o36b01301999-10-26 14:38:36 +000049#define ext2magic(s) ((unsigned int) s.s_magic[0] + (((unsigned int) s.s_magic[1]) << 8))
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000050
Theodore Ts'o28412de2000-07-27 02:45:55 +000051static struct uuidCache_s {
52 struct uuidCache_s *next;
53 char uuid[16];
54 char *label;
55 char *device;
56} *uuidCache = NULL;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000057
58/* for now, only ext2 is supported */
59static int
Theodore Ts'o28412de2000-07-27 02:45:55 +000060get_label_uuid(const char *device, char **label, char *uuid) {
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000061
62 /* start with a test for ext2, taken from mount_guess_fstype */
Theodore Ts'o28412de2000-07-27 02:45:55 +000063 /* should merge these later */
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000064 int fd;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000065 struct ext2_super_block e2sb;
66
67 fd = open(device, O_RDONLY);
68 if (fd < 0)
Theodore Ts'o28412de2000-07-27 02:45:55 +000069 return 1;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000070
71 if (lseek(fd, 1024, SEEK_SET) != 1024
72 || read(fd, (char *) &e2sb, sizeof(e2sb)) != sizeof(e2sb)
73 || (ext2magic(e2sb) != EXT2_SUPER_MAGIC)) {
74 close(fd);
Theodore Ts'o28412de2000-07-27 02:45:55 +000075 return 1;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000076 }
77
78 close(fd);
79
80 /* superblock is ext2 - now what is its label? */
Theodore Ts'o28412de2000-07-27 02:45:55 +000081 memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
Theodore Ts'o0056be12000-10-25 02:24:33 +000082
83 *label = calloc(sizeof(e2sb.s_volume_name) + 1, 1);
84 memcpy(*label, e2sb.s_volume_name, sizeof(e2sb.s_volume_name));
Theodore Ts'o28412de2000-07-27 02:45:55 +000085
86 return 0;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000087}
88
Theodore Ts'o28412de2000-07-27 02:45:55 +000089static void
90uuidcache_addentry(char *device, char *label, char *uuid) {
91 struct uuidCache_s *last;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000092
Theodore Ts'o28412de2000-07-27 02:45:55 +000093 if (!uuidCache) {
94 last = uuidCache = malloc(sizeof(*uuidCache));
95 } else {
96 for (last = uuidCache; last->next; last = last->next) ;
97 last->next = malloc(sizeof(*uuidCache));
98 last = last->next;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000099 }
Theodore Ts'o28412de2000-07-27 02:45:55 +0000100 last->next = NULL;
101 last->device = device;
102 last->label = label;
103 memcpy(last->uuid, uuid, sizeof(last->uuid));
104}
105
106static void
107uuidcache_init(void) {
108 char line[100];
109 char *s;
110 int ma, mi, sz;
111 static char ptname[100];
112 FILE *procpt;
Theodore Ts'o556ccbd2000-08-20 19:11:05 +0000113 char uuid[16], *label, *devname;
Theodore Ts'o28412de2000-07-27 02:45:55 +0000114 char device[110];
Theodore Ts'o556ccbd2000-08-20 19:11:05 +0000115 dev_t dev;
116 struct stat statbuf;
Theodore Ts'o28412de2000-07-27 02:45:55 +0000117 int firstPass;
118 int handleOnFirst;
119
120 if (uuidCache)
121 return;
122
123 procpt = fopen(PROC_PARTITIONS, "r");
124 if (!procpt)
125 return;
126
127 for (firstPass = 1; firstPass >= 0; firstPass--) {
128 fseek(procpt, 0, SEEK_SET);
129
130 while (fgets(line, sizeof(line), procpt)) {
131 if (sscanf (line, " %d %d %d %[^\n ]",
132 &ma, &mi, &sz, ptname) != 4)
133 continue;
134
135 /* skip extended partitions (heuristic: size 1) */
136 if (sz == 1)
137 continue;
138
139 /* look only at md devices on first pass */
140 handleOnFirst = !strncmp(ptname, "md", 2);
141 if (firstPass != handleOnFirst)
142 continue;
143
144 /* skip entire disk (minor 0, 64, ... on ide;
145 0, 16, ... on sd) */
146 /* heuristic: partition name ends in a digit */
147
148 for(s = ptname; *s; s++);
149 if (isdigit(s[-1])) {
Theodore Ts'o556ccbd2000-08-20 19:11:05 +0000150 /*
151 * We first look in /dev for the device, but
152 * if we don't find it, or if the stat
153 * information doesn't check out, we use
154 * ext2fs_find_block_device to find it.
155 */
Theodore Ts'o28412de2000-07-27 02:45:55 +0000156 sprintf(device, "%s/%s", DEVLABELDIR, ptname);
Theodore Ts'o556ccbd2000-08-20 19:11:05 +0000157 dev = makedev(ma, mi);
158 if ((stat(device, &statbuf) < 0) ||
159 (statbuf.st_rdev != dev)) {
160 devname = ext2fs_find_block_device(dev);
161 } else
Theodore Ts'o8820c792001-01-06 04:20:03 +0000162 devname = string_copy(device);
Theodore Ts'o556ccbd2000-08-20 19:11:05 +0000163 if (!devname)
164 continue;
165 if (!get_label_uuid(devname, &label, uuid))
166 uuidcache_addentry(devname, label, uuid);
167 else
168 free(devname);
Theodore Ts'o28412de2000-07-27 02:45:55 +0000169 }
170 }
171 }
172
173 fclose(procpt);
174}
175
176#define UUID 1
177#define VOL 2
178
179static char *
180get_spec_by_x(int n, const char *t) {
181 struct uuidCache_s *uc;
182
183 uuidcache_init();
184 uc = uuidCache;
185
186 while(uc) {
187 switch (n) {
188 case UUID:
189 if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
Theodore Ts'o8820c792001-01-06 04:20:03 +0000190 return string_copy(uc->device);
Theodore Ts'o28412de2000-07-27 02:45:55 +0000191 break;
192 case VOL:
193 if (!strcmp(t, uc->label))
Theodore Ts'o8820c792001-01-06 04:20:03 +0000194 return string_copy(uc->device);
Theodore Ts'o28412de2000-07-27 02:45:55 +0000195 break;
196 }
197 uc = uc->next;
198 }
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000199 return NULL;
200}
201
Theodore Ts'o8820c792001-01-06 04:20:03 +0000202static char fromhex(char c)
203{
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000204 if (isdigit(c))
205 return (c - '0');
206 else if (islower(c))
207 return (c - 'a' + 10);
208 else
209 return (c - 'A' + 10);
210}
211
212char *
Theodore Ts'o8820c792001-01-06 04:20:03 +0000213get_spec_by_uuid(const char *s)
214{
215 char uuid[16];
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000216 int i;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000217
218 if (strlen(s) != 36 ||
219 s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
220 goto bad_uuid;
221 for (i=0; i<16; i++) {
222 if (*s == '-') s++;
223 if (!isxdigit(s[0]) || !isxdigit(s[1]))
224 goto bad_uuid;
225 uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
226 s += 2;
227 }
228 return get_spec_by_x(UUID, uuid);
229
230 bad_uuid:
Theodore Ts'o28412de2000-07-27 02:45:55 +0000231 fprintf(stderr, _("WARNING: %s: bad UUID"), s);
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000232 return NULL;
233}
234
235char *
236get_spec_by_volume_label(const char *s) {
237 return get_spec_by_x(VOL, s);
238}
Theodore Ts'o28412de2000-07-27 02:45:55 +0000239
240const char *
241get_volume_label_by_spec(const char *spec) {
242 struct uuidCache_s *uc;
243
244 uuidcache_init();
245 uc = uuidCache;
246
247 while(uc) {
248 if (!strcmp(spec, uc->device))
249 return uc->label;
250 uc = uc->next;
251 }
252 return NULL;
253}