~ubuntu-branches/ubuntu/edgy/e2fsprogs/edgy-security

« back to all changes in this revision

Viewing changes to misc/get_device_by_label.c

  • Committer: Bazaar Package Importer
  • Author(s): Matt Zimmerman
  • Date: 2004-09-19 09:43:14 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040919094314-ypmsn0h1ke583yda
Tags: 1.35-6ubuntu1
Remove ext3-add-journal.sh script.  It overcomplicates the initrd setup,
and the only problem it solves is to prevent a visible /.journal

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * get_device_by_label.h
3
 
 *
4
 
 * Copyright 1999 by Andries Brouwer
5
 
 * Copyright 1999, 2000 by Theodore Ts'o
6
 
 *
7
 
 * This file may be redistributed under the terms of the GNU Public
8
 
 * License.
9
 
 *
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.
15
 
 */
16
 
 
17
 
#include <stdio.h>
18
 
#include <string.h>
19
 
#include <stdlib.h>
20
 
#include <ctype.h>
21
 
#include <fcntl.h>
22
 
#include <unistd.h>
23
 
#include <sys/types.h>
24
 
#include <sys/stat.h>
25
 
#ifdef HAVE_SYS_MKDEV_H
26
 
#include <sys/mkdev.h>
27
 
#endif
28
 
#ifdef HAVE_SYS_SYSMACROS_H
29
 
#include <sys/sysmacros.h>
30
 
#endif
31
 
#include <dirent.h>
32
 
#include "nls-enable.h"
33
 
#include "fsck.h"
34
 
#include "get_device_by_label.h"
35
 
 
36
 
/* function prototype from libext2 */
37
 
extern char *ext2fs_find_block_device(dev_t device);
38
 
 
39
 
#define PROC_PARTITIONS "/proc/partitions"
40
 
#define DEVLABELDIR     "/dev"
41
 
#define VG_DIR          "/proc/lvm/VGs"
42
 
 
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];
50
 
};
51
 
#define ext2magic(s)    ((unsigned int) s.s_magic[0] + (((unsigned int) s.s_magic[1]) << 8))
52
 
 
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];
60
 
};
61
 
 
62
 
static struct uuidCache_s {
63
 
        struct uuidCache_s *next;
64
 
        char uuid[16];
65
 
        char *label;
66
 
        char *device;
67
 
} *uuidCache = NULL;
68
 
 
69
 
char *string_copy(const char *s)
70
 
{
71
 
        char    *ret;
72
 
 
73
 
        ret = malloc(strlen(s)+1);
74
 
        if (ret)
75
 
                strcpy(ret, s);
76
 
        return ret;
77
 
}
78
 
 
79
 
/* for now, only ext2 and xfs are supported */
80
 
static int
81
 
get_label_uuid(const char *device, char **label, char *uuid) {
82
 
 
83
 
        /* start with ext2 and xfs tests, taken from mount_guess_fstype */
84
 
        /* should merge these later */
85
 
        int fd;
86
 
        size_t label_size;
87
 
        unsigned char *sb_uuid = 0, *sb_label = 0;
88
 
        struct ext2_super_block e2sb;
89
 
        struct xfs_super_block xfsb;
90
 
 
91
 
        fd = open(device, O_RDONLY);
92
 
        if (fd < 0)
93
 
                return 1;
94
 
 
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);
107
 
        } else {
108
 
                close(fd);
109
 
                return 1;
110
 
        }
111
 
 
112
 
        close(fd);
113
 
        if (sb_uuid)
114
 
                memcpy(uuid, sb_uuid, sizeof(e2sb.s_uuid));
115
 
        if (sb_label) {
116
 
                if ((*label = calloc(label_size + 1, 1)) != NULL)
117
 
                        memcpy(*label, sb_label, label_size);
118
 
        }
119
 
        return 0;
120
 
}
121
 
 
122
 
static void
123
 
uuidcache_addentry(char *device, char *label, char *uuid) {
124
 
        struct uuidCache_s *last;
125
 
 
126
 
        if (!uuidCache) {
127
 
                last = uuidCache = malloc(sizeof(*uuidCache));
128
 
        } else {
129
 
                for (last = uuidCache; last->next; last = last->next) ;
130
 
                last->next = malloc(sizeof(*uuidCache));
131
 
                last = last->next;
132
 
        }
133
 
        last->next = NULL;
134
 
        last->device = device;
135
 
        last->label = label;
136
 
        memcpy(last->uuid, uuid, sizeof(last->uuid));
137
 
}
138
 
 
139
 
/*
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
143
 
 * safe thing to do?)
144
 
 */
145
 
#ifdef VG_DIR
146
 
static void init_lvm(void)
147
 
{
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;
152
 
        
153
 
        if ((vg_dir = opendir(VG_DIR)) == NULL)
154
 
                return;
155
 
 
156
 
        while ((vg_iter = readdir(vg_dir)) != 0) {
157
 
                vname = vg_iter->d_name;
158
 
                if (!strcmp(vname, ".") || !strcmp(vname, ".."))
159
 
                        continue;
160
 
                vdirname = malloc(strlen(VG_DIR)+strlen(vname)+8);
161
 
                if (!vdirname) {
162
 
                        closedir(vg_dir);
163
 
                        return;
164
 
                }
165
 
                sprintf(vdirname, "%s/%s/LVs", VG_DIR, vname);
166
 
 
167
 
                lv_list = opendir(vdirname);
168
 
                free(vdirname);
169
 
                if (lv_list != NULL)
170
 
                        return;
171
 
 
172
 
                while ((lv_iter = readdir(lv_list)) != 0) {
173
 
                        lname = lv_iter->d_name;
174
 
                        if (!strcmp(lname, ".") || !strcmp(lname, ".."))
175
 
                                continue;
176
 
 
177
 
                        lvm_device = malloc(strlen(DEVLABELDIR) +
178
 
                                            strlen(vname)+
179
 
                                            strlen(lname)+8);
180
 
                        if (!lvm_device) {
181
 
                                closedir(lv_list);
182
 
                                closedir(vg_dir);
183
 
                                return;
184
 
                        }
185
 
                        sprintf(lvm_device, "%s/%s/%s", DEVLABELDIR,
186
 
                                vname, lname);
187
 
                        if (!get_label_uuid(lvm_device, &label, uuid)) {
188
 
                                uuidcache_addentry(string_copy(lvm_device),
189
 
                                                   label, uuid);
190
 
                        } else
191
 
                                free(lvm_device);
192
 
                }
193
 
                closedir(lv_list);
194
 
        }
195
 
        closedir( vg_dir );
196
 
}
197
 
#endif
198
 
 
199
 
static void
200
 
uuidcache_init(void) {
201
 
        char line[100];
202
 
        char *s;
203
 
        int ma, mi, sz;
204
 
        static char ptname[100];
205
 
        FILE *procpt;
206
 
        char uuid[16], *label, *devname;
207
 
        char device[110];
208
 
        dev_t   dev;
209
 
        struct stat statbuf;
210
 
        int firstPass;
211
 
        int handleOnFirst;
212
 
 
213
 
        if (uuidCache)
214
 
                return;
215
 
 
216
 
#ifdef VG_DIR
217
 
        init_lvm();
218
 
#endif
219
 
        
220
 
        procpt = fopen(PROC_PARTITIONS, "r");
221
 
        if (!procpt)
222
 
                return;
223
 
 
224
 
        for (firstPass = 1; firstPass >= 0; firstPass--) {
225
 
            fseek(procpt, 0, SEEK_SET);
226
 
 
227
 
            while (fgets(line, sizeof(line), procpt)) {
228
 
                if (sscanf (line, " %d %d %d %[^\n ]",
229
 
                            &ma, &mi, &sz, ptname) != 4)
230
 
                        continue;
231
 
 
232
 
                /* skip extended partitions (heuristic: size 1) */
233
 
                if (sz == 1)
234
 
                        continue;
235
 
 
236
 
                /* look only at md devices on first pass */
237
 
                handleOnFirst = !strncmp(ptname, "md", 2);
238
 
                if (firstPass != handleOnFirst)
239
 
                        continue;
240
 
 
241
 
                /* skip entire disk (minor 0, 64, ... on ide;
242
 
                   0, 16, ... on sd) */
243
 
                /* heuristic: partition name ends in a digit */
244
 
 
245
 
                for(s = ptname; *s; s++);
246
 
                if (isdigit(s[-1])) {
247
 
                        /*
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.
252
 
                         */
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);
258
 
                        } else
259
 
                                devname = string_copy(device);
260
 
                        if (!devname)
261
 
                                continue;
262
 
                        if (!get_label_uuid(devname, &label, uuid))
263
 
                                uuidcache_addentry(devname, label, uuid);
264
 
                        else
265
 
                                free(devname);
266
 
                }
267
 
            }
268
 
        }
269
 
 
270
 
        fclose(procpt);
271
 
}
272
 
 
273
 
#define UUID   1
274
 
#define VOL    2
275
 
 
276
 
static char *
277
 
get_spec_by_x(int n, const char *t) {
278
 
        struct uuidCache_s *uc;
279
 
 
280
 
        uuidcache_init();
281
 
        uc = uuidCache;
282
 
 
283
 
        if (t == NULL)
284
 
                return NULL;
285
 
 
286
 
        while(uc) {
287
 
                switch (n) {
288
 
                case UUID:
289
 
                        if (!memcmp(t, uc->uuid, sizeof(uc->uuid)))
290
 
                                return string_copy(uc->device);
291
 
                        break;
292
 
                case VOL:
293
 
                        if (!strcmp(t, uc->label))
294
 
                                return string_copy(uc->device);
295
 
                        break;
296
 
                }
297
 
                uc = uc->next;
298
 
        }
299
 
        return NULL;
300
 
}
301
 
 
302
 
static char fromhex(char c)
303
 
{
304
 
        if (isdigit(c))
305
 
                return (c - '0');
306
 
        else if (islower(c))
307
 
                return (c - 'a' + 10);
308
 
        else
309
 
                return (c - 'A' + 10);
310
 
}
311
 
 
312
 
char *
313
 
get_spec_by_uuid(const char *s)
314
 
{
315
 
        char uuid[16];
316
 
        int i;
317
 
 
318
 
        if (strlen(s) != 36 ||
319
 
            s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
320
 
                goto bad_uuid;
321
 
        for (i=0; i<16; i++) {
322
 
            if (*s == '-') s++;
323
 
            if (!isxdigit(s[0]) || !isxdigit(s[1]))
324
 
                    goto bad_uuid;
325
 
            uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
326
 
            s += 2;
327
 
        }
328
 
        return get_spec_by_x(UUID, uuid);
329
 
 
330
 
 bad_uuid:
331
 
        fprintf(stderr, _("WARNING: %s: bad UUID"), s);
332
 
        return NULL;
333
 
}
334
 
 
335
 
char *
336
 
get_spec_by_volume_label(const char *s) {
337
 
        return get_spec_by_x(VOL, s);
338
 
}
339
 
 
340
 
const char *
341
 
get_volume_label_by_spec(const char *spec) {
342
 
        struct uuidCache_s *uc;
343
 
 
344
 
        uuidcache_init();
345
 
        uc = uuidCache;
346
 
 
347
 
        while(uc) {
348
 
                if (!strcmp(spec, uc->device))
349
 
                        return uc->label;
350
 
                uc = uc->next;
351
 
        }
352
 
        return NULL;
353
 
}
354
 
 
355
 
/*
356
 
 * Interpret the device name if necessary.
357
 
 * Frees the pointer passed to it if we return a different device string.
358
 
 */
359
 
char *interpret_spec(char *spec)
360
 
{
361
 
        char *dev = NULL;
362
 
 
363
 
        if (!spec)
364
 
                return NULL;
365
 
 
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);
370
 
        else
371
 
                dev = string_copy(spec);
372
 
        return dev;
373
 
}