Make fsck ignore mounted filesystems if given the -M option

Adapted from the SuSE patch, but fixes a number of very serious
problems with the patch in SLES:

1) This changeset uses -M instead of -m; most lowercase options are
reserved for use by the filesystem-specific fsck programs.  All new
fsck options must be upper case.

2)  This changeset will skip the root filesystem in "fsck -AM", which
the SLES patch will not do.

3)  Loading /proc/mounts into the fs_info can cause -t opts matching to
malfuction.  So this changeset uses a simplified version of the
ismounted.c function from the ext2fs library.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
bitmap-optimize
Theodore Ts'o 2008-02-16 14:14:24 -05:00
parent e7cc6f7d0b
commit fe263da923
4 changed files with 236 additions and 8 deletions

View File

@ -40,7 +40,7 @@ UUIDD_OBJS= uuidd.o
DUMPE2FS_OBJS= dumpe2fs.o
BADBLOCKS_OBJS= badblocks.o
E2IMAGE_OBJS= e2image.o
FSCK_OBJS= fsck.o base_device.o
FSCK_OBJS= fsck.o base_device.o ismounted.o
BLKID_OBJS= blkid.o
FILEFRAG_OBJS= filefrag.o
@ -51,7 +51,7 @@ SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c \
$(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \
$(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
$(srcdir)/filefrag.c $(srcdir)/base_device.c \
$(srcdir)/../e2fsck/profile.c
$(srcdir)/ismounted.c $(srcdir)/../e2fsck/profile.c
LIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
@ -173,6 +173,10 @@ filefrag: $(FILEFRAG_OBJS)
@echo " LD $@"
@$(CC) $(ALL_LDFLAGS) -o filefrag $(FILEFRAG_OBJS)
tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS)
@echo " LD $@"
$(CC) -o tst_ismounted $(srcdir)/ismounted.c -DDEBUG $(ALL_CFLAGS) $(LIBCOM_ERR)
tune2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/tune2fs.8.in
@echo " SUBST $@"
@$(SUBSTITUTE_UPTIME) $(srcdir)/tune2fs.8.in tune2fs.8
@ -368,7 +372,7 @@ clean:
$(FMANPAGES) \
base_device base_device.out mke2fs.static filefrag \
e2initrd_helper partinfo prof_err.[ch] default_profile.c \
uuidd e2image \#* *.s *.o *.a *~ core
uuidd e2image tst_ismounted \#* *.s *.o *.a *~ core
mostlyclean: clean
distclean: clean
@ -444,5 +448,6 @@ blkid.o: $(srcdir)/blkid.c $(top_srcdir)/lib/blkid/blkid.h \
logsave.o: $(srcdir)/logsave.c
filefrag.o: $(srcdir)/filefrag.c
base_device.o: $(srcdir)/base_device.c $(srcdir)/fsck.h
ismounted.o: $(srcdir)/ismounted.c $(top_srcdir)/lib/et/com_err.h
profile.o: $(srcdir)/../e2fsck/profile.c $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/../e2fsck/profile.h prof_err.h

View File

@ -8,7 +8,7 @@ fsck \- check and repair a Linux file system
.SH SYNOPSIS
.B fsck
[
.B \-sAVRTNP
.B \-sAVRTMNP
]
[
.B \-C
@ -233,6 +233,10 @@ a progress bar at a time. GUI front-ends may specify a file descriptor
.IR fd ,
in which case the progress bar information will be sent to that file descriptor.
.TP
.B \-M
Do not check mounted filesystems and return an exit code of 0
for mounted filesystems.
.TP
.B \-N
Don't execute, just show what would be done.
.TP

View File

@ -102,7 +102,7 @@ int doall = 0;
int noexecute = 0;
int serialize = 0;
int skip_root = 0;
int like_mount = 0;
int ignore_mounted = 0;
int notitle = 0;
int parallel_root = 0;
int progress = 0;
@ -973,7 +973,8 @@ static int check_all(NOARGS)
break;
}
if (fs) {
if (!skip_root && !ignore(fs)) {
if (!skip_root && !ignore(fs) &&
!(ignore_mounted && is_mounted(fs->device))) {
fsck_device(fs, 1);
status |= wait_many(FLAG_WAIT_ALL);
if (status > EXIT_NONDESTRUCT)
@ -1009,6 +1010,10 @@ static int check_all(NOARGS)
not_done_yet++;
continue;
}
if (ignore_mounted && is_mounted(fs->device)) {
fs->flags |= FLAG_DONE;
continue;
}
/*
* If a filesystem on a particular device has
* already been spawned, then we need to defer
@ -1058,7 +1063,7 @@ static int check_all(NOARGS)
static void usage(NOARGS)
{
fputs(_("Usage: fsck [-ANPRTV] [ -C [ fd ] ] [-t fstype] [fs-options] [filesys ...]\n"), stderr);
fputs(_("Usage: fsck [-AMNPRTV] [ -C [ fd ] ] [-t fstype] [fs-options] [filesys ...]\n"), stderr);
exit(EXIT_USAGE);
}
@ -1181,7 +1186,7 @@ static void PRS(int argc, char *argv[])
notitle++;
break;
case 'M':
like_mount++;
ignore_mounted++;
break;
case 'P':
parallel_root++;
@ -1303,6 +1308,8 @@ int main(int argc, char *argv[])
if (!fs)
continue;
}
if (ignore_mounted && is_mounted(fs->device))
continue;
fsck_device(fs, interactive);
if (serialize ||
(max_running && (num_running >= max_running))) {

212
misc/ismounted.c Normal file
View File

@ -0,0 +1,212 @@
/*
* ismounted.c --- Check to see if the filesystem was mounted
*
* Copyright (C) 1995,1996,1997,1998,1999,2000,2008 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <fcntl.h>
#ifdef HAVE_LINUX_FD_H
#include <linux/fd.h>
#endif
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#include <string.h>
#include <sys/stat.h>
/*
* ext2fs_check_if_mounted flags
*/
#define MF_MOUNTED 1
#include "et/com_err.h"
static char *skip_over_blank(char *cp)
{
while (*cp && isspace(*cp))
cp++;
return cp;
}
static char *skip_over_word(char *cp)
{
while (*cp && !isspace(*cp))
cp++;
return cp;
}
static char *parse_word(char **buf)
{
char *word, *next;
word = *buf;
if (*word == 0)
return 0;
word = skip_over_blank(word);
next = skip_over_word(word);
if (*next)
*next++ = 0;
*buf = next;
return word;
}
/*
* Helper function which checks a file in /etc/mtab format to see if a
* filesystem is mounted. Returns an error if the file doesn't exist
* or can't be opened.
*/
static errcode_t check_mntent_file(const char *mtab_file, const char *file,
int *mount_flags)
{
struct stat st_buf;
errcode_t retval = 0;
dev_t file_dev=0, file_rdev=0;
ino_t file_ino=0;
FILE *f;
char buf[1024], *device = 0, *mnt_dir = 0, *cp;
int fd;
*mount_flags = 0;
if ((f = fopen(mtab_file, "r")) == NULL)
return errno;
if ((f = setmntent (mtab_file, "r")) == NULL)
return errno;
if (stat(file, &st_buf) == 0) {
if (S_ISBLK(st_buf.st_mode)) {
#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
file_rdev = st_buf.st_rdev;
#endif /* __GNU__ */
} else {
file_dev = st_buf.st_dev;
file_ino = st_buf.st_ino;
}
}
while (1) {
if (!fgets(buf, sizeof(buf), f)) {
device = mnt_dir = 0;
break;
}
buf[sizeof(buf)-1] = 0;
cp = buf;
device = parse_word(&cp);
if (!device || *device == '#')
return 0; /* Ignore blank lines and comments */
mnt_dir = parse_word(&cp);
if (device[0] != '/')
continue;
if (strcmp(file, device) == 0)
break;
if (stat(device, &st_buf) == 0) {
if (S_ISBLK(st_buf.st_mode)) {
#ifndef __GNU__
if (file_rdev && (file_rdev == st_buf.st_rdev))
break;
#endif /* __GNU__ */
} else {
if (file_dev && ((file_dev == st_buf.st_dev) &&
(file_ino == st_buf.st_ino)))
break;
}
}
}
if (mnt_dir == 0) {
#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
/*
* Do an extra check to see if this is the root device. We
* can't trust /etc/mtab, and /proc/mounts will only list
* /dev/root for the root filesystem. Argh. Instead we
* check if the given device has the same major/minor number
* as the device that the root directory is on.
*/
if (file_rdev && (stat("/", &st_buf) == 0) &&
(st_buf.st_dev == file_rdev))
*mount_flags = MF_MOUNTED;
#endif /* __GNU__ */
goto errout;
}
#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
/* Validate the entry in case /etc/mtab is out of date */
/*
* We need to be paranoid, because some broken distributions
* (read: Slackware) don't initialize /etc/mtab before checking
* all of the non-root filesystems on the disk.
*/
if (stat(mnt_dir, &st_buf) < 0) {
retval = errno;
if (retval == ENOENT) {
#ifdef DEBUG
printf("Bogus entry in %s! (%s does not exist)\n",
mtab_file, mnt_dir);
#endif /* DEBUG */
retval = 0;
}
goto errout;
}
if (file_rdev && (st_buf.st_dev != file_rdev)) {
#ifdef DEBUG
printf("Bogus entry in %s! (%s not mounted on %s)\n",
mtab_file, file, mnt_dir);
#endif /* DEBUG */
goto errout;
}
#endif /* __GNU__ */
*mount_flags = MF_MOUNTED;
retval = 0;
errout:
endmntent (f);
return retval;
}
int is_mounted(const char *file)
{
errcode_t retval;
int mount_flags = 0;
#ifdef __linux__
retval = check_mntent_file("/proc/mounts", file, &mount_flags);
if (retval)
return 0;
if (mount_flags)
return 1;
#endif /* __linux__ */
retval = check_mntent_file("/etc/mtab", file, &mount_flags);
if (retval)
return 0;
return (mount_flags);
}
#ifdef DEBUG
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "Usage: %s device\n", argv[0]);
exit(1);
}
if (is_mounted(argv[1]))
printf("\t%s is mounted.\n", argv[1]);
exit(0);
}
#endif /* DEBUG */