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 #pragma ident "%Z%%M% %I% %E% SMI" 23 24 /* 25 * Copyright 2004 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 39 #define WRITEBUF_SIZE 8192 40 41 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 42 43 #define BLOCK_SIZE 512 /* bytes */ 44 #define KILOBYTE 1024 45 #define MEGABYTE (KILOBYTE * KILOBYTE) 46 #define GIGABYTE (KILOBYTE * MEGABYTE) 47 48 #define FILE_MODE (S_ISVTX + S_IRUSR + S_IWUSR) 49 50 static void usage(void); 51 52 char buf[WRITEBUF_SIZE]; 53 54 int 55 main(int argc, char **argv) 56 { 57 char *opts; 58 off_t size; 59 size_t len; 60 size_t mult = 1; 61 int errors = 0; 62 int i; 63 int verbose = 0; /* option variable */ 64 int nobytes = 0; /* option variable */ 65 int saverr; 66 67 if (argc == 1) 68 usage(); 69 70 while (argv[1] && argv[1][0] == '-') { 71 opts = &argv[1][0]; 72 while (*(++opts)) { 73 switch (*opts) { 74 case 'v': 75 verbose++; 76 break; 77 case 'n': 78 nobytes++; 79 break; 80 default: 81 usage(); 82 } 83 } 84 argc--; 85 argv++; 86 } 87 if (argc < 3) 88 usage(); 89 90 len = strlen(argv[1]); 91 if (len && isalpha(argv[1][len-1])) { 92 switch (argv[1][len-1]) { 93 case 'k': 94 case 'K': 95 mult = KILOBYTE; 96 break; 97 case 'b': 98 case 'B': 99 mult = BLOCK_SIZE; 100 break; 101 case 'm': 102 case 'M': 103 mult = MEGABYTE; 104 break; 105 case 'g': 106 case 'G': 107 mult = GIGABYTE; 108 break; 109 default: 110 (void) fprintf(stderr, "unknown size %s\n", argv[1]); 111 usage(); 112 } 113 114 for (i = 0; i <= (len-2); i++) { 115 if (!isdigit(argv[1][i])) { 116 (void) fprintf(stderr, "unknown size " 117 "%s\n", argv[1]); 118 usage(); 119 } 120 } 121 argv[1][len-1] = '\0'; 122 } 123 size = ((off_t)atoll(argv[1]) * (off_t)mult); 124 125 argv++; 126 argc--; 127 128 while (argc > 1) { 129 int fd; 130 131 if (verbose) 132 (void) fprintf(stdout, "%s %lld bytes\n", argv[1], 133 (offset_t)size); 134 fd = open(argv[1], O_CREAT|O_TRUNC|O_RDWR, FILE_MODE); 135 if (fd < 0) { 136 saverr = errno; 137 (void) fprintf(stderr, 138 gettext("Could not open %s: %s\n"), 139 argv[1], strerror(saverr)); 140 errors++; 141 argv++; 142 argc--; 143 continue; 144 } 145 if (lseek(fd, (off_t)size-1, SEEK_SET) < 0) { 146 saverr = errno; 147 (void) fprintf(stderr, gettext( 148 "Could not seek to offset %ld in %s: %s\n"), 149 (ulong_t)size-1, argv[1], strerror(saverr)); 150 (void) close(fd); 151 errors++; 152 argv++; 153 argc--; 154 continue; 155 } else if (write(fd, "", 1) != 1) { 156 saverr = errno; 157 (void) fprintf(stderr, gettext( 158 "Could not set length of %s: %s\n"), 159 argv[1], strerror(saverr)); 160 (void) close(fd); 161 errors++; 162 argv++; 163 argc--; 164 continue; 165 } 166 167 if (!nobytes) { 168 off_t written = 0; 169 170 if (lseek(fd, (off_t)0, SEEK_SET) < 0) { 171 saverr = errno; 172 (void) fprintf(stderr, gettext( 173 "Could not seek to beginning of %s: %s\n"), 174 argv[1], strerror(saverr)); 175 (void) close(fd); 176 errors++; 177 argv++; 178 argc--; 179 continue; 180 } 181 while (written < size) { 182 ssize_t result; 183 size_t bytes = (size_t)MIN(sizeof (buf), 184 size-written); 185 186 if ((result = write(fd, buf, bytes)) != 187 (ssize_t)bytes) { 188 saverr = errno; 189 if (result < 0) 190 result = 0; 191 written += result; 192 (void) fprintf(stderr, gettext( 193 "%s: initialized %lu of %lu bytes: %s\n"), 194 argv[1], (ulong_t)written, 195 (ulong_t)size, 196 strerror(saverr)); 197 errors++; 198 break; 199 } 200 written += bytes; 201 } 202 203 /* 204 * A write(2) call in the above loop failed so 205 * close out this file and go on (error was 206 * already incremented when the write(2) failed). 207 */ 208 if (written < size) { 209 (void) close(fd); 210 argv++; 211 argc--; 212 continue; 213 } 214 } 215 if (close(fd) < 0) { 216 saverr = errno; 217 (void) fprintf(stderr, gettext( 218 "Error encountered when closing %s: %s\n"), 219 argv[1], strerror(saverr)); 220 errors++; 221 argv++; 222 argc--; 223 continue; 224 } 225 226 /* 227 * Only set the modes (including the sticky bit) if we 228 * had no problems. It is not an error for the chmod(2) 229 * to fail, but do issue a warning. 230 */ 231 if (chmod(argv[1], FILE_MODE) < 0) 232 (void) fprintf(stderr, 233 "warning: couldn't set mode to %#o\n", FILE_MODE); 234 235 argv++; 236 argc--; 237 } 238 return (errors); 239 } 240 241 static void usage() 242 { 243 (void) fprintf(stderr, 244 "Usage: mkfile [-nv] <size>[g|k|b|m] <name1> [<name2>] ...\n"); 245 exit(1); 246 /* NOTREACHED */ 247 } 248