diff options
Diffstat (limited to 'collage')
-rw-r--r-- | collage/Makefile | 2 | ||||
-rw-r--r-- | collage/commands.c | 7 | ||||
-rw-r--r-- | collage/linux_fs.h | 151 | ||||
-rw-r--r-- | collage/mount_by_label.c | 236 | ||||
-rw-r--r-- | collage/mount_by_label.h | 3 |
5 files changed, 398 insertions, 1 deletions
diff --git a/collage/Makefile b/collage/Makefile index 47ce210f8..47648588d 100644 --- a/collage/Makefile +++ b/collage/Makefile @@ -14,7 +14,7 @@ everything: $(TARGET) all: collage -collage: collage.o commands.o idmap.o ls.o +collage: collage.o commands.o idmap.o ls.o mount_by_label.o install: mkdir -p $(DESTDIR)/$(RUNTIMEDIR) diff --git a/collage/commands.c b/collage/commands.c index 211b344e7..c6cae1c94 100644 --- a/collage/commands.c +++ b/collage/commands.c @@ -18,6 +18,7 @@ #include "commands.h" #include "idmap.h" #include "ls.h" +#include "mount_by_label.h" #include "popt.h" #include "../isys/cpio.h" @@ -113,6 +114,12 @@ int mountCommand(int argc, char ** argv) { dir = argv[4]; } + if (!strncmp(dev, "LABEL=", 6)) { + dev = get_spec_by_volume_label(dev + 6); + } else if (!strncmp(dev, "UUID=", 5)) { + dev = get_spec_by_uuid(dev + 5); + } + if (!strncmp(dev, "/dev/", 5) && access(dev, X_OK)) { dev += 5; buf = alloca(strlen(dev) + 10); diff --git a/collage/linux_fs.h b/collage/linux_fs.h new file mode 100644 index 000000000..043ac16a7 --- /dev/null +++ b/collage/linux_fs.h @@ -0,0 +1,151 @@ +/* Including <linux/fs.h> became more and more painful. + Below a very abbreviated version of some declarations, + only designed to be able to check a magic number + in case no filesystem type was given. */ + +#ifndef BLKGETSIZE +#ifndef _IO +/* pre-1.3.45 */ +#define BLKGETSIZE 0x1260 /* return device size */ +#else +/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */ +#define BLKGETSIZE _IO(0x12,96) +#endif +#endif + +#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ +#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ +struct minix_super_block { + u_char s_dummy[16]; + u_char s_magic[2]; +}; +#define minixmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +#define ISODCL(from, to) (to - from + 1) +#define ISO_STANDARD_ID "CD001" +struct iso_volume_descriptor { + char type[ISODCL(1,1)]; /* 711 */ + char id[ISODCL(2,6)]; + char version[ISODCL(7,7)]; + char data[ISODCL(8,2048)]; +}; + +#define HS_STANDARD_ID "CDROM" +struct hs_volume_descriptor { + char foo[ISODCL ( 1, 8)]; /* 733 */ + char type[ISODCL ( 9, 9)]; /* 711 */ + char id[ISODCL ( 10, 14)]; + char version[ISODCL ( 15, 15)]; /* 711 */ + char data[ISODCL(16,2048)]; +}; + +#define EXT_SUPER_MAGIC 0x137D +struct ext_super_block { + u_char s_dummy[56]; + u_char s_magic[2]; +}; +#define extmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +#define EXT2_PRE_02B_MAGIC 0xEF51 +#define EXT2_SUPER_MAGIC 0xEF53 +struct ext2_super_block { + u_char s_dummy1[56]; + u_char s_magic[2]; + u_char s_dummy2[46]; + u_char s_uuid[16]; + u_char s_volume_name[16]; +}; +#define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +#define _XIAFS_SUPER_MAGIC 0x012FD16D +struct xiafs_super_block { + u_char s_boot_segment[512]; /* 1st sector reserved for boot */ + u_char s_dummy[60]; + u_char s_magic[4]; +}; +#define xiafsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) + +/* From jj@sunsite.ms.mff.cuni.cz Mon Mar 23 15:19:05 1998 */ +#define UFS_SUPER_MAGIC 0x00011954 +struct ufs_super_block { + u_char s_dummy[0x55c]; + u_char s_magic[4]; +}; +#define ufsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) + +/* From Richard.Russon@ait.co.uk Wed Feb 24 08:05:27 1999 */ +#define NTFS_SUPER_MAGIC "NTFS" +struct ntfs_super_block { + u_char s_dummy[3]; + u_char s_magic[4]; +}; + +/* From inspection of a few FAT filesystems - aeb */ +/* Unfortunately I find almost the same thing on an extended partition; + it looks like a primary has some directory entries where the extended + has a partition table: IO.SYS, MSDOS.SYS, WINBOOT.SYS */ +struct fat_super_block { + u_char s_dummy[3]; + u_char s_os[8]; /* "MSDOS5.0" or "MSWIN4.0" or "MSWIN4.1" */ + /* mtools-3.9.4 writes "MTOOL394" */ + u_char s_dummy2[32]; + u_char s_label[11]; /* for DOS? */ + u_char s_fs[8]; /* "FAT12 " or "FAT16 " or all zero */ + /* OS/2 BM has "FAT " here. */ + u_char s_dummy3[9]; + u_char s_label2[11]; /* for Windows? */ + u_char s_fs2[8]; /* garbage or "FAT32 " */ +}; + +#define XFS_SUPER_MAGIC "XFSB" +#define XFS_SUPER_MAGIC2 "BSFX" +struct xfs_super_block { + u_char s_magic[4]; + u_char s_dummy[28]; + u_char s_uuid[16]; + u_char s_dummy2[60]; + u_char s_fname[12]; +}; + +#define CRAMFS_SUPER_MAGIC 0x28cd3d45 +struct cramfs_super_block { + u_char s_magic[4]; + u_char s_dummy[12]; + u_char s_id[16]; +}; +#define cramfsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) + +#define HFS_SUPER_MAGIC 0x4244 +struct hfs_super_block { + u_char s_magic[2]; + u_char s_dummy[18]; + u_char s_blksize[4]; +}; +#define hfsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) +#define hfsblksize(s) ((uint) s.s_blksize[0] + \ + (((uint) s.s_blksize[1]) << 8) + \ + (((uint) s.s_blksize[2]) << 16) + \ + (((uint) s.s_blksize[3]) << 24)) + +#define HPFS_SUPER_MAGIC 0xf995e849 +struct hpfs_super_block { + u_char s_magic[4]; + u_char s_magic2[4]; +}; +#define hpfsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) + +struct adfs_super_block { + u_char s_dummy[448]; + u_char s_blksize[1]; + u_char s_dummy2[62]; + u_char s_checksum[1]; +}; +#define adfsblksize(s) ((uint) s.s_blksize[0]) diff --git a/collage/mount_by_label.c b/collage/mount_by_label.c new file mode 100644 index 000000000..b806accd9 --- /dev/null +++ b/collage/mount_by_label.c @@ -0,0 +1,236 @@ +/* + * mount_by_label.c - aeb + * + * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> + * - added Native Language Support + * 2000-01-20 James Antill <james@and.org> + * - Added error message if /proc/partitions cannot be opened + * 2000-05-09 Erik Troan <ewt@redhat.com> + * - Added cache for UUID and disk labels + * 2000-11-07 Nathan Scott <nathans@sgi.com> + * - Added XFS support + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include "linux_fs.h" +#include "mount_by_label.h" + +#define xstrdup strdup + +#define PROC_PARTITIONS "/proc/partitions" +#define DEVLABELDIR "/dev" + +static struct uuidCache_s { + struct uuidCache_s *next; + char uuid[16]; + char *label; + char *device; +} *uuidCache = NULL; + +/* for now, only ext2 and xfs are supported */ +static int +get_label_uuid(const char *device, char **label, char *uuid) { + + /* start with ext2 and xfs tests, taken from mount_guess_fstype */ + /* should merge these later */ + int fd; + int rv = 1; + size_t namesize; + struct ext2_super_block e2sb; + struct xfs_super_block xfsb; + + fd = open(device, O_RDONLY); + if (fd < 0) + return rv; + + if (lseek(fd, 1024, SEEK_SET) == 1024 + && read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb) + && (ext2magic(e2sb) == EXT2_SUPER_MAGIC)) { + memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid)); + namesize = sizeof(e2sb.s_volume_name); + if ((*label = calloc(namesize + 1, 1)) != NULL) + memcpy(*label, e2sb.s_volume_name, namesize); + rv = 0; + } + else if (lseek(fd, 0, SEEK_SET) == 0 + && read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb) + && (strncmp((char *) &xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0 || + strncmp((char *) &xfsb.s_magic, XFS_SUPER_MAGIC2,4) == 0)) { + memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid)); + namesize = sizeof(xfsb.s_fname); + if ((*label = calloc(namesize + 1, 1)) != NULL) + memcpy(*label, xfsb.s_fname, namesize); + rv = 0; + } + + close(fd); + return rv; +} + +static void +uuidcache_addentry(char *device, char *label, char *uuid) { + struct uuidCache_s *last; + + if (!uuidCache) { + last = uuidCache = malloc(sizeof(*uuidCache)); + } else { + for (last = uuidCache; last->next; last = last->next) ; + last->next = malloc(sizeof(*uuidCache)); + last = last->next; + } + last->next = NULL; + last->device = device; + last->label = label; + memcpy(last->uuid, uuid, sizeof(last->uuid)); +} + +static void +uuidcache_init(void) { + char line[100]; + char *s; + int ma, mi, sz; + static char ptname[100]; + FILE *procpt; + char uuid[16], *label; + char device[110]; + int firstPass; + int handleOnFirst; + + if (uuidCache) + return; + + procpt = fopen(PROC_PARTITIONS, "r"); + if (!procpt) { + static int warn = 0; + if (!warn++) + fprintf (stderr, "mount: could not open %s, so UUID and LABEL " + "conversion cannot be done.\n", + PROC_PARTITIONS); + return; + } + + for (firstPass = 1; firstPass >= 0; firstPass--) { + fseek(procpt, 0, SEEK_SET); + + while (fgets(line, sizeof(line), procpt)) { + if (sscanf (line, " %d %d %d %[^\n ]", + &ma, &mi, &sz, ptname) != 4) + continue; + + /* skip extended partitions (heuristic: size 1) */ + if (sz == 1) + continue; + + /* look only at md devices on first pass */ + handleOnFirst = !strncmp(ptname, "md", 2); + if (firstPass != handleOnFirst) + continue; + + /* skip entire disk (minor 0, 64, ... on ide; + 0, 16, ... on sd) */ + /* heuristic: partition name ends in a digit */ + + for(s = ptname; *s; s++); + if (isdigit(s[-1])) { + /* + * Note: this is a heuristic only - there is no reason + * why these devices should live in /dev. + * Perhaps this directory should be specifiable by option. + * One might for example have /devlabel with links to /dev + * for the devices that may be accessed in this way. + * (This is useful, if the cdrom on /dev/hdc must not + * be accessed.) + */ + sprintf(device, "%s/%s", DEVLABELDIR, ptname); + if (!get_label_uuid(device, &label, uuid)) + uuidcache_addentry(strdup(device), label, uuid); + } + } + } + + fclose(procpt); +} + +#define UUID 1 +#define VOL 2 + +static char * +get_spec_by_x(int n, const char *t) { + struct uuidCache_s *uc; + + uuidcache_init(); + uc = uuidCache; + + while(uc) { + switch (n) { + case UUID: + if (!memcmp(t, uc->uuid, sizeof(uc->uuid))) + return xstrdup(uc->device); + break; + case VOL: + if (!strcmp(t, uc->label)) + return xstrdup(uc->device); + break; + } + uc = uc->next; + } + return NULL; +} + +static u_char +fromhex(char c) { + if (isdigit(c)) + return (c - '0'); + else if (islower(c)) + return (c - 'a' + 10); + else + return (c - 'A' + 10); +} + +char * +get_spec_by_uuid(const char *s) { + u_char uuid[16]; + int i; + + if (strlen(s) != 36 || + s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') + goto bad_uuid; + for (i=0; i<16; i++) { + if (*s == '-') s++; + if (!isxdigit(s[0]) || !isxdigit(s[1])) + goto bad_uuid; + uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1])); + s += 2; + } + return get_spec_by_x(UUID, uuid); + + bad_uuid: + fprintf(stderr, "mount: bad UUID\n"); + exit(1); + return NULL; /* just for gcc */ +} + +char * +get_spec_by_volume_label(const char *s) { + return get_spec_by_x(VOL, s); +} + +const char * +get_volume_label_by_spec(const char *spec) { + struct uuidCache_s *uc; + + uuidcache_init(); + uc = uuidCache; + + while(uc) { + if (!strcmp(spec, uc->device)) + return uc->label; + uc = uc->next; + } + return NULL; +} diff --git a/collage/mount_by_label.h b/collage/mount_by_label.h new file mode 100644 index 000000000..64bbbfa7d --- /dev/null +++ b/collage/mount_by_label.h @@ -0,0 +1,3 @@ +char *get_spec_by_uuid(const char *uuid); +char *get_spec_by_volume_label(const char *volumelabel); +const char *get_volume_label_by_spec(const char *spec); |