2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
36 * Derived from fill.c, adds command line options, block boundary marking
37 * and allows me to tweak to suit fill2fs without breaking other qa tests.
38 * This version marks block boundaries (512, 1k, 4k and 16k) within the file
39 * using characters guaranteed not to appear anywhere else, this may allow
40 * simple checks in future which can inspect these offsets and ensure one of
41 * of the four characters is present. Also fixes off-by-one error in fill.c
42 * and is more careful about checking when write operations fail - this is
43 * needed by fill2fs to ensure that the number of bytes written is accurately
46 * To compile standalone on IRIX: cc -DTOOL_ONLY -o fill2 fill2.c -lgen
60 #include <platform_defs.h>
62 #define constpp char * const *
63 #endif /* TOOL_ONLY */
65 #define N(x) (sizeof(x)/sizeof(x[0]))
67 /* function prototypes */
68 static void illegal(char *, char *);
69 static void reqval(char, char * [], int);
70 static void respec(char, char * [], int);
71 static void unknown(char, char *);
72 static void usage(void);
73 static char *progname;
75 char *dopts[] = { "nbytes", "linelength", "seed", "file", NULL };
76 enum { D_NBYTES, D_LINELENGTH, D_SEED, D_FILE, D_ISSET, D_NUM };
77 int dflags[D_NUM] = { 0 };
78 char *bopts[] = { "512", "1k", "4k", "16k" };
79 enum { B_512, B_1K, B_4K, B_16K, B_ISSET, B_NUM };
80 int bflags[B_NUM] = { 0 };
88 /* block boundaries which should be flagged in the output file */
89 /* flag is the character that should be used to indicate each type */
90 /* of block boundary */
99 static struct s_block_type btypes[] = {
100 { 0, 512, '!' }, /* 512 */
101 { 0, 1024, '"' }, /* 1k */
102 { 0, 4096, '#' }, /* 4k */
103 { 0, 16384, '$' }, /* 16k */
112 main(int argc, char **argv)
114 int status = 0; /* return status */
115 int c; /* current option character */
116 char *p; /* for getsubopt calls */
117 long nbytes; /* total number of bytes to write */
118 int dlen; /* length of normal output data line */
119 const char *dseed = NULL; /* input string for seeding rand */
120 unsigned int seed; /* seed for output data */
121 char *dfile = NULL; /* where to write output */
123 FILE *f; /* output file */
124 char *dbuf; /* output line buffer */
125 char bbuf[50]; /* block boundary string */
126 char *active = NULL; /* active buffer to copy out of */
127 size_t hlen; /* header length (bytes+key) in output */
129 char *hptr; /* pointer to end of header */
130 char *ptr; /* current position to copy from */
131 int blktype = 0; /* current block boundary type */
132 int boundary; /* set if current output char lies on */
140 progname = basename(argv[0]);
141 nbytes = 1024 * 1024;
142 dlen = 73; /* includes the trailing newline */
144 while ((c = getopt(argc, argv, "d:b:")) != EOF) {
148 respec('d', NULL, 0);
154 switch (getsubopt(&p, (constpp)dopts, &value)) {
156 if (! value) reqval('d', dopts, D_NBYTES);
157 if (dflags[D_NBYTES]) respec('d', dopts, D_NBYTES);
158 dflags[D_NBYTES] = 1;
159 nbytes = strtol(value, &ptr, 10);
160 if (ptr == value) illegal(value, "d nbytes");
164 if (! value) reqval('d', dopts, D_LINELENGTH);
165 if (dflags[D_LINELENGTH]) respec('d', dopts, D_LINELENGTH);
166 dflags[D_LINELENGTH] = 1;
167 dlen = (int) strtol(value, &ptr, 10) + 1;
168 if (ptr == value) illegal(value, "d linelength");
172 if (! value) reqval('d', dopts, D_SEED);
173 if (dflags[D_SEED]) respec('D', dopts, D_SEED);
179 if (! value) reqval('d', dopts, D_FILE);
180 if (dflags[D_FILE]) respec('d', dopts, D_FILE);
193 respec('b', NULL, 0);
199 switch (getsubopt(&p, (constpp)bopts, &value)) {
201 if (value) illegal(value, "b 512");
202 if (bflags[B_512]) respec('b', bopts, B_512);
208 if (value) illegal(value, "b 1k");
209 if (bflags[B_1K]) respec('b', bopts, B_1K);
215 if (value) illegal(value, "b 4k");
216 if (bflags[B_4K]) respec('b', bopts, B_4K);
222 if (value) illegal(value, "b 16k");
223 if (bflags[B_16K]) respec('b', bopts, B_16K);
240 if (dflags[D_FILE] && optind != argc)
243 if (! dflags[D_FILE] && argc - optind != 1)
246 if (! dflags[D_FILE])
247 dfile = argv[optind];
249 if ((f = fopen(dfile, "w")) == NULL) {
250 fprintf(stderr, "fill2: cannot create \"%s\": %s\n",
251 dfile, strerror(errno));
256 if (! dflags[D_SEED])
259 /* seed is an ascii string */
270 /* normal data line format: XXXXXXXXXXXX CCCC...CCC CCCCCCCCCCCC...CCC */
271 /* block boundary format: CXXXXXXX */
273 dbuf = (char *) malloc(dlen + 1);
274 hlen = 12+1+strlen(dseed)+1;
278 for (i = 0; i < nbytes; i++) {
281 /* is this a block boundary? check largest to smallest */
283 for (j = N(btypes) - 1; j >= 0; j--) {
284 if (btypes[j].mark) {
285 /* first time through or just before a block boundary? */
286 if (i == 0 || i % btypes[j].size == btypes[j].size - 1) {
295 /* are there block boundaries to check? */
296 /* is this the first time through? */
297 /* block boundaries take priority over other output */
298 if (bflags[B_ISSET] && (i == 0 || boundary)) {
299 sprintf(bbuf, "%s%c%07ld\n",
301 btypes[blktype].flag,
302 /* remember i is one less than block boundary */
303 i ? (i+1) / btypes[blktype].size : 0);
307 /* are we at the start of a new line? */
309 || (active == bbuf && *ptr == '\0')
310 || (active == dbuf && l == dlen))
312 sprintf(dbuf, "%012ld %s ", i, dseed);
313 assert(*hptr == '\0');
314 for (ptr = hptr; ptr != dbuf + dlen - 1; ptr++) {
315 /* characters upto 126 '~' are used */
316 /* do not use !"#$ - leave free for use as block markers */
317 *ptr = 37 + (rand() % (127 - 37));
321 assert(ptr == dbuf + dlen);
327 /* continue copying from the active buffer */
330 /* output one new character from current buffer */
331 if (fputc(*ptr++, f) == EOF) {
332 fprintf(stderr, "fill2: could not write character to \"%s\": %s\n",
333 dfile, strerror(errno));
337 if (active == dbuf) l++;
343 /* close file and flush buffers - check if this fails */
344 if (fclose(f) != 0) {
345 fprintf(stderr, "fill2: fclose() on \"%s\" failed: %s\n",
346 dfile, strerror(errno));
355 * suboption checking functions
360 illegal(char *value, char *opt)
362 fprintf(stderr, "%s: Error: Illegal value \"%s\" for -%s option\n",
363 progname, value, opt);
367 reqval(char opt, char *tab[], int idx)
369 fprintf(stderr, "%s: Error: -%c %s option requires a value\n",
370 progname, opt, tab[idx]);
374 respec(char opt, char *tab[], int idx)
376 fprintf(stderr, "%s: Error: ", progname);
377 fprintf(stderr, "-%c ", opt);
378 if (tab) fprintf(stderr, "%s ", tab[idx]);
379 fprintf(stderr, "option respecified\n");
383 unknown(char opt, char *s)
385 fprintf(stderr, "%s: Error: Unknown option -%c %s\n", progname, opt, s);
391 fprintf(stderr, "Usage: %s [options] filename\n"
393 " -d [nbytes=num,linelength=num, output data properties\n"
394 " seed=string,file=name]\n"
395 " -b [512,1k,4k,16k] where to mark block boundaries\n", progname);