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