⛏️ index : haiku.git

/*
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2007, Marcus Overhagen. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 */

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>


#define EXIT_FAILURE 1


static void
print_usage(bool error)
{
	printf("\n");
	printf("create_image\n");
	printf("\n");
	printf("usage: create_image -i <imagesize> [-c] [-f] <file>\n");
	printf("       -i, --imagesize    size of raw partition image file\n");
	printf("       -f, --file         the raw partition image file\n");
	printf("       -c, --clear-image  set the image content to zero\n");
	exit(error ? EXIT_FAILURE : 0);
}


int
main(int argc, char *argv[])
{
	off_t imageSize = 0;
	const char *file = NULL;
	bool clearImage = false;

	while (1) {
		int c;
		static struct option long_options[] = {
			{"file", required_argument, 0, 'f'},
			{"clear-image", no_argument, 0, 'c'},
			{"help", no_argument, 0, 'h'},
			{"imagesize", required_argument, 0, 'i'},
			{0, 0, 0, 0}
		};

		opterr = 0; /* don't print errors */
		c = getopt_long(argc, argv, "+hi:cf:", long_options, NULL);
		if (c == -1)
			break;

		switch (c) {
			case 'h':
				print_usage(false);
				break;

			case 'i':
				imageSize = strtoull(optarg, NULL, 10);
				if (strchr(optarg, 'G') || strchr(optarg, 'g'))
					imageSize *= 1024 * 1024 * 1024;
				else if (strchr(optarg, 'M') || strchr(optarg, 'm'))
					imageSize *= 1024 * 1024;
				else if (strchr(optarg, 'K') || strchr(optarg, 'k'))
					imageSize *= 1024;
				break;

			case 'f':
				file = optarg;
				break;

			case 'c':
				clearImage = true;
				break;

			default:
				print_usage(true);
		}
	}

	if (file == NULL && optind == argc - 1)
		file = argv[optind];

	if (!imageSize || !file)
		print_usage(true);

	if (imageSize < 0) {
		fprintf(stderr, "Error: invalid image size\n");
		exit(EXIT_FAILURE);
	}

	if (imageSize % 512) {
		fprintf(stderr, "Error: image size must be a multiple of 512 bytes\n");
		exit(EXIT_FAILURE);
	}

	int fd = open(file, O_RDWR | O_CREAT, 0666);
	if (fd < 0) {
		fprintf(stderr, "Error: couldn't open file %s (%s)\n", file,
			strerror(errno));
		exit(EXIT_FAILURE);
	}

	struct stat st;
	if (fstat(fd, &st) < 0) {
		fprintf(stderr, "Error: stat()ing file %s failed (%s)\n", file,
			strerror(errno));
		exit(EXIT_FAILURE);
	}

	if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) {
		fprintf(stderr, "Error: type of file %s not supported\n", file);
		exit(EXIT_FAILURE);
	}

	if (S_ISREG(st.st_mode)) {
		// regular file -- use ftruncate() to resize it
		if ((clearImage && ftruncate(fd, 0) != 0)
			|| ftruncate(fd, imageSize) != 0) {
			fprintf(stderr, "Error: resizing file %s failed (%s)\n", file,
				strerror(errno));
			exit(EXIT_FAILURE);
		}
	} else {
		// some kind of device -- clear it manually, if we have to
		if (clearImage) {
			char buffer[1024 * 1024];
			memset(buffer, 0, sizeof(buffer));

			off_t totalWritten = 0;
			ssize_t written;
			while ((written = write(fd, buffer, sizeof(buffer))) > 0)
				totalWritten += written;

			// Only fail, if an error occurs and we haven't written anything at
			// all yet.
			// TODO: We should probably first determine the size of the device
			// and try to write only that much.
			if (totalWritten == 0 && written < 0) {
				fprintf(stderr, "Error: writing to device file %s failed "
					"(%s)\n", file, strerror(errno));
				exit(EXIT_FAILURE);
			}
		}
	}

	close(fd);
	return 0;
}