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