diff --git a/misc/Makefile.in b/misc/Makefile.in index 58b35519..b4c39eec 100644 --- a/misc/Makefile.in +++ b/misc/Makefile.in @@ -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 diff --git a/misc/fsck.8.in b/misc/fsck.8.in index aa5fd05f..50fd8cef 100644 --- a/misc/fsck.8.in +++ b/misc/fsck.8.in @@ -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 diff --git a/misc/fsck.c b/misc/fsck.c index 5cf1a1c8..24c095a4 100644 --- a/misc/fsck.c +++ b/misc/fsck.c @@ -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))) { diff --git a/misc/ismounted.c b/misc/ismounted.c new file mode 100644 index 00000000..72f4cbae --- /dev/null +++ b/misc/ismounted.c @@ -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 +#if HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_LINUX_FD_H +#include +#endif +#ifdef HAVE_MNTENT_H +#include +#endif +#include +#include + +/* + * 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 */