]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
blkdiscard: Refuse to proceed if signatures are found
authorLukas Czerner <lczerner@redhat.com>
Thu, 18 Jun 2020 10:50:34 +0000 (12:50 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 19 Jun 2020 08:03:00 +0000 (10:03 +0200)
Currently the blkdiscard has the ability to wipe out entere device in a
matter of seconds. This is fine as long as it's intentional, it is
potentially catastrophic if it's not.

With this commit blkdiscard will check for existing signatures on the
device and refuse to continue if any are found unless the operation is
forced with the -f option.

In an attempt to avoid breaking existing automation scripts the force is
only required when stdin refers to a terminal.

Signed-off-by: Lukas Czerner <lczerner@redhat.com>
sys-utils/Makemodule.am
sys-utils/blkdiscard.c

index 5855e1cc1a78bcf09817bd91ed565cdc43559e19..b5f6c1b1b00b6719c31acba9431371924da0aea6 100644 (file)
@@ -165,7 +165,7 @@ if BUILD_BLKDISCARD
 sbin_PROGRAMS += blkdiscard
 dist_man_MANS += sys-utils/blkdiscard.8
 blkdiscard_SOURCES = sys-utils/blkdiscard.c lib/monotonic.c
-blkdiscard_LDADD = $(LDADD) libcommon.la $(REALTIME_LIBS)
+blkdiscard_LDADD = $(LDADD) libblkid.la libcommon.la $(REALTIME_LIBS)
 endif
 
 if BUILD_BLKZONE
index e83f69b11f09f46e70cbc5cd4382b9a4a9dde114..2dd4638aa6a60cd4f15619675207d76ff8e72bb3 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <linux/fs.h>
+#include <blkid/blkid.h>
 
 #include "nls.h"
 #include "strutils.h"
@@ -106,6 +107,41 @@ static void __attribute__((__noreturn__)) usage(void)
        exit(EXIT_SUCCESS);
 }
 
+/*
+ * Check existing signature on the open fd
+ * Returns     0  signature found
+ *             1  no signature
+ *             <0 error
+ */
+static int probe_device(int fd, char *path)
+{
+       const char *type;
+       blkid_probe pr = NULL;
+       int ret = -1;
+
+       pr = blkid_new_probe();
+       if (!pr || blkid_probe_set_device(pr, fd, 0, 0))
+               return ret;
+
+       blkid_probe_enable_superblocks(pr, TRUE);
+       blkid_probe_enable_partitions(pr, TRUE);
+
+       ret = blkid_do_fullprobe(pr);
+       if (ret)
+               goto out;
+
+       if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) {
+               warnx("%s contains existing file system (%s).",path ,type);
+       } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) {
+               warnx("%s contains existing partition (%s).",path ,type);
+       } else {
+               warnx("%s contains existing signature.", path);
+       }
+
+out:
+       blkid_free_probe(pr);
+       return ret;
+}
 
 int main(int argc, char **argv)
 {
@@ -184,7 +220,7 @@ int main(int argc, char **argv)
                errtryhelp(EXIT_FAILURE);
        }
 
-       fd = open(path, O_WRONLY | (force ? 0 : O_EXCL));
+       fd = open(path, O_RDWR | (force ? 0 : O_EXCL));
        if (fd < 0)
                err(EXIT_FAILURE, _("cannot open %s"), path);
 
@@ -217,6 +253,27 @@ int main(int argc, char **argv)
                errx(EXIT_FAILURE, _("%s: length %" PRIu64 " is not aligned "
                         "to sector size %i"), path, range[1], secsize);
 
+        /* Check for existing signatures on the device */
+       switch(probe_device(fd, path)) {
+       case 0: /* signature detected */
+               /*
+                * Only require force in interactive mode to avoid
+                * breaking existing scripts
+                */
+               if (!force && isatty(STDIN_FILENO)) {
+                       errx(EXIT_FAILURE,
+                            _("This is destructive operation, data will " \
+                              "be lost! Use the -f option to override."));
+               }
+               warnx(_("Operation forced, data will be lost!"));
+               break;
+       case 1: /* no signature */
+               break;
+       default: /* error */
+               err(EXIT_FAILURE, _("failed to probe the device"));
+               break;
+       }
+
        stats[0] = range[0], stats[1] = 0;
        gettime_monotonic(&last);