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