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