]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - disk-utils/fsck.c
wipefs: add --lock and LOCK_BLOCK_DEVICE
[thirdparty/util-linux.git] / disk-utils / fsck.c
index ff504aa1da5fa3552595585d35a8a28469b7a6fe..fda80a6fe85be0c6fe3e8ec9f7ddb1cf8d5ca754 100644 (file)
 #include "pathnames.h"
 #include "exitcodes.h"
 #include "c.h"
-#include "closestream.h"
 #include "fileutils.h"
 #include "monotonic.h"
-
-#define STRTOXX_EXIT_CODE      FSCK_EX_ERROR
 #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
@@ -89,7 +89,7 @@ static const char *really_wanted[] = {
 };
 
 /*
- * Internal structure for mount tabel entries.
+ * Internal structure for mount table entries.
  */
 struct fsck_fs_data
 {
@@ -172,8 +172,8 @@ static int string_to_int(const char *s)
        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? */
@@ -316,7 +316,7 @@ static int is_irrotational_disk(dev_t disk)
                        "/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");
@@ -398,7 +398,6 @@ done:
                inst->lockpath = NULL;
        }
        free(diskpath);
-       return;
 }
 
 static void unlock_disk(struct fsck_instance *inst)
@@ -410,7 +409,6 @@ static void unlock_disk(struct fsck_instance *inst)
                printf(_("Unlocking %s.\n"), inst->lockpath);
 
        close(inst->lock);                      /* unlock */
-       unlink(inst->lockpath);
 
        free(inst->lockpath);
 
@@ -426,7 +424,6 @@ static void free_instance(struct fsck_instance *i)
        free(i->lockpath);
        mnt_unref_fs(i->fs);
        free(i);
-       return;
 }
 
 static struct libmnt_fs *add_dummy_fs(const char *device)
@@ -470,7 +467,7 @@ static void fs_interpret_type(struct libmnt_fs *fs)
 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);
+       warnx(_("%s: parse error at line %d -- ignored"), filename, line);
        return 1;
 }
 
@@ -491,7 +488,7 @@ static void load_fs_info(void)
        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");
 
@@ -541,25 +538,34 @@ static struct libmnt_fs *lookup(char *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;
 
-       return(s ? prog : NULL);
+       if (progpath)
+               *progpath = prog;
+       else
+               free(prog);
+
+       return rc;
 }
 
 static int progress_active(void)
@@ -592,26 +598,26 @@ static void print_stats(struct fsck_instance *inst)
 
        if (report_stats_file)
                fprintf(report_stats_file, "%s %d %ld "
-                                          "%ld.%06ld %d.%06d %d.%06d\n",
+                                          "%ld.%06ld %ld.%06ld %ld.%06ld\n",
                        fs_get_device(inst->fs),
                        inst->exit_status,
                        inst->rusage.ru_maxrss,
-                       delta.tv_sec, delta.tv_usec,
-                       (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);
+                       (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 %d.%06d, sys %d.%06d\n",
+                               "real %ld.%06ld, user %ld.%06ld, sys %ld.%06ld\n",
                        fs_get_device(inst->fs),
                        inst->exit_status,
                        inst->rusage.ru_maxrss,
-                       delta.tv_sec, delta.tv_usec,
-                       (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);
+                       (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);
 }
 
 /*
@@ -634,26 +640,25 @@ static int execute(const char *progname, const char *progpath,
        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;
+       argv[argc] = NULL;
 
        if (verbose || noexecute) {
                const char *tgt = mnt_fs_get_target(fs);
@@ -743,7 +748,7 @@ static struct fsck_instance *wait_one(int flags)
 
        if (noexecute) {
                inst = instance_list;
-               prev = 0;
+               prev = NULL;
 #ifdef RANDOM_DEBUG
                while (inst->next && (random() & 1)) {
                        prev = inst;
@@ -778,7 +783,7 @@ static struct fsck_instance *wait_one(int flags)
                        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)
@@ -814,17 +819,17 @@ static struct fsck_instance *wait_one(int flags)
                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);
@@ -888,7 +893,7 @@ static int wait_many(int flags)
  */
 static int fsck_device(struct libmnt_fs *fs, int interactive)
 {
-       char progname[80], *progpath;
+       char *progname, *progpath;
        const char *type;
        int retval;
 
@@ -898,16 +903,17 @@ static int fsck_device(struct libmnt_fs *fs, int interactive)
 
        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;
 
-       sprintf(progname, "fsck.%s", type);
-       progpath = find_fsck(progname);
-       if (progpath == NULL) {
+       xasprintf(&progname, "fsck.%s", type);
+
+       if (!find_fsck(progname, &progpath)) {
+               free(progname);
                if (fs_check_required(type)) {
                        retval = ENOENT;
                        goto err;
@@ -917,6 +923,8 @@ static int fsck_device(struct libmnt_fs *fs, int interactive)
 
        num_running++;
        retval = execute(progname, progpath, type, fs, interactive);
+       free(progname);
+       free(progpath);
        if (retval) {
                num_running--;
                goto err;
@@ -932,7 +940,7 @@ err:
 /*
  * Deal with the fsck -t argument.
  */
-struct fs_type_compile {
+static struct fs_type_compile {
        char **list;
        int *type;
        int  negate;
@@ -1030,7 +1038,7 @@ static int fs_match(struct libmnt_fs *fs, struct fs_type_compile *cmp)
        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++) {
@@ -1151,7 +1159,7 @@ static int ignore(struct libmnt_fs *fs)
 
 
        /* See if the <fsck.fs> program is available. */
-       if (find_fsck(type) == NULL) {
+       if (!find_fsck(type, NULL)) {
                if (fs_check_required(type))
                        warnx(_("cannot check %s: fsck.%s not found"),
                                fs_get_device(fs), type);
@@ -1176,7 +1184,7 @@ static int count_slaves(dev_t disk)
        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;
@@ -1218,7 +1226,7 @@ static int disk_already_active(struct libmnt_fs *fs)
         * 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);
@@ -1281,7 +1289,7 @@ static int check_all(void)
 
        /*
         * 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);
@@ -1370,8 +1378,9 @@ static int check_all(void)
        return status;
 }
 
-static void __attribute__((__noreturn__)) usage(FILE *out)
+static void __attribute__((__noreturn__)) usage(void)
 {
+       FILE *out = stdout;
        fputs(USAGE_HEADER, out);
        fprintf(out, _(" %s [options] -- [fs-options] [<filesystem> ...]\n"),
                         program_invocation_short_name);
@@ -1394,13 +1403,14 @@ static void __attribute__((__noreturn__)) usage(FILE *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(_(" -?         display this help and exit\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);
-       fprintf(out, USAGE_MAN_TAIL("fsck(8)"));
-
-       exit(out == stderr ? FSCK_EX_USAGE : FSCK_EX_OK);
+       printf(USAGE_MAN_TAIL("fsck(8)"));
+       exit(FSCK_EX_OK);
 }
 
 static void signal_cancel(int sig __attribute__((__unused__)))
@@ -1411,7 +1421,7 @@ 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;
@@ -1423,17 +1433,24 @@ static void parse_argv(int argc, char *argv[])
         */
        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"));
@@ -1535,15 +1552,17 @@ static void parse_argv(int argc, char *argv[])
                                serialize = 1;
                                break;
                        case 't':
-                               tmp = 0;
+                               tmp = NULL;
                                if (fstype)
-                                       usage(stderr);
+                                       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(stderr);
+                                       errx(FSCK_EX_USAGE,
+                                               _("option '%s' requires an argument"), "-t");
                                fstype = xstrdup(tmp);
                                compile_fs_type(fstype, &fs_type_compiled);
                                goto next_arg;
@@ -1551,7 +1570,7 @@ static void parse_argv(int argc, char *argv[])
                                opts_for_fsck++;
                                break;
                        case '?':
-                               usage(stdout);
+                               usage();
                                break;
                        default:
                                options[++opt] = arg[j];
@@ -1598,8 +1617,9 @@ int main(int argc, char *argv[])
        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 */