git » dm-csum-tools » master » tree

[master] / mk-dm-csum.c

/* Formats the given file for use by dm-csum */

/* Needed to use pwrite() and strtoll() */
#define _XOPEN_SOURCE 600

#include <stdio.h>		/* printf() */
#include <stdlib.h>		/* malloc() */
#include <unistd.h>		/* pwrite() and friends */
#include <sys/types.h>		/* open() */
#include <sys/stat.h>		/* open() */
#include <fcntl.h>		/* open() */
#include <stdint.h>		/* uint8_t and friends */
#include <string.h>		/* memset() */


/* simple definitions so we can copy-paste the structs from the kernel */
#define u8 uint8_t
#define __be16 uint16_t
#define __be32 uint32_t

/*
 * Copied from the kernel definition, MUST match
 */

#define RESERVED_INITIAL_SECTORS_D 1
#define RESERVED_INITIAL_SECTORS_M 1
#define SECTORS_PER_IMD 62

struct imd_tuple {
        __be16 crc;
        __be16 flags;
        __be32 tag;
} __attribute__ ((packed));

struct imd_sector_header {
        u8 last_updated;
        u8 unused1;
        __be16 crc;
        __be32 unused3;
} __attribute__ ((packed));


/* Format function to use when imd and data are on the same device */
int format_same(int fd, off_t total_size) {
	int r;
	off_t off;
	unsigned char buf[1024];
	struct imd_sector_header *m1, *m2;

	memset(buf, 0, sizeof(buf));

	m1 = (struct imd_sector_header *) buf;
	m2 = (struct imd_sector_header *) (buf + 512);

	m1->last_updated = 2;
	m2->last_updated = 1;

	off = RESERVED_INITIAL_SECTORS_D * 512;

	while (off < total_size) {
		r = pwrite(fd, buf, 1024, off);
		if (r != 1024)
			return -1;
		off += 1024 + SECTORS_PER_IMD * 512;
	}

	return 0;
}

int format_diff(int data_fd, int imd_fd, off_t total_size)
{
	printf("Not implemented yet\n");
	return 0;
}

void usage()
{
	printf("Use: mk-dm-csum same <device> [data length]\n");
	printf(" or: mk-dm-csum diff <data device> <imd device> [data length]\n");
	printf("\n");
	printf("Note: data length is in bytes, and will be rounded down to\n");
	printf("an appropriate bound.\n");
}

int main(int argc, char **argv)
{
	int fd = -1, imd_fd = -1;
	long long total_size;
	int same;

	if (argc < 3) {
		usage();
		return 1;
	}

	if (strcmp(argv[1], "same") == 0) {
		same = 1;
	} else if (strcmp(argv[1], "diff") == 0) {
		/* TODO */
		same = 0;
		printf("Error: not implemented yet.\n");
		return 1;
	} else {
		usage();
		return 1;
	}

	fd = open(argv[2], O_WRONLY);
	if (fd < 0) {
		perror("Error opening device");
		return 1;
	}

	if (argc >= 4) {
		total_size = strtoll(argv[3], NULL, 0);
	} else {
		total_size = lseek(fd, 0, SEEK_END);
		if (total_size == -1) {
			perror("Error finding out the size");
			return 1;
		}
	}

	/* round down to a multiple of SECTORS_PER_IMD */
	total_size -= total_size % SECTORS_PER_IMD;
	printf("Effective total size: %llu\n", total_size);

	if (same) {
		if (format_same(fd, total_size) != 0) {
			perror("Error formatting");
			return 2;
		}
	} else {
		if (format_diff(fd, imd_fd, total_size) != 0) {
			perror("Error formatting");
			return 2;
		}
	}

	if (fsync(fd) != 0) {
		perror("Error syncing data to disk");
		return 3;
	}

	return 0;
}