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