2
* get_device_by_label.h
4
* Copyright 1999 by Andries Brouwer
5
* Copyright 1999, 2000 by Theodore Ts'o
7
* This file may be redistributed under the terms of the GNU Public
10
* Taken from aeb's mount, 990619
11
* Updated from aeb's mount, 20000725
12
* 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.
23
#include <sys/types.h>
25
#ifdef HAVE_SYS_MKDEV_H
26
#include <sys/mkdev.h>
28
#ifdef HAVE_SYS_SYSMACROS_H
29
#include <sys/sysmacros.h>
32
#include "nls-enable.h"
34
#include "get_device_by_label.h"
36
/* function prototype from libext2 */
37
extern char *ext2fs_find_block_device(dev_t device);
39
#define PROC_PARTITIONS "/proc/partitions"
40
#define DEVLABELDIR "/dev"
41
#define VG_DIR "/proc/lvm/VGs"
43
#define EXT2_SUPER_MAGIC 0xEF53
44
struct ext2_super_block {
45
unsigned char s_dummy1[56];
46
unsigned char s_magic[2];
47
unsigned char s_dummy2[46];
48
unsigned char s_uuid[16];
49
unsigned char s_volume_name[16];
51
#define ext2magic(s) ((unsigned int) s.s_magic[0] + (((unsigned int) s.s_magic[1]) << 8))
53
#define XFS_SUPER_MAGIC "XFSB"
54
struct xfs_super_block {
55
unsigned char s_magic[4];
56
unsigned char s_dummy[28];
57
unsigned char s_uuid[16];
58
unsigned char s_dummy2[60];
59
unsigned char s_fname[12];
62
static struct uuidCache_s {
63
struct uuidCache_s *next;
69
char *string_copy(const char *s)
73
ret = malloc(strlen(s)+1);
79
/* for now, only ext2 and xfs are supported */
81
get_label_uuid(const char *device, char **label, char *uuid) {
83
/* start with ext2 and xfs tests, taken from mount_guess_fstype */
84
/* should merge these later */
87
unsigned char *sb_uuid = 0, *sb_label = 0;
88
struct ext2_super_block e2sb;
89
struct xfs_super_block xfsb;
91
fd = open(device, O_RDONLY);
95
if (lseek(fd, 1024, SEEK_SET) == 1024
96
&& read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb)
97
&& (ext2magic(e2sb) == EXT2_SUPER_MAGIC)) {
98
sb_uuid = e2sb.s_uuid;
99
sb_label = e2sb.s_volume_name;
100
label_size = sizeof(e2sb.s_volume_name);
101
} else if (lseek(fd, 0, SEEK_SET) == 0
102
&& read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb)
103
&& strncmp((char *) &xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0) {
104
sb_uuid = xfsb.s_uuid;
105
sb_label = xfsb.s_fname;
106
label_size = sizeof(xfsb.s_fname);
114
memcpy(uuid, sb_uuid, sizeof(e2sb.s_uuid));
116
if ((*label = calloc(label_size + 1, 1)) != NULL)
117
memcpy(*label, sb_label, label_size);
123
uuidcache_addentry(char *device, char *label, char *uuid) {
124
struct uuidCache_s *last;
127
last = uuidCache = malloc(sizeof(*uuidCache));
129
for (last = uuidCache; last->next; last = last->next) ;
130
last->next = malloc(sizeof(*uuidCache));
134
last->device = device;
136
memcpy(last->uuid, uuid, sizeof(last->uuid));
140
* This function initializes the UUID cache with devices from the LVM
141
* proc hierarchy. We currently depend on the names of the LVM
142
* hierarchy giving us the device structure in /dev. (XXX is this a
146
static void init_lvm(void)
148
DIR *vg_dir, *lv_list;
149
char *vdirname, *lvm_device;
150
char uuid[16], *label, *vname, *lname;
151
struct dirent *vg_iter, *lv_iter;
153
if ((vg_dir = opendir(VG_DIR)) == NULL)
156
while ((vg_iter = readdir(vg_dir)) != 0) {
157
vname = vg_iter->d_name;
158
if (!strcmp(vname, ".") || !strcmp(vname, ".."))
160
vdirname = malloc(strlen(VG_DIR)+strlen(vname)+8);
165
sprintf(vdirname, "%s/%s/LVs", VG_DIR, vname);
167
lv_list = opendir(vdirname);
172
while ((lv_iter = readdir(lv_list)) != 0) {
173
lname = lv_iter->d_name;
174
if (!strcmp(lname, ".") || !strcmp(lname, ".."))
177
lvm_device = malloc(strlen(DEVLABELDIR) +
185
sprintf(lvm_device, "%s/%s/%s", DEVLABELDIR,
187
if (!get_label_uuid(lvm_device, &label, uuid)) {
188
uuidcache_addentry(string_copy(lvm_device),
200
uuidcache_init(void) {
204
static char ptname[100];
206
char uuid[16], *label, *devname;
220
procpt = fopen(PROC_PARTITIONS, "r");
224
for (firstPass = 1; firstPass >= 0; firstPass--) {
225
fseek(procpt, 0, SEEK_SET);
227
while (fgets(line, sizeof(line), procpt)) {
228
if (sscanf (line, " %d %d %d %[^\n ]",
229
&ma, &mi, &sz, ptname) != 4)
232
/* skip extended partitions (heuristic: size 1) */
236
/* look only at md devices on first pass */
237
handleOnFirst = !strncmp(ptname, "md", 2);
238
if (firstPass != handleOnFirst)
241
/* skip entire disk (minor 0, 64, ... on ide;
243
/* heuristic: partition name ends in a digit */
245
for(s = ptname; *s; s++);
246
if (isdigit(s[-1])) {
248
* We first look in /dev for the device, but
249
* if we don't find it, or if the stat
250
* information doesn't check out, we use
251
* ext2fs_find_block_device to find it.
253
sprintf(device, "%s/%s", DEVLABELDIR, ptname);
254
dev = makedev(ma, mi);
255
if ((stat(device, &statbuf) < 0) ||
256
(statbuf.st_rdev != dev)) {
257
devname = ext2fs_find_block_device(dev);
259
devname = string_copy(device);
262
if (!get_label_uuid(devname, &label, uuid))
263
uuidcache_addentry(devname, label, uuid);
277
get_spec_by_x(int n, const char *t) {
278
struct uuidCache_s *uc;
289
if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
290
return string_copy(uc->device);
293
if (!strcmp(t, uc->label))
294
return string_copy(uc->device);
302
static char fromhex(char c)
307
return (c - 'a' + 10);
309
return (c - 'A' + 10);
313
get_spec_by_uuid(const char *s)
318
if (strlen(s) != 36 ||
319
s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
321
for (i=0; i<16; i++) {
323
if (!isxdigit(s[0]) || !isxdigit(s[1]))
325
uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
328
return get_spec_by_x(UUID, uuid);
331
fprintf(stderr, _("WARNING: %s: bad UUID"), s);
336
get_spec_by_volume_label(const char *s) {
337
return get_spec_by_x(VOL, s);
341
get_volume_label_by_spec(const char *spec) {
342
struct uuidCache_s *uc;
348
if (!strcmp(spec, uc->device))
356
* Interpret the device name if necessary.
357
* Frees the pointer passed to it if we return a different device string.
359
char *interpret_spec(char *spec)
366
if (!strncmp(spec, "UUID=", 5))
367
dev = get_spec_by_uuid(spec+5);
368
else if (!strncmp(spec, "LABEL=", 6))
369
dev = get_spec_by_volume_label(spec+6);
371
dev = string_copy(spec);