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