xref: /illumos-gate/usr/src/cmd/mkfile/mkfile.c (revision e3ae4b35c024af1196582063ecee3ab79367227d)
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 
38 #define	MIN(a, b)	((a) < (b) ? (a) : (b))
39 
40 #define	BLOCK_SIZE	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
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 = BLOCK_SIZE;
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 		}
143 		if (lseek(fd, (off_t)size-1, SEEK_SET) < 0) {
144 			saverr = errno;
145 			(void) fprintf(stderr, gettext(
146 			    "Could not seek to offset %ld in %s: %s\n"),
147 			    (ulong_t)size-1, argv[1], strerror(saverr));
148 			(void) close(fd);
149 			errors++;
150 			argv++;
151 			argc--;
152 			continue;
153 		} else if (write(fd, "", 1) != 1) {
154 			saverr = errno;
155 			(void) fprintf(stderr, gettext(
156 			    "Could not set length of %s: %s\n"),
157 			    argv[1], strerror(saverr));
158 			(void) close(fd);
159 			errors++;
160 			argv++;
161 			argc--;
162 			continue;
163 		}
164 
165 		if (!nobytes) {
166 			off_t written = 0;
167 			struct stat64 st;
168 
169 			if (lseek(fd, (off_t)0, SEEK_SET) < 0) {
170 				saverr = errno;
171 				(void) fprintf(stderr, gettext(
172 				    "Could not seek to beginning of %s: %s\n"),
173 				    argv[1], strerror(saverr));
174 				(void) close(fd);
175 				errors++;
176 				argv++;
177 				argc--;
178 				continue;
179 			}
180 			if (fstat64(fd, &st) < 0) {
181 				saverr = errno;
182 				(void) fprintf(stderr, gettext(
183 				    "Could not fstat64 %s: %s\n"),
184 				    argv[1], strerror(saverr));
185 				(void) close(fd);
186 				errors++;
187 				argv++;
188 				argc--;
189 				continue;
190 			}
191 			if (bufsz != st.st_blksize) {
192 				if (buf)
193 					free(buf);
194 				bufsz = (size_t)st.st_blksize;
195 				buf = calloc(bufsz, 1);
196 				if (buf == NULL) {
197 					(void) fprintf(stderr, gettext(
198 					    "Could not allocate buffer of"
199 					    " size %d\n"), (int)bufsz);
200 					(void) close(fd);
201 					bufsz = 0;
202 					errors++;
203 					argv++;
204 					argc--;
205 					continue;
206 				}
207 			}
208 			while (written < size) {
209 				ssize_t result;
210 				size_t bytes = (size_t)MIN(bufsz, size-written);
211 
212 				if ((result = write(fd, buf, bytes)) !=
213 				    (ssize_t)bytes) {
214 					saverr = errno;
215 					if (result < 0)
216 					    result = 0;
217 					written += result;
218 					(void) fprintf(stderr, gettext(
219 			    "%s: initialized %lu of %lu bytes: %s\n"),
220 					    argv[1], (ulong_t)written,
221 					    (ulong_t)size,
222 					    strerror(saverr));
223 					errors++;
224 					break;
225 				}
226 				written += bytes;
227 			}
228 
229 			/*
230 			 * A write(2) call in the above loop failed so
231 			 * close out this file and go on (error was
232 			 * already incremented when the write(2) failed).
233 			 */
234 			if (written < size) {
235 				(void) close(fd);
236 				argv++;
237 				argc--;
238 				continue;
239 			}
240 		}
241 		if (close(fd) < 0) {
242 			saverr = errno;
243 			(void) fprintf(stderr, gettext(
244 			    "Error encountered when closing %s: %s\n"),
245 			    argv[1], strerror(saverr));
246 			errors++;
247 			argv++;
248 			argc--;
249 			continue;
250 		}
251 
252 		/*
253 		 * Only set the modes (including the sticky bit) if we
254 		 * had no problems.  It is not an error for the chmod(2)
255 		 * to fail, but do issue a warning.
256 		 */
257 		if (chmod(argv[1], FILE_MODE) < 0)
258 			(void) fprintf(stderr, gettext(
259 			    "warning: couldn't set mode to %#o\n"), FILE_MODE);
260 
261 		argv++;
262 		argc--;
263 	}
264 	return (errors);
265 }
266 
267 static void usage()
268 {
269 	(void) fprintf(stderr, gettext(
270 		"Usage: mkfile [-nv] <size>[g|k|b|m] <name1> [<name2>] ...\n"));
271 	exit(1);
272 	/* NOTREACHED */
273 }
274