#include "clusterautoconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "copyright.cf" #include "hexedit.h" #include "libgfs2.h" #include "gfs2hex.h" #include "extended.h" #include "journal.h" const char *mtypes[] = {"none", "sb", "rg", "rb", "di", "in", "lf", "jd", "lh", "ld", "ea", "ed", "lb", "13", "qc"}; const char *allocdesc[2][5] = { {"Free ", "Data ", "Unlnk", "Meta ", "Resrv"}, {"Free ", "Data ", "FreeM", "Meta ", "Resrv"},}; struct gfs2_buffer_head *bh; struct gfs2_rgrp *lrgrp; struct gfs2_meta_header *lmh; struct gfs2_dinode *ldi; struct gfs2_leaf *lleaf; struct gfs2_log_header *llh; struct gfs2_log_descriptor *lld; int pgnum; int details = 0; long int gziplevel = 9; static int termcols; char *device = NULL; extern uint64_t block; /* ------------------------------------------------------------------------- */ /* erase - clear the screen */ /* ------------------------------------------------------------------------- */ static void Erase(void) { bkgd(A_NORMAL|COLOR_PAIR(COLOR_NORMAL)); /* clear();*/ /* doesn't set background correctly */ erase(); /*bkgd(bg);*/ } /* ------------------------------------------------------------------------- */ /* display_title_lines */ /* ------------------------------------------------------------------------- */ static void display_title_lines(void) { Erase(); COLORS_TITLE; move(0, 0); printw("%-80s",TITLE1); move(termlines, 0); printw("%-79s",TITLE2); COLORS_NORMAL; } /* ------------------------------------------------------------------------- */ /* bobgets - get a string */ /* returns: 1 if user exited by hitting enter */ /* 0 if user exited by hitting escape */ /* ------------------------------------------------------------------------- */ static int bobgets(char string[],int x,int y,int sz,int *ch) { int done,runningy,rc; move(x,y); done=FALSE; COLORS_INVERSE; move(x,y); addstr(string); move(x,y); curs_set(2); refresh(); runningy=y; rc=0; while (!done) { *ch = getch(); if(*ch < 0x0100 && isprint(*ch)) { char *p=string+strlen(string); // end of the string *(p+1)='\0'; while (insert && p > &string[runningy-y]) { *p=*(p-1); p--; } string[runningy-y]=*ch; runningy++; move(x,y); addstr(string); if (runningy-y >= sz) { rc=1; *ch = KEY_RIGHT; done = TRUE; } } else { // special character, is it one we recognize? switch(*ch) { case(KEY_ENTER): case('\n'): case('\r'): rc=1; done=TRUE; string[runningy-y] = '\0'; break; case(KEY_CANCEL): case(0x01B): rc=0; done=TRUE; break; case(KEY_LEFT): if (dmode == HEX_MODE) { done = TRUE; rc = 1; } else runningy--; break; case(KEY_RIGHT): if (dmode == HEX_MODE) { done = TRUE; rc = 1; } else runningy++; break; case(KEY_DC): case(0x07F): if (runningy>=y) { char *p; p = &string[runningy - y]; while (*p) { *p = *(p + 1); p++; } *p = '\0'; runningy--; // remove the character from the string move(x,y); addstr(string); COLORS_NORMAL; addstr(" "); COLORS_INVERSE; runningy++; } break; case(KEY_BACKSPACE): if (runningy>y) { char *p; p = &string[runningy - y - 1]; while (*p) { *p = *(p + 1); p++; } *p='\0'; runningy--; // remove the character from the string move(x,y); addstr(string); COLORS_NORMAL; addstr(" "); COLORS_INVERSE; } break; case KEY_DOWN: // Down rc=0x5000U; done=TRUE; break; case KEY_UP: // Up rc=0x4800U; done=TRUE; break; case 0x014b: insert=!insert; move(0,68); if (insert) printw("insert "); else printw("replace"); break; default: move(0,70); printw("%08x",*ch); // ignore all other characters break; } // end switch on non-printable character } // end non-printable character move(x,runningy); refresh(); } // while !done if (sz>0) string[sz]='\0'; COLORS_NORMAL; return rc; }/* bobgets */ /****************************************************************************** ** instr - instructions ******************************************************************************/ static void gfs2instr(const char *s1, const char *s2) { COLORS_HIGHLIGHT; move(line,0); printw(s1); COLORS_NORMAL; move(line,17); printw(s2); line++; } /****************************************************************************** ******************************************************************************* ** ** void print_usage() ** ** Description: ** This routine prints out the appropriate commands for this application. ** ******************************************************************************* ******************************************************************************/ static void print_usage(void) { int ch; line = 2; Erase(); display_title_lines(); move(line++,0); printw("Supported commands: (roughly conforming to the rules of 'less')"); line++; move(line++,0); printw("Navigation:"); gfs2instr("/","Move up or down one screen full"); gfs2instr("/","Move up or down one line"); gfs2instr("/","Move left or right one byte"); gfs2instr("","Return to the superblock."); gfs2instr(" f","Forward one 4K block"); gfs2instr(" b","Backward one 4K block"); gfs2instr(" g","Goto a given block (number, master, root, rindex, jindex, etc)"); gfs2instr(" j","Jump to the highlighted 64-bit block number."); gfs2instr(" ","(You may also arrow up to the block number and hit enter)"); gfs2instr("","Return to a previous block (a block stack is kept)"); gfs2instr("","Jump forward to block before backspace (opposite of backspace)"); line++; move(line++, 0); printw("Other commands:"); gfs2instr(" h","This Help display"); gfs2instr(" c","Toggle the color scheme"); gfs2instr(" m","Switch display mode: hex -> GFS2 structure -> Extended"); gfs2instr(" q","Quit (same as hitting key)"); gfs2instr("","Edit a value (enter to save, esc to discard)"); gfs2instr(" ","(Currently only works on the hex display)"); gfs2instr("","Quit the program"); line++; move(line++, 0); printw("Notes: Areas shown in red are outside the bounds of the struct/file."); move(line++, 0); printw(" Areas shown in blue are file contents."); move(line++, 0); printw(" Characters shown in green are selected for edit on ."); move(line++, 0); move(line++, 0); printw("Press any key to return."); refresh(); while ((ch=getch()) == 0); // wait for input Erase(); } /* ------------------------------------------------------------------------ */ /* get_block_type */ /* returns: metatype if block is a GFS2 structure block type */ /* 0 if block is not a GFS2 structure */ /* ------------------------------------------------------------------------ */ uint32_t get_block_type(const struct gfs2_buffer_head *lbh, int *structlen) { uint32_t ty = lgfs2_get_block_type(lbh); if (ty != 0 && structlen != NULL) { unsigned ver = sbd.gfs1 ? LGFS2_MD_GFS1 : LGFS2_MD_GFS2; const struct lgfs2_metadata *mtype = lgfs2_find_mtype(ty, ver); if (mtype != NULL) *structlen = mtype->size; else *structlen = sbd.bsize; } return ty; } /* ------------------------------------------------------------------------ */ /* display_block_type */ /* returns: metatype if block is a GFS2 structure block type */ /* 0 if block is not a GFS2 structure */ /* ------------------------------------------------------------------------ */ int display_block_type(struct gfs2_buffer_head *dbh, int from_restore) { const struct gfs2_meta_header *mh; int ret_type = 0; /* return type */ /* first, print out the kind of GFS2 block this is */ if (termlines) { line = 1; move(line, 0); } print_gfs2("Block #"); if (termlines) { if (edit_row[dmode] == -1) COLORS_HIGHLIGHT; } if (block == RGLIST_DUMMY_BLOCK) print_gfs2("RG List "); else if (block == JOURNALS_DUMMY_BLOCK) print_gfs2("Journal Status: "); else print_gfs2("%"PRIu64" (0x%"PRIx64")", dbh->b_blocknr, dbh->b_blocknr); if (termlines) { if (edit_row[dmode] == -1) COLORS_NORMAL; } print_gfs2(" "); if (!from_restore) print_gfs2("of %"PRIu64" (0x%"PRIx64") ", max_block, max_block); if (block == RGLIST_DUMMY_BLOCK) { ret_type = GFS2_METATYPE_RG; struct_len = sbd.gfs1 ? sizeof(struct gfs_rgrp) : sizeof(struct gfs2_rgrp); } else if (block == JOURNALS_DUMMY_BLOCK) { ret_type = GFS2_METATYPE_DI; struct_len = 0; } else { ret_type = get_block_type(dbh, &struct_len); switch (ret_type) { case GFS2_METATYPE_SB: /* 1 */ print_gfs2("(superblock)"); break; case GFS2_METATYPE_RG: /* 2 */ print_gfs2("(rsrc grp hdr)"); break; case GFS2_METATYPE_RB: /* 3 */ print_gfs2("(rsrc grp bitblk)"); break; case GFS2_METATYPE_DI: /* 4 */ print_gfs2("(disk inode)"); break; case GFS2_METATYPE_IN: /* 5 */ print_gfs2("(indir blklist)"); break; case GFS2_METATYPE_LF: /* 6 */ print_gfs2("(directory leaf)"); break; case GFS2_METATYPE_JD: print_gfs2("(journal data)"); break; case GFS2_METATYPE_LH: print_gfs2("(log header)"); break; case GFS2_METATYPE_LD: print_gfs2("(log descriptor)"); break; case GFS2_METATYPE_EA: print_gfs2("(extended attr hdr)"); break; case GFS2_METATYPE_ED: print_gfs2("(extended attr data)"); break; case GFS2_METATYPE_LB: print_gfs2("(log buffer)"); break; case GFS2_METATYPE_QC: print_gfs2("(quota change)"); break; case 0: struct_len = sbd.bsize; break; default: print_gfs2("(wtf?)"); break; } } mh = dbh->iov.iov_base; eol(0); if (from_restore) return ret_type; if (termlines && dmode == HEX_MODE) { int type; struct rgrp_tree *rgd; rgd = gfs2_blk2rgrpd(&sbd, block); if (rgd) { gfs2_rgrp_read(&sbd, rgd); if ((be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RG) || (be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RB)) type = 4; else { type = lgfs2_get_bitmap(&sbd, block, rgd); } } else type = 4; screen_chunk_size = ((termlines - 4) * 16) >> 8 << 8; if (!screen_chunk_size) screen_chunk_size = 256; pgnum = (offset / screen_chunk_size); if (type >= 0) { print_gfs2("(p.%d of %d--%s)", pgnum + 1, (sbd.bsize % screen_chunk_size) > 0 ? sbd.bsize / screen_chunk_size + 1 : sbd.bsize / screen_chunk_size, allocdesc[sbd.gfs1][type]); } /*eol(9);*/ if ((be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RG)) { int ptroffset = edit_row[dmode] * 16 + edit_col[dmode]; if (rgd && (ptroffset >= struct_len || pgnum)) { int blknum, b, btype; blknum = pgnum * screen_chunk_size; blknum += (ptroffset - struct_len); blknum *= 4; blknum += rgd->ri.ri_data0; print_gfs2(" blk "); for (b = blknum; b < blknum + 4; b++) { btype = lgfs2_get_bitmap(&sbd, b, rgd); if (btype >= 0) { print_gfs2("0x%x-%s ", b, allocdesc[sbd.gfs1][btype]); } } } } else if ((be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RB)) { int ptroffset = edit_row[dmode] * 16 + edit_col[dmode]; if (rgd && (ptroffset >= struct_len || pgnum)) { int blknum, b, btype, rb_number; rb_number = block - rgd->ri.ri_addr; blknum = 0; /* count the number of bytes representing blocks prior to the displayed screen. */ for (b = 0; b < rb_number; b++) { struct_len = (b ? sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_rgrp)); blknum += (sbd.bsize - struct_len); } struct_len = sizeof(struct gfs2_meta_header); /* add the number of bytes on this screen */ blknum += (ptroffset - struct_len); /* factor in the page number */ blknum += pgnum * screen_chunk_size; /* convert bytes to blocks */ blknum *= GFS2_NBBY; /* add the starting offset for this rgrp */ blknum += rgd->ri.ri_data0; print_gfs2(" blk "); for (b = blknum; b < blknum + 4; b++) { btype = lgfs2_get_bitmap(&sbd, b, rgd); if (btype >= 0) { print_gfs2("0x%x-%s ", b, allocdesc[sbd.gfs1][btype]); } } } } if (rgd) gfs2_rgrp_relse(rgd); } if (block == sbd.sd_sb.sb_root_dir.no_addr) print_gfs2("--------------- Root directory ------------------"); else if (!sbd.gfs1 && block == sbd.sd_sb.sb_master_dir.no_addr) print_gfs2("-------------- Master directory -----------------"); else if (!sbd.gfs1 && block == RGLIST_DUMMY_BLOCK) print_gfs2("------------------ RG List ----------------------"); else if (!sbd.gfs1 && block == JOURNALS_DUMMY_BLOCK) print_gfs2("-------------------- Journal List --------------------"); else { if (sbd.gfs1) { if (block == sbd1->sb_rindex_di.no_addr) print_gfs2("---------------- rindex file -------------------"); else if (block == gfs1_quota_di.no_addr) print_gfs2("---------------- Quota file --------------------"); else if (block == sbd1->sb_jindex_di.no_addr) print_gfs2("--------------- Journal Index ------------------"); else if (block == gfs1_license_di.no_addr) print_gfs2("--------------- License file -------------------"); } else { int d; for (d = 2; d < 8; d++) { if (block == masterdir.dirent[d].block) { if (!strncmp(masterdir.dirent[d].filename, "jindex", 6)) print_gfs2("--------------- Journal Index ------------------"); else if (!strncmp(masterdir.dirent[d].filename, "per_node", 8)) print_gfs2("--------------- Per-node Dir -------------------"); else if (!strncmp(masterdir.dirent[d].filename, "inum", 4)) print_gfs2("---------------- Inum file ---------------------"); else if (!strncmp(masterdir.dirent[d].filename, "statfs", 6)) print_gfs2("---------------- statfs file -------------------"); else if (!strncmp(masterdir.dirent[d].filename, "rindex", 6)) print_gfs2("---------------- rindex file -------------------"); else if (!strncmp(masterdir.dirent[d].filename, "quota", 5)) print_gfs2("---------------- Quota file --------------------"); } } } } eol(0); return ret_type; } static const struct lgfs2_metadata *find_mtype(uint32_t mtype, const unsigned versions) { const struct lgfs2_metadata *m = lgfs2_metadata; unsigned n = 0; do { if ((m[n].versions & versions) && m[n].mh_type == mtype) return &m[n]; n++; } while (n < lgfs2_metadata_size); return NULL; } static int get_pnum(int ptroffset) { int pnum; pnum = pgnum * screen_chunk_size; pnum += (ptroffset - struct_len); pnum /= sizeof(uint64_t); return pnum; } /* ------------------------------------------------------------------------ */ /* hexdump - hex dump the filesystem block to the screen */ /* ------------------------------------------------------------------------ */ static int hexdump(uint64_t startaddr, int len, int trunc_zeros, uint64_t flagref, uint64_t ref_blk) { const unsigned char *pointer, *ptr2; int i; uint64_t l; const char *lpBuffer = bh->b_data; const char *zeros_strt = lpBuffer + sbd.bsize; int print_field, cursor_line; const uint32_t block_type = get_block_type(bh, NULL); uint64_t *ref; int ptroffset = 0; strcpy(edit_fmt,"%02x"); pointer = (unsigned char *)lpBuffer + offset; ptr2 = (unsigned char *)lpBuffer + offset; ref = (uint64_t *)lpBuffer + offset; if (trunc_zeros) { while (zeros_strt > lpBuffer && (*(zeros_strt - 1) == 0)) zeros_strt--; } l = offset; print_entry_ndx = 0; while (((termlines && line < termlines && line <= ((screen_chunk_size / 16) + 2)) || (!termlines && l < len)) && l < sbd.bsize) { int ptr_not_null = 0; if (termlines) { move(line, 0); COLORS_OFFSETS; /* cyan for offsets */ } if (startaddr < 0xffffffff) print_gfs2("%.8"PRIx64, startaddr + l); else print_gfs2("%.16"PRIx64, startaddr + l); if (termlines) { if (l < struct_len) COLORS_NORMAL; /* normal part of structure */ else if (gfs2_struct_type == GFS2_METATYPE_DI && l < struct_len + di.di_size) COLORS_CONTENTS; /* after struct but not eof */ else COLORS_SPECIAL; /* beyond end of the struct */ } print_field = -1; cursor_line = 0; for (i = 0; i < 16; i++) { /* first print it in hex */ /* Figure out if we have a null pointer--for colors */ if (((gfs2_struct_type == GFS2_METATYPE_IN) || (gfs2_struct_type == GFS2_METATYPE_DI && l < struct_len + di.di_size && (di.di_height > 0 || !S_ISREG(di.di_mode)))) && (i==0 || i==8)) { int j; ptr_not_null = 0; for (j = 0; j < 8; j++) { if (*(pointer + j)) { ptr_not_null = 1; break; } } } if (termlines) { if (l + i < struct_len) COLORS_NORMAL; /* in the structure */ else if (gfs2_struct_type == GFS2_METATYPE_DI && l + i < struct_len + di.di_size) { if ((!di.di_height && S_ISREG(di.di_mode)) || !ptr_not_null) COLORS_CONTENTS;/*stuff data */ else COLORS_SPECIAL;/* non-null */ } else if (gfs2_struct_type == GFS2_METATYPE_IN){ if (ptr_not_null) COLORS_SPECIAL;/* non-null */ else COLORS_CONTENTS;/* null */ } else COLORS_SPECIAL; /* past the struct */ } if (i%4 == 0) print_gfs2(" "); if (termlines && line == edit_row[dmode] + 3 && i == edit_col[dmode]) { COLORS_HIGHLIGHT; /* in the structure */ memset(estring,0,3); sprintf(estring,"%02x",*pointer); cursor_line = 1; print_field = (char *)pointer - bh->b_data; } print_gfs2("%02x",*pointer); if (termlines && line == edit_row[dmode] + 3 && i == edit_col[dmode]) { if (l < struct_len + offset) COLORS_NORMAL; /* in the structure */ else COLORS_SPECIAL; /* beyond structure */ } pointer++; } print_gfs2(" ["); for (i=0; i<16; i++) { /* now print it in character format */ if ((*ptr2 >=' ') && (*ptr2 <= '~')) print_gfs2("%c",*ptr2); else print_gfs2("."); ptr2++; } print_gfs2("] "); if (print_field >= 0) { const struct lgfs2_metadata *m = find_mtype(block_type, sbd.gfs1 ? LGFS2_MD_GFS1 : LGFS2_MD_GFS2); if (m) { const struct lgfs2_metafield *f; unsigned n; for (n = 0; n < m->nfields; n++) { f = &m->fields[n]; if (print_field >= f->offset && print_field < (f->offset + f->length)) { print_gfs2("%s", m->fields[n].name); break; } } } } if (cursor_line) { if (block_type == GFS2_METATYPE_IN || block_type == GFS2_METATYPE_LD || ((block_type == GFS2_METATYPE_DI) && ((struct gfs2_dinode*)bh->b_data)->di_height) || S_ISDIR(di.di_mode)) { ptroffset = edit_row[dmode] * 16 + edit_col[dmode]; if (ptroffset >= struct_len || pgnum) { int pnum = get_pnum(ptroffset); if (block_type == GFS2_METATYPE_LD) print_gfs2("*"); print_gfs2("pointer 0x%x", pnum); } } } if (line - 3 > last_entry_onscreen[dmode]) last_entry_onscreen[dmode] = line - 3; if (flagref && be64_to_cpu(*ref) == flagref) print_gfs2("<------------------------- ref in 0x%"PRIx64" " "to 0x%"PRIx64, ref_blk, flagref); ref++; if (flagref && be64_to_cpu(*ref) == flagref) print_gfs2("<------------------------- ref in 0x%"PRIx64" " "to 0x%"PRIx64, ref_blk, flagref); ref++; eol(0); l += 16; print_entry_ndx++; /* This should only happen if trunc_zeros is specified: */ if ((const char *)pointer >= zeros_strt) break; } /* while */ if (block_type == GFS2_METATYPE_LD && ptroffset >= struct_len) { COLORS_NORMAL; eol(0); print_gfs2(" * 'j' will jump to the journaled block, " "not the absolute block."); eol(0); } if (sbd.gfs1) { COLORS_NORMAL; print_gfs2(" *** This seems to be a GFS-1 file system ***"); eol(0); } return (offset+len); }/* hexdump */ /* ------------------------------------------------------------------------ */ /* masterblock - find a file (by name) in the master directory and return */ /* its block number. */ /* ------------------------------------------------------------------------ */ uint64_t masterblock(const char *fn) { int d; for (d = 2; d < 8; d++) if (!strncmp(masterdir.dirent[d].filename, fn, strlen(fn))) return (masterdir.dirent[d].block); return 0; } /* ------------------------------------------------------------------------ */ /* rgcount - return how many rgrps there are. */ /* ------------------------------------------------------------------------ */ static void rgcount(void) { printf("%lld RGs in this file system.\n", (unsigned long long)sbd.md.riinode->i_di.di_size / sizeof(struct gfs2_rindex)); inode_put(&sbd.md.riinode); gfs2_rgrp_free(&sbd.rgtree); exit(EXIT_SUCCESS); } /* ------------------------------------------------------------------------ */ /* find_rgrp_block - locate the block for a given rgrp number */ /* ------------------------------------------------------------------------ */ static uint64_t find_rgrp_block(struct gfs2_inode *dif, int rg) { int amt; struct gfs2_rindex fbuf, ri; uint64_t foffset, gfs1_adj = 0; foffset = rg * sizeof(struct gfs2_rindex); if (sbd.gfs1) { uint64_t sd_jbsize = (sbd.bsize - sizeof(struct gfs2_meta_header)); gfs1_adj = (foffset / sd_jbsize) * sizeof(struct gfs2_meta_header); gfs1_adj += sizeof(struct gfs2_meta_header); } amt = gfs2_readi(dif, (void *)&fbuf, foffset + gfs1_adj, sizeof(struct gfs2_rindex)); if (!amt) /* end of file */ return 0; gfs2_rindex_in(&ri, (void *)&fbuf); return ri.ri_addr; } /* ------------------------------------------------------------------------ */ /* gfs_rgrp_print - print a gfs1 resource group */ /* ------------------------------------------------------------------------ */ void gfs_rgrp_print(struct gfs_rgrp *rg) { gfs2_meta_header_print(&rg->rg_header); pv(rg, rg_flags, "%u", "0x%x"); pv(rg, rg_free, "%u", "0x%x"); pv(rg, rg_useddi, "%u", "0x%x"); pv(rg, rg_freedi, "%u", "0x%x"); gfs2_inum_print(&rg->rg_freedi_list); pv(rg, rg_usedmeta, "%u", "0x%x"); pv(rg, rg_freemeta, "%u", "0x%x"); } /* ------------------------------------------------------------------------ */ /* get_rg_addr */ /* ------------------------------------------------------------------------ */ static uint64_t get_rg_addr(int rgnum) { uint64_t rgblk = 0, gblock; struct gfs2_inode *riinode; if (sbd.gfs1) gblock = sbd1->sb_rindex_di.no_addr; else gblock = masterblock("rindex"); riinode = lgfs2_inode_read(&sbd, gblock); if (riinode == NULL) return 0; if (rgnum < riinode->i_di.di_size / sizeof(struct gfs2_rindex)) rgblk = find_rgrp_block(riinode, rgnum); else fprintf(stderr, "Error: File system only has %lld RGs.\n", (unsigned long long)riinode->i_di.di_size / sizeof(struct gfs2_rindex)); inode_put(&riinode); return rgblk; } /* ------------------------------------------------------------------------ */ /* set_rgrp_flags - Set an rgrp's flags to a given value */ /* rgnum: which rg to print or modify flags for (0 - X) */ /* new_flags: value to set new rg_flags to (if modify == TRUE) */ /* modify: TRUE if the value is to be modified, FALSE if it's to be printed */ /* full: TRUE if the full RG should be printed. */ /* ------------------------------------------------------------------------ */ static void set_rgrp_flags(int rgnum, uint32_t new_flags, int modify, int full) { union { struct gfs2_rgrp rg2; struct gfs_rgrp rg1; } rg; struct gfs2_buffer_head *rbh; uint64_t rgblk; rgblk = get_rg_addr(rgnum); rbh = bread(&sbd, rgblk); if (sbd.gfs1) gfs_rgrp_in(&rg.rg1, rbh); else gfs2_rgrp_in(&rg.rg2, rbh->b_data); if (modify) { printf("RG #%d (block %llu / 0x%llx) rg_flags changed from 0x%08x to 0x%08x\n", rgnum, (unsigned long long)rgblk, (unsigned long long)rgblk, rg.rg2.rg_flags, new_flags); rg.rg2.rg_flags = new_flags; if (sbd.gfs1) gfs_rgrp_out(&rg.rg1, rbh); else gfs2_rgrp_out(&rg.rg2, rbh->b_data); bmodified(rbh); brelse(rbh); } else { if (full) { print_gfs2("RG #%d", rgnum); print_gfs2(" located at: %"PRIu64" (0x%"PRIx64")", rgblk, rgblk); eol(0); if (sbd.gfs1) gfs_rgrp_print(&rg.rg1); else gfs2_rgrp_print(&rg.rg2); } else printf("RG #%d (block %llu / 0x%llx) rg_flags = 0x%08x\n", rgnum, (unsigned long long)rgblk, (unsigned long long)rgblk, rg.rg2.rg_flags); brelse(rbh); } if (modify) fsync(sbd.device_fd); } /* ------------------------------------------------------------------------ */ /* has_indirect_blocks */ /* ------------------------------------------------------------------------ */ int has_indirect_blocks(void) { if (indirect_blocks || gfs2_struct_type == GFS2_METATYPE_SB || gfs2_struct_type == GFS2_METATYPE_LF || (gfs2_struct_type == GFS2_METATYPE_DI && (S_ISDIR(di.di_mode) || (sbd.gfs1 && di.__pad1 == GFS_FILE_DIR)))) return TRUE; return FALSE; } int block_is_rindex(uint64_t blk) { if ((sbd.gfs1 && blk == sbd1->sb_rindex_di.no_addr) || (blk == masterblock("rindex"))) return TRUE; return FALSE; } int block_is_jindex(uint64_t blk) { if ((sbd.gfs1 && blk == sbd1->sb_jindex_di.no_addr)) return TRUE; return FALSE; } int block_is_inum_file(uint64_t blk) { if (!sbd.gfs1 && blk == masterblock("inum")) return TRUE; return FALSE; } int block_is_statfs_file(uint64_t blk) { if (sbd.gfs1 && blk == gfs1_license_di.no_addr) return TRUE; if (!sbd.gfs1 && blk == masterblock("statfs")) return TRUE; return FALSE; } int block_is_quota_file(uint64_t blk) { if (sbd.gfs1 && blk == gfs1_quota_di.no_addr) return TRUE; if (!sbd.gfs1 && blk == masterblock("quota")) return TRUE; return FALSE; } int block_is_per_node(uint64_t blk) { if (!sbd.gfs1 && blk == masterblock("per_node")) return TRUE; return FALSE; } /* ------------------------------------------------------------------------ */ /* block_has_extended_info */ /* ------------------------------------------------------------------------ */ static int block_has_extended_info(void) { if (has_indirect_blocks() || block_is_rindex(block) || block_is_rgtree(block) || block_is_journals(block) || block_is_jindex(block) || block_is_inum_file(block) || block_is_statfs_file(block) || block_is_quota_file(block)) return TRUE; return FALSE; } static void read_superblock(int fd) { sbd1 = (struct gfs_sb *)&sbd.sd_sb; ioctl(fd, BLKFLSBUF, 0); memset(&sbd, 0, sizeof(struct gfs2_sbd)); sbd.bsize = GFS2_DEFAULT_BSIZE; sbd.device_fd = fd; bh = bread(&sbd, 0x10); sbd.jsize = GFS2_DEFAULT_JSIZE; sbd.rgsize = GFS2_DEFAULT_RGSIZE; sbd.qcsize = GFS2_DEFAULT_QCSIZE; sbd.time = time(NULL); sbd.rgtree.osi_node = NULL; gfs2_sb_in(&sbd.sd_sb, bh->b_data); /* Check to see if this is really gfs1 */ if (sbd1->sb_fs_format == GFS_FORMAT_FS && sbd1->sb_header.mh_type == GFS_METATYPE_SB && sbd1->sb_header.mh_format == GFS_FORMAT_SB && sbd1->sb_multihost_format == GFS_FORMAT_MULTI) { struct gfs_sb *sbbuf = (struct gfs_sb *)bh->b_data; sbd.gfs1 = TRUE; sbd1->sb_flags = be32_to_cpu(sbbuf->sb_flags); sbd1->sb_seg_size = be32_to_cpu(sbbuf->sb_seg_size); gfs2_inum_in(&sbd1->sb_rindex_di, (void *)&sbbuf->sb_rindex_di); gfs2_inum_in(&gfs1_quota_di, (void *)&sbbuf->sb_quota_di); gfs2_inum_in(&gfs1_license_di, (void *)&sbbuf->sb_license_di); } else sbd.gfs1 = FALSE; sbd.bsize = sbd.sd_sb.sb_bsize; if (!sbd.bsize) sbd.bsize = GFS2_DEFAULT_BSIZE; if (lgfs2_get_dev_info(fd, &sbd.dinfo)) { perror(device); exit(-1); } if(compute_constants(&sbd)) { fprintf(stderr, "Failed to compute constants.\n"); exit(-1); } if (sbd.gfs1 || (sbd.sd_sb.sb_header.mh_magic == GFS2_MAGIC && sbd.sd_sb.sb_header.mh_type == GFS2_METATYPE_SB)) block = 0x10 * (GFS2_DEFAULT_BSIZE / sbd.bsize); else { block = starting_blk = 0; } fix_device_geometry(&sbd); if(sbd.gfs1) { sbd.sd_inptrs = (sbd.bsize - sizeof(struct gfs_indirect)) / sizeof(uint64_t); sbd.sd_diptrs = (sbd.bsize - sizeof(struct gfs_dinode)) / sizeof(uint64_t); sbd.md.riinode = lgfs2_inode_read(&sbd, sbd1->sb_rindex_di.no_addr); } else { sbd.sd_inptrs = (sbd.bsize - sizeof(struct gfs2_meta_header)) / sizeof(uint64_t); sbd.sd_diptrs = (sbd.bsize - sizeof(struct gfs2_dinode)) / sizeof(uint64_t); sbd.master_dir = lgfs2_inode_read(&sbd, sbd.sd_sb.sb_master_dir.no_addr); if (sbd.master_dir == NULL) { sbd.md.riinode = NULL; } else { gfs2_lookupi(sbd.master_dir, "rindex", 6, &sbd.md.riinode); } } brelse(bh); bh = NULL; } static int read_rindex(void) { struct gfs2_rindex *ri; uint64_t count; int sane; sbd.fssize = sbd.device.length; if (sbd.md.riinode) /* If we found the rindex */ rindex_read(&sbd, 0, &count, &sane); if (!OSI_EMPTY_ROOT(&sbd.rgtree)) { ri = &((struct rgrp_tree *)osi_last(&sbd.rgtree))->ri; sbd.fssize = ri->ri_data0 + ri->ri_data; } return 0; } static int read_master_dir(void) { ioctl(sbd.device_fd, BLKFLSBUF, 0); bh = bread(&sbd, sbd.sd_sb.sb_master_dir.no_addr); if (bh == NULL) return 1; gfs2_dinode_in(&di, bh->b_data); do_dinode_extended(&di, bh); /* get extended data, if any */ memcpy(&masterdir, &indirect[0], sizeof(struct indirect_info)); return 0; } int display(int identify_only, int trunc_zeros, uint64_t flagref, uint64_t ref_blk) { uint64_t blk; if (block == RGLIST_DUMMY_BLOCK) { if (sbd.gfs1) blk = sbd1->sb_rindex_di.no_addr; else blk = masterblock("rindex"); } else if (block == JOURNALS_DUMMY_BLOCK) { if (sbd.gfs1) blk = sbd1->sb_jindex_di.no_addr; else blk = masterblock("jindex"); } else blk = block; if (termlines) { display_title_lines(); move(2,0); } if (bh == NULL || bh->b_blocknr != blk) { /* If we changed blocks from the last read */ if (bh != NULL) brelse(bh); dev_offset = blk * sbd.bsize; ioctl(sbd.device_fd, BLKFLSBUF, 0); if (!(bh = bread(&sbd, blk))) { fprintf(stderr, "read error: %s from %s:%d: " "offset %lld (0x%llx)\n", strerror(errno), __FUNCTION__, __LINE__, (unsigned long long)dev_offset, (unsigned long long)dev_offset); exit(-1); } } line = 1; gfs2_struct_type = display_block_type(bh, FALSE); if (identify_only) return 0; indirect_blocks = 0; lines_per_row[dmode] = 1; if (gfs2_struct_type == GFS2_METATYPE_SB || blk == 0x10 * (4096 / sbd.bsize)) { gfs2_sb_in(&sbd.sd_sb, bh->b_data); memset(indirect, 0, sizeof(struct iinfo)); indirect->ii[0].block = sbd.sd_sb.sb_master_dir.no_addr; indirect->ii[0].is_dir = TRUE; indirect->ii[0].dirents = 2; memcpy(&indirect->ii[0].dirent[0].filename, "root", 4); indirect->ii[0].dirent[0].dirent.de_inum.no_formal_ino = sbd.sd_sb.sb_root_dir.no_formal_ino; indirect->ii[0].dirent[0].dirent.de_inum.no_addr = sbd.sd_sb.sb_root_dir.no_addr; indirect->ii[0].dirent[0].block = sbd.sd_sb.sb_root_dir.no_addr; indirect->ii[0].dirent[0].dirent.de_type = DT_DIR; memcpy(&indirect->ii[0].dirent[1].filename, "master", 7); indirect->ii[0].dirent[1].dirent.de_inum.no_formal_ino = sbd.sd_sb.sb_master_dir.no_formal_ino; indirect->ii[0].dirent[1].dirent.de_inum.no_addr = sbd.sd_sb.sb_master_dir.no_addr; indirect->ii[0].dirent[1].block = sbd.sd_sb.sb_master_dir.no_addr; indirect->ii[0].dirent[1].dirent.de_type = DT_DIR; } else if (gfs2_struct_type == GFS2_METATYPE_DI) { gfs2_dinode_in(&di, bh->b_data); do_dinode_extended(&di, bh); /* get extended data, if any */ } else if (gfs2_struct_type == GFS2_METATYPE_IN) { /* indirect block list */ if (blockhist) { int i; for (i = 0; i < 512; i++) memcpy(&indirect->ii[i].mp, &blockstack[blockhist - 1].mp, sizeof(struct metapath)); } indirect_blocks = do_indirect_extended(bh->b_data, indirect); } else if (gfs2_struct_type == GFS2_METATYPE_LF) { /* directory leaf */ do_leaf_extended(bh->b_data, indirect); } last_entry_onscreen[dmode] = 0; if (dmode == EXTENDED_MODE && !block_has_extended_info()) dmode = HEX_MODE; if (termlines) { move(termlines, 63); if (dmode==HEX_MODE) printw("Mode: Hex %s", (editing?"edit ":"view ")); else printw("Mode: %s", (dmode==GFS2_MODE?"Structure": "Pointers ")); move(line, 0); } if (dmode == HEX_MODE) /* if hex display mode */ hexdump(dev_offset, (gfs2_struct_type == GFS2_METATYPE_DI)? struct_len + di.di_size:sbd.bsize, trunc_zeros, flagref, ref_blk); else if (dmode == GFS2_MODE) { /* if structure display */ if (block != JOURNALS_DUMMY_BLOCK) display_gfs2(bh); /* display the gfs2 structure */ } else display_extended(); /* display extended blocks */ /* No else here because display_extended can switch back to hex mode */ if (termlines) refresh(); return(0); } /* ------------------------------------------------------------------------ */ /* push_block - push a block onto the block stack */ /* ------------------------------------------------------------------------ */ static void push_block(uint64_t blk) { int i, bhst; bhst = blockhist % BLOCK_STACK_SIZE; if (blk) { blockstack[bhst].dmode = dmode; for (i = 0; i < DMODES; i++) { blockstack[bhst].start_row[i] = start_row[i]; blockstack[bhst].end_row[i] = end_row[i]; blockstack[bhst].edit_row[i] = edit_row[i]; blockstack[bhst].edit_col[i] = edit_col[i]; blockstack[bhst].lines_per_row[i] = lines_per_row[i]; } blockstack[bhst].gfs2_struct_type = gfs2_struct_type; if (edit_row[dmode] >= 0 && !block_is_rindex(block)) memcpy(&blockstack[bhst].mp, &indirect->ii[edit_row[dmode]].mp, sizeof(struct metapath)); blockhist++; blockstack[blockhist % BLOCK_STACK_SIZE].block = blk; } } /* ------------------------------------------------------------------------ */ /* pop_block - pop a block off the block stack */ /* ------------------------------------------------------------------------ */ static uint64_t pop_block(void) { int i, bhst; if (!blockhist) return block; blockhist--; bhst = blockhist % BLOCK_STACK_SIZE; dmode = blockstack[bhst].dmode; for (i = 0; i < DMODES; i++) { start_row[i] = blockstack[bhst].start_row[i]; end_row[i] = blockstack[bhst].end_row[i]; edit_row[i] = blockstack[bhst].edit_row[i]; edit_col[i] = blockstack[bhst].edit_col[i]; lines_per_row[i] = blockstack[bhst].lines_per_row[i]; } gfs2_struct_type = blockstack[bhst].gfs2_struct_type; return blockstack[bhst].block; } /* ------------------------------------------------------------------------ */ /* Find next metadata block of a given type AFTER a given point in the fs */ /* */ /* This is used to find blocks that aren't represented in the bitmaps, such */ /* as the RGs and bitmaps or the superblock. */ /* ------------------------------------------------------------------------ */ static uint64_t find_metablockoftype_slow(uint64_t startblk, int metatype, int print) { uint64_t blk, last_fs_block; int found = 0; struct gfs2_buffer_head *lbh; last_fs_block = lseek(sbd.device_fd, 0, SEEK_END) / sbd.bsize; for (blk = startblk + 1; blk < last_fs_block; blk++) { lbh = bread(&sbd, blk); /* Can't use get_block_type here (returns false "none") */ if (lbh->b_data[0] == 0x01 && lbh->b_data[1] == 0x16 && lbh->b_data[2] == 0x19 && lbh->b_data[3] == 0x70 && lbh->b_data[4] == 0x00 && lbh->b_data[5] == 0x00 && lbh->b_data[6] == 0x00 && lbh->b_data[7] == metatype) { found = 1; brelse(lbh); break; } brelse(lbh); } if (!found) blk = 0; if (print) { if (dmode == HEX_MODE) printf("0x%llx\n", (unsigned long long)blk); else printf("%llu\n", (unsigned long long)blk); } gfs2_rgrp_free(&sbd.rgtree); if (print) exit(0); return blk; } static int find_rg_metatype(struct rgrp_tree *rgd, uint64_t *blk, uint64_t startblk, int mtype) { int found; unsigned i, j, m; struct gfs2_buffer_head *bhp = NULL; uint64_t *ibuf = malloc(sbd.bsize * GFS2_NBBY * sizeof(uint64_t)); for (i = 0; i < rgd->ri.ri_length; i++) { m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_DINODE); for (j = 0; j < m; j++) { *blk = ibuf[j]; bhp = bread(&sbd, *blk); found = (*blk > startblk) && !gfs2_check_meta(bhp, mtype); brelse(bhp); if (found) { free(ibuf); return 0; } } } free(ibuf); return -1; } /* ------------------------------------------------------------------------ */ /* Find next "metadata in use" block AFTER a given point in the fs */ /* */ /* This version does its magic by searching the bitmaps of the RG. After */ /* all, if we're searching for a dinode, we want a real allocated inode, */ /* not just some block that used to be an inode in a previous incarnation. */ /* ------------------------------------------------------------------------ */ static uint64_t find_metablockoftype_rg(uint64_t startblk, int metatype, int print) { struct osi_node *next = NULL; uint64_t blk, errblk; int first = 1, found = 0; struct rgrp_tree *rgd = NULL; struct gfs2_rindex *ri; blk = 0; /* Skip the rgs prior to the block we've been given */ for (next = osi_first(&sbd.rgtree); next; next = osi_next(next)) { rgd = (struct rgrp_tree *)next; ri = &rgd->ri; if (first && startblk <= ri->ri_data0) { startblk = ri->ri_data0; break; } else if (ri->ri_addr <= startblk && startblk < ri->ri_data0 + ri->ri_data) break; else rgd = NULL; first = 0; } if (!rgd) { if (print) printf("0\n"); gfs2_rgrp_free(&sbd.rgtree); if (print) exit(-1); } for (; !found && next; next = osi_next(next)){ rgd = (struct rgrp_tree *)next; errblk = gfs2_rgrp_read(&sbd, rgd); if (errblk) continue; found = !find_rg_metatype(rgd, &blk, startblk, metatype); if (found) break; gfs2_rgrp_relse(rgd); } if (!found) blk = 0; if (print) { if (dmode == HEX_MODE) printf("0x%llx\n", (unsigned long long)blk); else printf("%llu\n", (unsigned long long)blk); } gfs2_rgrp_free(&sbd.rgtree); if (print) exit(0); return blk; } /* ------------------------------------------------------------------------ */ /* Find next metadata block AFTER a given point in the fs */ /* ------------------------------------------------------------------------ */ static uint64_t find_metablockoftype(const char *strtype, int print) { int mtype = 0; uint64_t startblk, blk = 0; if (print) startblk = blockstack[blockhist % BLOCK_STACK_SIZE].block; else startblk = block; for (mtype = GFS2_METATYPE_NONE; mtype <= GFS2_METATYPE_QC; mtype++) if (!strcasecmp(strtype, mtypes[mtype])) break; if (!strcmp(strtype, "dinode")) mtype = GFS2_METATYPE_DI; if (mtype >= GFS2_METATYPE_NONE && mtype <= GFS2_METATYPE_RB) blk = find_metablockoftype_slow(startblk, mtype, print); else if (mtype >= GFS2_METATYPE_DI && mtype <= GFS2_METATYPE_QC) blk = find_metablockoftype_rg(startblk, mtype, print); else if (print) { fprintf(stderr, "Error: metadata type not " "specified: must be one of:\n"); fprintf(stderr, "sb rg rb di in lf jd lh ld" " ea ed lb 13 qc\n"); gfs2_rgrp_free(&sbd.rgtree); exit(-1); } return blk; } /* ------------------------------------------------------------------------ */ /* Check if the word is a keyword such as "sb" or "rindex" */ /* Returns: block number if it is, else 0 */ /* ------------------------------------------------------------------------ */ uint64_t check_keywords(const char *kword) { unsigned long long blk = 0; if (!strcmp(kword, "sb") ||!strcmp(kword, "superblock")) blk = 0x10 * (4096 / sbd.bsize); /* superblock */ else if (!strcmp(kword, "root") || !strcmp(kword, "rootdir")) blk = sbd.sd_sb.sb_root_dir.no_addr; else if (!strcmp(kword, "master")) { if (sbd.gfs1) fprintf(stderr, "This is GFS1; there's no master directory.\n"); else if (!sbd.sd_sb.sb_master_dir.no_addr) { fprintf(stderr, "GFS2 master directory not found on %s\n", device); exit(-1); } else blk = sbd.sd_sb.sb_master_dir.no_addr; } else if (!strcmp(kword, "jindex")) { if (sbd.gfs1) blk = sbd1->sb_jindex_di.no_addr; else blk = masterblock("jindex"); /* journal index */ } else if (!sbd.gfs1 && !strcmp(kword, "per_node")) blk = masterblock("per_node"); else if (!sbd.gfs1 && !strcmp(kword, "inum")) blk = masterblock("inum"); else if (!strcmp(kword, "statfs")) { if (sbd.gfs1) blk = gfs1_license_di.no_addr; else blk = masterblock("statfs"); } else if (!strcmp(kword, "rindex") || !strcmp(kword, "rgindex")) { if (sbd.gfs1) blk = sbd1->sb_rindex_di.no_addr; else blk = masterblock("rindex"); } else if (!strcmp(kword, "rgs")) { blk = RGLIST_DUMMY_BLOCK; } else if (!strcmp(kword, "quota")) { if (sbd.gfs1) blk = gfs1_quota_di.no_addr; else blk = masterblock("quota"); } else if (!strncmp(kword, "rg ", 3)) { int rgnum = 0; rgnum = atoi(kword + 3); blk = get_rg_addr(rgnum); } else if (!strncmp(kword, "journals", 8)) { blk = JOURNALS_DUMMY_BLOCK; } else if (strlen(kword) > 7 && !strncmp(kword, "journal", 7) && isdigit(kword[7])) { uint64_t j_size; blk = find_journal_block(kword, &j_size); } else if (kword[0]=='/') /* search */ blk = find_metablockoftype(&kword[1], 0); else if (kword[0]=='0' && kword[1]=='x') /* hex addr */ sscanf(kword, "%llx", &blk);/* retrieve in hex */ else sscanf(kword, "%llu", &blk); /* retrieve decimal */ return blk; } /* ------------------------------------------------------------------------ */ /* goto_block - go to a desired block entered by the user */ /* ------------------------------------------------------------------------ */ static uint64_t goto_block(void) { char string[256]; int ch, delta; memset(string, 0, sizeof(string)); sprintf(string,"%lld", (long long)block); if (bobgets(string, 1, 7, 16, &ch)) { if (isalnum(string[0]) || string[0] == '/') temp_blk = check_keywords(string); else if (string[0] == '+' || string[0] == '-') { if (string[1] == '0' && string[2] == 'x') sscanf(string, "%x", &delta); else sscanf(string, "%d", &delta); temp_blk = block + delta; } if (temp_blk == RGLIST_DUMMY_BLOCK || temp_blk == JOURNALS_DUMMY_BLOCK || temp_blk < max_block) { offset = 0; block = temp_blk; push_block(block); } } return block; } /* ------------------------------------------------------------------------ */ /* init_colors */ /* ------------------------------------------------------------------------ */ static void init_colors(void) { if (color_scheme) { init_pair(COLOR_TITLE, COLOR_BLACK, COLOR_CYAN); init_pair(COLOR_NORMAL, COLOR_WHITE, COLOR_BLACK); init_pair(COLOR_INVERSE, COLOR_BLACK, COLOR_WHITE); init_pair(COLOR_SPECIAL, COLOR_RED, COLOR_BLACK); init_pair(COLOR_HIGHLIGHT, COLOR_GREEN, COLOR_BLACK); init_pair(COLOR_OFFSETS, COLOR_CYAN, COLOR_BLACK); init_pair(COLOR_CONTENTS, COLOR_YELLOW, COLOR_BLACK); } else { init_pair(COLOR_TITLE, COLOR_BLACK, COLOR_CYAN); init_pair(COLOR_NORMAL, COLOR_BLACK, COLOR_WHITE); init_pair(COLOR_INVERSE, COLOR_WHITE, COLOR_BLACK); init_pair(COLOR_SPECIAL, COLOR_MAGENTA, COLOR_WHITE); init_pair(COLOR_HIGHLIGHT, COLOR_RED, COLOR_WHITE); /*cursor*/ init_pair(COLOR_OFFSETS, COLOR_CYAN, COLOR_WHITE); init_pair(COLOR_CONTENTS, COLOR_BLUE, COLOR_WHITE); } } /* ------------------------------------------------------------------------ */ /* hex_edit - Allow the user to edit the page by entering hex digits */ /* ------------------------------------------------------------------------ */ static void hex_edit(int *exitch) { int left_off; int ch; left_off = ((block * sbd.bsize) < 0xffffffff) ? 9 : 17; /* 8 and 16 char addresses on screen */ if (bobgets(estring, edit_row[HEX_MODE] + 3, (edit_col[HEX_MODE] * 2) + (edit_col[HEX_MODE] / 4) + left_off, 2, exitch)) { if (strstr(edit_fmt,"X") || strstr(edit_fmt,"x")) { int hexoffset; int i, sl = strlen(estring); for (i = 0; i < sl; i+=2) { hexoffset = (edit_row[HEX_MODE] * 16) + edit_col[HEX_MODE] + (i / 2); ch = 0x00; if (isdigit(estring[i])) ch = (estring[i] - '0') * 0x10; else if (estring[i] >= 'a' && estring[i] <= 'f') ch = (estring[i]-'a' + 0x0a)*0x10; else if (estring[i] >= 'A' && estring[i] <= 'F') ch = (estring[i] - 'A' + 0x0a) * 0x10; if (isdigit(estring[i+1])) ch += (estring[i+1] - '0'); else if (estring[i+1] >= 'a' && estring[i+1] <= 'f') ch += (estring[i+1] - 'a' + 0x0a); else if (estring[i+1] >= 'A' && estring[i+1] <= 'F') ch += (estring[i+1] - 'A' + 0x0a); bh->b_data[offset + hexoffset] = ch; } if (pwrite(sbd.device_fd, bh->b_data, sbd.bsize, dev_offset) != sbd.bsize) { fprintf(stderr, "write error: %s from %s:%d: " "offset %lld (0x%llx)\n", strerror(errno), __FUNCTION__, __LINE__, (unsigned long long)dev_offset, (unsigned long long)dev_offset); exit(-1); } fsync(sbd.device_fd); } } } /* ------------------------------------------------------------------------ */ /* page up */ /* ------------------------------------------------------------------------ */ static void pageup(void) { if (dmode == EXTENDED_MODE) { if (edit_row[dmode] - (dsplines / lines_per_row[dmode]) > 0) edit_row[dmode] -= (dsplines / lines_per_row[dmode]); else edit_row[dmode] = 0; if (start_row[dmode] - (dsplines / lines_per_row[dmode]) > 0) start_row[dmode] -= (dsplines / lines_per_row[dmode]); else start_row[dmode] = 0; } else { start_row[dmode] = edit_row[dmode] = 0; if (dmode == GFS2_MODE || offset==0) { block--; if (dmode == HEX_MODE) offset = (sbd.bsize % screen_chunk_size) > 0 ? screen_chunk_size * (sbd.bsize / screen_chunk_size) : sbd.bsize - screen_chunk_size; else offset = 0; } else offset -= screen_chunk_size; } } /* ------------------------------------------------------------------------ */ /* page down */ /* ------------------------------------------------------------------------ */ static void pagedn(void) { if (dmode == EXTENDED_MODE) { if ((edit_row[dmode] + dsplines) / lines_per_row[dmode] + 1 <= end_row[dmode]) { start_row[dmode] += dsplines / lines_per_row[dmode]; edit_row[dmode] += dsplines / lines_per_row[dmode]; } else { edit_row[dmode] = end_row[dmode] - 1; while (edit_row[dmode] - start_row[dmode] + 1 > last_entry_onscreen[dmode]) start_row[dmode]++; } } else { start_row[dmode] = edit_row[dmode] = 0; if (dmode == GFS2_MODE || offset + screen_chunk_size >= sbd.bsize) { block++; offset = 0; } else offset += screen_chunk_size; } } /* ------------------------------------------------------------------------ */ /* jump - jump to the address the cursor is on */ /* */ /* If the cursor is in a log descriptor, jump to the log-descriptor version */ /* of the block instead of the "real" block. */ /* ------------------------------------------------------------------------ */ static void jump(void) { if (dmode == HEX_MODE) { unsigned int col2; uint64_t *b; const uint32_t block_type = get_block_type(bh, NULL); /* special exception for log descriptors: jump the journaled version of the block, not the "real" block */ if (block_type == GFS2_METATYPE_LD) { int ptroffset = edit_row[dmode] * 16 + edit_col[dmode]; int pnum = get_pnum(ptroffset); temp_blk = bh->b_blocknr + pnum + 1; } else if (edit_row[dmode] >= 0) { col2 = edit_col[dmode] & 0x08;/* thus 0-7->0, 8-15->8 */ b = (uint64_t *)&bh->b_data[edit_row[dmode]*16 + offset + col2]; temp_blk = be64_to_cpu(*b); } } else sscanf(estring, "%"SCNx64, &temp_blk);/* retrieve in hex */ if (temp_blk < max_block) { /* if the block number is valid */ int i; offset = 0; push_block(temp_blk); block = temp_blk; for (i = 0; i < DMODES; i++) { start_row[i] = end_row[i] = edit_row[i] = 0; edit_col[i] = 0; } } } /* ------------------------------------------------------------------------ */ /* print block type */ /* ------------------------------------------------------------------------ */ static void print_block_type(uint64_t tblock, int type, const char *additional) { if (type <= GFS2_METATYPE_QC) printf("%d (Block %lld is type %d: %s%s)\n", type, (unsigned long long)tblock, type, block_type_str[type], additional); else printf("%d (Block %lld is type %d: unknown%s)\n", type, (unsigned long long)tblock, type, additional); } /* ------------------------------------------------------------------------ */ /* find_print block type */ /* ------------------------------------------------------------------------ */ static void find_print_block_type(void) { uint64_t tblock; struct gfs2_buffer_head *lbh; int type; tblock = blockstack[blockhist % BLOCK_STACK_SIZE].block; lbh = bread(&sbd, tblock); type = get_block_type(lbh, NULL); print_block_type(tblock, type, ""); brelse(lbh); gfs2_rgrp_free(&sbd.rgtree); exit(0); } /* ------------------------------------------------------------------------ */ /* Find and print the resource group associated with a given block */ /* ------------------------------------------------------------------------ */ static void find_print_block_rg(int bitmap) { uint64_t rblock, rgblock; int i; struct rgrp_tree *rgd; rblock = blockstack[blockhist % BLOCK_STACK_SIZE].block; if (rblock == LGFS2_SB_ADDR(&sbd)) printf("0 (the superblock is not in the bitmap)\n"); else { rgd = gfs2_blk2rgrpd(&sbd, rblock); if (rgd) { rgblock = rgd->ri.ri_addr; if (bitmap) { struct gfs2_bitmap *bits = NULL; for (i = 0; i < rgd->ri.ri_length; i++) { bits = &(rgd->bits[i]); if (rblock - rgd->ri.ri_data0 < ((bits->bi_start + bits->bi_len) * GFS2_NBBY)) { break; } } if (i < rgd->ri.ri_length) rgblock += i; } if (dmode == HEX_MODE) printf("0x%llx\n",(unsigned long long)rgblock); else printf("%llu\n", (unsigned long long)rgblock); } else { printf("-1 (block invalid or part of an rgrp).\n"); } } gfs2_rgrp_free(&sbd.rgtree); exit(0); } /* ------------------------------------------------------------------------ */ /* find/change/print block allocation (what the bitmap says about block) */ /* ------------------------------------------------------------------------ */ static void find_change_block_alloc(int *newval) { uint64_t ablock; int type; struct rgrp_tree *rgd; if (newval && (*newval < GFS2_BLKST_FREE || *newval > GFS2_BLKST_DINODE)) { int i; printf("Error: value %d is not valid.\nValid values are:\n", *newval); for (i = GFS2_BLKST_FREE; i <= GFS2_BLKST_DINODE; i++) printf("%d - %s\n", i, allocdesc[sbd.gfs1][i]); gfs2_rgrp_free(&sbd.rgtree); exit(-1); } ablock = blockstack[blockhist % BLOCK_STACK_SIZE].block; if (ablock == LGFS2_SB_ADDR(&sbd)) printf("3 (the superblock is not in the bitmap)\n"); else { rgd = gfs2_blk2rgrpd(&sbd, ablock); if (rgd) { gfs2_rgrp_read(&sbd, rgd); if (newval) { if (gfs2_set_bitmap(rgd, ablock, *newval)) printf("-1 (block invalid or part of an rgrp).\n"); else printf("%d\n", *newval); } else { type = lgfs2_get_bitmap(&sbd, ablock, rgd); if (type < 0) { printf("-1 (block invalid or part of " "an rgrp).\n"); exit(-1); } printf("%d (%s)\n", type, allocdesc[sbd.gfs1][type]); } gfs2_rgrp_relse(rgd); } else { gfs2_rgrp_free(&sbd.rgtree); printf("-1 (block invalid or part of an rgrp).\n"); exit(-1); } } gfs2_rgrp_free(&sbd.rgtree); if (newval) fsync(sbd.device_fd); exit(0); } /** * process request to print a certain field from a previously pushed block */ static void process_field(const char *field, const char *nstr) { uint64_t fblock; struct gfs2_buffer_head *rbh; int type; const struct lgfs2_metadata *mtype; const struct lgfs2_metafield *mfield; fblock = blockstack[blockhist % BLOCK_STACK_SIZE].block; rbh = bread(&sbd, fblock); type = get_block_type(rbh, NULL); mtype = lgfs2_find_mtype(type, sbd.gfs1 ? LGFS2_MD_GFS1 : LGFS2_MD_GFS2); if (mtype == NULL) { fprintf(stderr, "Metadata type '%d' invalid\n", type); exit(1); } mfield = lgfs2_find_mfield_name(field, mtype); if (mfield == NULL) { fprintf(stderr, "No field '%s' in block type '%s'\n", field, mtype->name); exit(1); } if (nstr != device) { int err = 0; if (mfield->flags & (LGFS2_MFF_UUID|LGFS2_MFF_STRING)) { err = lgfs2_field_assign(rbh->b_data, mfield, nstr); } else { uint64_t val = 0; err = sscanf(nstr, "%"SCNi64, &val); if (err == 1) err = lgfs2_field_assign(rbh->b_data, mfield, &val); else err = -1; } if (err != 0) { fprintf(stderr, "Could not set '%s' to '%s': %s\n", field, nstr, strerror(errno)); exit(1); } bmodified(rbh); } if (!termlines) { char str[GFS2_LOCKNAME_LEN] = ""; lgfs2_field_str(str, GFS2_LOCKNAME_LEN, rbh->b_data, mfield, (dmode == HEX_MODE)); printf("%s\n", str); } brelse(rbh); fsync(sbd.device_fd); exit(0); } /* ------------------------------------------------------------------------ */ /* interactive_mode - accept keystrokes from user and display structures */ /* ------------------------------------------------------------------------ */ static void interactive_mode(void) { int ch = 0, Quit; if ((wind = initscr()) == NULL) { fprintf(stderr, "Error: unable to initialize screen."); eol(0); exit(-1); } getmaxyx(stdscr, termlines, termcols); termlines--; /* Do our initial screen stuff: */ clear(); /* don't use Erase */ start_color(); noecho(); keypad(stdscr, TRUE); raw(); curs_set(0); init_colors(); /* Accept keystrokes and act on them accordingly */ Quit = FALSE; editing = FALSE; while (!Quit) { display(FALSE, 0, 0, 0); if (editing) { if (edit_row[dmode] == -1) block = goto_block(); else { if (dmode == HEX_MODE) hex_edit(&ch); else if (dmode == GFS2_MODE) { bobgets(estring, edit_row[dmode]+4, 24, 10, &ch); process_field(efield, estring); } else bobgets(estring, edit_row[dmode]+6, 14, edit_size[dmode], &ch); } } else while ((ch=getch()) == 0); // wait for input switch (ch) { /* --------------------------------------------------------- */ /* escape or 'q' */ /* --------------------------------------------------------- */ case 0x1b: case 0x03: case 'q': if (editing) editing = FALSE; else Quit=TRUE; break; /* --------------------------------------------------------- */ /* home - return to the superblock */ /* --------------------------------------------------------- */ case KEY_HOME: if (dmode == EXTENDED_MODE) { start_row[dmode] = end_row[dmode] = 0; edit_row[dmode] = 0; } else { block = 0x10 * (4096 / sbd.bsize); push_block(block); offset = 0; } break; /* --------------------------------------------------------- */ /* backspace - return to the previous block on the stack */ /* --------------------------------------------------------- */ case KEY_BACKSPACE: case 0x7f: block = pop_block(); offset = 0; break; /* --------------------------------------------------------- */ /* space - go down the block stack (opposite of backspace) */ /* --------------------------------------------------------- */ case ' ': blockhist++; block = blockstack[blockhist % BLOCK_STACK_SIZE].block; offset = 0; break; /* --------------------------------------------------------- */ /* arrow up */ /* --------------------------------------------------------- */ case KEY_UP: case '-': if (dmode == EXTENDED_MODE) { if (edit_row[dmode] > 0) edit_row[dmode]--; if (edit_row[dmode] < start_row[dmode]) start_row[dmode] = edit_row[dmode]; } else { if (edit_row[dmode] >= 0) edit_row[dmode]--; } break; /* --------------------------------------------------------- */ /* arrow down */ /* --------------------------------------------------------- */ case KEY_DOWN: case '+': if (dmode == EXTENDED_MODE) { if (edit_row[dmode] + 1 < end_row[dmode]) { if (edit_row[dmode] - start_row[dmode] + 1 > last_entry_onscreen[dmode]) start_row[dmode]++; edit_row[dmode]++; } } else { if (edit_row[dmode] < last_entry_onscreen[dmode]) edit_row[dmode]++; } break; /* --------------------------------------------------------- */ /* arrow left */ /* --------------------------------------------------------- */ case KEY_LEFT: if (dmode == HEX_MODE) { if (edit_col[dmode] > 0) edit_col[dmode]--; else edit_col[dmode] = 15; } break; /* --------------------------------------------------------- */ /* arrow right */ /* --------------------------------------------------------- */ case KEY_RIGHT: if (dmode == HEX_MODE) { if (edit_col[dmode] < 15) edit_col[dmode]++; else edit_col[dmode] = 0; } break; /* --------------------------------------------------------- */ /* m - change display mode key */ /* --------------------------------------------------------- */ case 'm': dmode = ((dmode + 1) % DMODES); break; /* --------------------------------------------------------- */ /* J - Jump to highlighted block number */ /* --------------------------------------------------------- */ case 'j': jump(); break; /* --------------------------------------------------------- */ /* g - goto block */ /* --------------------------------------------------------- */ case 'g': block = goto_block(); break; /* --------------------------------------------------------- */ /* h - help key */ /* --------------------------------------------------------- */ case 'h': print_usage(); break; /* --------------------------------------------------------- */ /* e - change to extended mode */ /* --------------------------------------------------------- */ case 'e': dmode = EXTENDED_MODE; break; /* --------------------------------------------------------- */ /* b - Back one 4K block */ /* --------------------------------------------------------- */ case 'b': start_row[dmode] = end_row[dmode] = edit_row[dmode] = 0; if (block > 0) block--; offset = 0; break; /* --------------------------------------------------------- */ /* c - Change color scheme */ /* --------------------------------------------------------- */ case 'c': color_scheme = !color_scheme; init_colors(); break; /* --------------------------------------------------------- */ /* page up key */ /* --------------------------------------------------------- */ case 0x19: // ctrl-y for vt100 case KEY_PPAGE: // PgUp case 0x15: // ctrl-u for vi compat. case 0x02: // ctrl-b for less compat. pageup(); break; /* --------------------------------------------------------- */ /* end - Jump to the end of the list */ /* --------------------------------------------------------- */ case 0x168: if (dmode == EXTENDED_MODE) { int ents_per_screen = dsplines / lines_per_row[dmode]; edit_row[dmode] = end_row[dmode] - 1; if ((edit_row[dmode] - ents_per_screen)+1 > 0) start_row[dmode] = edit_row[dmode] - ents_per_screen + 1; else start_row[dmode] = 0; } /* TODO: Make end key work for other display modes. */ break; /* --------------------------------------------------------- */ /* f - Forward one 4K block */ /* --------------------------------------------------------- */ case 'f': start_row[dmode]=end_row[dmode]=edit_row[dmode] = 0; lines_per_row[dmode] = 1; block++; offset = 0; break; /* --------------------------------------------------------- */ /* page down key */ /* --------------------------------------------------------- */ case 0x16: // ctrl-v for vt100 case KEY_NPAGE: // PgDown case 0x04: // ctrl-d for vi compat. pagedn(); break; /* --------------------------------------------------------- */ /* enter key - change a value */ /* --------------------------------------------------------- */ case KEY_ENTER: case('\n'): case('\r'): editing = !editing; break; case KEY_RESIZE: getmaxyx(stdscr, termlines, termcols); termlines--; break; default: move(termlines - 1, 0); printw("Keystroke not understood: 0x%03x",ch); refresh(); usleep(50000); break; } /* switch */ } /* while !Quit */ Erase(); refresh(); endwin(); }/* interactive_mode */ /* ------------------------------------------------------------------------ */ /* gfs_log_header_in - read in a gfs1-style log header */ /* ------------------------------------------------------------------------ */ void gfs_log_header_in(struct gfs_log_header *head, struct gfs2_buffer_head *lbh) { struct gfs_log_header *str = lbh->iov.iov_base; gfs2_meta_header_in(&head->lh_header, lbh->b_data); head->lh_flags = be32_to_cpu(str->lh_flags); head->lh_pad = be32_to_cpu(str->lh_pad); head->lh_first = be64_to_cpu(str->lh_first); head->lh_sequence = be64_to_cpu(str->lh_sequence); head->lh_tail = be64_to_cpu(str->lh_tail); head->lh_last_dump = be64_to_cpu(str->lh_last_dump); memcpy(head->lh_reserved, str->lh_reserved, 64); } /* ------------------------------------------------------------------------ */ /* gfs_log_header_print - print a gfs1-style log header */ /* ------------------------------------------------------------------------ */ void gfs_log_header_print(struct gfs_log_header *lh) { gfs2_meta_header_print(&lh->lh_header); pv(lh, lh_flags, "%u", "0x%.8x"); pv(lh, lh_pad, "%u", "%x"); pv((unsigned long long)lh, lh_first, "%llu", "%llx"); pv((unsigned long long)lh, lh_sequence, "%llu", "%llx"); pv((unsigned long long)lh, lh_tail, "%llu", "%llx"); pv((unsigned long long)lh, lh_last_dump, "%llu", "%llx"); } /* ------------------------------------------------------------------------ */ /* usage - print command line usage */ /* ------------------------------------------------------------------------ */ static void usage(void) { fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-z <0-9>] [-p structures|blocks][blocktype][blockalloc [val]][blockbits][blockrg][rgcount][rgflags][rgbitmaps][find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|13|qc][field [val]] /dev/device\n\n"); fprintf(stderr,"If only the device is specified, it enters into hexedit mode.\n"); fprintf(stderr,"identify - prints out only the block type, not the details.\n"); fprintf(stderr,"printsavedmeta - prints out the saved metadata blocks from a savemeta file.\n"); fprintf(stderr,"savemeta - save off your metadata for analysis and debugging.\n"); fprintf(stderr," (The intelligent way: assume bitmap is correct).\n"); fprintf(stderr,"savemetaslow - save off your metadata for analysis and debugging. The SLOW way (block by block).\n"); fprintf(stderr,"savergs - save off only the resource group information (rindex and rgs).\n"); fprintf(stderr,"restoremeta - restore metadata for debugging (DANGEROUS).\n"); fprintf(stderr,"rgcount - print how many RGs in the file system.\n"); fprintf(stderr,"rgflags rgnum [new flags] - print or modify flags for rg #rgnum (0 - X)\n"); fprintf(stderr,"rgbitmaps - print out the bitmaps for rgrp " "rgnum.\n"); fprintf(stderr,"rgrepair - find and repair damaged rgrp.\n"); fprintf(stderr,"-V prints version number.\n"); fprintf(stderr,"-c 1 selects alternate color scheme 1\n"); fprintf(stderr,"-d prints details (for printing journals)\n"); fprintf(stderr,"-p prints GFS2 structures or blocks to stdout.\n"); fprintf(stderr," sb - prints the superblock.\n"); fprintf(stderr," size - prints the filesystem size.\n"); fprintf(stderr," master - prints the master directory.\n"); fprintf(stderr," root - prints the root directory.\n"); fprintf(stderr," jindex - prints the journal index directory.\n"); fprintf(stderr," journals - prints the journal status.\n"); fprintf(stderr," per_node - prints the per_node directory.\n"); fprintf(stderr," inum - prints the inum file.\n"); fprintf(stderr," statfs - prints the statfs file.\n"); fprintf(stderr," rindex - prints the rindex file.\n"); fprintf(stderr," rg X - print resource group X.\n"); fprintf(stderr," rgs - prints all the resource groups (rgs).\n"); fprintf(stderr," quota - prints the quota file.\n"); fprintf(stderr," 0x1234 - prints the specified block\n"); fprintf(stderr,"-p blocktype - prints the type " "of the specified block\n"); fprintf(stderr,"-p blockrg - prints the resource group " "block corresponding to the specified block\n"); fprintf(stderr,"-p blockbits - prints the block with " "the bitmap corresponding to the specified block\n"); fprintf(stderr,"-p blockalloc [0|1|2|3] - print or change " "the allocation type of the specified block\n"); fprintf(stderr,"-p field [new_value] - prints or change the " "structure field\n"); fprintf(stderr,"-p find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|" "13|qc - find block of given type after block \n"); fprintf(stderr," specifies the starting block for search\n"); fprintf(stderr,"-z 1 use gzip compression level 1 for savemeta (default 9)\n"); fprintf(stderr,"-z 0 do not use compression\n"); fprintf(stderr,"-s specifies a starting block such as root, rindex, quota, inum.\n"); fprintf(stderr,"-x print in hexmode.\n"); fprintf(stderr,"-h prints this help.\n\n"); fprintf(stderr,"Examples:\n"); fprintf(stderr," To run in interactive mode:\n"); fprintf(stderr," gfs2_edit /dev/bobs_vg/lvol0\n"); fprintf(stderr," To print out the superblock and master directory:\n"); fprintf(stderr," gfs2_edit -p sb master /dev/bobs_vg/lvol0\n"); fprintf(stderr," To print out the master directory in hex:\n"); fprintf(stderr," gfs2_edit -x -p master /dev/bobs_vg/lvol0\n"); fprintf(stderr," To print out the block-type for block 0x27381:\n"); fprintf(stderr," gfs2_edit identify -p 0x27381 /dev/bobs_vg/lvol0\n"); fprintf(stderr," To print out the fourth Resource Group. (the first R is #0)\n"); fprintf(stderr," gfs2_edit -p rg 3 /dev/sdb1\n"); fprintf(stderr," To print out the metadata type of block 1234\n"); fprintf(stderr," gfs2_edit -p 1234 blocktype /dev/roth_vg/roth_lb\n"); fprintf(stderr," To print out the allocation type of block 2345\n"); fprintf(stderr," gfs2_edit -p 2345 blockalloc /dev/vg/lv\n"); fprintf(stderr," To change the allocation type of block 2345 to a 'free block'\n"); fprintf(stderr," gfs2_edit -p 2345 blockalloc 0 /dev/vg/lv\n"); fprintf(stderr," To print out the file size of the dinode at block 0x118\n"); fprintf(stderr," gfs2_edit -p 0x118 field di_size /dev/roth_vg/roth_lb\n"); fprintf(stderr," To find any dinode higher than the quota file dinode:\n"); fprintf(stderr," gfs2_edit -p quota find di /dev/x/y\n"); fprintf(stderr," To set the Resource Group flags for rg #7 to 3.\n"); fprintf(stderr," gfs2_edit rgflags 7 3 /dev/sdc2\n"); fprintf(stderr," To save off all metadata for /dev/vg/lv:\n"); fprintf(stderr," gfs2_edit savemeta /dev/vg/lv /tmp/metasave.gz\n"); }/* usage */ /** * getgziplevel - Process the -z parameter to savemeta operations * argv - argv * i - a pointer to the argv index at which to begin processing * The index pointed to by i will be incremented past the -z option if found */ static void getgziplevel(char *argv[], int *i) { char *opt, *arg; char *endptr; arg = argv[1 + *i]; if (strncmp(arg, "-z", 2)) { return; } else if (arg[2] != '\0') { opt = &arg[2]; } else { (*i)++; opt = argv[1 + *i]; } errno = 0; gziplevel = strtol(opt, &endptr, 10); if (errno || endptr == opt || gziplevel < 0 || gziplevel > 9) { fprintf(stderr, "Compression level out of range: %s\n", opt); exit(-1); } (*i)++; } static int count_dinode_blks(struct rgrp_tree *rgd, int bitmap, struct gfs2_buffer_head *rbh) { struct gfs2_buffer_head *tbh; uint64_t b; int dinodes = 0; char *byte, cur_state, new_state; int bit, off; if (bitmap) off = sizeof(struct gfs2_meta_header); else off = sizeof(struct gfs2_rgrp); for (b = 0; b < rgd->bits[bitmap].bi_len << GFS2_BIT_SIZE; b++) { tbh = bread(&sbd, rgd->ri.ri_data0 + rgd->bits[bitmap].bi_start + b); byte = rbh->b_data + off + (b / GFS2_NBBY); bit = (b % GFS2_NBBY) * GFS2_BIT_SIZE; if (gfs2_check_meta(tbh, GFS2_METATYPE_DI) == 0) { dinodes++; new_state = GFS2_BLKST_DINODE; } else { new_state = GFS2_BLKST_USED; } cur_state = (*byte >> bit) & GFS2_BIT_MASK; *byte ^= cur_state << bit; *byte |= new_state << bit; brelse(tbh); } bmodified(rbh); return dinodes; } static int count_dinode_bits(struct gfs2_buffer_head *rbh) { uint64_t blk; struct gfs2_meta_header *mh = (struct gfs2_meta_header *)rbh->b_data; char *byte; int bit; int dinodes = 0; if (be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RG) blk = sizeof(struct gfs2_rgrp); else blk = sizeof(struct gfs2_meta_header); for (; blk < sbd.bsize; blk++) { byte = rbh->b_data + (blk / GFS2_NBBY); bit = (blk % GFS2_NBBY) * GFS2_BIT_SIZE; if (((*byte >> bit) & GFS2_BIT_MASK) == GFS2_BLKST_DINODE) dinodes++; } return dinodes; } static void rg_repair(void) { struct gfs2_buffer_head *rbh; struct rgrp_tree *rgd; struct osi_node *n; int b; int rgs_fixed = 0; int dinodes_found = 0, dinodes_total = 0; /* Walk through the resource groups saving everything within */ for (n = osi_first(&sbd.rgtree); n; n = osi_next(n)) { rgd = (struct rgrp_tree *)n; if (gfs2_rgrp_read(&sbd, rgd) == 0) { /* was read in okay */ gfs2_rgrp_relse(rgd); continue; /* ignore it */ } /* If we get here, it's because we have an rgrp in the rindex file that can't be read in. So attempt to repair it. If we find a damaged rgrp or bitmap, fix the metadata. Then scan all its blocks: if we find a dinode, set the repaired bitmap to GFS2_BLKST_DINODE. Set all others to GFS2_BLKST_USED so fsck can sort it out. If we set them to FREE, fsck would just nuke it all. */ printf("Resource group at block %llu (0x%llx) appears to be " "damaged. Attempting to fix it (in reverse order).\n", (unsigned long long)rgd->ri.ri_addr, (unsigned long long)rgd->ri.ri_addr); for (b = rgd->ri.ri_length - 1; b >= 0; b--) { int mtype = (b ? GFS2_METATYPE_RB : GFS2_METATYPE_RG); struct gfs2_meta_header *mh; printf("Bitmap #%d:", b); rbh = bread(&sbd, rgd->ri.ri_addr + b); if (gfs2_check_meta(rbh, mtype)) { /* wrong type */ printf("Damaged. Repairing..."); /* Fix the meta header */ memset(rbh->b_data, 0, sbd.bsize); mh = (struct gfs2_meta_header *)rbh->b_data; mh->mh_magic = cpu_to_be32(GFS2_MAGIC); mh->mh_type = cpu_to_be32(mtype); if (b) mh->mh_format = cpu_to_be32(GFS2_FORMAT_RB); else mh->mh_format = cpu_to_be32(GFS2_FORMAT_RG); bmodified(rbh); /* Count the dinode blocks */ dinodes_found = count_dinode_blks(rgd, b, rbh); } else { /* bitmap info is okay: tally it. */ printf("Undamaged. Analyzing..."); dinodes_found = count_dinode_bits(rbh); } printf("Dinodes found: %d\n", dinodes_found); dinodes_total += dinodes_found; if (b == 0) { /* rgrp itself was damaged */ rgd->rg.rg_dinodes = dinodes_total; rgd->rg.rg_free = 0; } brelse(rbh); } rgs_fixed++; } if (rgs_fixed) printf("%d resource groups fixed.\n" "You should run fsck.gfs2 to reconcile the bitmaps.\n", rgs_fixed); else printf("All resource groups are okay. No repairs needed.\n"); exit(0); } /* ------------------------------------------------------------------------ */ /* parameterpass1 - pre-processing for command-line parameters */ /* ------------------------------------------------------------------------ */ static void parameterpass1(int argc, char *argv[], int i) { if (!strcasecmp(argv[i], "-V")) { printf("%s version %s (built %s %s)\n", argv[0], VERSION, __DATE__, __TIME__); printf("%s\n", REDHAT_COPYRIGHT); exit(0); } else if (!strcasecmp(argv[i], "-h") || !strcasecmp(argv[i], "-help") || !strcasecmp(argv[i], "-usage")) { usage(); exit(0); } else if (!strcasecmp(argv[i], "-c")) { i++; color_scheme = atoi(argv[i]); } else if (!strcasecmp(argv[i], "-p") || !strcasecmp(argv[i], "-print")) { termlines = 0; /* initial value--we'll figure it out later */ dmode = GFS2_MODE; } else if (!strcasecmp(argv[i], "-d") || !strcasecmp(argv[i], "-details")) details = 1; else if (!strcasecmp(argv[i], "savemeta")) termlines = 0; else if (!strcasecmp(argv[i], "savemetaslow")) termlines = 0; else if (!strcasecmp(argv[i], "savergs")) termlines = 0; else if (!strcasecmp(argv[i], "printsavedmeta")) { if (dmode == INIT_MODE) dmode = GFS2_MODE; restoremeta(argv[i+1], argv[i+2], TRUE); } else if (!strcasecmp(argv[i], "restoremeta")) { if (dmode == INIT_MODE) dmode = HEX_MODE; /* hopefully not used */ restoremeta(argv[i+1], argv[i+2], FALSE); } else if (!strcmp(argv[i], "rgcount")) termlines = 0; else if (!strcmp(argv[i], "rgflags")) termlines = 0; else if (!strcmp(argv[i], "rgrepair")) termlines = 0; else if (!strcmp(argv[i], "rg")) termlines = 0; else if (!strcasecmp(argv[i], "-x")) dmode = HEX_MODE; else if (device == NULL && strchr(argv[i],'/')) { device = argv[i]; } } /* ------------------------------------------------------------------------ */ /* process_parameters - process commandline parameters */ /* pass - we make two passes through the parameters; the first pass gathers */ /* normals parameters, device name, etc. The second pass is for */ /* figuring out what structures to print out. */ /* ------------------------------------------------------------------------ */ static void process_parameters(int argc, char *argv[], int pass) { int i; uint64_t keyword_blk; if (argc < 2) { usage(); die("no device specified\n"); } for (i = 1; i < argc; i++) { if (!pass) { /* first pass */ parameterpass1(argc, argv, i); continue; } /* second pass */ if (!strcasecmp(argv[i], "-s")) { i++; if (i >= argc - 1) { printf("Error: starting block not specified " "with -s.\n"); printf("%s -s [starting block | keyword] " "\n", argv[0]); printf("For example: %s -s \"rg 3\" " "/dev/exxon_vg/exxon_lv\n", argv[0]); exit(EXIT_FAILURE); } starting_blk = check_keywords(argv[i]); continue; } if (termlines || strchr(argv[i],'/')) /* if print or slash */ continue; if (!strncmp(argv[i], "journal", 7) && isdigit(argv[i][7]) && strcmp(argv[i+1], "field")) { int blk = 0; if (i < argc - 1 && isdigit(argv[i + 1][0])) { if (argv[i + 1][0]=='0' && argv[i + 1][1]=='x') sscanf(argv[i + 1], "%x", &blk); else blk = atoi(argv[i + 1]); } dump_journal(argv[i], blk); continue; } keyword_blk = check_keywords(argv[i]); if (keyword_blk) push_block(keyword_blk); else if (!strcasecmp(argv[i], "-x")) dmode = HEX_MODE; else if (argv[i][0] == '-') /* if it starts with a dash */ ; /* ignore it--meant for pass == 0 */ else if (!strcmp(argv[i], "identify")) identify = TRUE; else if (!strcmp(argv[i], "size")) { printf("Device size: %llu (0x%llx)\n", (unsigned long long)max_block, (unsigned long long)max_block); exit(EXIT_SUCCESS); } else if (!strcmp(argv[i], "rgcount")) rgcount(); else if (!strcmp(argv[i], "field")) { i++; if (i >= argc - 1) { printf("Error: field not specified.\n"); printf("Format is: %s -p field " " [newvalue]\n", argv[0]); gfs2_rgrp_free(&sbd.rgtree); exit(EXIT_FAILURE); } process_field(argv[i], argv[i + 1]); } else if (!strcmp(argv[i], "blocktype")) { find_print_block_type(); } else if (!strcmp(argv[i], "blockrg")) { find_print_block_rg(0); } else if (!strcmp(argv[i], "blockbits")) { find_print_block_rg(1); } else if (!strcmp(argv[i], "blockalloc")) { if (isdigit(argv[i + 1][0])) { int newval; if (argv[i + 1][0]=='0' && argv[i + 1][1]=='x') sscanf(argv[i + 1], "%x", &newval); else newval = (uint64_t)atoi(argv[i + 1]); find_change_block_alloc(&newval); } else { find_change_block_alloc(NULL); } } else if (!strcmp(argv[i], "find")) { find_metablockoftype(argv[i + 1], 1); } else if (!strcmp(argv[i], "rgflags")) { int rg, set = FALSE; uint32_t new_flags = 0; i++; if (i >= argc - 1) { printf("Error: rg # not specified.\n"); printf("Format is: %s rgflags rgnum" "[newvalue]\n", argv[0]); gfs2_rgrp_free(&sbd.rgtree); exit(EXIT_FAILURE); } if (argv[i][0]=='0' && argv[i][1]=='x') sscanf(argv[i], "%"SCNx32, &rg); else rg = atoi(argv[i]); i++; if (i < argc - 1 && isdigit(argv[i][0])) { set = TRUE; if (argv[i][0]=='0' && argv[i][1]=='x') sscanf(argv[i], "%"SCNx32, &new_flags); else new_flags = atoi(argv[i]); } set_rgrp_flags(rg, new_flags, set, FALSE); gfs2_rgrp_free(&sbd.rgtree); exit(EXIT_SUCCESS); } else if (!strcmp(argv[i], "rg")) { int rg; i++; if (i >= argc - 1) { printf("Error: rg # not specified.\n"); printf("Format is: %s rg rgnum\n", argv[0]); gfs2_rgrp_free(&sbd.rgtree); exit(EXIT_FAILURE); } rg = atoi(argv[i]); if (!strcasecmp(argv[i + 1], "find")) { temp_blk = get_rg_addr(rg); push_block(temp_blk); } else { set_rgrp_flags(rg, 0, FALSE, TRUE); gfs2_rgrp_free(&sbd.rgtree); exit(EXIT_SUCCESS); } } else if (!strcmp(argv[i], "rgbitmaps")) { int rg, bmap; uint64_t rgblk; struct rgrp_tree *rgd; i++; if (i >= argc - 1) { printf("Error: rg # not specified.\n"); printf("Format is: %s rgbitmaps rgnum\n", argv[0]); gfs2_rgrp_free(&sbd.rgtree); exit(EXIT_FAILURE); } rg = atoi(argv[i]); rgblk = get_rg_addr(rg); rgd = gfs2_blk2rgrpd(&sbd, rgblk); if (rgd == NULL) { printf("Error: rg # is invalid.\n"); gfs2_rgrp_free(&sbd.rgtree); exit(EXIT_FAILURE); } for (bmap = 0; bmap < rgd->ri.ri_length; bmap++) push_block(rgblk + bmap); } else if (!strcmp(argv[i], "rgrepair")) rg_repair(); else if (!strcasecmp(argv[i], "savemeta")) { getgziplevel(argv, &i); savemeta(argv[i+2], 0, gziplevel); } else if (!strcasecmp(argv[i], "savemetaslow")) { getgziplevel(argv, &i); savemeta(argv[i+2], 1, gziplevel); } else if (!strcasecmp(argv[i], "savergs")) { getgziplevel(argv, &i); savemeta(argv[i+2], 2, gziplevel); } else if (isdigit(argv[i][0])) { /* decimal addr */ sscanf(argv[i], "%"SCNd64, &temp_blk); push_block(temp_blk); } else { fprintf(stderr,"I don't know what '%s' means.\n", argv[i]); usage(); exit(EXIT_FAILURE); } } /* for */ }/* process_parameters */ int main(int argc, char *argv[]) { int i, j, fd; indirect = malloc(sizeof(struct iinfo)); if (!indirect) die("Out of memory."); memset(indirect, 0, sizeof(struct iinfo)); memset(start_row, 0, sizeof(start_row)); memset(lines_per_row, 0, sizeof(lines_per_row)); memset(end_row, 0, sizeof(end_row)); memset(edit_row, 0, sizeof(edit_row)); memset(edit_col, 0, sizeof(edit_col)); memset(edit_size, 0, sizeof(edit_size)); memset(last_entry_onscreen, 0, sizeof(last_entry_onscreen)); dmode = INIT_MODE; sbd.bsize = 4096; block = starting_blk = 0x10; for (i = 0; i < BLOCK_STACK_SIZE; i++) { blockstack[i].dmode = HEX_MODE; blockstack[i].block = block; for (j = 0; j < DMODES; j++) { blockstack[i].start_row[j] = 0; blockstack[i].end_row[j] = 0; blockstack[i].edit_row[j] = 0; blockstack[i].edit_col[j] = 0; blockstack[i].lines_per_row[j] = 0; } } edit_row[GFS2_MODE] = 10; /* Start off at root inode pointer in superblock */ termlines = 30; /* assume interactive mode until we find -p */ process_parameters(argc, argv, 0); if (dmode == INIT_MODE) dmode = HEX_MODE; fd = open(device, O_RDWR); if (fd < 0) die("can't open %s: %s\n", device, strerror(errno)); max_block = lseek(fd, 0, SEEK_END) / sbd.bsize; read_superblock(fd); if (read_rindex()) exit(-1); max_block = lseek(fd, 0, SEEK_END) / sbd.bsize; if (sbd.gfs1) edit_row[GFS2_MODE]++; else if (read_master_dir() != 0) exit(-1); process_parameters(argc, argv, 1); /* get what to print from cmdline */ block = blockstack[0].block = starting_blk * (4096 / sbd.bsize); if (termlines) interactive_mode(); else { /* print all the structures requested */ i = 0; while (blockhist > 0) { block = blockstack[i + 1].block; if (!block) break; display(identify, 0, 0, 0); if (!identify) { display_extended(); printf("-------------------------------------" \ "-----------------"); eol(0); } block = pop_block(); i++; } } close(fd); if (indirect) free(indirect); gfs2_rgrp_free(&sbd.rgtree); exit(EXIT_SUCCESS); }