diff options
Diffstat (limited to 'libfdisk/src/wipe.c')
-rw-r--r-- | libfdisk/src/wipe.c | 209 |
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 |