1 /*
2 * test_rel.c
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12 #include "config.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #ifdef HAVE_GETOPT_H
18 #include <getopt.h>
19 #endif
20 #include <fcntl.h>
21
22 #include <et/com_err.h>
23 #include <ss/ss.h>
24 #include <ext2fs/ext2_fs.h>
25 #include <ext2fs/ext2fs.h>
26 #include <ext2fs/irel.h>
27 #include <ext2fs/brel.h>
28
29 #include "test_rel.h"
30
31 extern ss_request_table test_cmds;
32
33 ext2_irel irel = NULL;
34 ext2_brel brel = NULL;
35
36 /*
37 * Helper function which parses an inode number.
38 */
parse_inode(const char * request,const char * desc,const char * str,ext2_ino_t * ino)39 static int parse_inode(const char *request, const char *desc,
40 const char *str, ext2_ino_t *ino)
41 {
42 char *tmp;
43
44 *ino = strtoul(str, &tmp, 0);
45 if (*tmp) {
46 com_err(request, 0, "Bad %s - %s", desc, str);
47 return 1;
48 }
49 return 0;
50 }
51
52 /*
53 * Helper function which parses a block number.
54 */
parse_block(const char * request,const char * desc,const char * str,blk_t * blk)55 static int parse_block(const char *request, const char *desc,
56 const char *str, blk_t *blk)
57 {
58 char *tmp;
59
60 *blk = strtoul(str, &tmp, 0);
61 if (*tmp) {
62 com_err(request, 0, "Bad %s - %s", desc, str);
63 return 1;
64 }
65 return 0;
66 }
67
68 /*
69 * Helper function which assures that a brel table is open
70 */
check_brel(char * request)71 static int check_brel(char *request)
72 {
73 if (brel)
74 return 0;
75 com_err(request, 0, "A block relocation table must be open.");
76 return 1;
77 }
78
79 /*
80 * Helper function which assures that an irel table is open
81 */
check_irel(char * request)82 static int check_irel(char *request)
83 {
84 if (irel)
85 return 0;
86 com_err(request, 0, "An inode relocation table must be open.");
87 return 1;
88 }
89
90 /*
91 * Helper function which displays a brel entry
92 */
display_brel_entry(blk_t old,struct ext2_block_relocate_entry * ent)93 static void display_brel_entry(blk_t old,
94 struct ext2_block_relocate_entry *ent)
95 {
96 printf("Old= %u, New= %u, Owner= %u:%u\n", old, ent->new,
97 ent->owner.block_ref, ent->offset);
98 }
99
100 /*
101 * Helper function which displays an irel entry
102 */
display_irel_entry(ext2_ino_t old,struct ext2_inode_relocate_entry * ent,int do_refs)103 static void display_irel_entry(ext2_ino_t old,
104 struct ext2_inode_relocate_entry *ent,
105 int do_refs)
106 {
107 struct ext2_inode_reference ref;
108 errcode_t retval;
109 int first = 1;
110
111 printf("Old= %lu, New= %lu, Original=%lu, Max_refs=%u\n", old,
112 ent->new, ent->orig, ent->max_refs);
113 if (!do_refs)
114 return;
115
116 retval = ext2fs_irel_start_iter_ref(irel, old);
117 if (retval) {
118 printf("\tCouldn't get references: %s\n",
119 error_message(retval));
120 return;
121 }
122 while (1) {
123 retval = ext2fs_irel_next_ref(irel, &ref);
124 if (retval) {
125 printf("(%s) ", error_message(retval));
126 break;
127 }
128 if (ref.block == 0)
129 break;
130 if (first) {
131 fputc('\t', stdout);
132 first = 0;
133 } else
134 printf(", ");
135 printf("%u:%u", ref.block, ref.offset);
136 }
137 if (!first)
138 fputc('\n', stdout);
139 }
140
141 /*
142 * These are the actual command table procedures
143 */
do_brel_ma_create(int argc,char ** argv)144 void do_brel_ma_create(int argc, char **argv)
145 {
146 const char *usage = "Usage: %s name max_blocks\n";
147 errcode_t retval;
148 blk_t max_blk;
149
150 if (argc < 3) {
151 printf(usage, argv[0]);
152 return;
153 }
154 if (parse_block(argv[0], "max_blocks", argv[2], &max_blk))
155 return;
156 retval = ext2fs_brel_memarray_create(argv[1], max_blk, &brel);
157 if (retval) {
158 com_err(argv[0], retval, "while opening memarray brel");
159 return;
160 }
161 return;
162 }
163
do_brel_free(int argc,char ** argv)164 void do_brel_free(int argc, char **argv)
165 {
166 if (check_brel(argv[0]))
167 return;
168 ext2fs_brel_free(brel);
169 brel = NULL;
170 return;
171 }
172
do_brel_put(int argc,char ** argv)173 void do_brel_put(int argc, char **argv)
174 {
175 const char *usage = "usage: %s old_block new_block [owner] [offset]";
176 errcode_t retval;
177 struct ext2_block_relocate_entry ent;
178 blk_t old, new, offset=0, owner=0;
179
180 if (check_brel(argv[0]))
181 return;
182
183 if (argc < 3) {
184 printf(usage, argv[0]);
185 return;
186 }
187 if (parse_block(argv[0], "old block", argv[1], &old))
188 return;
189 if (parse_block(argv[0], "new block", argv[2], &new))
190 return;
191 if (argc > 3 &&
192 parse_block(argv[0], "owner block", argv[3], &owner))
193 return;
194 if (argc > 4 &&
195 parse_block(argv[0], "offset", argv[4], &offset))
196 return;
197 if (offset > 65535) {
198 printf("Offset too large.\n");
199 return;
200 }
201 ent.new = new;
202 ent.offset = (__u16) offset;
203 ent.flags = 0;
204 ent.owner.block_ref = owner;
205
206 retval = ext2fs_brel_put(brel, old, &ent);
207 if (retval) {
208 com_err(argv[0], retval, "while calling ext2fs_brel_put");
209 return;
210 }
211 return;
212 }
213
do_brel_get(int argc,char ** argv)214 void do_brel_get(int argc, char **argv)
215 {
216 const char *usage = "%s block";
217 errcode_t retval;
218 struct ext2_block_relocate_entry ent;
219 blk_t blk;
220
221 if (check_brel(argv[0]))
222 return;
223 if (argc < 2) {
224 printf(usage, argv[0]);
225 return;
226 }
227 if (parse_block(argv[0], "block", argv[1], &blk))
228 return;
229 retval = ext2fs_brel_get(brel, blk, &ent);
230 if (retval) {
231 com_err(argv[0], retval, "while calling ext2fs_brel_get");
232 return;
233 }
234 display_brel_entry(blk, &ent);
235 return;
236 }
237
do_brel_start_iter(int argc,char ** argv)238 void do_brel_start_iter(int argc, char **argv)
239 {
240 errcode_t retval;
241
242 if (check_brel(argv[0]))
243 return;
244
245 retval = ext2fs_brel_start_iter(brel);
246 if (retval) {
247 com_err(argv[0], retval, "while calling ext2fs_brel_start_iter");
248 return;
249 }
250 return;
251 }
252
do_brel_next(int argc,char ** argv)253 void do_brel_next(int argc, char **argv)
254 {
255 errcode_t retval;
256 struct ext2_block_relocate_entry ent;
257 blk_t blk;
258
259 if (check_brel(argv[0]))
260 return;
261
262 retval = ext2fs_brel_next(brel, &blk, &ent);
263 if (retval) {
264 com_err(argv[0], retval, "while calling ext2fs_brel_next");
265 return;
266 }
267 if (blk == 0) {
268 printf("No more entries!\n");
269 return;
270 }
271 display_brel_entry(blk, &ent);
272 return;
273 }
274
do_brel_dump(int argc,char ** argv)275 void do_brel_dump(int argc, char **argv)
276 {
277 errcode_t retval;
278 struct ext2_block_relocate_entry ent;
279 blk_t blk;
280
281 if (check_brel(argv[0]))
282 return;
283
284 retval = ext2fs_brel_start_iter(brel);
285 if (retval) {
286 com_err(argv[0], retval, "while calling ext2fs_brel_start_iter");
287 return;
288 }
289
290 while (1) {
291 retval = ext2fs_brel_next(brel, &blk, &ent);
292 if (retval) {
293 com_err(argv[0], retval, "while calling ext2fs_brel_next");
294 return;
295 }
296 if (blk == 0)
297 break;
298
299 display_brel_entry(blk, &ent);
300 }
301 return;
302 }
303
do_brel_move(int argc,char ** argv)304 void do_brel_move(int argc, char **argv)
305 {
306 const char *usage = "%s old_block new_block";
307 errcode_t retval;
308 blk_t old, new;
309
310 if (check_brel(argv[0]))
311 return;
312 if (argc < 2) {
313 printf(usage, argv[0]);
314 return;
315 }
316 if (parse_block(argv[0], "old block", argv[1], &old))
317 return;
318 if (parse_block(argv[0], "new block", argv[2], &new))
319 return;
320
321 retval = ext2fs_brel_move(brel, old, new);
322 if (retval) {
323 com_err(argv[0], retval, "while calling ext2fs_brel_move");
324 return;
325 }
326 return;
327 }
328
do_brel_delete(int argc,char ** argv)329 void do_brel_delete(int argc, char **argv)
330 {
331 const char *usage = "%s block";
332 errcode_t retval;
333 blk_t blk;
334
335 if (check_brel(argv[0]))
336 return;
337 if (argc < 2) {
338 printf(usage, argv[0]);
339 return;
340 }
341 if (parse_block(argv[0], "block", argv[1], &blk))
342 return;
343
344 retval = ext2fs_brel_delete(brel, blk);
345 if (retval) {
346 com_err(argv[0], retval, "while calling ext2fs_brel_delete");
347 return;
348 }
349 }
350
do_irel_ma_create(int argc,char ** argv)351 void do_irel_ma_create(int argc, char **argv)
352 {
353 const char *usage = "Usage: %s name max_inode\n";
354 errcode_t retval;
355 ext2_ino_t max_ino;
356
357 if (argc < 3) {
358 printf(usage, argv[0]);
359 return;
360 }
361 if (parse_inode(argv[0], "max_inodes", argv[2], &max_ino))
362 return;
363 retval = ext2fs_irel_memarray_create(argv[1], max_ino, &irel);
364 if (retval) {
365 com_err(argv[0], retval, "while opening memarray irel");
366 return;
367 }
368 return;
369 }
370
do_irel_free(int argc,char ** argv)371 void do_irel_free(int argc, char **argv)
372 {
373 if (check_irel(argv[0]))
374 return;
375
376 ext2fs_irel_free(irel);
377 irel = NULL;
378 return;
379 }
380
do_irel_put(int argc,char ** argv)381 void do_irel_put(int argc, char **argv)
382 {
383 const char *usage = "%s old new max_refs";
384 errcode_t retval;
385 ext2_ino_t old, new, max_refs;
386 struct ext2_inode_relocate_entry ent;
387
388 if (check_irel(argv[0]))
389 return;
390
391 if (argc < 4) {
392 printf(usage, argv[0]);
393 return;
394 }
395 if (parse_inode(argv[0], "old inode", argv[1], &old))
396 return;
397 if (parse_inode(argv[0], "new inode", argv[2], &new))
398 return;
399 if (parse_inode(argv[0], "max_refs", argv[3], &max_refs))
400 return;
401 if (max_refs > 65535) {
402 printf("max_refs too big\n");
403 return;
404 }
405 ent.new = new;
406 ent.max_refs = (__u16) max_refs;
407 ent.flags = 0;
408
409 retval = ext2fs_irel_put(irel, old, &ent);
410 if (retval) {
411 com_err(argv[0], retval, "while calling ext2fs_irel_put");
412 return;
413 }
414 return;
415 }
416
do_irel_get(int argc,char ** argv)417 void do_irel_get(int argc, char **argv)
418 {
419 const char *usage = "%s inode";
420 errcode_t retval;
421 ext2_ino_t old;
422 struct ext2_inode_relocate_entry ent;
423
424 if (check_irel(argv[0]))
425 return;
426
427 if (argc < 2) {
428 printf(usage, argv[0]);
429 return;
430 }
431 if (parse_inode(argv[0], "inode", argv[1], &old))
432 return;
433
434 retval = ext2fs_irel_get(irel, old, &ent);
435 if (retval) {
436 com_err(argv[0], retval, "while calling ext2fs_irel_get");
437 return;
438 }
439 display_irel_entry(old, &ent, 1);
440 return;
441 }
442
do_irel_get_by_orig(int argc,char ** argv)443 void do_irel_get_by_orig(int argc, char **argv)
444 {
445 const char *usage = "%s orig_inode";
446 errcode_t retval;
447 ext2_ino_t orig, old;
448 struct ext2_inode_relocate_entry ent;
449
450 if (check_irel(argv[0]))
451 return;
452
453 if (argc < 2) {
454 printf(usage, argv[0]);
455 return;
456 }
457 if (parse_inode(argv[0], "original inode", argv[1], &orig))
458 return;
459
460 retval = ext2fs_irel_get_by_orig(irel, orig, &old, &ent);
461 if (retval) {
462 com_err(argv[0], retval, "while calling ext2fs_irel_get_by_orig");
463 return;
464 }
465 display_irel_entry(old, &ent, 1);
466 return;
467 }
468
do_irel_start_iter(int argc,char ** argv)469 void do_irel_start_iter(int argc, char **argv)
470 {
471 errcode_t retval;
472
473 if (check_irel(argv[0]))
474 return;
475
476 retval = ext2fs_irel_start_iter(irel);
477 if (retval) {
478 com_err(argv[0], retval, "while calling ext2fs_irel_start_iter");
479 return;
480 }
481 return;
482 }
483
do_irel_next(int argc,char ** argv)484 void do_irel_next(int argc, char **argv)
485 {
486 errcode_t retval;
487 ext2_ino_t old;
488 struct ext2_inode_relocate_entry ent;
489
490 if (check_irel(argv[0]))
491 return;
492
493 retval = ext2fs_irel_next(irel, &old, &ent);
494 if (retval) {
495 com_err(argv[0], retval, "while calling ext2fs_irel_next");
496 return;
497 }
498 if (old == 0) {
499 printf("No more entries!\n");
500 return;
501 }
502 display_irel_entry(old, &ent, 1);
503 return;
504 }
505
do_irel_dump(int argc,char ** argv)506 void do_irel_dump(int argc, char **argv)
507 {
508 errcode_t retval;
509 ext2_ino_t ino;
510 struct ext2_inode_relocate_entry ent;
511
512 if (check_irel(argv[0]))
513 return;
514
515 retval = ext2fs_irel_start_iter(irel);
516 if (retval) {
517 com_err(argv[0], retval, "while calling ext2fs_irel_start_iter");
518 return;
519 }
520
521 while (1) {
522 retval = ext2fs_irel_next(irel, &ino, &ent);
523 if (retval) {
524 com_err(argv[0], retval, "while calling ext2fs_irel_next");
525 return;
526 }
527 if (ino == 0)
528 break;
529
530 display_irel_entry(ino, &ent, 1);
531 }
532 return;
533 }
534
do_irel_add_ref(int argc,char ** argv)535 void do_irel_add_ref(int argc, char **argv)
536 {
537 const char *usage = "%s inode block offset";
538 errcode_t retval;
539 blk_t block, offset;
540 ext2_ino_t ino;
541 struct ext2_inode_reference ref;
542
543
544 if (check_irel(argv[0]))
545 return;
546
547 if (argc < 4) {
548 printf(usage, argv[0]);
549 return;
550 }
551 if (parse_inode(argv[0], "inode", argv[1], &ino))
552 return;
553 if (parse_block(argv[0], "block", argv[2], &block))
554 return;
555 if (parse_block(argv[0], "offset", argv[3], &offset))
556 return;
557 if (offset > 65535) {
558 printf("Offset too big.\n");
559 return;
560 }
561 ref.block = block;
562 ref.offset = offset;
563
564 retval = ext2fs_irel_add_ref(irel, ino, &ref);
565 if (retval) {
566 com_err(argv[0], retval, "while calling ext2fs_irel_add_ref");
567 return;
568 }
569 return;
570 }
571
do_irel_start_iter_ref(int argc,char ** argv)572 void do_irel_start_iter_ref(int argc, char **argv)
573 {
574 const char *usage = "%s inode";
575 errcode_t retval;
576 ext2_ino_t ino;
577
578 if (check_irel(argv[0]))
579 return;
580
581 if (argc < 2) {
582 printf(usage, argv[0]);
583 return;
584 }
585
586 if (parse_inode(argv[0], "inode", argv[1], &ino))
587 return;
588 retval = ext2fs_irel_start_iter_ref(irel, ino);
589 if (retval) {
590 com_err(argv[0], retval, "while calling ext2fs_irel_start_iter_ref");
591 return;
592 }
593 return;
594 }
595
do_irel_next_ref(int argc,char ** argv)596 void do_irel_next_ref(int argc, char **argv)
597 {
598 struct ext2_inode_reference ref;
599 errcode_t retval;
600
601 if (check_irel(argv[0]))
602 return;
603
604 retval = ext2fs_irel_next_ref(irel, &ref);
605 if (retval) {
606 com_err(argv[0], retval, "while calling ext2fs_irel_next_ref");
607 return;
608 }
609 printf("Inode reference: %u:%u\n", ref.block, ref.offset);
610 return;
611 }
612
do_irel_move(int argc,char ** argv)613 void do_irel_move(int argc, char **argv)
614 {
615 const char *usage = "%s old new";
616 errcode_t retval;
617 ext2_ino_t old, new;
618
619 if (check_irel(argv[0]))
620 return;
621
622 if (argc < 3) {
623 printf(usage, argv[0]);
624 return;
625 }
626 if (parse_inode(argv[0], "old inode", argv[1], &old))
627 return;
628 if (parse_inode(argv[0], "new inode", argv[2], &new))
629 return;
630
631 retval = ext2fs_irel_move(irel, old, new);
632 if (retval) {
633 com_err(argv[0], retval, "while calling ext2fs_irel_move");
634 return;
635 }
636 return;
637 }
638
do_irel_delete(int argc,char ** argv)639 void do_irel_delete(int argc, char **argv)
640 {
641 const char *usage = "%s inode";
642 errcode_t retval;
643 ext2_ino_t ino;
644
645 if (check_irel(argv[0]))
646 return;
647
648 if (argc < 2) {
649 printf(usage, argv[0]);
650 return;
651 }
652 if (parse_inode(argv[0], "inode", argv[1], &ino))
653 return;
654
655 retval = ext2fs_irel_delete(irel, ino);
656 if (retval) {
657 com_err(argv[0], retval, "while calling ext2fs_irel_delete");
658 return;
659 }
660 return;
661 }
662
source_file(const char * cmd_file,int sci_idx)663 static int source_file(const char *cmd_file, int sci_idx)
664 {
665 FILE *f;
666 char buf[256];
667 char *cp;
668 int exit_status = 0;
669 int retval;
670 int noecho;
671
672 if (strcmp(cmd_file, "-") == 0)
673 f = stdin;
674 else {
675 f = fopen(cmd_file, "r");
676 if (!f) {
677 perror(cmd_file);
678 exit(1);
679 }
680 }
681 fflush(stdout);
682 fflush(stderr);
683 setbuf(stdout, NULL);
684 setbuf(stderr, NULL);
685 while (!feof(f)) {
686 if (fgets(buf, sizeof(buf), f) == NULL)
687 break;
688 if (buf[0] == '#')
689 continue;
690 noecho = 0;
691 if (buf[0] == '-') {
692 noecho = 1;
693 buf[0] = ' ';
694 }
695 cp = strchr(buf, '\n');
696 if (cp)
697 *cp = 0;
698 cp = strchr(buf, '\r');
699 if (cp)
700 *cp = 0;
701 if (!noecho)
702 printf("test_rel: %s\n", buf);
703 retval = ss_execute_line(sci_idx, buf);
704 if (retval) {
705 ss_perror(sci_idx, retval, buf);
706 exit_status++;
707 }
708 }
709 return exit_status;
710 }
711
main(int argc,char ** argv)712 void main(int argc, char **argv)
713 {
714 int retval;
715 int sci_idx;
716 const char *usage = "Usage: test_rel [-R request] [-f cmd_file]";
717 int c;
718 char *request = 0;
719 int exit_status = 0;
720 char *cmd_file = 0;
721
722 initialize_ext2_error_table();
723
724 while ((c = getopt (argc, argv, "wR:f:")) != EOF) {
725 switch (c) {
726 case 'R':
727 request = optarg;
728 break;
729 case 'f':
730 cmd_file = optarg;
731 break;
732 default:
733 com_err(argv[0], 0, usage);
734 return;
735 }
736 }
737 sci_idx = ss_create_invocation("test_rel", "0.0", (char *) NULL,
738 &test_cmds, &retval);
739 if (retval) {
740 ss_perror(sci_idx, retval, "creating invocation");
741 exit(1);
742 }
743
744 (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval);
745 if (retval) {
746 ss_perror(sci_idx, retval, "adding standard requests");
747 exit (1);
748 }
749 if (request) {
750 retval = 0;
751 retval = ss_execute_line(sci_idx, request);
752 if (retval) {
753 ss_perror(sci_idx, retval, request);
754 exit_status++;
755 }
756 } else if (cmd_file) {
757 exit_status = source_file(cmd_file, sci_idx);
758 } else {
759 ss_listen(sci_idx);
760 }
761
762 exit(exit_status);
763 }
764
765