xref: /freebsd/tests/sys/cddl/zfs/bin/mkfile.c (revision c8e7f78a3d28ff6e6223ed136ada8e1e2f34965e)
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