blob: 7a1a4bd559a4c71ecd788b8bfcbcc5d5dbea2bd3 [file] [log] [blame]
Theodore Ts'o2d8defd1999-07-03 01:59:42 +00001/*
2 * get_device_by_label.h
3 *
4 * Copyright 1999 by Andries Brouwer and Theodore Ts'o
5 *
6 * This file may be redistributed under the terms of the GNU Public
7 * License.
8 *
9 * Taken from aeb's mount, 990619
Theodore Ts'o28412de2000-07-27 02:45:55 +000010 * Updated from aeb's mount, 20000725
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000011 */
12
13#include <stdio.h>
14#include <string.h>
15#include <ctype.h>
16#include <fcntl.h>
17#include <unistd.h>
Theodore Ts'od9c56d32000-02-08 00:47:55 +000018#include "nls-enable.h"
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000019#include "get_device_by_label.h"
20
21#define PROC_PARTITIONS "/proc/partitions"
22#define DEVLABELDIR "/dev"
23
24#define EXT2_SUPER_MAGIC 0xEF53
25struct ext2_super_block {
Theodore Ts'o36b01301999-10-26 14:38:36 +000026 unsigned char s_dummy1[56];
27 unsigned char s_magic[2];
28 unsigned char s_dummy2[46];
29 unsigned char s_uuid[16];
30 unsigned char s_volume_name[16];
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000031};
Theodore Ts'o36b01301999-10-26 14:38:36 +000032#define ext2magic(s) ((unsigned int) s.s_magic[0] + (((unsigned int) s.s_magic[1]) << 8))
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000033
Theodore Ts'o28412de2000-07-27 02:45:55 +000034static struct uuidCache_s {
35 struct uuidCache_s *next;
36 char uuid[16];
37 char *label;
38 char *device;
39} *uuidCache = NULL;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000040
41/* for now, only ext2 is supported */
42static int
Theodore Ts'o28412de2000-07-27 02:45:55 +000043get_label_uuid(const char *device, char **label, char *uuid) {
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000044
45 /* start with a test for ext2, taken from mount_guess_fstype */
Theodore Ts'o28412de2000-07-27 02:45:55 +000046 /* should merge these later */
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000047 int fd;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000048 struct ext2_super_block e2sb;
49
50 fd = open(device, O_RDONLY);
51 if (fd < 0)
Theodore Ts'o28412de2000-07-27 02:45:55 +000052 return 1;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000053
54 if (lseek(fd, 1024, SEEK_SET) != 1024
55 || read(fd, (char *) &e2sb, sizeof(e2sb)) != sizeof(e2sb)
56 || (ext2magic(e2sb) != EXT2_SUPER_MAGIC)) {
57 close(fd);
Theodore Ts'o28412de2000-07-27 02:45:55 +000058 return 1;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000059 }
60
61 close(fd);
62
63 /* superblock is ext2 - now what is its label? */
Theodore Ts'o28412de2000-07-27 02:45:55 +000064 memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
65 *label = strdup(e2sb.s_volume_name);
66
67 return 0;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000068}
69
Theodore Ts'o28412de2000-07-27 02:45:55 +000070static void
71uuidcache_addentry(char *device, char *label, char *uuid) {
72 struct uuidCache_s *last;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000073
Theodore Ts'o28412de2000-07-27 02:45:55 +000074 if (!uuidCache) {
75 last = uuidCache = malloc(sizeof(*uuidCache));
76 } else {
77 for (last = uuidCache; last->next; last = last->next) ;
78 last->next = malloc(sizeof(*uuidCache));
79 last = last->next;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000080 }
Theodore Ts'o28412de2000-07-27 02:45:55 +000081 last->next = NULL;
82 last->device = device;
83 last->label = label;
84 memcpy(last->uuid, uuid, sizeof(last->uuid));
85}
86
87static void
88uuidcache_init(void) {
89 char line[100];
90 char *s;
91 int ma, mi, sz;
92 static char ptname[100];
93 FILE *procpt;
94 char uuid[16], *label;
95 char device[110];
96 int firstPass;
97 int handleOnFirst;
98
99 if (uuidCache)
100 return;
101
102 procpt = fopen(PROC_PARTITIONS, "r");
103 if (!procpt)
104 return;
105
106 for (firstPass = 1; firstPass >= 0; firstPass--) {
107 fseek(procpt, 0, SEEK_SET);
108
109 while (fgets(line, sizeof(line), procpt)) {
110 if (sscanf (line, " %d %d %d %[^\n ]",
111 &ma, &mi, &sz, ptname) != 4)
112 continue;
113
114 /* skip extended partitions (heuristic: size 1) */
115 if (sz == 1)
116 continue;
117
118 /* look only at md devices on first pass */
119 handleOnFirst = !strncmp(ptname, "md", 2);
120 if (firstPass != handleOnFirst)
121 continue;
122
123 /* skip entire disk (minor 0, 64, ... on ide;
124 0, 16, ... on sd) */
125 /* heuristic: partition name ends in a digit */
126
127 for(s = ptname; *s; s++);
128 if (isdigit(s[-1])) {
129 /*
130 * Note: this is a heuristic only - there is no reason
131 * why these devices should live in /dev.
132 * Perhaps this directory should be specifiable by option.
133 * One might for example have /devlabel with links to /dev
134 * for the devices that may be accessed in this way.
135 * (This is useful, if the cdrom on /dev/hdc must not
136 * be accessed.)
137 */
138 sprintf(device, "%s/%s", DEVLABELDIR, ptname);
139 if (!get_label_uuid(device, &label, uuid))
140 uuidcache_addentry(strdup(device), label, uuid);
141 }
142 }
143 }
144
145 fclose(procpt);
146}
147
148#define UUID 1
149#define VOL 2
150
151static char *
152get_spec_by_x(int n, const char *t) {
153 struct uuidCache_s *uc;
154
155 uuidcache_init();
156 uc = uuidCache;
157
158 while(uc) {
159 switch (n) {
160 case UUID:
161 if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
162 return strdup(uc->device);
163 break;
164 case VOL:
165 if (!strcmp(t, uc->label))
166 return strdup(uc->device);
167 break;
168 }
169 uc = uc->next;
170 }
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000171 return NULL;
172}
173
Theodore Ts'o28412de2000-07-27 02:45:55 +0000174static u_char
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000175fromhex(char c) {
176 if (isdigit(c))
177 return (c - '0');
178 else if (islower(c))
179 return (c - 'a' + 10);
180 else
181 return (c - 'A' + 10);
182}
183
184char *
Theodore Ts'o28412de2000-07-27 02:45:55 +0000185get_spec_by_uuid(const char *s) {
186 u_char uuid[16];
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000187 int i;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000188
189 if (strlen(s) != 36 ||
190 s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
191 goto bad_uuid;
192 for (i=0; i<16; i++) {
193 if (*s == '-') s++;
194 if (!isxdigit(s[0]) || !isxdigit(s[1]))
195 goto bad_uuid;
196 uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
197 s += 2;
198 }
199 return get_spec_by_x(UUID, uuid);
200
201 bad_uuid:
Theodore Ts'o28412de2000-07-27 02:45:55 +0000202 fprintf(stderr, _("WARNING: %s: bad UUID"), s);
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000203 return NULL;
204}
205
206char *
207get_spec_by_volume_label(const char *s) {
208 return get_spec_by_x(VOL, s);
209}
Theodore Ts'o28412de2000-07-27 02:45:55 +0000210
211const char *
212get_volume_label_by_spec(const char *spec) {
213 struct uuidCache_s *uc;
214
215 uuidcache_init();
216 uc = uuidCache;
217
218 while(uc) {
219 if (!strcmp(spec, uc->device))
220 return uc->label;
221 uc = uc->next;
222 }
223 return NULL;
224}