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