#include "unittest.h"
#include <sys/param.h>
#include "blk.h"
#include "btt_layout.h"
#include <endian.h>
static size_t Bsize;
static void
construct(unsigned char *buf)
{
static int ord = 1;
for (int i = 0; i < Bsize; i++)
buf[i] = ord;
ord++;
if (ord > 255)
ord = 1;
}
static char *
ident(unsigned char *buf)
{
static char descr[100];
unsigned val = *buf;
for (int i = 1; i < Bsize; i++)
if (buf[i] != val) {
sprintf(descr, "{%u} TORN at byte %d", val, i);
return descr;
}
sprintf(descr, "{%u}", val);
return descr;
}
static ut_jmp_buf_t Jmp;
static void
signal_handler(int sig)
{
UT_OUT("signal: %s", os_strsignal(sig));
ut_siglongjmp(Jmp);
}
int
main(int argc, char *argv[])
{
START(argc, argv, "blk_recovery");
if (argc != 5)
UT_FATAL("usage: %s bsize file first_lba lba", argv[0]);
Bsize = strtoul(argv[1], NULL, 0);
const char *path = argv[2];
PMEMblkpool *handle;
if ((handle = pmemblk_create(path, Bsize, 0,
S_IWUSR | S_IRUSR)) == NULL)
UT_FATAL("!%s: pmemblk_create", path);
UT_OUT("%s block size %zu usable blocks %zu",
argv[1], Bsize, pmemblk_nblock(handle));
os_off_t lba = strtoul(argv[3], NULL, 0);
unsigned char *buf = MALLOC(Bsize);
construct(buf);
if (pmemblk_write(handle, buf, lba) < 0)
UT_FATAL("!write lba %zu", lba);
UT_OUT("write lba %zu: %s", lba, ident(buf));
struct btt_info *infop = (void *)((char *)handle +
roundup(sizeof(struct pmemblk), BLK_FORMAT_DATA_ALIGN));
char *mapaddr = (char *)infop + le32toh(infop->mapoff);
char *flogaddr = (char *)infop + le32toh(infop->flogoff);
UT_OUT("write-protecting map, length %zu",
(size_t)(flogaddr - mapaddr));
MPROTECT(mapaddr, (size_t)(flogaddr - mapaddr), PROT_READ);
struct sigaction v;
sigemptyset(&v.sa_mask);
v.sa_flags = 0;
v.sa_handler = signal_handler;
SIGACTION(SIGSEGV, &v, NULL);
lba = strtoul(argv[4], NULL, 0);
construct(buf);
if (!ut_sigsetjmp(Jmp)) {
if (pmemblk_write(handle, buf, lba) < 0)
UT_FATAL("!write lba %zu", lba);
else
UT_FATAL("write lba %zu: %s", lba, ident(buf));
}
pmemblk_close(handle);
FREE(buf);
int result = pmemblk_check(path, Bsize);
if (result < 0)
UT_OUT("!%s: pmemblk_check", path);
else if (result == 0)
UT_OUT("%s: pmemblk_check: not consistent", path);
else
UT_OUT("%s: consistent", path);
DONE(NULL);
}