+1999-07-02 <tytso@rsts-11.mit.edu>
+
+ * 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 <tytso@valinux.com>
* badblocks.c: Make the "done" string include enough spaces to
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 \
#include "../version.h"
#include "fsck.h"
+#include "get_device_by_label.h"
#ifndef _PATH_MNTTAB
#define _PATH_MNTTAB "/etc/fstab"
}
/*
+ * 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)
}
if (!fs)
continue;
+ fs->device = interpret_device(fs->device);
if (!filesys_info)
filesys_info = fs;
else
* 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;
perror("fork");
return errno;
} else if (pid == 0) {
+ if (!interactive)
+ close(0);
(void) execv(s, argv);
perror(argv[0]);
exit(EXIT_ERROR);
* 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;
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);
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)
/*
* Spawn off the fsck process
*/
- fsck_device(fs->device);
+ fsck_device(fs->device, 0);
fs->flags |= FLAG_DONE;
if (serialize) {
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);
{
int i;
int status = 0;
+ int interactive = 0;
char *oldpath = getenv("PATH");
char *fstab;
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;
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#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);
+}
--- /dev/null
+/*
+ * 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);