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
main(int argc,char ** argv)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
usage()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