#include "c.h" #include "strutils.h" #ifdef HAVE_LIBBLKID # include #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