blob: ab1d7b8519d9b45d8f3f8169e9e2fb0e0cdec8f2 [file] [log] [blame]
#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