]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/nash/mount_by_label.c
75ff9be4df611ee4983e109a84c07f89cdd03358
[people/pmueller/ipfire-2.x.git] / src / nash / mount_by_label.c
1 /*
2 * taken from util-linux 2.11g and hacked into nash
3 *
4 * mount_by_label.c - aeb
5 *
6 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
7 * - added Native Language Support
8 * 2000-01-20 James Antill <james@and.org>
9 * - Added error message if /proc/partitions cannot be opened
10 * 2000-05-09 Erik Troan <ewt@redhat.com>
11 * - Added cache for UUID and disk labels
12 * 2000-11-07 Nathan Scott <nathans@sgi.com>
13 * - Added XFS support
14 */
15
16 #include <errno.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include "linux_fs.h"
25 #include "mount_by_label.h"
26
27 #define PROC_PARTITIONS "/proc/partitions"
28 #define DEVLABELDIR "/dev"
29
30 #define _(str) (str)
31
32 static struct uuidCache_s {
33 struct uuidCache_s *next;
34 char uuid[16];
35 char *device;
36 char *label;
37 int major, minor;
38 } *uuidCache = NULL;
39
40 /* for now, only ext2, ext3 and xfs are supported */
41 static int
42 get_label_uuid(const char *device, char **label, char *uuid) {
43
44 /* start with ext2/3 and xfs tests, taken from mount_guess_fstype */
45 /* should merge these later */
46 int fd;
47 int rv = 1;
48 size_t namesize;
49 struct ext2_super_block e2sb;
50 struct xfs_super_block xfsb;
51
52 fd = open(device, O_RDONLY);
53 if (fd < 0)
54 return rv;
55
56 if (lseek(fd, 1024, SEEK_SET) == 1024
57 && read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb)
58 && (ext2magic(e2sb) == EXT2_SUPER_MAGIC)) {
59 memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
60 namesize = sizeof(e2sb.s_volume_name);
61 if ((*label = calloc(namesize + 1, 1)) != NULL)
62 memcpy(*label, e2sb.s_volume_name, namesize);
63 rv = 0;
64 }
65 else if (lseek(fd, 0, SEEK_SET) == 0
66 && read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb)
67 && (strncmp(xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0)) {
68 memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid));
69 namesize = sizeof(xfsb.s_fname);
70 if ((*label = calloc(namesize + 1, 1)) != NULL)
71 memcpy(*label, xfsb.s_fname, namesize);
72 rv = 0;
73 }
74
75 close(fd);
76 return rv;
77 }
78
79 static void
80 uuidcache_addentry(char * device, int major, int minor, char *label, char *uuid) {
81 struct uuidCache_s *last;
82
83 if (!uuidCache) {
84 last = uuidCache = malloc(sizeof(*uuidCache));
85 } else {
86 for (last = uuidCache; last->next; last = last->next) ;
87 last->next = malloc(sizeof(*uuidCache));
88 last = last->next;
89 }
90 last->next = NULL;
91 last->label = label;
92 last->device = device;
93 last->major = major;
94 last->minor = minor;
95 memcpy(last->uuid, uuid, sizeof(last->uuid));
96 }
97
98 static void
99 uuidcache_init(void) {
100 char line[100];
101 char *s;
102 int ma, mi, sz;
103 static char ptname[100];
104 FILE *procpt;
105 char uuid[16], *label;
106 char device[110];
107 int firstPass;
108 int handleOnFirst;
109 char * chptr, * endptr;
110
111 if (uuidCache)
112 return;
113
114 procpt = fopen(PROC_PARTITIONS, "r");
115 if (!procpt) {
116 static int warn = 0;
117 if (!warn++)
118 fprintf (stderr, _("mount: could not open %s, so UUID and LABEL "
119 "conversion cannot be done.\n"),
120 PROC_PARTITIONS);
121 return;
122 }
123
124 for (firstPass = 1; firstPass >= 0; firstPass--) {
125 fseek(procpt, 0, SEEK_SET);
126
127 while (fgets(line, sizeof(line), procpt)) {
128 /* The original version of this code used sscanf, but
129 diet's sscanf is quite limited */
130 chptr = line;
131 if (*chptr++ != ' ') continue;
132
133 ma = strtol(chptr, &endptr, 0);
134 if (endptr == chptr) continue;
135 while (isspace(*endptr)) endptr++;
136 chptr = endptr;
137
138 mi = strtol(chptr, &endptr, 0);
139 if (endptr == chptr) continue;
140 while (isspace(*endptr)) endptr++;
141 chptr = endptr;
142
143 sz = strtol(chptr, &endptr, 0);
144 if (endptr == chptr) continue;
145 while (isspace(*endptr)) endptr++;
146 chptr = endptr;
147
148 while (!isspace(*endptr) && *endptr != '\n') endptr++;
149 if (chptr == endptr) continue;
150 strncpy(ptname, chptr, endptr - chptr);
151 ptname[endptr - chptr] = '\0';
152
153 /* skip extended partitions (heuristic: size 1) */
154 if (sz == 1)
155 continue;
156
157 /* look only at md devices on first pass */
158 handleOnFirst = !strncmp(ptname, "md", 2);
159 if (firstPass != handleOnFirst)
160 continue;
161
162 /* skip entire disk (minor 0, 64, ... on ide;
163 0, 16, ... on sd) */
164 /* heuristic: partition name ends in a digit */
165
166 for(s = ptname; *s; s++);
167
168 if (isdigit(s[-1])) {
169 char * ptr;
170 char * deviceDir;
171 int mustRemove = 0;
172 int mustRemoveDir = 0;
173 int i;
174
175 sprintf(device, "%s/%s", DEVLABELDIR, ptname);
176 if (access(device, F_OK)) {
177 ptr = device;
178 i = 0;
179 while (*ptr)
180 if (*ptr++ == '/')
181 i++;
182 if (i > 2) {
183 deviceDir = alloca(strlen(device) + 1);
184 strcpy(deviceDir, device);
185 ptr = deviceDir + (strlen(device) - 1);
186 while (*ptr != '/')
187 *ptr-- = '\0';
188 if (mkdir(deviceDir, 0644)) {
189 printf("mkdir: cannot create directory %s: %d\n", deviceDir, errno);
190 } else {
191 mustRemoveDir = 1;
192 }
193 }
194
195 mknod(device, S_IFBLK | 0600, makedev(ma, mi));
196 mustRemove = 1;
197 }
198 if (!get_label_uuid(device, &label, uuid))
199 uuidcache_addentry(strdup(device), ma, mi,
200 label, uuid);
201
202 if (mustRemove) unlink(device);
203 if (mustRemoveDir) rmdir(deviceDir);
204 }
205 }
206 }
207
208 fclose(procpt);
209 }
210
211 #define UUID 1
212 #define VOL 2
213
214 static char *
215 get_spec_by_x(int n, const char *t, int * majorPtr, int * minorPtr) {
216 struct uuidCache_s *uc;
217
218 uuidcache_init();
219 uc = uuidCache;
220
221 while(uc) {
222 switch (n) {
223 case UUID:
224 if (!memcmp(t, uc->uuid, sizeof(uc->uuid))) {
225 *majorPtr = uc->major;
226 *minorPtr = uc->minor;
227 return uc->device;
228 }
229 break;
230 case VOL:
231 if (!strcmp(t, uc->label)) {
232 *majorPtr = uc->major;
233 *minorPtr = uc->minor;
234 return uc->device;
235 }
236 break;
237 }
238 uc = uc->next;
239 }
240 return NULL;
241 }
242
243 static unsigned char
244 fromhex(char c) {
245 if (isdigit(c))
246 return (c - '0');
247 else if (islower(c))
248 return (c - 'a' + 10);
249 else
250 return (c - 'A' + 10);
251 }
252
253 char *
254 get_spec_by_uuid(const char *s, int * major, int * minor) {
255 unsigned char uuid[16];
256 int i;
257
258 if (strlen(s) != 36 ||
259 s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
260 goto bad_uuid;
261 for (i=0; i<16; i++) {
262 if (*s == '-') s++;
263 if (!isxdigit(s[0]) || !isxdigit(s[1]))
264 goto bad_uuid;
265 uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
266 s += 2;
267 }
268 return get_spec_by_x(UUID, uuid, major, minor);
269
270 bad_uuid:
271 fprintf(stderr, _("mount: bad UUID"));
272 return 0;
273 }
274
275 char *
276 get_spec_by_volume_label(const char *s, int * major, int * minor) {
277 return get_spec_by_x(VOL, s, major, minor);
278 }
279
280 int display_uuid_cache(void) {
281 struct uuidCache_s * u;
282 int i;
283
284 uuidcache_init();
285
286 u = uuidCache;
287 while (u) {
288 printf("%s %s ", u->device, u->label);
289 for (i = 0; i < sizeof(u->uuid); i++) {
290 if (i == 4 || i == 6 || i == 8 || i == 10)
291 printf("-");
292 printf("%x", u->uuid[i] & 0xff);
293 }
294 printf("\n");
295 u = u->next;
296 }
297
298 return 0;
299 }
300