Whamcloud - gitweb
libext2fs: add sanity checks for ea_in_inode
[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, int flags)
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", flags, &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_free(&test_fs);
191 }
192
193 void setup_cmd(int argc, char **argv)
194 {
195         int             c, err;
196         unsigned int    blocks = 128;
197         unsigned int    inodes = 0;
198         unsigned int    type = EXT2FS_BMAP64_BITARRAY;
199         int             flags = EXT2_FLAG_64BITS;
200
201         if (test_fs)
202                 ext2fs_close_free(&test_fs);
203
204         reset_getopt();
205         while ((c = getopt(argc, argv, "b:i:lt:")) != EOF) {
206                 switch (c) {
207                 case 'b':
208                         blocks = parse_ulong(optarg, argv[0],
209                                              "number of blocks", &err);
210                         if (err)
211                                 return;
212                         break;
213                 case 'i':
214                         inodes = parse_ulong(optarg, argv[0],
215                                              "number of blocks", &err);
216                         if (err)
217                                 return;
218                         break;
219                 case 'l':       /* Legacy bitmaps */
220                         flags = 0;
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, flags);
235 }
236
237 void close_cmd(int argc, char **argv)
238 {
239         if (check_fs_open(argv[0]))
240                 return;
241
242         ext2fs_close_free(&test_fs);
243 }
244
245
246 void dump_bitmap(ext2fs_generic_bitmap bmap, unsigned int start, unsigned num)
247 {
248         unsigned char   *buf;
249         errcode_t       retval;
250         int             i, len = (num - start + 7) / 8;
251
252         buf = malloc(len);
253         if (!buf) {
254                 com_err("dump_bitmap", 0, "couldn't allocate buffer");
255                 return;
256         }
257         memset(buf, 0, len);
258         retval = ext2fs_get_generic_bmap_range(bmap, (__u64) start, num, buf);
259         if (retval) {
260                 com_err("dump_bitmap", retval, 
261                         "while calling ext2fs_generic_bmap_range");
262                 free(buf);
263                 return;
264         }
265         for (i=0; i < len; i++)
266                 printf("%02x", buf[i]);
267         printf("\n");
268         printf("bits set: %u\n", ext2fs_bitcount(buf, len));
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;
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_ffzb(int argc, char *argv[])
403 {
404         unsigned int start, end;
405         int err;
406         errcode_t retval;
407         blk64_t out;
408
409         if (check_fs_open(argv[0]))
410                 return;
411
412         if (argc != 3 && argc != 3) {
413                 com_err(argv[0], 0, "Usage: ffzb <start> <end>");
414                 return;
415         }
416
417         start = parse_ulong(argv[1], argv[0], "start", &err);
418         if (err)
419                 return;
420
421         end = parse_ulong(argv[2], argv[0], "end", &err);
422         if (err)
423                 return;
424
425         retval = ext2fs_find_first_zero_block_bitmap2(test_fs->block_map,
426                                                       start, end, &out);
427         if (retval) {
428                 printf("ext2fs_find_first_zero_block_bitmap2() returned %s\n",
429                        error_message(retval));
430                 return;
431         }
432         printf("First unmarked block is %llu\n", out);
433 }
434
435 void do_ffsb(int argc, char *argv[])
436 {
437         unsigned int start, end;
438         int err;
439         errcode_t retval;
440         blk64_t out;
441
442         if (check_fs_open(argv[0]))
443                 return;
444
445         if (argc != 3 && argc != 3) {
446                 com_err(argv[0], 0, "Usage: ffsb <start> <end>");
447                 return;
448         }
449
450         start = parse_ulong(argv[1], argv[0], "start", &err);
451         if (err)
452                 return;
453
454         end = parse_ulong(argv[2], argv[0], "end", &err);
455         if (err)
456                 return;
457
458         retval = ext2fs_find_first_set_block_bitmap2(test_fs->block_map,
459                                                       start, end, &out);
460         if (retval) {
461                 printf("ext2fs_find_first_set_block_bitmap2() returned %s\n",
462                        error_message(retval));
463                 return;
464         }
465         printf("First marked block is %llu\n", out);
466 }
467
468
469 void do_zerob(int argc, char *argv[])
470 {
471         if (check_fs_open(argv[0]))
472                 return;
473
474         printf("Clearing block bitmap.\n");
475         ext2fs_clear_block_bitmap(test_fs->block_map);
476 }
477
478 void do_seti(int argc, char *argv[])
479 {
480         unsigned int inode;
481         int err;
482         int test_result, op_result;
483
484         if (check_fs_open(argv[0]))
485                 return;
486
487         if (argc != 2) {
488                 com_err(argv[0], 0, "Usage: seti <inode>");
489                 return;
490         }
491
492         inode = parse_ulong(argv[1], argv[0], "inode", &err);
493         if (err)
494                 return;
495
496         test_result = ext2fs_test_inode_bitmap2(test_fs->inode_map, inode);
497         op_result = ext2fs_mark_inode_bitmap2(test_fs->inode_map, inode);
498         printf("Setting inode %u, was %s before\n", inode, op_result ?
499                "set" : "clear");
500         if (!test_result != !op_result) {
501                 com_err(argv[0], 0, "*ERROR* test_result different! (%d, %d)",
502                         test_result, op_result);
503                 exit_status++;
504         }
505 }
506
507 void do_cleari(int argc, char *argv[])
508 {
509         unsigned int inode;
510         int err;
511         int test_result, op_result;
512
513         if (check_fs_open(argv[0]))
514                 return;
515
516         if (argc != 2) {
517                 com_err(argv[0], 0, "Usage: clearb <inode>");
518                 return;
519         }
520
521         inode = parse_ulong(argv[1], argv[0], "inode", &err);
522         if (err)
523                 return;
524
525         test_result = ext2fs_test_inode_bitmap2(test_fs->inode_map, inode);
526         op_result = ext2fs_unmark_inode_bitmap2(test_fs->inode_map, inode);
527         printf("Clearing inode %u, was %s before\n", inode, op_result ?
528                "set" : "clear");
529         if (!test_result != !op_result) {
530                 com_err(argv[0], 0, "*ERROR* test_result different! (%d, %d)",
531                         test_result, op_result);
532                 exit_status++;
533         }
534 }
535
536 void do_testi(int argc, char *argv[])
537 {
538         unsigned int inode;
539         int err;
540         int test_result;
541
542         if (check_fs_open(argv[0]))
543                 return;
544
545         if (argc != 2) {
546                 com_err(argv[0], 0, "Usage: testb <inode>");
547                 return;
548         }
549
550         inode = parse_ulong(argv[1], argv[0], "inode", &err);
551         if (err)
552                 return;
553
554         test_result = ext2fs_test_inode_bitmap2(test_fs->inode_map, inode);
555         printf("Inode %u is %s\n", inode, test_result ? "set" : "clear");
556 }
557
558 void do_ffzi(int argc, char *argv[])
559 {
560         unsigned int start, end;
561         int err;
562         errcode_t retval;
563         ext2_ino_t out;
564
565         if (check_fs_open(argv[0]))
566                 return;
567
568         if (argc != 3 && argc != 3) {
569                 com_err(argv[0], 0, "Usage: ffzi <start> <end>");
570                 return;
571         }
572
573         start = parse_ulong(argv[1], argv[0], "start", &err);
574         if (err)
575                 return;
576
577         end = parse_ulong(argv[2], argv[0], "end", &err);
578         if (err)
579                 return;
580
581         retval = ext2fs_find_first_zero_inode_bitmap2(test_fs->inode_map,
582                                                       start, end, &out);
583         if (retval) {
584                 printf("ext2fs_find_first_zero_inode_bitmap2() returned %s\n",
585                        error_message(retval));
586                 return;
587         }
588         printf("First unmarked inode is %u\n", out);
589 }
590
591 void do_ffsi(int argc, char *argv[])
592 {
593         unsigned int start, end;
594         int err;
595         errcode_t retval;
596         ext2_ino_t out;
597
598         if (check_fs_open(argv[0]))
599                 return;
600
601         if (argc != 3 && argc != 3) {
602                 com_err(argv[0], 0, "Usage: ffsi <start> <end>");
603                 return;
604         }
605
606         start = parse_ulong(argv[1], argv[0], "start", &err);
607         if (err)
608                 return;
609
610         end = parse_ulong(argv[2], argv[0], "end", &err);
611         if (err)
612                 return;
613
614         retval = ext2fs_find_first_set_inode_bitmap2(test_fs->inode_map,
615                                                      start, end, &out);
616         if (retval) {
617                 printf("ext2fs_find_first_set_inode_bitmap2() returned %s\n",
618                        error_message(retval));
619                 return;
620         }
621         printf("First marked inode is %u\n", out);
622 }
623
624 void do_zeroi(int argc, char *argv[])
625 {
626         if (check_fs_open(argv[0]))
627                 return;
628
629         printf("Clearing inode bitmap.\n");
630         ext2fs_clear_inode_bitmap(test_fs->inode_map);
631 }
632
633 int main(int argc, char **argv)
634 {
635         unsigned int    blocks = 128;
636         unsigned int    inodes = 0;
637         unsigned int    type = EXT2FS_BMAP64_BITARRAY;
638         int             c, err, code;
639         char            *request = (char *)NULL;
640         char            *cmd_file = 0;
641         int             sci_idx;
642         int             flags = EXT2_FLAG_64BITS;
643
644         add_error_table(&et_ss_error_table);
645         add_error_table(&et_ext2_error_table);
646         while ((c = getopt (argc, argv, "b:i:lt:R:f:")) != EOF) {
647                 switch (c) {
648                 case 'b':
649                         blocks = parse_ulong(optarg, argv[0],
650                                              "number of blocks", &err);
651                         if (err)
652                                 exit(1);
653                         break;
654                 case 'i':
655                         inodes = parse_ulong(optarg, argv[0],
656                                              "number of blocks", &err);
657                         if (err)
658                                 exit(1);
659                         break;
660                 case 'l':       /* Legacy bitmaps */
661                         flags = 0;
662                         break;
663                 case 't':
664                         type = parse_ulong(optarg, argv[0],
665                                            "bitmap backend type", &err);
666                         if (err)
667                                 exit(1);
668                         break;
669                 case 'R':
670                         request = optarg;
671                         break;
672                 case 'f':
673                         cmd_file = optarg;
674                         break;
675                 default:
676                         com_err(argv[0], 0, "Usage: %s [-R request] "
677                                 "[-f cmd_file]", subsystem_name);
678                         exit(1);
679                 }
680         }
681
682         sci_idx = ss_create_invocation(subsystem_name, version,
683                                        (char *)NULL, &tst_bitmaps_cmds, &code);
684         if (code) {
685                 ss_perror(sci_idx, code, "creating invocation");
686                 exit(1);
687         }
688
689         (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &code);
690         if (code) {
691                 ss_perror(sci_idx, code, "adding standard requests");
692                 exit (1);
693         }
694
695         printf("%s %s.  Type '?' for a list of commands.\n\n",
696                subsystem_name, version);
697
698         setup_filesystem(argv[0], blocks, inodes, type, flags);
699
700         if (request) {
701                 code = ss_execute_line(sci_idx, request);
702                 if (code) {
703                         ss_perror(sci_idx, code, request);
704                         exit_status++;
705                 }
706         } else if (cmd_file) {
707                 exit_status = source_file(cmd_file, sci_idx);
708         } else {
709                 ss_listen(sci_idx);
710         }
711
712         exit(exit_status);
713 }
714