Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*-
 * Copyright (c) 2001-2013
 *	HATANO Tomomi.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#ifndef	lint
static char rcsid[] = "$Id: mkfile.c,v 1.5 2013-10-26 10:11:34+09 hatanou Exp $";
#endif	/* !lint */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>

#define	MKFILE_WBUF	((size_t)(1048576))	/* Is 1M a reasonable value? */

/* SunOS's mkfile(8) sets "sticky bit." */
#define	MKFILE_FLAG	(O_WRONLY | O_CREAT | O_TRUNC)
#define	MKFILE_MODE	(S_IRUSR | S_IWUSR | S_ISVTX)

static char	buf[MKFILE_WBUF];
static int	nofill = 0;
static int	verbose = 0;

static void
usage()
{
	fprintf(stderr,
	    "Usage: mkfile [-nv] <size>[e|p|t|g|m|k|b] <filename> ...\n");
}

static unsigned long long
getsize(char *s)
{
	int sh;
	unsigned long long length;
	char *suffix;

	/*
	 * NOTE: We don't handle 'Z' (zetta) or 'Y' (yotta) suffixes yet.
	 * These are too large to store in unsigned long long (64bits).
	 * In the future, we'll have to use larger type,
	 * something like uint128_t.
	 */
	length = strtoull(s, &suffix, 10);
	sh = 0;
	switch (tolower(*suffix)) {
	case 'e':	/* Exabytes. */
		sh = 60;
		break;
	case 'p':	/* Petabytes. */
		sh = 50;
		break;
	case 't':	/* Terabytes. */
		sh = 40;
		break;
	case 'g':	/* Gigabytes. */
		sh = 30;
		break;
	case 'm':	/* Megabytes. */
		sh = 20;
		break;
	case 'k':	/* Kilobytes. */
		sh = 10;
		break;
	case 'b':	/* Blocks. */
		sh = 9;
		break;
	case '\0':	/* Bytes. */
		break;
	default:	/* Unknown... */
		errno = EINVAL;
		return 0;
	}
	if (sh) {
		unsigned long long l;

		l = length;
		length <<= sh;
		/* Check overflow. */
		if ((length >> sh) != l) {
			errno = ERANGE;
			return 0;
		}
	}

	return length;
}

static int
create_file(char *f, unsigned long long s)
{
	int fd;
	size_t w;
	ssize_t ws;

	if (verbose) {
		fprintf(stdout, "%s %llu bytes\n", f, s);
		fflush(stdout);
	}

	/* Open file to create. */
	if ((fd = open(f, MKFILE_FLAG, MKFILE_MODE)) < 0) {
		return -1;
	}

	/* Seek to the end and write 1 byte. */
	if ((lseek(fd, (off_t)(s - 1LL), SEEK_SET) == (off_t)-1) ||
	    (write(fd, buf, (size_t)1) == (ssize_t)-1)) {
		/*
		 * We don't close(fd) here to avoid overwriting errno.
		 * This is fd-leak, but is not harmful
		 * because returning error causes mkfile(8) to exit.
		 */
		return -1;
	}

	/* Fill. */
	if (!nofill) {
		if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
			/* Same as above. */
			return -1;
		}
		while (s) {
			w = (s > MKFILE_WBUF) ? MKFILE_WBUF : s;
			if ((ws = write(fd, buf, w)) == (ssize_t)-1) {
				/* Same as above. */
				return -1;
			}
			s -= ws;
		}
	}
	close(fd);

	return 0;
}

int
main(int argc, char *argv[])
{
	unsigned long long fsize;
	char ch;

	/* We have at least 2 arguments. */
	if (argc < 3) {
		usage();
		return EXIT_FAILURE;
	}

	/* Options. */
	while ((ch = getopt(argc, argv, "nv")) != -1) {
		switch (ch) {
		case 'n':
			nofill = 1;
			break;
		case 'v':
			verbose = 1;
			break;
		default:
			usage();
			return EXIT_FAILURE;
		}
	}
	argc -= optind;
	argv += optind;

	/* File size to create. */
	if ((fsize = getsize(*argv)) == 0) {
		perror(*argv);
		return EXIT_FAILURE;
	}

	/* Filenames to create. */
	bzero(buf, MKFILE_WBUF);
	while (++argv, --argc) {
		if (create_file(*argv, fsize) == -1) {
			perror(*argv);
			return EXIT_FAILURE;
		}
	}

	return EXIT_SUCCESS;
}