/* * test_rel.c * * Copyright (C) 1997 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU Public * License. * %End-Header% */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #ifdef HAVE_GETOPT_H #include <getopt.h> #endif #include <fcntl.h> #include <et/com_err.h> #include <ss/ss.h> #include <ext2fs/ext2_fs.h> #include <ext2fs/ext2fs.h> #include <ext2fs/irel.h> #include <ext2fs/brel.h> #include "test_rel.h" extern ss_request_table test_cmds; ext2_irel irel = NULL; ext2_brel brel = NULL; /* * Helper function which parses an inode number. */ static int parse_inode(const char *request, const char *desc, const char *str, ext2_ino_t *ino) { char *tmp; *ino = strtoul(str, &tmp, 0); if (*tmp) { com_err(request, 0, "Bad %s - %s", desc, str); return 1; } return 0; } /* * Helper function which parses a block number. */ static int parse_block(const char *request, const char *desc, const char *str, blk_t *blk) { char *tmp; *blk = strtoul(str, &tmp, 0); if (*tmp) { com_err(request, 0, "Bad %s - %s", desc, str); return 1; } return 0; } /* * Helper function which assures that a brel table is open */ static int check_brel(char *request) { if (brel) return 0; com_err(request, 0, "A block relocation table must be open."); return 1; } /* * Helper function which assures that an irel table is open */ static int check_irel(char *request) { if (irel) return 0; com_err(request, 0, "An inode relocation table must be open."); return 1; } /* * Helper function which displays a brel entry */ static void display_brel_entry(blk_t old, struct ext2_block_relocate_entry *ent) { printf("Old= %u, New= %u, Owner= %u:%u\n", old, ent->new, ent->owner.block_ref, ent->offset); } /* * Helper function which displays an irel entry */ static void display_irel_entry(ext2_ino_t old, struct ext2_inode_relocate_entry *ent, int do_refs) { struct ext2_inode_reference ref; errcode_t retval; int first = 1; printf("Old= %lu, New= %lu, Original=%lu, Max_refs=%u\n", old, ent->new, ent->orig, ent->max_refs); if (!do_refs) return; retval = ext2fs_irel_start_iter_ref(irel, old); if (retval) { printf("\tCouldn't get references: %s\n", error_message(retval)); return; } while (1) { retval = ext2fs_irel_next_ref(irel, &ref); if (retval) { printf("(%s) ", error_message(retval)); break; } if (ref.block == 0) break; if (first) { fputc('\t', stdout); first = 0; } else printf(", "); printf("%u:%u", ref.block, ref.offset); } if (!first) fputc('\n', stdout); } /* * These are the actual command table procedures */ void do_brel_ma_create(int argc, char **argv) { const char *usage = "Usage: %s name max_blocks\n"; errcode_t retval; blk_t max_blk; if (argc < 3) { printf(usage, argv[0]); return; } if (parse_block(argv[0], "max_blocks", argv[2], &max_blk)) return; retval = ext2fs_brel_memarray_create(argv[1], max_blk, &brel); if (retval) { com_err(argv[0], retval, "while opening memarray brel"); return; } return; } void do_brel_free(int argc, char **argv) { if (check_brel(argv[0])) return; ext2fs_brel_free(brel); brel = NULL; return; } void do_brel_put(int argc, char **argv) { const char *usage = "usage: %s old_block new_block [owner] [offset]"; errcode_t retval; struct ext2_block_relocate_entry ent; blk_t old, new, offset=0, owner=0; if (check_brel(argv[0])) return; if (argc < 3) { printf(usage, argv[0]); return; } if (parse_block(argv[0], "old block", argv[1], &old)) return; if (parse_block(argv[0], "new block", argv[2], &new)) return; if (argc > 3 && parse_block(argv[0], "owner block", argv[3], &owner)) return; if (argc > 4 && parse_block(argv[0], "offset", argv[4], &offset)) return; if (offset > 65535) { printf("Offset too large.\n"); return; } ent.new = new; ent.offset = (__u16) offset; ent.flags = 0; ent.owner.block_ref = owner; retval = ext2fs_brel_put(brel, old, &ent); if (retval) { com_err(argv[0], retval, "while calling ext2fs_brel_put"); return; } return; } void do_brel_get(int argc, char **argv) { const char *usage = "%s block"; errcode_t retval; struct ext2_block_relocate_entry ent; blk_t blk; if (check_brel(argv[0])) return; if (argc < 2) { printf(usage, argv[0]); return; } if (parse_block(argv[0], "block", argv[1], &blk)) return; retval = ext2fs_brel_get(brel, blk, &ent); if (retval) { com_err(argv[0], retval, "while calling ext2fs_brel_get"); return; } display_brel_entry(blk, &ent); return; } void do_brel_start_iter(int argc, char **argv) { errcode_t retval; if (check_brel(argv[0])) return; retval = ext2fs_brel_start_iter(brel); if (retval) { com_err(argv[0], retval, "while calling ext2fs_brel_start_iter"); return; } return; } void do_brel_next(int argc, char **argv) { errcode_t retval; struct ext2_block_relocate_entry ent; blk_t blk; if (check_brel(argv[0])) return; retval = ext2fs_brel_next(brel, &blk, &ent); if (retval) { com_err(argv[0], retval, "while calling ext2fs_brel_next"); return; } if (blk == 0) { printf("No more entries!\n"); return; } display_brel_entry(blk, &ent); return; } void do_brel_dump(int argc, char **argv) { errcode_t retval; struct ext2_block_relocate_entry ent; blk_t blk; if (check_brel(argv[0])) return; retval = ext2fs_brel_start_iter(brel); if (retval) { com_err(argv[0], retval, "while calling ext2fs_brel_start_iter"); return; } while (1) { retval = ext2fs_brel_next(brel, &blk, &ent); if (retval) { com_err(argv[0], retval, "while calling ext2fs_brel_next"); return; } if (blk == 0) break; display_brel_entry(blk, &ent); } return; } void do_brel_move(int argc, char **argv) { const char *usage = "%s old_block new_block"; errcode_t retval; blk_t old, new; if (check_brel(argv[0])) return; if (argc < 2) { printf(usage, argv[0]); return; } if (parse_block(argv[0], "old block", argv[1], &old)) return; if (parse_block(argv[0], "new block", argv[2], &new)) return; retval = ext2fs_brel_move(brel, old, new); if (retval) { com_err(argv[0], retval, "while calling ext2fs_brel_move"); return; } return; } void do_brel_delete(int argc, char **argv) { const char *usage = "%s block"; errcode_t retval; blk_t blk; if (check_brel(argv[0])) return; if (argc < 2) { printf(usage, argv[0]); return; } if (parse_block(argv[0], "block", argv[1], &blk)) return; retval = ext2fs_brel_delete(brel, blk); if (retval) { com_err(argv[0], retval, "while calling ext2fs_brel_delete"); return; } } void do_irel_ma_create(int argc, char **argv) { const char *usage = "Usage: %s name max_inode\n"; errcode_t retval; ext2_ino_t max_ino; if (argc < 3) { printf(usage, argv[0]); return; } if (parse_inode(argv[0], "max_inodes", argv[2], &max_ino)) return; retval = ext2fs_irel_memarray_create(argv[1], max_ino, &irel); if (retval) { com_err(argv[0], retval, "while opening memarray irel"); return; } return; } void do_irel_free(int argc, char **argv) { if (check_irel(argv[0])) return; ext2fs_irel_free(irel); irel = NULL; return; } void do_irel_put(int argc, char **argv) { const char *usage = "%s old new max_refs"; errcode_t retval; ext2_ino_t old, new, max_refs; struct ext2_inode_relocate_entry ent; if (check_irel(argv[0])) return; if (argc < 4) { printf(usage, argv[0]); return; } if (parse_inode(argv[0], "old inode", argv[1], &old)) return; if (parse_inode(argv[0], "new inode", argv[2], &new)) return; if (parse_inode(argv[0], "max_refs", argv[3], &max_refs)) return; if (max_refs > 65535) { printf("max_refs too big\n"); return; } ent.new = new; ent.max_refs = (__u16) max_refs; ent.flags = 0; retval = ext2fs_irel_put(irel, old, &ent); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_put"); return; } return; } void do_irel_get(int argc, char **argv) { const char *usage = "%s inode"; errcode_t retval; ext2_ino_t old; struct ext2_inode_relocate_entry ent; if (check_irel(argv[0])) return; if (argc < 2) { printf(usage, argv[0]); return; } if (parse_inode(argv[0], "inode", argv[1], &old)) return; retval = ext2fs_irel_get(irel, old, &ent); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_get"); return; } display_irel_entry(old, &ent, 1); return; } void do_irel_get_by_orig(int argc, char **argv) { const char *usage = "%s orig_inode"; errcode_t retval; ext2_ino_t orig, old; struct ext2_inode_relocate_entry ent; if (check_irel(argv[0])) return; if (argc < 2) { printf(usage, argv[0]); return; } if (parse_inode(argv[0], "original inode", argv[1], &orig)) return; retval = ext2fs_irel_get_by_orig(irel, orig, &old, &ent); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_get_by_orig"); return; } display_irel_entry(old, &ent, 1); return; } void do_irel_start_iter(int argc, char **argv) { errcode_t retval; if (check_irel(argv[0])) return; retval = ext2fs_irel_start_iter(irel); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_start_iter"); return; } return; } void do_irel_next(int argc, char **argv) { errcode_t retval; ext2_ino_t old; struct ext2_inode_relocate_entry ent; if (check_irel(argv[0])) return; retval = ext2fs_irel_next(irel, &old, &ent); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_next"); return; } if (old == 0) { printf("No more entries!\n"); return; } display_irel_entry(old, &ent, 1); return; } void do_irel_dump(int argc, char **argv) { errcode_t retval; ext2_ino_t ino; struct ext2_inode_relocate_entry ent; if (check_irel(argv[0])) return; retval = ext2fs_irel_start_iter(irel); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_start_iter"); return; } while (1) { retval = ext2fs_irel_next(irel, &ino, &ent); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_next"); return; } if (ino == 0) break; display_irel_entry(ino, &ent, 1); } return; } void do_irel_add_ref(int argc, char **argv) { const char *usage = "%s inode block offset"; errcode_t retval; blk_t block, offset; ext2_ino_t ino; struct ext2_inode_reference ref; if (check_irel(argv[0])) return; if (argc < 4) { printf(usage, argv[0]); return; } if (parse_inode(argv[0], "inode", argv[1], &ino)) return; if (parse_block(argv[0], "block", argv[2], &block)) return; if (parse_block(argv[0], "offset", argv[3], &offset)) return; if (offset > 65535) { printf("Offset too big.\n"); return; } ref.block = block; ref.offset = offset; retval = ext2fs_irel_add_ref(irel, ino, &ref); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_add_ref"); return; } return; } void do_irel_start_iter_ref(int argc, char **argv) { const char *usage = "%s inode"; errcode_t retval; ext2_ino_t ino; if (check_irel(argv[0])) return; if (argc < 2) { printf(usage, argv[0]); return; } if (parse_inode(argv[0], "inode", argv[1], &ino)) return; retval = ext2fs_irel_start_iter_ref(irel, ino); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_start_iter_ref"); return; } return; } void do_irel_next_ref(int argc, char **argv) { struct ext2_inode_reference ref; errcode_t retval; if (check_irel(argv[0])) return; retval = ext2fs_irel_next_ref(irel, &ref); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_next_ref"); return; } printf("Inode reference: %u:%u\n", ref.block, ref.offset); return; } void do_irel_move(int argc, char **argv) { const char *usage = "%s old new"; errcode_t retval; ext2_ino_t old, new; if (check_irel(argv[0])) return; if (argc < 3) { printf(usage, argv[0]); return; } if (parse_inode(argv[0], "old inode", argv[1], &old)) return; if (parse_inode(argv[0], "new inode", argv[2], &new)) return; retval = ext2fs_irel_move(irel, old, new); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_move"); return; } return; } void do_irel_delete(int argc, char **argv) { const char *usage = "%s inode"; errcode_t retval; ext2_ino_t ino; if (check_irel(argv[0])) return; if (argc < 2) { printf(usage, argv[0]); return; } if (parse_inode(argv[0], "inode", argv[1], &ino)) return; retval = ext2fs_irel_delete(irel, ino); if (retval) { com_err(argv[0], retval, "while calling ext2fs_irel_delete"); return; } return; } static int source_file(const char *cmd_file, int sci_idx) { FILE *f; char buf[256]; char *cp; int exit_status = 0; int retval; int noecho; if (strcmp(cmd_file, "-") == 0) f = stdin; else { f = fopen(cmd_file, "r"); if (!f) { perror(cmd_file); exit(1); } } setbuf(stdout, NULL); setbuf(stderr, NULL); while (!feof(f)) { if (fgets(buf, sizeof(buf), f) == NULL) break; if (buf[0] == '#') continue; noecho = 0; if (buf[0] == '-') { noecho = 1; buf[0] = ' '; } cp = strchr(buf, '\n'); if (cp) *cp = 0; cp = strchr(buf, '\r'); if (cp) *cp = 0; if (!noecho) printf("test_rel: %s\n", buf); retval = ss_execute_line(sci_idx, buf); if (retval) { ss_perror(sci_idx, retval, buf); exit_status++; } } return exit_status; } void main(int argc, char **argv) { int retval; int sci_idx; const char *usage = "Usage: test_rel [-R request] [-f cmd_file]"; char c; char *request = 0; int exit_status = 0; char *cmd_file = 0; initialize_ext2_error_table(); while ((c = getopt (argc, argv, "wR:f:")) != EOF) { switch (c) { case 'R': request = optarg; break; case 'f': cmd_file = optarg; break; default: com_err(argv[0], 0, usage); return; } } sci_idx = ss_create_invocation("test_rel", "0.0", (char *) NULL, &test_cmds, &retval); if (retval) { ss_perror(sci_idx, retval, "creating invocation"); exit(1); } (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval); if (retval) { ss_perror(sci_idx, retval, "adding standard requests"); exit (1); } if (request) { retval = 0; retval = ss_execute_line(sci_idx, request); if (retval) { ss_perror(sci_idx, retval, request); exit_status++; } } else if (cmd_file) { exit_status = source_file(cmd_file, sci_idx); } else { ss_listen(sci_idx); } exit(exit_status); }