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