/*- * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #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] [e|p|t|g|m|k|b] ...\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; int 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; }