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 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 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