Whamcloud - gitweb
libext2fs: add tests for the bitmap functions
[tools/e2fsprogs.git] / lib / ext2fs / tst_bitmaps.c
1 /*
2  * tst_bitmaps.c
3  *
4  * Copyright (C) 2011 Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Library
8  * General Public License, version 2.
9  * %End-Header%
10  */
11
12 #include "config.h"
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #ifdef HAVE_GETOPT_H
17 #include <getopt.h>
18 #endif
19 #include <string.h>
20 #include <fcntl.h>
21 #include <time.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include "ss/ss.h"
25
26 #include "ext2_fs.h"
27 #include "ext2fs.h"
28 #include "ext2fsP.h"
29
30 extern ss_request_table tst_bitmaps_cmds;
31
32 static char subsystem_name[] = "tst_bitmaps";
33 static char version[] = "1.0";
34
35 ext2_filsys     test_fs;
36 int             exit_status = 0;
37
38 static int source_file(const char *cmd_file, int sci_idx)
39 {
40         FILE            *f;
41         char            buf[256];
42         char            *cp;
43         int             retval;
44         int             noecho;
45
46         if (strcmp(cmd_file, "-") == 0)
47                 f = stdin;
48         else {
49                 f = fopen(cmd_file, "r");
50                 if (!f) {
51                         perror(cmd_file);
52                         exit(1);
53                 }
54         }
55         fflush(stdout);
56         fflush(stderr);
57         setbuf(stdout, NULL);
58         setbuf(stderr, NULL);
59         while (!feof(f)) {
60                 if (fgets(buf, sizeof(buf), f) == NULL)
61                         break;
62                 if (buf[0] == '#')
63                         continue;
64                 noecho = 0;
65                 if (buf[0] == '-') {
66                         noecho = 1;
67                         buf[0] = ' ';
68                 }
69                 cp = strchr(buf, '\n');
70                 if (cp)
71                         *cp = 0;
72                 cp = strchr(buf, '\r');
73                 if (cp)
74                         *cp = 0;
75                 if (!noecho)
76                         printf("%s: %s\n", subsystem_name, buf);
77                 retval = ss_execute_line(sci_idx, buf);
78                 if (retval) {
79                         ss_perror(sci_idx, retval, buf);
80                         exit_status++;
81                 }
82         }
83         return exit_status;
84 }
85
86
87 /*
88  * This function resets the libc getopt() function, which keeps
89  * internal state.  Bad design!  Stupid libc API designers!  No
90  * biscuit!
91  *
92  * BSD-derived getopt() functions require that optind be reset to 1 in
93  * order to reset getopt() state.  This used to be generally accepted
94  * way of resetting getopt().  However, glibc's getopt()
95  * has additional getopt() state beyond optind, and requires that
96  * optind be set zero to reset its state.  So the unfortunate state of
97  * affairs is that BSD-derived versions of getopt() misbehave if
98  * optind is set to 0 in order to reset getopt(), and glibc's getopt()
99  * will core dump if optind is set 1 in order to reset getopt().
100  *
101  * More modern versions of BSD require that optreset be set to 1 in
102  * order to reset getopt().   Sigh.  Standards, anyone?
103  *
104  * We hide the hair here.
105  */
106 void reset_getopt(void)
107 {
108 #if defined(__GLIBC__) || defined(__linux__)
109         optind = 0;
110 #else
111         optind = 1;
112 #endif
113 #ifdef HAVE_OPTRESET
114         optreset = 1;           /* Makes BSD getopt happy */
115 #endif
116 }
117
118 /*
119  * This function will convert a string to an unsigned long, printing
120  * an error message if it fails, and returning success or failure in err.
121  */
122 unsigned long parse_ulong(const char *str, const char *cmd,
123                           const char *descr, int *err)
124 {
125         char            *tmp;
126         unsigned long   ret;
127
128         ret = strtoul(str, &tmp, 0);
129         if (*tmp == 0) {
130                 if (err)
131                         *err = 0;
132                 return ret;
133         }
134         com_err(cmd, 0, "Bad %s - %s", descr, str);
135         if (err)
136                 *err = 1;
137         else
138                 exit(1);
139         return 0;
140 }
141
142
143 int check_fs_open(char *name)
144 {
145         if (!test_fs) {
146                 com_err(name, 0, "Filesystem not open");
147                 return 1;
148         }
149         return 0;
150 }
151
152 static void setup_filesystem(const char *name,
153                              unsigned int blocks, unsigned int inodes,
154                              unsigned int type)
155 {
156         struct ext2_super_block param;
157         errcode_t retval;
158
159         memset(&param, 0, sizeof(param));
160         ext2fs_blocks_count_set(&param, blocks);
161         param.s_inodes_count = inodes;
162
163         retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
164                                    test_io_manager, &test_fs);
165
166         if (retval) {
167                 com_err(name, retval, "while initializing filesystem");
168                 return;
169         }
170         test_fs->default_bitmap_type = type;
171         ext2fs_free_block_bitmap(test_fs->block_map);
172         test_fs->block_map = 0;
173         ext2fs_free_inode_bitmap(test_fs->inode_map);
174         test_fs->inode_map = 0;
175         retval = ext2fs_allocate_block_bitmap(test_fs, "block bitmap",
176                                               &test_fs->block_map);
177         if (retval) {
178                 com_err(name, retval, "while allocating block bitmap");
179                 goto errout;
180         }
181         retval = ext2fs_allocate_inode_bitmap(test_fs, "inode bitmap",
182                                               &test_fs->inode_map);
183         if (retval) {
184                 com_err(name, retval, "while allocating inode bitmap");
185                 goto errout;
186         }
187         return;
188
189 errout:
190         ext2fs_close(test_fs);
191         test_fs = 0;
192 }
193
194 void setup_cmd(int argc, char **argv)
195 {
196         errcode_t       retval;
197         int             i, c, err;
198         unsigned int    blocks = 128;
199         unsigned int    inodes = 0;
200         unsigned int    type = EXT2FS_BMAP64_BITARRAY;
201
202         if (test_fs) {
203                 ext2fs_close(test_fs);
204                 test_fs = 0;
205         }
206
207         reset_getopt();
208         while ((c = getopt(argc, argv, "b:i:t:")) != EOF) {
209                 switch (c) {
210                 case 'b':
211                         blocks = parse_ulong(optarg, argv[0],
212                                              "number of blocks", &err);
213                         if (err)
214                                 return;
215                         break;
216                 case 'i':
217                         inodes = parse_ulong(optarg, argv[0],
218                                              "number of blocks", &err);
219                         if (err)
220                                 return;
221                         break;
222                 case 't':
223                         type = parse_ulong(optarg, argv[0],
224                                            "bitmap backend type", &err);
225                         if (err)
226                                 return;
227                         break;
228                 default:
229                         fprintf(stderr, "%s: usage: setup [-b blocks] "
230                                 "[-i inodes] [-t type]\n", argv[0]);
231                         return;
232                 }
233         }
234         setup_filesystem(argv[0], blocks, inodes, type);
235 }
236
237 void close_cmd(int argc, char **argv)
238 {
239         if (check_fs_open(argv[0]))
240                 return;
241
242         ext2fs_close(test_fs);
243         test_fs = 0;
244 }
245
246
247 void dump_bitmap(ext2fs_generic_bitmap bmap, unsigned int start, unsigned num)
248 {
249         unsigned char   *buf;
250         errcode_t       retval;
251         int             i, len = (num - start + 7) / 8;
252
253         buf = malloc(len);
254         if (!buf) {
255                 com_err("dump_bitmap", 0, "couldn't allocate buffer");
256                 return;
257         }
258         memset(buf, 0, len);
259         retval = ext2fs_get_generic_bmap_range(bmap, (__u64) start, num, buf);
260         if (retval) {
261                 com_err("dump_bitmap", retval, 
262                         "while calling ext2fs_generic_bmap_range");
263                 free(buf);
264                 return;
265         }
266         for (i=0; i < len; i++)
267                 printf("%02x", buf[i]);
268         printf("\n");
269         free(buf);
270 }
271
272 void dump_inode_bitmap_cmd(int argc, char **argv)
273 {
274         if (check_fs_open(argv[0]))
275                 return;
276
277         printf("inode bitmap: ");
278         dump_bitmap(test_fs->inode_map, 1, test_fs->super->s_inodes_count);
279 }
280         
281 void dump_block_bitmap_cmd(int argc, char **argv)
282 {
283         if (check_fs_open(argv[0]))
284                 return;
285
286         printf("block bitmap: ");
287         dump_bitmap(test_fs->block_map, test_fs->super->s_first_data_block,
288                     test_fs->super->s_blocks_count);
289 }
290         
291 void do_setb(int argc, char *argv[])
292 {
293         unsigned int block, num;
294         int err;
295         int test_result, op_result;
296
297         if (check_fs_open(argv[0]))
298                 return;
299
300         if (argc != 2 && argc != 3) {
301                 com_err(argv[0], 0, "Usage: setb <block> [num]");
302                 return;
303         }
304
305         block = parse_ulong(argv[1], argv[0], "block", &err);
306         if (err)
307                 return;
308
309         if (argc == 3) {
310                 num = parse_ulong(argv[2], argv[0], "num", &err);
311                 if (err)
312                         return;
313
314                 ext2fs_mark_block_bitmap_range2(test_fs->block_map,
315                                                 block, num);
316                 printf("Marking blocks %u to %u\n", block, block + num - 1);
317                 return;
318         }
319
320         test_result = ext2fs_test_block_bitmap2(test_fs->block_map, block);
321         op_result = ext2fs_mark_block_bitmap2(test_fs->block_map, block);
322         printf("Setting block %u, was %s before\n", block, op_result ?
323                "set" : "clear");
324         if (!test_result != !op_result)
325                 com_err(argv[0], 0, "*ERROR* test_result different! (%d, %d)",
326                         test_result, op_result);
327 }
328
329 void do_clearb(int argc, char *argv[])
330 {
331         unsigned int block, num;
332         int err;
333         int test_result, op_result;
334
335         if (check_fs_open(argv[0]))
336                 return;
337
338         if (argc != 2 && argc != 3) {
339                 com_err(argv[0], 0, "Usage: clearb <block> [num]");
340                 return;
341         }
342
343         block = parse_ulong(argv[1], argv[0], "block", &err);
344         if (err)
345                 return;
346
347         if (argc == 3) {
348                 num = parse_ulong(argv[2], argv[0], "num", &err);
349                 if (err)
350                         return;
351
352                 ext2fs_unmark_block_bitmap_range2(test_fs->block_map,
353                                                 block, num);
354                 printf("Clearing blocks %u to %u\n", block, block + num - 1);
355                 return;
356         }
357
358         test_result = ext2fs_test_block_bitmap2(test_fs->block_map, block);
359         op_result = ext2fs_unmark_block_bitmap2(test_fs->block_map, block);
360         printf("Clearing block %u, was %s before\n", block, op_result ?
361                "set" : "clear");
362         if (!test_result != !op_result)
363                 com_err(argv[0], 0, "*ERROR* test_result different! (%d, %d)",
364                         test_result, op_result);
365 }
366
367 void do_testb(int argc, char *argv[])
368 {
369         unsigned int block, num;
370         int err;
371         int test_result, op_result;
372
373         if (check_fs_open(argv[0]))
374                 return;
375
376         if (argc != 2 && argc != 3) {
377                 com_err(argv[0], 0, "Usage: testb <block> [num]");
378                 return;
379         }
380
381         block = parse_ulong(argv[1], argv[0], "block", &err);
382         if (err)
383                 return;
384
385         if (argc == 3) {
386                 num = parse_ulong(argv[2], argv[0], "num", &err);
387                 if (err)
388                         return;
389
390                 test_result =
391                         ext2fs_test_block_bitmap_range2(test_fs->block_map,
392                                                         block, num);
393                 printf("Blocks %u to %u are %sall clear.\n",
394                        block, block + num - 1, test_result ? "" : "NOT ");
395                 return;
396         }
397
398         test_result = ext2fs_test_block_bitmap2(test_fs->block_map, block);
399         printf("Block %u is %s\n", block, test_result ? "set" : "clear");
400 }
401
402 void do_zerob(int argc, char *argv[])
403 {
404         if (check_fs_open(argv[0]))
405                 return;
406
407         printf("Clearing block bitmap.\n");
408         ext2fs_clear_block_bitmap(test_fs->block_map);
409 }
410
411 void do_seti(int argc, char *argv[])
412 {
413         unsigned int inode;
414         int err;
415         int test_result, op_result;
416
417         if (check_fs_open(argv[0]))
418                 return;
419
420         if (argc != 2) {
421                 com_err(argv[0], 0, "Usage: seti <inode>");
422                 return;
423         }
424
425         inode = parse_ulong(argv[1], argv[0], "inode", &err);
426         if (err)
427                 return;
428
429         test_result = ext2fs_test_inode_bitmap2(test_fs->inode_map, inode);
430         op_result = ext2fs_mark_inode_bitmap2(test_fs->inode_map, inode);
431         printf("Setting inode %u, was %s before\n", inode, op_result ?
432                "set" : "clear");
433         if (!test_result != !op_result) {
434                 com_err(argv[0], 0, "*ERROR* test_result different! (%d, %d)",
435                         test_result, op_result);
436                 exit_status++;
437         }
438 }
439
440 void do_cleari(int argc, char *argv[])
441 {
442         unsigned int inode;
443         int err;
444         int test_result, op_result;
445
446         if (check_fs_open(argv[0]))
447                 return;
448
449         if (argc != 2) {
450                 com_err(argv[0], 0, "Usage: clearb <inode>");
451                 return;
452         }
453
454         inode = parse_ulong(argv[1], argv[0], "inode", &err);
455         if (err)
456                 return;
457
458         test_result = ext2fs_test_inode_bitmap2(test_fs->inode_map, inode);
459         op_result = ext2fs_unmark_inode_bitmap2(test_fs->inode_map, inode);
460         printf("Clearing inode %u, was %s before\n", inode, op_result ?
461                "set" : "clear");
462         if (!test_result != !op_result) {
463                 com_err(argv[0], 0, "*ERROR* test_result different! (%d, %d)",
464                         test_result, op_result);
465                 exit_status++;
466         }
467 }
468
469 void do_testi(int argc, char *argv[])
470 {
471         unsigned int inode;
472         int err;
473         int test_result, op_result;
474
475         if (check_fs_open(argv[0]))
476                 return;
477
478         if (argc != 2) {
479                 com_err(argv[0], 0, "Usage: testb <inode>");
480                 return;
481         }
482
483         inode = parse_ulong(argv[1], argv[0], "inode", &err);
484         if (err)
485                 return;
486
487         test_result = ext2fs_test_inode_bitmap2(test_fs->inode_map, inode);
488         printf("Inode %u is %s\n", inode, test_result ? "set" : "clear");
489 }
490
491 void do_zeroi(int argc, char *argv[])
492 {
493         if (check_fs_open(argv[0]))
494                 return;
495
496         printf("Clearing inode bitmap.\n");
497         ext2fs_clear_inode_bitmap(test_fs->inode_map);
498 }
499
500 int main(int argc, char **argv)
501 {
502         unsigned int    blocks = 128;
503         unsigned int    inodes = 0;
504         unsigned int    type = EXT2FS_BMAP64_BITARRAY;
505         int             c, err, code;
506         char            *request = (char *)NULL;
507         char            *cmd_file = 0;
508         int             sci_idx;
509
510         add_error_table(&et_ss_error_table);
511         add_error_table(&et_ext2_error_table);
512         while ((c = getopt (argc, argv, "b:i:t:R:f:")) != EOF) {
513                 switch (c) {
514                 case 'b':
515                         blocks = parse_ulong(optarg, argv[0],
516                                              "number of blocks", &err);
517                         if (err)
518                                 return;
519                         break;
520                 case 'i':
521                         inodes = parse_ulong(optarg, argv[0],
522                                              "number of blocks", &err);
523                         if (err)
524                                 return;
525                         break;
526                 case 't':
527                         type = parse_ulong(optarg, argv[0],
528                                            "bitmap backend type", &err);
529                         if (err)
530                                 return;
531                         break;
532                 case 'R':
533                         request = optarg;
534                         break;
535                 case 'f':
536                         cmd_file = optarg;
537                         break;
538                 default:
539                         com_err(argv[0], 0, "Usage: %s [-R request] "
540                                 "[-f cmd_file]", subsystem_name);
541                         exit(1);
542                 }
543         }
544
545         sci_idx = ss_create_invocation(subsystem_name, version,
546                                        (char *)NULL, &tst_bitmaps_cmds, &code);
547         if (code) {
548                 ss_perror(sci_idx, code, "creating invocation");
549                 exit(1);
550         }
551
552         (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &code);
553         if (code) {
554                 ss_perror(sci_idx, code, "adding standard requests");
555                 exit (1);
556         }
557
558         printf("%s %s.  Type '?' for a list of commands.\n\n",
559                subsystem_name, version);
560
561         setup_filesystem(argv[0], blocks, inodes, type);
562
563         if (request) {
564                 code = ss_execute_line(sci_idx, request);
565                 if (code) {
566                         ss_perror(sci_idx, code, request);
567                         exit_status++;
568                 }
569         } else if (cmd_file) {
570                 exit_status = source_file(cmd_file, sci_idx);
571         } else {
572                 ss_listen(sci_idx);
573         }
574
575         exit(exit_status);
576 }
577