xref: /illumos-gate/usr/src/cmd/mkfile/mkfile.c (revision 6db6c2a6)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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 
39 #define	MIN(a, b)	((a) < (b) ? (a) : (b))
40 
41 #define	BLOCK_SIZE	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 void usage(void);
49 
50 int
51 main(int argc, char **argv)
52 {
53 	char	*opts;
54 	off_t	size;
55 	size_t	len;
56 	size_t	mult = 1;
57 	char	*buf = NULL;
58 	size_t	bufsz = 0;
59 	int	errors = 0;
60 	int	i;
61 	int	verbose = 0;	/* option variable */
62 	int	nobytes = 0;	/* option variable */
63 	int	saverr;
64 
65 	if (argc == 1)
66 		usage();
67 
68 	while (argv[1] && argv[1][0] == '-') {
69 		opts = &argv[1][0];
70 		while (*(++opts)) {
71 			switch (*opts) {
72 			case 'v':
73 				verbose++;
74 				break;
75 			case 'n':
76 				nobytes++;
77 				break;
78 			default:
79 				usage();
80 			}
81 		}
82 		argc--;
83 		argv++;
84 	}
85 	if (argc < 3)
86 		usage();
87 
88 	len = strlen(argv[1]);
89 	if (len && isalpha(argv[1][len-1])) {
90 		switch (argv[1][len-1]) {
91 		case 'k':
92 		case 'K':
93 			mult = KILOBYTE;
94 			break;
95 		case 'b':
96 		case 'B':
97 			mult = BLOCK_SIZE;
98 			break;
99 		case 'm':
100 		case 'M':
101 			mult = MEGABYTE;
102 			break;
103 		case 'g':
104 		case 'G':
105 			mult = GIGABYTE;
106 			break;
107 		default:
108 			(void) fprintf(stderr,
109 			    gettext("unknown size %s\n"), argv[1]);
110 			usage();
111 		}
112 
113 		for (i = 0; i <= (len-2); i++) {
114 			if (!isdigit(argv[1][i])) {
115 				(void) fprintf(stderr,
116 				    gettext("unknown size %s\n"), argv[1]);
117 				usage();
118 			}
119 		}
120 		argv[1][len-1] = '\0';
121 	}
122 	size = ((off_t)atoll(argv[1]) * (off_t)mult);
123 
124 	argv++;
125 	argc--;
126 
127 	while (argc > 1) {
128 		int fd;
129 
130 		if (verbose)
131 			(void) fprintf(stdout, gettext("%s %lld bytes\n"),
132 			    argv[1], (offset_t)size);
133 		fd = open(argv[1], O_CREAT|O_TRUNC|O_RDWR, FILE_MODE);
134 		if (fd < 0) {
135 			saverr = errno;
136 			(void) fprintf(stderr,
137 			    gettext("Could not open %s: %s\n"),
138 			    argv[1], strerror(saverr));
139 			errors++;
140 			argv++;
141 			argc--;
142 			continue;
143 		}
144 		if (lseek(fd, (off_t)size-1, SEEK_SET) < 0) {
145 			saverr = errno;
146 			(void) fprintf(stderr, gettext(
147 			    "Could not seek to offset %ld in %s: %s\n"),
148 			    (ulong_t)size-1, argv[1], strerror(saverr));
149 			(void) close(fd);
150 			errors++;
151 			argv++;
152 			argc--;
153 			continue;
154 		} else if (write(fd, "", 1) != 1) {
155 			saverr = errno;
156 			(void) fprintf(stderr, gettext(
157 			    "Could not set length of %s: %s\n"),
158 			    argv[1], strerror(saverr));
159 			(void) close(fd);
160 			errors++;
161 			argv++;
162 			argc--;
163 			continue;
164 		}
165 
166 		if (!nobytes) {
167 			off_t written = 0;
168 			struct stat64 st;
169 
170 			if (lseek(fd, (off_t)0, SEEK_SET) < 0) {
171 				saverr = errno;
172 				(void) fprintf(stderr, gettext(
173 				    "Could not seek to beginning of %s: %s\n"),
174 				    argv[1], strerror(saverr));
175 				(void) close(fd);
176 				errors++;
177 				argv++;
178 				argc--;
179 				continue;
180 			}
181 			if (fstat64(fd, &st) < 0) {
182 				saverr = errno;
183 				(void) fprintf(stderr, gettext(
184 				    "Could not fstat64 %s: %s\n"),
185 				    argv[1], strerror(saverr));
186 				(void) close(fd);
187 				errors++;
188 				argv++;
189 				argc--;
190 				continue;
191 			}
192 			if (bufsz != st.st_blksize) {
193 				if (buf)
194 					free(buf);
195 				bufsz = (size_t)st.st_blksize;
196 				buf = calloc(bufsz, 1);
197 				if (buf == NULL) {
198 					(void) fprintf(stderr, gettext(
199 					    "Could not allocate buffer of"
200 					    " size %d\n"), (int)bufsz);
201 					(void) close(fd);
202 					bufsz = 0;
203 					errors++;
204 					argv++;
205 					argc--;
206 					continue;
207 				}
208 			}
209 			while (written < size) {
210 				ssize_t result;
211 				size_t bytes = (size_t)MIN(bufsz, size-written);
212 
213 				if ((result = write(fd, buf, bytes)) !=
214 				    (ssize_t)bytes) {
215 					saverr = errno;
216 					if (result < 0)
217 					    result = 0;
218 					written += result;
219 					(void) fprintf(stderr, gettext(
220 			    "%s: initialized %lu of %lu bytes: %s\n"),
221 					    argv[1], (ulong_t)written,
222 					    (ulong_t)size,
223 					    strerror(saverr));
224 					errors++;
225 					break;
226 				}
227 				written += bytes;
228 			}
229 
230 			/*
231 			 * A write(2) call in the above loop failed so
232 			 * close out this file and go on (error was
233 			 * already incremented when the write(2) failed).
234 			 */
235 			if (written < size) {
236 				(void) close(fd);
237 				argv++;
238 				argc--;
239 				continue;
240 			}
241 		}
242 		if (close(fd) < 0) {
243 			saverr = errno;
244 			(void) fprintf(stderr, gettext(
245 			    "Error encountered when closing %s: %s\n"),
246 			    argv[1], strerror(saverr));
247 			errors++;
248 			argv++;
249 			argc--;
250 			continue;
251 		}
252 
253 		/*
254 		 * Only set the modes (including the sticky bit) if we
255 		 * had no problems.  It is not an error for the chmod(2)
256 		 * to fail, but do issue a warning.
257 		 */
258 		if (chmod(argv[1], FILE_MODE) < 0)
259 			(void) fprintf(stderr, gettext(
260 			    "warning: couldn't set mode to %#o\n"), FILE_MODE);
261 
262 		argv++;
263 		argc--;
264 	}
265 	return (errors);
266 }
267 
268 static void usage()
269 {
270 	(void) fprintf(stderr, gettext(
271 		"Usage: mkfile [-nv] <size>[g|k|b|m] <name1> [<name2>] ...\n"));
272 	exit(1);
273 	/* NOTREACHED */
274 }
275