src/locktest: Add lease testing for basic signal reception
[xfstests-dev.git] / src / fill2.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000-2003 Silicon Graphics, Inc.
4  * All Rights Reserved.
5  */
6
7
8 /*
9  * fill2:
10  *   Derived from fill.c, adds command line options, block boundary marking
11  *   and allows me to tweak to suit fill2fs without breaking other qa tests.
12  *   This version marks block boundaries (512, 1k, 4k and 16k) within the file
13  *   using characters guaranteed not to appear anywhere else, this may allow
14  *   simple checks in future which can inspect these offsets and ensure one of
15  *   of the four characters is present. Also fixes off-by-one error in fill.c
16  *   and is more careful about checking when write operations fail - this is 
17  *   needed by fill2fs to ensure that the number of bytes written is accurately
18  *   determined.
19  */
20
21 #include "global.h"
22
23 #define constpp char * const *
24
25 #define N(x) (sizeof(x)/sizeof(x[0]))
26
27 /* function prototypes */
28 static void illegal(char *, char *);
29 static void reqval(char, char * [], int);
30 static void respec(char, char * [], int);
31 static void unknown(char, char *);
32 static void usage(void);
33 char *progname;
34
35 char *dopts[] =         { "nbytes", "linelength", "seed", "file", NULL };
36 enum                    { D_NBYTES, D_LINELENGTH, D_SEED, D_FILE, D_ISSET, D_NUM };
37 int dflags[D_NUM] =     { 0 };
38 char *bopts[] =         { "512", "1k", "4k", "16k" };
39 enum                    { B_512, B_1K, B_4K, B_16K, B_ISSET, B_NUM };
40 int bflags[B_NUM] =     { 0 };
41
42
43 /*
44  * block boundaries
45  *
46  */
47
48 /* block boundaries which should be flagged in the output file */
49 /* flag is the character that should be used to indicate each type */
50 /* of block boundary */
51
52
53 struct s_block_type {
54     int mark;
55     int size;
56     char flag;
57 };
58
59 static struct s_block_type btypes[] = {
60     { 0, 512, '!' },    /* 512 */
61     { 0, 1024, '"' },   /* 1k */
62     { 0, 4096, '#' },   /* 4k */
63     { 0, 16384, '$' },  /* 16k */
64 };
65
66 /*
67  * main
68  *
69  */
70
71 int
72 main(int argc, char **argv)
73 {
74     int                 status = 0;     /* return status */
75     int                 c;              /* current option character */
76     char                *p;             /* for getsubopt calls */
77     long                nbytes;         /* total number of bytes to write */
78     int                 dlen;           /* length of normal output data line */
79     const char          *dseed = NULL;  /* input string for seeding rand */
80     unsigned int        seed;           /* seed for output data */    
81     char                *dfile = NULL;  /* where to write output */
82
83     FILE                *f;             /* output file */
84     char                *dbuf;          /* output line buffer */
85     char                bbuf[50];       /* block boundary string */
86     char                *active = NULL; /* active buffer to copy out of */
87     size_t              hlen;           /* header length (bytes+key) in output */
88                                         /* lines */
89     char                *hptr;          /* pointer to end of header */
90     char                *ptr;           /* current position to copy from */
91     int                 blktype = 0;    /* current block boundary type */
92     int                 boundary;       /* set if current output char lies on */
93                                         /* block boundary */
94     long                i;
95     int                 j;
96     int                 l = 0;
97
98
99     /* defaults */
100
101     progname = basename(argv[0]);
102     for (p = progname; *p; p++) {
103             if (*p == '/') {
104                     progname = p + 1;
105             }
106     }
107     nbytes = 1024 * 1024;
108     dlen = 73;  /* includes the trailing newline */
109
110     while ((c = getopt(argc, argv, "d:b:")) != EOF) {
111         switch (c) {
112         case 'd':
113             if (dflags[D_ISSET])
114                 respec('d', NULL, 0);
115             dflags[D_ISSET] = 1;
116
117             p = optarg;
118             while (*p != '\0') {
119                 char *value;
120                 switch (getsubopt(&p, (constpp)dopts, &value)) {
121                 case D_NBYTES:
122                     if (! value) reqval('d', dopts, D_NBYTES);
123                     if (dflags[D_NBYTES]) respec('d', dopts, D_NBYTES);
124                     dflags[D_NBYTES] = 1;
125                     nbytes = strtol(value, &ptr, 10);
126                     if (ptr == value) illegal(value, "d nbytes");
127                     break;
128
129                 case D_LINELENGTH:
130                     if (! value) reqval('d', dopts, D_LINELENGTH);
131                     if (dflags[D_LINELENGTH]) respec('d', dopts, D_LINELENGTH);
132                     dflags[D_LINELENGTH] = 1;
133                     dlen = (int) strtol(value, &ptr, 10) + 1;
134                     if (ptr == value) illegal(value, "d linelength");
135                     break;
136
137                 case D_SEED:
138                     if (! value) reqval('d', dopts, D_SEED);
139                     if (dflags[D_SEED]) respec('D', dopts, D_SEED);
140                     dflags[D_SEED] = 1;
141                     dseed = value;
142                     break;
143
144                 case D_FILE:
145                     if (! value) reqval('d', dopts, D_FILE);
146                     if (dflags[D_FILE]) respec('d', dopts, D_FILE);
147                     dflags[D_FILE] = 1;
148                     dfile = value;
149                     break;
150                     
151                 default:
152                     unknown('d', value);
153                 }
154             }
155             break;
156
157         case 'b':
158             if (bflags[B_ISSET])
159                 respec('b', NULL, 0);
160             bflags[B_ISSET] = 1;
161
162             p = optarg;
163             while (*p != '\0') {
164                 char *value;
165                 switch (getsubopt(&p, (constpp)bopts, &value)) {
166                 case B_512:
167                     if (value) illegal(value, "b 512");
168                     if (bflags[B_512]) respec('b', bopts, B_512);
169                     bflags[B_512] = 1;
170                     btypes[0].mark = 1;
171                     break;
172
173                 case B_1K:
174                     if (value) illegal(value, "b 1k");
175                     if (bflags[B_1K]) respec('b', bopts, B_1K);
176                     bflags[B_1K] = 1;
177                     btypes[1].mark = 1;
178                     break;
179
180                 case B_4K:
181                     if (value) illegal(value, "b 4k");
182                     if (bflags[B_4K]) respec('b', bopts, B_4K);
183                     bflags[B_4K] = 1;
184                     btypes[2].mark = 1;
185                     break;
186
187                 case B_16K:
188                     if (value) illegal(value, "b 16k");
189                     if (bflags[B_16K]) respec('b', bopts, B_16K);
190                     bflags[B_16K] = 1;
191                     btypes[3].mark = 1;
192                     break;
193
194                 default:
195                     unknown('b', value);
196                     break;
197                 }
198             }
199             break;
200
201         case '?':
202             usage();
203         }
204     }
205
206     if (dflags[D_FILE] && optind != argc)
207         usage();
208
209     if (! dflags[D_FILE] && argc - optind != 1)
210         usage();
211
212     if (! dflags[D_FILE])
213         dfile = argv[optind];
214
215     if ((f = fopen(dfile, "w")) == NULL) {
216         fprintf(stderr, "fill2: cannot create \"%s\": %s\n",
217                 dfile, strerror(errno));
218         status = 1;
219         goto cleanup;
220     }
221
222     if (! dflags[D_SEED]) 
223         dseed = dfile;
224
225     /* seed is an ascii string */
226     seed = 0;
227     i = 0;
228     while (dseed[i]) {
229         seed <<= 8;
230         seed |= dseed[i];
231         i++;
232     }
233     srand(seed);
234
235
236     /* normal data line format: XXXXXXXXXXXX CCCC...CCC CCCCCCCCCCCC...CCC */
237     /* block boundary format: CXXXXXXX */
238
239     dbuf = (char *) malloc(dlen + 1);
240     hlen = 12+1+strlen(dseed)+1;
241     assert(hlen < dlen);
242     hptr = dbuf + hlen;
243
244     for (i = 0; i < nbytes; i++) {
245
246         
247         /* is this a block boundary? check largest to smallest */
248         boundary = 0;
249         for (j = N(btypes) - 1; j >= 0; j--) {
250             if (btypes[j].mark) {
251                 /* first time through or just before a block boundary? */
252                 if (i == 0 || i % btypes[j].size == btypes[j].size - 1) {
253                     boundary = 1;
254                     blktype = j;
255                     break;
256                 }
257             }
258         }
259
260
261         /* are there block boundaries to check? */
262         /* is this the first time through? */
263         /* block boundaries take priority over other output */
264         if (bflags[B_ISSET] && (i == 0 || boundary)) {
265             sprintf(bbuf, "%s%c%07ld\n",
266                     i ? "\n" : "",
267                     btypes[blktype].flag,
268                     /* remember i is one less than block boundary */
269                     i ? (i+1) / btypes[blktype].size : 0);
270             active = bbuf;
271             ptr = bbuf;
272         }
273         /* are we at the start of a new line? */
274         else if (i == 0
275                  || (active == bbuf && *ptr == '\0')
276                  || (active == dbuf && l == dlen))
277         {
278             sprintf(dbuf, "%012ld %s ", i, dseed);
279             assert(*hptr == '\0');
280             for (ptr = hptr; ptr != dbuf + dlen - 1; ptr++) {
281                 /* characters upto 126 '~' are used */
282                 /* do not use !"#$ - leave free for use as block markers */
283                 *ptr = 37 + (rand() % (127 - 37)); 
284             }
285             *ptr++ = '\n';
286             *ptr = '\0';
287             assert(ptr == dbuf + dlen);
288             active = dbuf;
289             ptr = dbuf;
290             l = 0;
291         }
292         else {
293             /* continue copying from the active buffer */
294         }
295
296         /* output one new character from current buffer */
297         if (fputc(*ptr++, f) == EOF) {
298             fprintf(stderr, "fill2: could not write character to \"%s\": %s\n",
299                     dfile, strerror(errno));
300             status = 1;
301             goto cleanup;
302         }
303         if (active == dbuf) l++;
304
305     }
306
307  cleanup:
308
309     /* close file and flush buffers - check if this fails */
310     if (fclose(f) != 0) {
311         fprintf(stderr, "fill2: fclose() on \"%s\" failed: %s\n",
312                 dfile, strerror(errno));
313         status = 1;
314     }
315     return status;
316 }
317
318
319
320 /*
321  * suboption checking functions
322  *
323  */
324
325 static void
326 illegal(char *value, char *opt)
327 {
328     fprintf(stderr, "%s: Error: Illegal value \"%s\" for -%s option\n",
329             progname, value, opt);
330     usage();
331 }
332 static void
333 reqval(char opt, char *tab[], int idx)
334 {
335     fprintf(stderr, "%s: Error: -%c %s option requires a value\n",
336             progname, opt, tab[idx]);
337     usage();
338 }
339 static void
340 respec(char opt, char *tab[], int idx)
341 {
342     fprintf(stderr, "%s: Error: ", progname);
343     fprintf(stderr, "-%c ", opt);
344     if (tab) fprintf(stderr, "%s ", tab[idx]);
345     fprintf(stderr, "option respecified\n");
346     usage();
347 }
348 static void
349 unknown(char opt, char *s)
350 {
351     fprintf(stderr, "%s: Error: Unknown option -%c %s\n", progname, opt, s);
352     usage();
353 }
354 static void
355 usage(void)
356 {
357     fprintf(stderr, "Usage: %s [options] filename\n"
358 "Options:\n"
359 "  -d [nbytes=num,linelength=num,   output data properties\n"
360 "      seed=string,file=name]\n"
361 "  -b [512,1k,4k,16k]               where to mark block boundaries\n", progname);
362     exit(2);
363 }