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
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 = 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
usage()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