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: stable/12/tests/sys/cddl/zfs/bin/mkfile.c 329867 2018-02-23 16:31:00Z asomers $
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
usage()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
getsize(char * s)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
create_file(char * f,unsigned long long s)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
main(int argc,char * argv[])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