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