/*-1* Copyright (c) 2001-20132* HATANO Tomomi. All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/252627#include <stdio.h>28#include <stdlib.h>29#include <string.h>30#include <strings.h>31#include <fcntl.h>32#include <limits.h>33#include <sys/stat.h>34#include <sys/types.h>35#include <sys/uio.h>36#include <unistd.h>37#include <ctype.h>38#include <errno.h>3940#define MKFILE_WBUF ((size_t)(1048576)) /* Is 1M a reasonable value? */4142/* SunOS's mkfile(8) sets "sticky bit." */43#define MKFILE_FLAG (O_WRONLY | O_CREAT | O_TRUNC)44#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_ISVTX)4546static char buf[MKFILE_WBUF];47static int nofill = 0;48static int verbose = 0;4950static void51usage()52{53fprintf(stderr,54"Usage: mkfile [-nv] <size>[e|p|t|g|m|k|b] <filename> ...\n");55}5657static unsigned long long58getsize(char *s)59{60int sh;61unsigned long long length;62char *suffix;6364/*65* NOTE: We don't handle 'Z' (zetta) or 'Y' (yotta) suffixes yet.66* These are too large to store in unsigned long long (64bits).67* In the future, we'll have to use larger type,68* something like uint128_t.69*/70length = strtoull(s, &suffix, 10);71sh = 0;72switch (tolower(*suffix)) {73case 'e': /* Exabytes. */74sh = 60;75break;76case 'p': /* Petabytes. */77sh = 50;78break;79case 't': /* Terabytes. */80sh = 40;81break;82case 'g': /* Gigabytes. */83sh = 30;84break;85case 'm': /* Megabytes. */86sh = 20;87break;88case 'k': /* Kilobytes. */89sh = 10;90break;91case 'b': /* Blocks. */92sh = 9;93break;94case '\0': /* Bytes. */95break;96default: /* Unknown... */97errno = EINVAL;98return 0;99}100if (sh) {101unsigned long long l;102103l = length;104length <<= sh;105/* Check overflow. */106if ((length >> sh) != l) {107errno = ERANGE;108return 0;109}110}111112return length;113}114115static int116create_file(char *f, unsigned long long s)117{118int fd;119size_t w;120ssize_t ws;121122if (verbose) {123fprintf(stdout, "%s %llu bytes\n", f, s);124fflush(stdout);125}126127/* Open file to create. */128if ((fd = open(f, MKFILE_FLAG, MKFILE_MODE)) < 0) {129return -1;130}131132/* Seek to the end and write 1 byte. */133if ((lseek(fd, (off_t)(s - 1LL), SEEK_SET) == (off_t)-1) ||134(write(fd, buf, (size_t)1) == (ssize_t)-1)) {135/*136* We don't close(fd) here to avoid overwriting errno.137* This is fd-leak, but is not harmful138* because returning error causes mkfile(8) to exit.139*/140return -1;141}142143/* Fill. */144if (!nofill) {145if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {146/* Same as above. */147return -1;148}149while (s) {150w = (s > MKFILE_WBUF) ? MKFILE_WBUF : s;151if ((ws = write(fd, buf, w)) == (ssize_t)-1) {152/* Same as above. */153return -1;154}155s -= ws;156}157}158close(fd);159160return 0;161}162163int164main(int argc, char *argv[])165{166unsigned long long fsize;167int ch;168169/* We have at least 2 arguments. */170if (argc < 3) {171usage();172return EXIT_FAILURE;173}174175/* Options. */176while ((ch = getopt(argc, argv, "nv")) != -1) {177switch (ch) {178case 'n':179nofill = 1;180break;181case 'v':182verbose = 1;183break;184default:185usage();186return EXIT_FAILURE;187}188}189argc -= optind;190argv += optind;191192/* File size to create. */193if ((fsize = getsize(*argv)) == 0) {194perror(*argv);195return EXIT_FAILURE;196}197198/* Filenames to create. */199bzero(buf, MKFILE_WBUF);200while (++argv, --argc) {201if (create_file(*argv, fsize) == -1) {202perror(*argv);203return EXIT_FAILURE;204}205}206207return EXIT_SUCCESS;208}209210211