summaryrefslogtreecommitdiffstats
path: root/libfdisk/src/wipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfdisk/src/wipe.c')
-rw-r--r--libfdisk/src/wipe.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/libfdisk/src/wipe.c b/libfdisk/src/wipe.c
new file mode 100644
index 0000000..ab1d7b8
--- /dev/null
+++ b/libfdisk/src/wipe.c
@@ -0,0 +1,209 @@
+#include "c.h"
+#include "strutils.h"
+
+#ifdef HAVE_LIBBLKID
+# include <blkid.h>
+#endif
+
+#include "fdiskP.h"
+
+struct fdisk_wipe {
+ struct list_head wipes;
+ uint64_t start; /* sectors */
+ uint64_t size; /* sectors */
+};
+
+static struct fdisk_wipe *fdisk_get_wipe_area(
+ struct fdisk_context *cxt,
+ uint64_t start,
+ uint64_t size)
+{
+ struct list_head *p;
+
+ if (cxt == NULL || list_empty(&cxt->wipes))
+ return NULL;
+
+ list_for_each(p, &cxt->wipes) {
+ struct fdisk_wipe *wp = list_entry(p, struct fdisk_wipe, wipes);
+ if (wp->start == start && wp->size == size)
+ return wp;
+ }
+ return NULL;
+}
+
+void fdisk_free_wipe_areas(struct fdisk_context *cxt)
+{
+ while (!list_empty(&cxt->wipes)) {
+ struct fdisk_wipe *wp = list_entry(cxt->wipes.next,
+ struct fdisk_wipe, wipes);
+ DBG(WIPE, ul_debugobj(wp, "free [start=%ju, size=%ju]",
+ (uintmax_t) wp->start, (uintmax_t) wp->size));
+ list_del(&wp->wipes);
+ free(wp);
+ }
+}
+
+int fdisk_has_wipe_area(struct fdisk_context *cxt,
+ uint64_t start,
+ uint64_t size)
+{
+ return fdisk_get_wipe_area(cxt, start, size) != NULL;
+}
+
+/* Add/remove new wiping area
+ *
+ * Returns: <0 on error, or old area setting (1: enabled, 0: disabled)
+ */
+int fdisk_set_wipe_area(struct fdisk_context *cxt,
+ uint64_t start,
+ uint64_t size,
+ int enable)
+{
+ struct fdisk_wipe *wp;
+
+ if (FDISK_IS_UNDEF(start) || FDISK_IS_UNDEF(size))
+ return -EINVAL;
+
+ wp = fdisk_get_wipe_area(cxt, start, size);
+
+ /* disable */
+ if (!enable) {
+ if (wp) {
+ DBG(WIPE, ul_debugobj(wp, "disable [start=%ju, size=%ju]",
+ (uintmax_t) start, (uintmax_t) size));
+ list_del(&wp->wipes);
+ free(wp);
+ return 1;
+ }
+ return 0;
+ }
+
+ /* enable */
+ if (wp)
+ return 1; /* already enabled */
+
+ wp = calloc(1, sizeof(*wp));
+ if (!wp)
+ return -ENOMEM;
+
+ DBG(WIPE, ul_debugobj(wp, "enable [start=%ju, size=%ju]",
+ (uintmax_t) start, (uintmax_t) size));
+
+ INIT_LIST_HEAD(&wp->wipes);
+ wp->start = start;
+ wp->size = size;
+ list_add_tail(&wp->wipes, &cxt->wipes);
+
+ return 0;
+}
+
+#ifndef HAVE_LIBBLKID
+int fdisk_do_wipe(struct fdisk_context *cxt __attribute__((__unused__)))
+{
+ return 0;
+}
+#else
+int fdisk_do_wipe(struct fdisk_context *cxt)
+{
+ struct list_head *p;
+ blkid_probe pr;
+ int rc;
+
+ assert(cxt);
+ assert(cxt->dev_fd >= 0);
+
+ if (list_empty(&cxt->wipes))
+ return 0;
+
+ pr = blkid_new_probe();
+ if (!pr)
+ return -ENOMEM;
+
+ list_for_each(p, &cxt->wipes) {
+ struct fdisk_wipe *wp = list_entry(p, struct fdisk_wipe, wipes);
+ blkid_loff_t start = (blkid_loff_t) wp->start * cxt->sector_size,
+ size = (blkid_loff_t) wp->size * cxt->sector_size;
+
+ DBG(WIPE, ul_debugobj(wp, "initialize libblkid prober [start=%ju, size=%ju]",
+ (uintmax_t) start, (uintmax_t) size));
+
+ rc = blkid_probe_set_device(pr, cxt->dev_fd, start, size);
+ if (rc) {
+ DBG(WIPE, ul_debugobj(wp, "blkid_probe_set_device() failed [rc=%d]", rc));
+ return rc;
+ }
+
+ blkid_probe_enable_superblocks(pr, 1);
+ blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC);
+ blkid_probe_enable_partitions(pr, 1);
+ blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC);
+
+ while (blkid_do_probe(pr) == 0) {
+ DBG(WIPE, ul_debugobj(wp, " wiping..."));
+ blkid_do_wipe(pr, FALSE);
+ }
+ }
+
+ blkid_free_probe(pr);
+ return 0;
+}
+#endif
+
+
+/*
+ * Please don't call this function if there is already a PT.
+ *
+ * Returns: 0 if nothing found, < 0 on error, 1 if found a signature
+ */
+#ifndef HAVE_LIBBLKID
+int fdisk_check_collisions(struct fdisk_context *cxt __attribute__((__unused__)))
+{
+ return 0;
+}
+#else
+int fdisk_check_collisions(struct fdisk_context *cxt)
+{
+ int rc = 0;
+ blkid_probe pr;
+
+ assert(cxt);
+ assert(cxt->dev_fd >= 0);
+
+ DBG(CXT, ul_debugobj(cxt, "wipe check: initialize libblkid prober"));
+
+ pr = blkid_new_probe();
+ if (!pr)
+ return -ENOMEM;
+ rc = blkid_probe_set_device(pr, cxt->dev_fd, 0, 0);
+ if (rc)
+ return rc;
+
+ cxt->pt_collision = 0;
+ free(cxt->collision);
+ cxt->collision = NULL;
+
+ blkid_probe_enable_superblocks(pr, 1);
+ blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE);
+ blkid_probe_enable_partitions(pr, 1);
+
+ /* we care about the first found FS/raid, so don't call blkid_do_probe()
+ * in loop or don't use blkid_do_fullprobe() ... */
+ rc = blkid_do_probe(pr);
+ if (rc == 0) {
+ const char *name = NULL;
+
+ if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0)
+ cxt->collision = strdup(name);
+ else if (blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) {
+ cxt->collision = strdup(name);
+ cxt->pt_collision = 1;
+ }
+
+ if (name && !cxt->collision)
+ rc = -ENOMEM;
+ }
+
+ blkid_free_probe(pr);
+ return rc;
+}
+#endif