blob: e03e0f17705ccf7366cad71ab06e7f6068e93a77 [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
10 */
11
12#include <stdio.h>
13#include <string.h>
14#include <ctype.h>
15#include <fcntl.h>
16#include <unistd.h>
Theodore Ts'od9c56d32000-02-08 00:47:55 +000017#include "nls-enable.h"
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000018#include "get_device_by_label.h"
19
20#define PROC_PARTITIONS "/proc/partitions"
21#define DEVLABELDIR "/dev"
22
23#define EXT2_SUPER_MAGIC 0xEF53
24struct ext2_super_block {
Theodore Ts'o36b01301999-10-26 14:38:36 +000025 unsigned char s_dummy1[56];
26 unsigned char s_magic[2];
27 unsigned char s_dummy2[46];
28 unsigned char s_uuid[16];
29 unsigned char s_volume_name[16];
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000030};
Theodore Ts'o36b01301999-10-26 14:38:36 +000031#define ext2magic(s) ((unsigned int) s.s_magic[0] + (((unsigned int) s.s_magic[1]) << 8))
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000032
33
34static FILE *procpt;
35
36static void
37procptclose(void) {
38 if (procpt)
39 fclose (procpt);
40 procpt = 0;
41}
42
43static int
44procptopen(void) {
45 return ((procpt = fopen(PROC_PARTITIONS, "r")) != NULL);
46}
47
48static char *
49procptnext(void) {
50 char line[100];
51 char *s;
52 int ma, mi, sz;
53 static char ptname[100];
54
55 while (fgets(line, sizeof(line), procpt)) {
56 if (sscanf (line, " %d %d %d %[^\n]\n", &ma, &mi, &sz, ptname) != 4)
57 continue;
58
59 /* skip extended partitions (heuristic: size 1) */
60 if (sz == 1)
61 continue;
62
63 /* skip entire disk (minor 0, 64, ... on ide; 0, 16, ... on sd) */
64 /* heuristic: partition name ends in a digit */
65 for(s = ptname; *s; s++);
66 if (isdigit(s[-1]))
67 return ptname;
68 }
69 return 0;
70}
71
72#define UUID 1
73#define VOL 2
74
75/* for now, only ext2 is supported */
76static int
Theodore Ts'o36b01301999-10-26 14:38:36 +000077has_right_label(const char *device, int n, const void *label) {
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000078
79 /* start with a test for ext2, taken from mount_guess_fstype */
80 int fd;
Theodore Ts'o2d8defd1999-07-03 01:59:42 +000081 struct ext2_super_block e2sb;
82
83 fd = open(device, O_RDONLY);
84 if (fd < 0)
85 return 0;
86
87 if (lseek(fd, 1024, SEEK_SET) != 1024
88 || read(fd, (char *) &e2sb, sizeof(e2sb)) != sizeof(e2sb)
89 || (ext2magic(e2sb) != EXT2_SUPER_MAGIC)) {
90 close(fd);
91 return 0;
92 }
93
94 close(fd);
95
96 /* superblock is ext2 - now what is its label? */
Theodore Ts'o36b01301999-10-26 14:38:36 +000097 if (n == UUID)
98 return (memcmp(e2sb.s_uuid, label, 16) == 0);
99 else
100 return (strncmp(e2sb.s_volume_name,
101 (const char *) label, 16) == 0);
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000102}
103
104static char *
Theodore Ts'o36b01301999-10-26 14:38:36 +0000105get_spec_by_x(int n, const void *t) {
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000106 char *pt;
107 char device[110];
108
109 if(!procptopen())
110 return NULL;
111 while((pt = procptnext()) != NULL) {
112 /* Note: this is a heuristic only - there is no reason
113 why these devices should live in /dev.
114 Perhaps this directory should be specifiable by option.
115 One might for example have /devlabel with links to /dev
116 for the devices that may be accessed in this way.
117 (This is useful, if the cdrom on /dev/hdc must not
118 be accessed.)
119 */
120 sprintf(device, "%s/%s", DEVLABELDIR, pt);
121 if (has_right_label(device, n, t)) {
122 procptclose();
123 return strdup(device);
124 }
125 }
126 procptclose();
127 return NULL;
128}
129
Theodore Ts'o36b01301999-10-26 14:38:36 +0000130static unsigned char
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000131fromhex(char c) {
132 if (isdigit(c))
133 return (c - '0');
134 else if (islower(c))
135 return (c - 'a' + 10);
136 else
137 return (c - 'A' + 10);
138}
139
140char *
141get_spec_by_uuid(const char *s0) {
Theodore Ts'o36b01301999-10-26 14:38:36 +0000142 unsigned char uuid[16];
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000143 int i;
144 const char *s = s0;
145
146 if (strlen(s) != 36 ||
147 s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
148 goto bad_uuid;
149 for (i=0; i<16; i++) {
150 if (*s == '-') s++;
151 if (!isxdigit(s[0]) || !isxdigit(s[1]))
152 goto bad_uuid;
153 uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
154 s += 2;
155 }
156 return get_spec_by_x(UUID, uuid);
157
158 bad_uuid:
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000159 fprintf(stderr, _("WARNING: %s: bad UUID"), s0);
Theodore Ts'o2d8defd1999-07-03 01:59:42 +0000160 return NULL;
161}
162
163char *
164get_spec_by_volume_label(const char *s) {
165 return get_spec_by_x(VOL, s);
166}