* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
* 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
*
- * Copyright (C) 2009, 2012 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2009-2014 Karel Zak <kzak@redhat.com>
*
* This file may be redistributed under the terms of the GNU Public
* License.
#include "pathnames.h"
#include "exitcodes.h"
#include "c.h"
-#include "closestream.h"
+#include "fileutils.h"
+#include "monotonic.h"
+#include "strutils.h"
#define XALLOC_EXIT_CODE FSCK_EX_ERROR
#include "xalloc.h"
+#define CLOSE_EXIT_CODE FSCK_EX_ERROR
+#include "closestream.h"
+
#ifndef DEFAULT_FSTYPE
# define DEFAULT_FSTYPE "ext2"
#endif
#define MAX_DEVICES 32
#define MAX_ARGS 32
+#define FSCK_RUNTIME_DIRNAME "/run/fsck"
+
static const char *ignored_types[] = {
"ignore",
"iso9660",
"ext4",
"ext4dev",
"jfs",
- "reiserfs",
- "xiafs",
- "xfs",
- NULL
+ "reiserfs"
};
/*
- * Internal structure for mount tabel entries.
+ * Internal structure for mount table entries.
*/
struct fsck_fs_data
{
struct fsck_instance {
int pid;
int flags; /* FLAG_{DONE|PROGRESS} */
- int lock; /* flock()ed whole disk file descriptor or -1 */
+
+ int lock; /* flock()ed lockpath file descriptor or -1 */
+ char *lockpath; /* /run/fsck/<diskname>.lock or NULL */
+
int exit_status;
struct timeval start_time;
struct timeval end_time;
static int progress_fd;
static int force_all_parallel;
static int report_stats;
+static FILE *report_stats_file;
static int num_running;
static int max_running;
static char *fstype;
static struct fsck_instance *instance_list;
-static const char fsck_prefix_path[] = FS_SEARCH_PATH;
+#define FSCK_DEFAULT_PATH "/sbin"
static char *fsck_path;
+
/* parsed fstab and mtab */
static struct libmnt_table *fstab, *mtab;
static struct libmnt_cache *mntcache;
l = strtol(s, &p, 0);
if (*p || l == LONG_MIN || l == LONG_MAX || l < 0 || l > INT_MAX)
return -1;
- else
- return (int) l;
+
+ return (int) l;
+}
+
+/* Do we really really want to check this fs? */
+static int fs_check_required(const char *type)
+{
+ size_t i;
+
+ for(i = 0; i < ARRAY_SIZE(really_wanted); i++) {
+ if (strcmp(type, really_wanted[i]) == 0)
+ return 1;
+ }
+
+ return 0;
}
static int is_mounted(struct libmnt_fs *fs)
"/sys/dev/block/%d:%d/queue/rotational",
major(disk), minor(disk));
- if (rc < 0 || (unsigned int) (rc + 1) > sizeof(path))
+ if (rc < 0 || (unsigned int) rc >= sizeof(path))
return 0;
f = fopen(path, "r");
rc = fscanf(f, "%d", &x);
if (rc != 1) {
if (ferror(f))
- warn(_("failed to read: %s"), path);
+ warn(_("cannot read %s"), path);
else
warnx(_("parse error: %s"), path);
}
static void lock_disk(struct fsck_instance *inst)
{
dev_t disk = fs_get_disk(inst->fs, 1);
- char *diskname;
+ char *diskpath = NULL, *diskname;
+
+ inst->lock = -1;
if (!disk || is_irrotational_disk(disk))
- return;
+ goto done;
+
+ diskpath = blkid_devno_to_devname(disk);
+ if (!diskpath)
+ goto done;
+
+ if (access(FSCK_RUNTIME_DIRNAME, F_OK) != 0) {
+ int rc = mkdir(FSCK_RUNTIME_DIRNAME,
+ S_IWUSR|
+ S_IRUSR|S_IRGRP|S_IROTH|
+ S_IXUSR|S_IXGRP|S_IXOTH);
+ if (rc && errno != EEXIST) {
+ warn(_("cannot create directory %s"),
+ FSCK_RUNTIME_DIRNAME);
+ goto done;
+ }
+ }
- diskname = blkid_devno_to_devname(disk);
+ diskname = stripoff_last_component(diskpath);
if (!diskname)
- return;
+ diskname = diskpath;
+
+ xasprintf(&inst->lockpath, FSCK_RUNTIME_DIRNAME "/%s.lock", diskname);
if (verbose)
- printf(_("Locking disk %s ... "), diskname);
+ printf(_("Locking disk by %s ... "), inst->lockpath);
- inst->lock = open(diskname, O_CLOEXEC | O_RDONLY);
+ inst->lock = open(inst->lockpath, O_RDONLY|O_CREAT|O_CLOEXEC,
+ S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
if (inst->lock >= 0) {
int rc = -1;
/* TRANSLATORS: These are followups to "Locking disk...". */
printf("%s.\n", inst->lock >= 0 ? _("succeeded") : _("failed"));
- free(diskname);
- return;
+
+done:
+ if (inst->lock < 0) {
+ free(inst->lockpath);
+ inst->lockpath = NULL;
+ }
+ free(diskpath);
}
static void unlock_disk(struct fsck_instance *inst)
{
- if (inst->lock >= 0) {
- /* explicitly unlock, don't rely on close(), maybe some library
- * (e.g. liblkid) has still open the device.
- */
- flock(inst->lock, LOCK_UN);
- close(inst->lock);
+ if (inst->lock < 0)
+ return;
- inst->lock = -1;
- }
+ if (verbose)
+ printf(_("Unlocking %s.\n"), inst->lockpath);
+
+ close(inst->lock); /* unlock */
+
+ free(inst->lockpath);
+
+ inst->lock = -1;
+ inst->lockpath = NULL;
}
static void free_instance(struct fsck_instance *i)
if (lockdisk)
unlock_disk(i);
free(i->prog);
+ free(i->lockpath);
+ mnt_unref_fs(i->fs);
free(i);
- return;
}
static struct libmnt_fs *add_dummy_fs(const char *device)
struct libmnt_fs *fs = mnt_new_fs();
if (fs && mnt_fs_set_source(fs, device) == 0 &&
- mnt_table_add_fs(fstab, fs) == 0)
+ mnt_table_add_fs(fstab, fs) == 0) {
+ mnt_unref_fs(fs);
return fs;
+ }
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
err(FSCK_EX_ERROR, _("failed to setup description for %s"), device);
}
device = fs_get_device(fs);
if (device) {
int ambi = 0;
+ char *tp;
+ struct libmnt_cache *cache = mnt_table_get_cache(fstab);
- type = mnt_get_fstype(device, &ambi, mnt_table_get_cache(fstab));
+ tp = mnt_get_fstype(device, &ambi, cache);
if (!ambi)
- mnt_fs_set_fstype(fs, type);
+ mnt_fs_set_fstype(fs, tp);
+ if (!cache)
+ free(tp);
}
}
static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)),
const char *filename, int line)
{
- warnx(_("%s: parse error at line %d -- ignore"), filename, line);
- return 0;
+ warnx(_("%s: parse error at line %d -- ignored"), filename, line);
+ return 1;
}
/*
errno = 0;
/*
- * Let's follow libmount defauls if $FSTAB_FILE is not specified
+ * Let's follow libmount defaults if $FSTAB_FILE is not specified
*/
path = getenv("FSTAB_FILE");
if (mnt_table_parse_fstab(fstab, path)) {
if (!path)
path = mnt_get_fstab_path();
- if (errno)
- warn(_("%s: failed to parse fstab"), path);
- else
- warnx(_("%s: failed to parse fstab"), path);
+
+ /* don't print error when there is no fstab at all */
+ if (access(path, F_OK) == 0) {
+ if (errno)
+ warn(_("%s: failed to parse fstab"), path);
+ else
+ warnx(_("%s: failed to parse fstab"), path);
+ }
}
}
}
/* Find fsck program for a given fs type. */
-static char *find_fsck(const char *type)
+static int find_fsck(const char *type, char **progpath)
{
char *s;
const char *tpl;
- static char prog[256];
+ char *prog = NULL;
char *p = xstrdup(fsck_path);
- struct stat st;
+ int rc;
/* Are we looking for a program or just a type? */
tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s");
for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
- sprintf(prog, tpl, s, type);
- if (stat(prog, &st) == 0)
+ xasprintf(&prog, tpl, s, type);
+ if (access(prog, X_OK) == 0)
break;
+ free(prog);
+ prog = NULL;
}
+
free(p);
+ rc = prog ? 1 : 0;
+
+ if (progpath)
+ *progpath = prog;
+ else
+ free(prog);
- return(s ? prog : NULL);
+ return rc;
}
static int progress_active(void)
*/
static void print_stats(struct fsck_instance *inst)
{
- double time_diff;
+ struct timeval delta;
if (!inst || !report_stats || noexecute)
return;
- time_diff = (inst->end_time.tv_sec - inst->start_time.tv_sec)
- + (inst->end_time.tv_usec - inst->start_time.tv_usec) / 1E6;
-
- fprintf(stdout, "%s: status %d, rss %ld, "
- "real %f, user %d.%06d, sys %d.%06d\n",
- fs_get_device(inst->fs),
- inst->exit_status,
- inst->rusage.ru_maxrss,
- time_diff,
- (int)inst->rusage.ru_utime.tv_sec,
- (int)inst->rusage.ru_utime.tv_usec,
- (int)inst->rusage.ru_stime.tv_sec,
- (int)inst->rusage.ru_stime.tv_usec);
+ timersub(&inst->end_time, &inst->start_time, &delta);
+
+ if (report_stats_file)
+ fprintf(report_stats_file, "%s %d %ld "
+ "%ld.%06ld %ld.%06ld %ld.%06ld\n",
+ fs_get_device(inst->fs),
+ inst->exit_status,
+ inst->rusage.ru_maxrss,
+ (long)delta.tv_sec, (long)delta.tv_usec,
+ (long)inst->rusage.ru_utime.tv_sec,
+ (long)inst->rusage.ru_utime.tv_usec,
+ (long)inst->rusage.ru_stime.tv_sec,
+ (long)inst->rusage.ru_stime.tv_usec);
+ else
+ fprintf(stdout, "%s: status %d, rss %ld, "
+ "real %ld.%06ld, user %ld.%06ld, sys %ld.%06ld\n",
+ fs_get_device(inst->fs),
+ inst->exit_status,
+ inst->rusage.ru_maxrss,
+ (long)delta.tv_sec, (long)delta.tv_usec,
+ (long)inst->rusage.ru_utime.tv_sec,
+ (long)inst->rusage.ru_utime.tv_usec,
+ (long)inst->rusage.ru_stime.tv_sec,
+ (long)inst->rusage.ru_stime.tv_usec);
}
/*
* Execute a particular fsck program, and link it into the list of
* child processes we are waiting for.
*/
-static int execute(const char *type, struct libmnt_fs *fs, int interactive)
+static int execute(const char *progname, const char *progpath,
+ const char *type, struct libmnt_fs *fs, int interactive)
{
- char *s, *argv[80], prog[80];
+ char *argv[80];
int argc, i;
struct fsck_instance *inst, *p;
pid_t pid;
inst = xcalloc(1, sizeof(*inst));
- sprintf(prog, "fsck.%s", type);
- argv[0] = xstrdup(prog);
+ argv[0] = xstrdup(progname);
argc = 1;
for (i=0; i <num_args; i++)
argv[argc++] = xstrdup(args[i]);
- if (progress) {
- if ((strcmp(type, "ext2") == 0) ||
- (strcmp(type, "ext3") == 0) ||
- (strcmp(type, "ext4") == 0) ||
- (strcmp(type, "ext4dev") == 0)) {
- char tmp[80];
-
- tmp[0] = 0;
- if (!progress_active()) {
- snprintf(tmp, 80, "-C%d", progress_fd);
- inst->flags |= FLAG_PROGRESS;
- } else if (progress_fd)
- snprintf(tmp, 80, "-C%d", progress_fd * -1);
- if (tmp[0])
- argv[argc++] = xstrdup(tmp);
- }
+ if (progress &&
+ ((strcmp(type, "ext2") == 0) ||
+ (strcmp(type, "ext3") == 0) ||
+ (strcmp(type, "ext4") == 0) ||
+ (strcmp(type, "ext4dev") == 0))) {
+
+ char tmp[80];
+ tmp[0] = 0;
+ if (!progress_active()) {
+ snprintf(tmp, 80, "-C%d", progress_fd);
+ inst->flags |= FLAG_PROGRESS;
+ } else if (progress_fd)
+ snprintf(tmp, 80, "-C%d", progress_fd * -1);
+ if (tmp[0])
+ argv[argc++] = xstrdup(tmp);
}
argv[argc++] = xstrdup(fs_get_device(fs));
- argv[argc] = 0;
-
- s = find_fsck(prog);
- if (s == NULL) {
- warnx(_("%s: not found"), prog);
- free(inst);
- return ENOENT;
- }
+ argv[argc] = NULL;
if (verbose || noexecute) {
const char *tgt = mnt_fs_get_target(fs);
if (!tgt)
tgt = fs_get_device(fs);
- printf("[%s (%d) -- %s] ", s, num_running, tgt);
+ printf("[%s (%d) -- %s] ", progpath, num_running, tgt);
for (i=0; i < argc; i++)
printf("%s ", argv[i]);
printf("\n");
}
+ mnt_ref_fs(fs);
inst->fs = fs;
inst->lock = -1;
pid = -1;
else if ((pid = fork()) < 0) {
warn(_("fork failed"));
- free(inst);
+ free_instance(inst);
return errno;
} else if (pid == 0) {
if (!interactive)
close(0);
- execv(s, argv);
- err(FSCK_EX_ERROR, _("%s: execute failed"), s);
+ execv(progpath, argv);
+ err(FSCK_EX_ERROR, _("%s: execute failed"), progpath);
}
for (i=0; i < argc; i++)
free(argv[i]);
inst->pid = pid;
- inst->prog = xstrdup(prog);
+ inst->prog = xstrdup(progname);
inst->type = xstrdup(type);
- gettimeofday(&inst->start_time, NULL);
+ gettime_monotonic(&inst->start_time);
inst->next = NULL;
/*
*/
static struct fsck_instance *wait_one(int flags)
{
- int status;
+ int status = 0;
int sig;
struct fsck_instance *inst, *inst2, *prev;
pid_t pid;
if (noexecute) {
inst = instance_list;
- prev = 0;
+ prev = NULL;
#ifdef RANDOM_DEBUG
while (inst->next && (random() & 1)) {
prev = inst;
warnx(_("wait: no more child process?!?"));
return NULL;
}
- warn(_("waidpid failed"));
+ warn(_("waitpid failed"));
continue;
}
- for (prev = 0, inst = instance_list;
+ for (prev = NULL, inst = instance_list;
inst;
prev = inst, inst = inst->next) {
if (inst->pid == pid)
inst->exit_status = status;
inst->flags |= FLAG_DONE;
- gettimeofday(&inst->end_time, NULL);
+ gettime_monotonic(&inst->end_time);
memcpy(&inst->rusage, &rusage, sizeof(struct rusage));
if (progress && (inst->flags & FLAG_PROGRESS) &&
for (inst2 = instance_list; inst2; inst2 = inst2->next) {
if (inst2->flags & FLAG_DONE)
continue;
- if (strcmp(inst2->type, "ext2") &&
+ if (strcmp(inst2->type, "ext2") != 0 &&
strcmp(inst2->type, "ext3") &&
- strcmp(inst2->type, "ext4") &&
- strcmp(inst2->type, "ext4dev"))
+ strcmp(inst2->type, "ext4") != 0 &&
+ strcmp(inst2->type, "ext4dev") != 0)
continue;
/*
* If we've just started the fsck, wait a tiny
* bit before sending the kill, to give it
* time to set up the signal handler
*/
- if (inst2->start_time.tv_sec < time(0) + 2) {
+ if (inst2->start_time.tv_sec < time(NULL) + 2) {
if (fork() == 0) {
sleep(1);
kill(inst2->pid, SIGUSR1);
*/
static int fsck_device(struct libmnt_fs *fs, int interactive)
{
+ char *progname, *progpath;
const char *type;
int retval;
if (type && strcmp(type, "auto") != 0)
;
- else if (fstype && strncmp(fstype, "no", 2) &&
- strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) &&
+ else if (fstype && strncmp(fstype, "no", 2) != 0 &&
+ strncmp(fstype, "opts=", 5) != 0 && strncmp(fstype, "loop", 4) != 0 &&
!strchr(fstype, ','))
type = fstype;
else
type = DEFAULT_FSTYPE;
+ xasprintf(&progname, "fsck.%s", type);
+
+ if (!find_fsck(progname, &progpath)) {
+ free(progname);
+ if (fs_check_required(type)) {
+ retval = ENOENT;
+ goto err;
+ }
+ return 0;
+ }
+
num_running++;
- retval = execute(type, fs, interactive);
+ retval = execute(progname, progpath, type, fs, interactive);
+ free(progname);
+ free(progpath);
if (retval) {
- warnx(_("error %d while executing fsck.%s for %s"),
- retval, type, fs_get_device(fs));
num_running--;
- return FSCK_EX_ERROR;
+ goto err;
}
return 0;
+err:
+ warnx(_("error %d (%m) while executing fsck.%s for %s"),
+ retval, type, fs_get_device(fs));
+ return FSCK_EX_ERROR;
}
/*
* Deal with the fsck -t argument.
*/
-struct fs_type_compile {
+static struct fs_type_compile {
char **list;
int *type;
int negate;
int n, ret = 0, checked_type = 0;
char *cp;
- if (cmp->list == 0 || cmp->list[0] == 0)
+ if (cmp->list == NULL || cmp->list[0] == NULL)
return 1;
for (n=0; (cp = cmp->list[n]); n++) {
/* Check if we should ignore this filesystem. */
static int ignore(struct libmnt_fs *fs)
{
- const char **ip, *type;
- int wanted = 0;
+ const char *type;
/*
* If the pass number is 0, ignore it.
if (fs_ignored_type(fs))
return 1;
- /* Do we really really want to check this fs? */
- for(ip = really_wanted; *ip; ip++)
- if (strcmp(type, *ip) == 0) {
- wanted = 1;
- break;
- }
+
/* See if the <fsck.fs> program is available. */
- if (find_fsck(type) == NULL) {
- if (wanted)
+ if (!find_fsck(type, NULL)) {
+ if (fs_check_required(type))
warnx(_("cannot check %s: fsck.%s not found"),
fs_get_device(fs), type);
return 1;
if (!(dir = opendir(dirname)))
return -1;
- while ((dp = readdir(dir)) != 0) {
+ while ((dp = readdir(dir)) != NULL) {
#ifdef _DIRENT_HAVE_D_TYPE
if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
continue;
* Don't check a stacked device with any other disk too.
*/
if (!disk || fs_is_stacked(fs))
- return (instance_list != 0);
+ return (instance_list != NULL);
for (inst = instance_list; inst; inst = inst->next) {
dev_t idisk = fs_get_disk(inst->fs, 0);
/*
* This is for the bone-headed user who enters the root
- * filesystem twice. Skip root will skep all root entries.
+ * filesystem twice. Skip root will skip all root entries.
*/
if (skip_root) {
mnt_reset_iter(itr, MNT_ITER_FORWARD);
static void __attribute__((__noreturn__)) usage(void)
{
- printf(_("\nUsage:\n"
- " %s [fsck-options] [fs-options] [filesys ...]\n"),
- program_invocation_short_name);
-
- puts(_( "\nOptions:\n"
- " -A check all filesystems\n"
- " -R skip root filesystem; useful only with `-A'\n"
- " -M do not check mounted filesystems\n"
- " -t <type> specify filesystem types to be checked;\n"
- " type is allowed to be comma-separated list\n"
- " -P check filesystems in parallel, including root\n"
- " -r report statistics for each device fsck\n"
- " -s serialize fsck operations\n"
- " -l lock the device using flock()\n"
- " -N do not execute, just show what would be done\n"
- " -T do not show the title on startup\n"
- " -C <fd> display progress bar; file descriptor is for GUIs\n"
- " -V explain what is being done\n"
- " -? display this help and exit\n\n"
- "See fsck.* commands for fs-options."));
-
- exit(FSCK_EX_USAGE);
+ FILE *out = stdout;
+ fputs(USAGE_HEADER, out);
+ fprintf(out, _(" %s [options] -- [fs-options] [<filesystem> ...]\n"),
+ program_invocation_short_name);
+
+ fputs(USAGE_SEPARATOR, out);
+ fputs(_("Check and repair a Linux filesystem.\n"), out);
+
+ fputs(USAGE_OPTIONS, out);
+ fputs(_(" -A check all filesystems\n"), out);
+ fputs(_(" -C [<fd>] display progress bar; file descriptor is for GUIs\n"), out);
+ fputs(_(" -l lock the device to guarantee exclusive access\n"), out);
+ fputs(_(" -M do not check mounted filesystems\n"), out);
+ fputs(_(" -N do not execute, just show what would be done\n"), out);
+ fputs(_(" -P check filesystems in parallel, including root\n"), out);
+ fputs(_(" -R skip root filesystem; useful only with '-A'\n"), out);
+ fputs(_(" -r [<fd>] report statistics for each device checked;\n"
+ " file descriptor is for GUIs\n"), out);
+ fputs(_(" -s serialize the checking operations\n"), out);
+ fputs(_(" -T do not show the title on startup\n"), out);
+ fputs(_(" -t <type> specify filesystem types to be checked;\n"
+ " <type> is allowed to be a comma-separated list\n"), out);
+ fputs(_(" -V explain what is being done\n"), out);
+
+ fputs(USAGE_SEPARATOR, out);
+ printf( " -?, --help %s\n", USAGE_OPTSTR_HELP);
+ printf( " --version %s\n", USAGE_OPTSTR_VERSION);
+ fputs(USAGE_SEPARATOR, out);
+ fputs(_("See the specific fsck.* commands for available fs-options."), out);
+ printf(USAGE_MAN_TAIL("fsck(8)"));
+ exit(FSCK_EX_OK);
}
static void signal_cancel(int sig __attribute__((__unused__)))
static void parse_argv(int argc, char *argv[])
{
int i, j;
- char *arg, *dev, *tmp = 0;
+ char *arg, *dev, *tmp = NULL;
char options[128];
int opt = 0;
int opts_for_fsck = 0;
struct sigaction sa;
+ int report_stats_fd = -1;
/*
* Set up signal action
*/
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = signal_cancel;
- sigaction(SIGINT, &sa, 0);
- sigaction(SIGTERM, &sa, 0);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
num_devices = 0;
num_args = 0;
- instance_list = 0;
+ instance_list = NULL;
for (i=1; i < argc; i++) {
arg = argv[i];
if (!arg)
continue;
+
+ /* the only two longopts to satisfy UL standards */
+ if (!opts_for_fsck && !strcmp(arg, "--help"))
+ usage();
+ if (!opts_for_fsck && !strcmp(arg, "--version"))
+ print_version(FSCK_EX_OK);
+
if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
if (num_devices >= MAX_DEVICES)
errx(FSCK_EX_ERROR, _("too many devices"));
break;
case 'C':
progress = 1;
- if (arg[j+1]) {
+ if (arg[j+1]) { /* -C<fd> */
progress_fd = string_to_int(arg+j+1);
if (progress_fd < 0)
progress_fd = 0;
else
goto next_arg;
- } else if ((i+1) < argc &&
- !strncmp(argv[i+1], "-", 1) == 0) {
- progress_fd = string_to_int(argv[i]);
+ } else if (i+1 < argc && *argv[i+1] != '-') { /* -C <fd> */
+ progress_fd = string_to_int(argv[i+1]);
if (progress_fd < 0)
progress_fd = 0;
else {
break;
case 'r':
report_stats = 1;
+ if (arg[j+1]) { /* -r<fd> */
+ report_stats_fd = strtou32_or_err(arg+j+1, _("invalid argument of -r"));
+ goto next_arg;
+ } else if (i+1 < argc && *argv[i+1] >= '0' && *argv[i+1] <= '9') { /* -r <fd> */
+ report_stats_fd = strtou32_or_err(argv[i+1], _("invalid argument of -r"));
+ ++i;
+ goto next_arg;
+ }
break;
case 's':
serialize = 1;
break;
case 't':
- tmp = 0;
+ tmp = NULL;
if (fstype)
- usage();
+ errx(FSCK_EX_USAGE,
+ _("option '%s' may be specified only once"), "-t");
if (arg[j+1])
tmp = arg+j+1;
else if ((i+1) < argc)
tmp = argv[++i];
else
- usage();
+ errx(FSCK_EX_USAGE,
+ _("option '%s' requires an argument"), "-t");
fstype = xstrdup(tmp);
compile_fs_type(fstype, &fs_type_compiled);
goto next_arg;
opt = 0;
}
}
+
+ /* Validate the report stats file descriptor to avoid disasters */
+ if (report_stats_fd >= 0) {
+ report_stats_file = fdopen(report_stats_fd, "w");
+ if (!report_stats_file)
+ err(FSCK_EX_ERROR,
+ _("invalid argument of -r: %d"),
+ report_stats_fd);
+ }
+
if (getenv("FSCK_FORCE_ALL_PARALLEL"))
force_all_parallel++;
if ((tmp = getenv("FSCK_MAX_INST")))
{
int i, status = 0;
int interactive = 0;
- char *oldpath = getenv("PATH");
struct libmnt_fs *fs;
+ const char *path = getenv("PATH");
setvbuf(stdout, NULL, _IONBF, BUFSIZ);
setvbuf(stderr, NULL, _IONBF, BUFSIZ);
setlocale(LC_CTYPE, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- atexit(close_stdout);
+ close_stdout_atexit();
+ strutils_set_exitcode(FSCK_EX_USAGE);
mnt_init_debug(0); /* init libmount debug mask */
mntcache = mnt_new_cache(); /* no fatal error if failed */
parse_argv(argc, argv);
if (!notitle)
- printf(_("%s from %s\n"), program_invocation_short_name, PACKAGE_STRING);
+ printf(UTIL_LINUX_VERSION);
load_fs_info();
- /* Update our search path to include uncommon directories. */
- if (oldpath) {
- fsck_path = xmalloc (strlen (fsck_prefix_path) + 1 +
- strlen (oldpath) + 1);
- strcpy (fsck_path, fsck_prefix_path);
- strcat (fsck_path, ":");
- strcat (fsck_path, oldpath);
- } else {
- fsck_path = xstrdup(fsck_prefix_path);
- }
+ fsck_path = xstrdup(path && *path ? path : FSCK_DEFAULT_PATH);
if ((num_devices == 1) || (serialize))
interactive = 1;
fs = add_dummy_fs(devices[i]);
else if (fs_ignored_type(fs))
continue;
-
if (ignore_mounted && is_mounted(fs))
continue;
status |= fsck_device(fs, interactive);
}
status |= wait_many(FLAG_WAIT_ALL);
free(fsck_path);
- mnt_free_cache(mntcache);
- mnt_free_table(fstab);
- mnt_free_table(mtab);
+ mnt_unref_cache(mntcache);
+ mnt_unref_table(fstab);
+ mnt_unref_table(mtab);
return status;
}