xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/mkfile.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License, Version 1.0 only
7  * (the "License").  You may not use this file except in compliance
8  * with the License.
9  *
10  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11  * or https://opensource.org/licenses/CDDL-1.0.
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 
24 /*
25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <libintl.h>
37 #include <errno.h>
38 #include <sys/stdtypes.h>
39 #include <sys/sysmacros.h>
40 
41 #define	BLOCKSIZE	512		/* bytes */
42 #define	KILOBYTE	1024
43 #define	MEGABYTE	(KILOBYTE * KILOBYTE)
44 #define	GIGABYTE	(KILOBYTE * MEGABYTE)
45 
46 #define	FILE_MODE	(S_ISVTX + S_IRUSR + S_IWUSR)
47 
48 static __attribute__((noreturn)) void
usage(void)49 usage(void)
50 {
51 	(void) fprintf(stderr, gettext(
52 	    "Usage: mkfile [-nv] <size>[g|k|b|m] <name1> [<name2>] ...\n"));
53 	exit(1);
54 }
55 
56 int
main(int argc,char ** argv)57 main(int argc, char **argv)
58 {
59 	char	*opts;
60 	off_t	size;
61 	size_t	len;
62 	size_t	mult = 1;
63 	char	*buf = NULL;
64 	size_t	bufsz = 0;
65 	int	errors = 0;
66 	int	i;
67 	int	verbose = 0;	/* option variable */
68 	int	nobytes = 0;	/* option variable */
69 	int	saverr;
70 
71 	if (argc == 1)
72 		usage();
73 
74 	while (argv[1] && argv[1][0] == '-') {
75 		opts = &argv[1][0];
76 		while (*(++opts)) {
77 			switch (*opts) {
78 			case 'v':
79 				verbose++;
80 				break;
81 			case 'n':
82 				nobytes++;
83 				break;
84 			default:
85 				usage();
86 			}
87 		}
88 		argc--;
89 		argv++;
90 	}
91 	if (argc < 3)
92 		usage();
93 
94 	len = strlen(argv[1]);
95 	if (len && isalpha(argv[1][len-1])) {
96 		switch (argv[1][len-1]) {
97 		case 'k':
98 		case 'K':
99 			mult = KILOBYTE;
100 			break;
101 		case 'b':
102 		case 'B':
103 			mult = BLOCKSIZE;
104 			break;
105 		case 'm':
106 		case 'M':
107 			mult = MEGABYTE;
108 			break;
109 		case 'g':
110 		case 'G':
111 			mult = GIGABYTE;
112 			break;
113 		default:
114 			(void) fprintf(stderr,
115 			    gettext("unknown size %s\n"), argv[1]);
116 			usage();
117 		}
118 
119 		for (i = 0; i <= (len-2); i++) {
120 			if (!isdigit(argv[1][i])) {
121 				(void) fprintf(stderr,
122 				    gettext("unknown size %s\n"), argv[1]);
123 				usage();
124 			}
125 		}
126 		argv[1][len-1] = '\0';
127 	}
128 	size = ((off_t)atoll(argv[1]) * (off_t)mult);
129 
130 	argv++;
131 	argc--;
132 
133 	while (argc > 1) {
134 		int fd;
135 
136 		if (verbose)
137 			(void) fprintf(stdout, gettext("%s %lld bytes\n"),
138 			    argv[1], (offset_t)size);
139 		fd = open(argv[1], O_CREAT|O_TRUNC|O_RDWR, FILE_MODE);
140 		if (fd < 0) {
141 			saverr = errno;
142 			(void) fprintf(stderr,
143 			    gettext("Could not open %s: %s\n"),
144 			    argv[1], strerror(saverr));
145 			errors++;
146 			argv++;
147 			argc--;
148 			continue;
149 		} else if (fchown(fd, getuid(), getgid()) < 0) {
150 			saverr = errno;
151 			(void) fprintf(stderr, gettext(
152 			    "Could not set owner/group of %s: %s\n"),
153 			    argv[1], strerror(saverr));
154 			(void) close(fd);
155 			errors++;
156 			argv++;
157 			argc--;
158 			continue;
159 		} else if (lseek(fd, (off_t)size-1, SEEK_SET) < 0) {
160 			saverr = errno;
161 			(void) fprintf(stderr, gettext(
162 			    "Could not seek to offset %ld in %s: %s\n"),
163 			    (unsigned long)size-1, argv[1], strerror(saverr));
164 			(void) close(fd);
165 			errors++;
166 			argv++;
167 			argc--;
168 			continue;
169 		} else if (write(fd, "", 1) != 1) {
170 			saverr = errno;
171 			(void) fprintf(stderr, gettext(
172 			    "Could not set length of %s: %s\n"),
173 			    argv[1], strerror(saverr));
174 			(void) close(fd);
175 			errors++;
176 			argv++;
177 			argc--;
178 			continue;
179 		}
180 
181 		if (!nobytes) {
182 			off_t written = 0;
183 			struct stat64 st;
184 
185 			if (lseek(fd, (off_t)0, SEEK_SET) < 0) {
186 				saverr = errno;
187 				(void) fprintf(stderr, gettext(
188 				    "Could not seek to beginning of %s: %s\n"),
189 				    argv[1], strerror(saverr));
190 				(void) close(fd);
191 				errors++;
192 				argv++;
193 				argc--;
194 				continue;
195 			}
196 			if (fstat64(fd, &st) < 0) {
197 				saverr = errno;
198 				(void) fprintf(stderr, gettext(
199 				    "Could not fstat64 %s: %s\n"),
200 				    argv[1], strerror(saverr));
201 				(void) close(fd);
202 				errors++;
203 				argv++;
204 				argc--;
205 				continue;
206 			}
207 			if (bufsz != st.st_blksize) {
208 				if (buf)
209 					free(buf);
210 				bufsz = (size_t)st.st_blksize;
211 				buf = calloc(1, bufsz);
212 				if (buf == NULL) {
213 					(void) fprintf(stderr, gettext(
214 					    "Could not allocate buffer of"
215 					    " size %d\n"), (int)bufsz);
216 					(void) close(fd);
217 					bufsz = 0;
218 					errors++;
219 					argv++;
220 					argc--;
221 					continue;
222 				}
223 			}
224 			while (written < size) {
225 				ssize_t result;
226 				size_t bytes = (size_t)MIN(bufsz, size-written);
227 
228 				if ((result = write(fd, buf, bytes)) !=
229 				    (ssize_t)bytes) {
230 					saverr = errno;
231 					if (result < 0)
232 						result = 0;
233 					written += result;
234 					(void) fprintf(stderr, gettext(
235 			    "%s: initialized %lu of %lu bytes: %s\n"),
236 					    argv[1], (unsigned long)written,
237 					    (unsigned long)size,
238 					    strerror(saverr));
239 					errors++;
240 					break;
241 				}
242 				written += bytes;
243 			}
244 
245 			/*
246 			 * A write(2) call in the above loop failed so
247 			 * close out this file and go on (error was
248 			 * already incremented when the write(2) failed).
249 			 */
250 			if (written < size) {
251 				(void) close(fd);
252 				argv++;
253 				argc--;
254 				continue;
255 			}
256 		}
257 		if (close(fd) < 0) {
258 			saverr = errno;
259 			(void) fprintf(stderr, gettext(
260 			    "Error encountered when closing %s: %s\n"),
261 			    argv[1], strerror(saverr));
262 			errors++;
263 			argv++;
264 			argc--;
265 			continue;
266 		}
267 
268 		/*
269 		 * Only set the modes (including the sticky bit) if we
270 		 * had no problems.  It is not an error for the chmod(2)
271 		 * to fail, but do issue a warning.
272 		 */
273 		if (chmod(argv[1], FILE_MODE) < 0)
274 			(void) fprintf(stderr, gettext(
275 			    "warning: couldn't set mode to %#o\n"), FILE_MODE);
276 
277 		argv++;
278 		argc--;
279 	}
280 
281 	if (buf)
282 		free(buf);
283 
284 	return (errors);
285 }
286