From 2d8defde38006fd4c92862db089ca2a1f0acda63 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 3 Jul 1999 01:59:42 +0000 Subject: [PATCH] ChangeLog, Makefile.in, fsck.c, get_device_by_label.c, get_device_by_label.h: fsck.c: Added support for LABEL= and UUID= specifications for the filesystem's device, to match what recent mount programs can support. Also, close stdin when doing fsck -A or when checking more than one filesystem at a time, so that e2fsck doesn't try to ask interactive questions if the filesystem appears to be mounted. get_device_by_label.c: New file added to support LABEL=foo and UUID=bar type specifications. --- misc/ChangeLog | 12 ++++ misc/Makefile.in | 2 +- misc/fsck.c | 54 ++++++++++----- misc/get_device_by_label.c | 163 +++++++++++++++++++++++++++++++++++++++++++++ misc/get_device_by_label.h | 10 +++ 5 files changed, 225 insertions(+), 16 deletions(-) create mode 100644 misc/get_device_by_label.c create mode 100644 misc/get_device_by_label.h diff --git a/misc/ChangeLog b/misc/ChangeLog index da3c7bb..9d7f372 100644 --- a/misc/ChangeLog +++ b/misc/ChangeLog @@ -1,3 +1,15 @@ +1999-07-02 + + * fsck.c: Added support for LABEL= and UUID= specifications for + the filesystem's device, to match what recent mount + programs can support. Also, close stdin when doing fsck + -A or when checking more than one filesystem at a time, so + that e2fsck doesn't try to ask interactive questions if + the filesystem appears to be mounted. + + * get_device_by_label.c: New file added to support LABEL=foo and + UUID=bar type specifications. + 1999-07-01 * badblocks.c: Make the "done" string include enough spaces to diff --git a/misc/Makefile.in b/misc/Makefile.in index e140db6..175201b 100644 --- a/misc/Makefile.in +++ b/misc/Makefile.in @@ -28,7 +28,7 @@ UUIDGEN_OBJS= uuidgen.o DUMPE2FS_OBJS= dumpe2fs.o BADBLOCKS_OBJS= badblocks.o E2LABEL_OBJS= e2label.o -FSCK_OBJS= fsck.o +FSCK_OBJS= fsck.o get_device_by_label.o SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c \ $(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \ diff --git a/misc/fsck.c b/misc/fsck.c index 669e307..db86f56 100644 --- a/misc/fsck.c +++ b/misc/fsck.c @@ -52,6 +52,7 @@ #include "../version.h" #include "fsck.h" +#include "get_device_by_label.h" #ifndef _PATH_MNTTAB #define _PATH_MNTTAB "/etc/fstab" @@ -242,6 +243,24 @@ int parse_fstab_line(char *line, struct fs_info **ret_fs) } /* + * Interpret the device name if necessary + */ +static char *interpret_device(char *spec) +{ + char *dev = NULL; + + if (!strncmp(spec, "UUID=", 5)) + dev = get_spec_by_uuid(spec+5); + else if (!strncmp(spec, "LABEL=", 6)) + dev = get_spec_by_volume_label(spec+6); + if (dev) { + free(spec); + spec = dev; + } + return spec; +} + +/* * Load the filesystem database from /etc/fstab */ static void load_fs_info(char *filename) @@ -270,6 +289,7 @@ static void load_fs_info(char *filename) } if (!fs) continue; + fs->device = interpret_device(fs->device); if (!filesys_info) filesys_info = fs; else @@ -339,7 +359,7 @@ static char *find_fsck(char *type) * Execute a particular fsck program, and link it into the list of * child processes we are waiting for. */ -static int execute(char *prog, char *device, char *mntpt) +static int execute(char *prog, char *device, char *mntpt, int interactive) { char *s, *argv[80]; int argc, i; @@ -375,6 +395,8 @@ static int execute(char *prog, char *device, char *mntpt) perror("fork"); return errno; } else if (pid == 0) { + if (!interactive) + close(0); (void) execv(s, argv); perror(argv[0]); exit(EXIT_ERROR); @@ -492,7 +514,7 @@ static int wait_all(NOARGS) * If the type isn't specified by the user, then use either the type * specified in /etc/fstab, or DEFAULT_FSTYPE. */ -static void fsck_device(char *device) +static void fsck_device(char *device, int interactive) { const char *type = 0; struct fs_info *fsent; @@ -507,17 +529,12 @@ static void fsck_device(char *device) if (!type) type = fsent->type; } - if (!fsent) { - fprintf(stderr, - "Error: no entry found the fstab file for %s.\n", - device); - exit(1); - } if (!type) type = DEFAULT_FSTYPE; sprintf(prog, "fsck.%s", type); - retval = execute(prog, device, fsent ? fsent->mountpt : 0); + retval = execute(prog, device, fsent ? fsent->mountpt : 0, + interactive); if (retval) { fprintf(stderr, "%s: Error %d while executing %s for %s\n", progname, retval, prog, device); @@ -649,7 +666,7 @@ static int check_all(NOARGS) break; } if (fs && !skip_root && !ignore(fs)) { - fsck_device(fs->device); + fsck_device(fs->device, 0); fs->flags |= FLAG_DONE; status |= wait_all(); if (status > EXIT_NONDESTRUCT) @@ -694,7 +711,7 @@ static int check_all(NOARGS) /* * Spawn off the fsck process */ - fsck_device(fs->device); + fsck_device(fs->device, 0); fs->flags |= FLAG_DONE; if (serialize) { @@ -747,16 +764,19 @@ static void PRS(int argc, char *argv[]) arg = argv[i]; if (!arg) continue; - if (arg[0] == '/') { + if ((arg[0] == '/' && !opts_for_fsck) || + (strncmp(arg, "LABEL=", 6) == 0) || + (strncmp(arg, "UUID=", 5) == 0)) { if (num_devices >= MAX_DEVICES) { fprintf(stderr, "%s: too many devices\n", progname); exit(1); } - devices[num_devices++] = string_copy(arg); + devices[num_devices++] = + interpret_device(string_copy(arg)); continue; } - if (arg[0] != '-') { + if (arg[0] != '-' || opts_for_fsck) { if (num_args >= MAX_ARGS) { fprintf(stderr, "%s: too many arguments\n", progname); @@ -835,6 +855,7 @@ int main(int argc, char *argv[]) { int i; int status = 0; + int interactive = 0; char *oldpath = getenv("PATH"); char *fstab; @@ -864,8 +885,11 @@ int main(int argc, char *argv[]) if (doall) return check_all(); + if ((num_devices == 1) || (serialize)) + interactive = 1; + for (i = 0 ; i < num_devices; i++) { - fsck_device(devices[i]); + fsck_device(devices[i], interactive); if (serialize) { struct fsck_instance *inst; diff --git a/misc/get_device_by_label.c b/misc/get_device_by_label.c new file mode 100644 index 0000000..64bda02 --- /dev/null +++ b/misc/get_device_by_label.c @@ -0,0 +1,163 @@ +/* + * get_device_by_label.h + * + * Copyright 1999 by Andries Brouwer and Theodore Ts'o + * + * This file may be redistributed under the terms of the GNU Public + * License. + * + * Taken from aeb's mount, 990619 + */ + +#include +#include +#include +#include +#include +#include "get_device_by_label.h" + +#define PROC_PARTITIONS "/proc/partitions" +#define DEVLABELDIR "/dev" + +#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)) + + +static FILE *procpt; + +static void +procptclose(void) { + if (procpt) + fclose (procpt); + procpt = 0; +} + +static int +procptopen(void) { + return ((procpt = fopen(PROC_PARTITIONS, "r")) != NULL); +} + +static char * +procptnext(void) { + char line[100]; + char *s; + int ma, mi, sz; + static char ptname[100]; + + while (fgets(line, sizeof(line), procpt)) { + if (sscanf (line, " %d %d %d %[^\n]\n", &ma, &mi, &sz, ptname) != 4) + continue; + + /* skip extended partitions (heuristic: size 1) */ + if (sz == 1) + 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])) + return ptname; + } + return 0; +} + +#define UUID 1 +#define VOL 2 + +/* for now, only ext2 is supported */ +static int +has_right_label(const char *device, int n, const char *label) { + + /* start with a test for ext2, taken from mount_guess_fstype */ + int fd; + char *s; + struct ext2_super_block e2sb; + + fd = open(device, O_RDONLY); + if (fd < 0) + return 0; + + if (lseek(fd, 1024, SEEK_SET) != 1024 + || read(fd, (char *) &e2sb, sizeof(e2sb)) != sizeof(e2sb) + || (ext2magic(e2sb) != EXT2_SUPER_MAGIC)) { + close(fd); + return 0; + } + + close(fd); + + /* superblock is ext2 - now what is its label? */ + s = ((n == UUID) ? e2sb.s_uuid : e2sb.s_volume_name); + return (strncmp(s, label, 16) == 0); +} + +static char * +get_spec_by_x(int n, const char *t) { + char *pt; + char device[110]; + + if(!procptopen()) + return NULL; + while((pt = procptnext()) != NULL) { + /* 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, pt); + if (has_right_label(device, n, t)) { + procptclose(); + return strdup(device); + } + } + procptclose(); + 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 *s0) { + u_char uuid[16]; + int i; + const char *s = s0; + + 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, "WARNING: %s: bad UUID", s0); + return NULL; +} + +char * +get_spec_by_volume_label(const char *s) { + return get_spec_by_x(VOL, s); +} diff --git a/misc/get_device_by_label.h b/misc/get_device_by_label.h new file mode 100644 index 0000000..f87b27f --- /dev/null +++ b/misc/get_device_by_label.h @@ -0,0 +1,10 @@ +/* + * get_device_by_label.h + * + * Copyright 1999 by Andries Brouwer and Theodore Ts'o + * + * This file may be redistributed under the terms of the GNU Public + * License. + */ +char *get_spec_by_uuid(const char *uuid); +char *get_spec_by_volume_label(const char *volumelabel); -- 1.8.3.1