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 * $FreeBSD$ 27 */ 28 29 #ifndef lint 30 static char rcsid[] = "$Id: mkfile.c,v 1.5 2013-10-26 10:11:34+09 hatanou Exp $"; 31 #endif /* !lint */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <fcntl.h> 38 #include <limits.h> 39 #include <sys/stat.h> 40 #include <sys/types.h> 41 #include <sys/uio.h> 42 #include <unistd.h> 43 #include <ctype.h> 44 #include <errno.h> 45 46 #define MKFILE_WBUF ((size_t)(1048576)) /* Is 1M a reasonable value? */ 47 48 /* SunOS's mkfile(8) sets "sticky bit." */ 49 #define MKFILE_FLAG (O_WRONLY | O_CREAT | O_TRUNC) 50 #define MKFILE_MODE (S_IRUSR | S_IWUSR | S_ISVTX) 51 52 static char buf[MKFILE_WBUF]; 53 static int nofill = 0; 54 static int verbose = 0; 55 56 static void 57 usage() 58 { 59 fprintf(stderr, 60 "Usage: mkfile [-nv] <size>[e|p|t|g|m|k|b] <filename> ...\n"); 61 } 62 63 static unsigned long long 64 getsize(char *s) 65 { 66 int sh; 67 unsigned long long length; 68 char *suffix; 69 70 /* 71 * NOTE: We don't handle 'Z' (zetta) or 'Y' (yotta) suffixes yet. 72 * These are too large to store in unsigned long long (64bits). 73 * In the future, we'll have to use larger type, 74 * something like uint128_t. 75 */ 76 length = strtoull(s, &suffix, 10); 77 sh = 0; 78 switch (tolower(*suffix)) { 79 case 'e': /* Exabytes. */ 80 sh = 60; 81 break; 82 case 'p': /* Petabytes. */ 83 sh = 50; 84 break; 85 case 't': /* Terabytes. */ 86 sh = 40; 87 break; 88 case 'g': /* Gigabytes. */ 89 sh = 30; 90 break; 91 case 'm': /* Megabytes. */ 92 sh = 20; 93 break; 94 case 'k': /* Kilobytes. */ 95 sh = 10; 96 break; 97 case 'b': /* Blocks. */ 98 sh = 9; 99 break; 100 case '\0': /* Bytes. */ 101 break; 102 default: /* Unknown... */ 103 errno = EINVAL; 104 return 0; 105 } 106 if (sh) { 107 unsigned long long l; 108 109 l = length; 110 length <<= sh; 111 /* Check overflow. */ 112 if ((length >> sh) != l) { 113 errno = ERANGE; 114 return 0; 115 } 116 } 117 118 return length; 119 } 120 121 static int 122 create_file(char *f, unsigned long long s) 123 { 124 int fd; 125 size_t w; 126 ssize_t ws; 127 128 if (verbose) { 129 fprintf(stdout, "%s %llu bytes\n", f, s); 130 fflush(stdout); 131 } 132 133 /* Open file to create. */ 134 if ((fd = open(f, MKFILE_FLAG, MKFILE_MODE)) < 0) { 135 return -1; 136 } 137 138 /* Seek to the end and write 1 byte. */ 139 if ((lseek(fd, (off_t)(s - 1LL), SEEK_SET) == (off_t)-1) || 140 (write(fd, buf, (size_t)1) == (ssize_t)-1)) { 141 /* 142 * We don't close(fd) here to avoid overwriting errno. 143 * This is fd-leak, but is not harmful 144 * because returning error causes mkfile(8) to exit. 145 */ 146 return -1; 147 } 148 149 /* Fill. */ 150 if (!nofill) { 151 if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 152 /* Same as above. */ 153 return -1; 154 } 155 while (s) { 156 w = (s > MKFILE_WBUF) ? MKFILE_WBUF : s; 157 if ((ws = write(fd, buf, w)) == (ssize_t)-1) { 158 /* Same as above. */ 159 return -1; 160 } 161 s -= ws; 162 } 163 } 164 close(fd); 165 166 return 0; 167 } 168 169 int 170 main(int argc, char *argv[]) 171 { 172 unsigned long long fsize; 173 char ch; 174 175 /* We have at least 2 arguments. */ 176 if (argc < 3) { 177 usage(); 178 return EXIT_FAILURE; 179 } 180 181 /* Options. */ 182 while ((ch = getopt(argc, argv, "nv")) != -1) { 183 switch (ch) { 184 case 'n': 185 nofill = 1; 186 break; 187 case 'v': 188 verbose = 1; 189 break; 190 default: 191 usage(); 192 return EXIT_FAILURE; 193 } 194 } 195 argc -= optind; 196 argv += optind; 197 198 /* File size to create. */ 199 if ((fsize = getsize(*argv)) == 0) { 200 perror(*argv); 201 return EXIT_FAILURE; 202 } 203 204 /* Filenames to create. */ 205 bzero(buf, MKFILE_WBUF); 206 while (++argv, --argc) { 207 if (create_file(*argv, fsize) == -1) { 208 perror(*argv); 209 return EXIT_FAILURE; 210 } 211 } 212 213 return EXIT_SUCCESS; 214 } 215