From mboxrd@z Thu Jan 1 00:00:00 1970 From: rpeterso@sourceware.org Date: 16 Nov 2007 19:42:36 -0000 Subject: [Cluster-devel] cluster/gfs2 edit/gfs2hex.c edit/hexedit.c edi ... Message-ID: <20071116194236.28694.qmail@sourceware.org> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit CVSROOT: /cvs/cluster Module name: cluster Branch: RHEL5 Changes by: rpeterso at sourceware.org 2007-11-16 19:42:35 Modified files: gfs2/edit : gfs2hex.c hexedit.c hexedit.h savemeta.c gfs2/libgfs2 : ondisk.c ondisk.h Log message: Resolves: bz 369771: GFS2: bring RHEL gfs2_edit up to date Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/gfs2hex.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.5.2.3&r2=1.5.2.4 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/hexedit.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.6.2.3&r2=1.6.2.4 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/hexedit.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4.2.5&r2=1.4.2.6 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/savemeta.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.1.2.2&r2=1.1.2.3 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/ondisk.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.5.2.3&r2=1.5.2.4 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/ondisk.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.2&r2=1.2.2.1 --- cluster/gfs2/edit/gfs2hex.c 2007/06/26 01:40:43 1.5.2.3 +++ cluster/gfs2/edit/gfs2hex.c 2007/11/16 19:42:34 1.5.2.4 @@ -192,6 +192,7 @@ memcpy(&indir->dirent[d].dirent, &de, sizeof(struct gfs2_dirent)); memcpy(&indir->dirent[d].filename, ptr + sizeof(struct gfs2_dirent), de.de_name_len); + indir->dirent[d].filename[de.de_name_len] = '\0'; indir->dirent[d].block = de.de_inum.no_addr; indir->is_dir = TRUE; indir->dirents++; @@ -222,7 +223,7 @@ (gfs1 && di->__pad1 == GFS_FILE_DIR); indirect_blocks = 0; - memset(&indirect, 0, sizeof(indirect)); + memset(indirect, 0, sizeof(indirect)); if (di->di_height > 0) { /* Indirect pointers */ for (x = sizeof(struct gfs2_dinode), y = 0; @@ -230,21 +231,23 @@ x += sizeof(uint64_t), y++) { p = be64_to_cpu(*(uint64_t *)(buf + x)); if (p) { - indirect[indirect_blocks].block = p; - indirect[indirect_blocks].is_dir = FALSE; + indirect->ii[indirect_blocks].block = p; + indirect->ii[indirect_blocks].is_dir = FALSE; indirect_blocks++; } } } - else if (isdir && - !(di->di_flags & GFS2_DIF_EXHASH)) { + else if (isdir && !(di->di_flags & GFS2_DIF_EXHASH)) { int skip = 0; + /* Directory Entries: */ - indirect[0].dirents = 0; - indirect[0].block = block; - indirect[0].is_dir = TRUE; + indirect->ii[0].dirents = 0; + indirect->ii[0].block = block; + indirect->ii[0].is_dir = TRUE; for (x = sizeof(struct gfs2_dinode); x < bufsize; x += skip) { - skip = indirect_dirent(&indirect[0], buf + x, indirect[0].dirents); + skip = indirect_dirent(indirect->ii, + buf + x, + indirect->ii[0].dirents); if (skip <= 0) break; } @@ -267,20 +270,22 @@ struct gfs2_leaf leaf; unsigned int bufoffset; + if (last >= max_block) + break; tmp_bh = bread(&sbd, last); gfs2_leaf_in(&leaf, tmp_bh->b_data); - indirect[indirect_blocks].dirents = 0; + indirect->ii[indirect_blocks].dirents = 0; for (direntcount = 0, bufoffset = sizeof(struct gfs2_leaf); bufoffset < bufsize; direntcount++, bufoffset += skip) { - skip = indirect_dirent(&indirect[indirect_blocks], + skip = indirect_dirent(&indirect->ii[indirect_blocks], tmp_bh->b_data + bufoffset, direntcount); if (skip <= 0) break; } brelse(tmp_bh, not_updated); - indirect[indirect_blocks].block = last; + indirect->ii[indirect_blocks].block = last; indirect_blocks++; last = p; } /* if not duplicate pointer */ @@ -303,24 +308,26 @@ ** ******************************************************************************* ******************************************************************************/ -void do_indirect_extended(char *buf) +int do_indirect_extended(char *buf, struct iinfo *iinf) { unsigned int x, y; uint64_t p; + int i_blocks; - indirect_blocks = 0; - memset(&indirect, 0, sizeof(indirect)); + i_blocks = 0; + memset(iinf, 0, sizeof(struct iinfo)); for (x = (gfs1 ? sizeof(struct gfs_indirect): sizeof(struct gfs2_meta_header)), y = 0; x < bufsize; x += sizeof(uint64_t), y++) { p = be64_to_cpu(*(uint64_t *)(buf + x)); if (p) { - indirect[indirect_blocks].block = p; - indirect[indirect_blocks].is_dir = FALSE; - indirect_blocks++; + iinf->ii[i_blocks].block = p; + iinf->ii[i_blocks].is_dir = FALSE; + i_blocks++; } } + return i_blocks; } /****************************************************************************** @@ -338,20 +345,32 @@ ** ******************************************************************************* ******************************************************************************/ -void do_leaf_extended(char *buf) +void do_leaf_extended(char *buf, struct iinfo *indir) { + int x, i; struct gfs2_dirent de; - unsigned int x; - eol(0); - print_gfs2("Directory Entries:"); - eol(0); - - for (x = sizeof(struct gfs2_leaf); x < bufsize; x += de.de_rec_len) { - eol(0); - gfs2_dirent_in(&de, buf + x); - if (de.de_inum.no_addr) - gfs2_dirent_print(&de, buf + x + sizeof(struct gfs2_dirent)); + x = 0; + memset(indir, 0, sizeof(indir)); + /* Directory Entries: */ + for (i = sizeof(struct gfs2_leaf); i < bufsize; + i += de.de_rec_len) { + gfs2_dirent_in(&de, buf + i); + if (de.de_inum.no_addr) { + indir->ii[0].block = de.de_inum.no_addr; + indir->ii[0].dirent[x].block = de.de_inum.no_addr; + memcpy(&indir->ii[0].dirent[x].dirent, + &de, sizeof(struct gfs2_dirent)); + memcpy(&indir->ii[0].dirent[x].filename, + buf + i + sizeof(struct gfs2_dirent), + de.de_name_len); + indir->ii[0].dirent[x].filename[de.de_name_len] = '\0'; + indir->ii[0].is_dir = TRUE; + indir->ii[0].dirents++; + x++; + } + if (de.de_rec_len <= sizeof(struct gfs2_dirent)) + break; } } @@ -456,7 +475,10 @@ struct gfs2_meta_header mh; struct gfs2_rgrp rg; struct gfs2_leaf lf; + struct gfs_log_header lh1; struct gfs2_log_header lh; + struct gfs2_log_descriptor ld; + struct gfs2_quota_change qc; uint32_t magic; @@ -517,14 +539,26 @@ case GFS2_METATYPE_LH: print_gfs2("Log Header:"); eol(0); - gfs2_log_header_in(&lh, buf); - gfs2_log_header_print(&lh); + if (gfs1) { + gfs_log_header_in(&lh1, buf); + gfs_log_header_print(&lh1); + } else { + gfs2_log_header_in(&lh, buf); + gfs2_log_header_print(&lh); + } break; + case GFS2_METATYPE_LD: + print_gfs2("Log descriptor"); + eol(0); + gfs2_log_descriptor_in(&ld, buf); + gfs2_log_descriptor_print(&ld); + break; + case GFS2_METATYPE_EA: print_gfs2("Eattr Block:"); eol(0); - gfs2_meta_header_print(&mh); + do_eattr_extended(buf); break; case GFS2_METATYPE_ED: @@ -533,6 +567,19 @@ gfs2_meta_header_print(&mh); break; + case GFS2_METATYPE_LB: + print_gfs2("Log Buffer"); + eol(0); + gfs2_meta_header_print(&mh); + break; + + case GFS2_METATYPE_QC: + print_gfs2("Quota Change"); + eol(0); + gfs2_quota_change_in(&qc, buf); + gfs2_quota_change_print(&qc); + break; + default: print_gfs2("Unknown metadata type"); eol(0); --- cluster/gfs2/edit/hexedit.c 2007/06/26 01:40:43 1.6.2.3 +++ cluster/gfs2/edit/hexedit.c 2007/11/16 19:42:34 1.6.2.4 @@ -46,9 +46,11 @@ int display(int identify_only); extern void eol(int col); -extern void do_indirect_extended(char *buf); -extern void savemeta(const char *in_fn, const char *out_fn, int slow); -extern void restoremeta(const char *in_fn, const char *out_device); +extern void do_leaf_extended(char *buf, struct iinfo *indir); +extern int do_indirect_extended(char *buf, struct iinfo *ii); +extern void savemeta(const char *out_fn, int slow); +extern void restoremeta(const char *in_fn, const char *out_device, + int printblocksonly); /* ------------------------------------------------------------------------ */ /* UpdateSize - screen size changed, so update it */ @@ -326,12 +328,31 @@ Erase(); } + + +/* ------------------------------------------------------------------------ */ +/* get_block_type */ +/* returns: metatype if block is a GFS2 structure block type */ +/* 0 if block is not a GFS2 structure */ +/* ------------------------------------------------------------------------ */ +int get_block_type(const char *lpBuffer) +{ + int ret_type = 0; + + if (*(lpBuffer+0)==0x01 && *(lpBuffer+1)==0x16 && + *(lpBuffer+2)==0x19 && *(lpBuffer+3)==0x70 && + *(lpBuffer+4)==0x00 && *(lpBuffer+5)==0x00 && + *(lpBuffer+6)==0x00) /* If magic number appears at the start */ + ret_type = *(lpBuffer+7); + return ret_type; +} + /* ------------------------------------------------------------------------ */ /* 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(const char *lpBuffer) +int display_block_type(const char *lpBuffer, int from_restore) { int ret_type = 0; /* return type */ @@ -356,21 +377,19 @@ } else print_gfs2(" "); - print_gfs2("of %" PRIu64 " (0x%" PRIX64 ")", max_block, max_block); - if (termlines) - move(line, 55); - else - printf(" "); - + if (!from_restore) { + print_gfs2("of %" PRIu64 " (0x%" PRIX64 ")", max_block, + max_block); + if (termlines) + move(line, 55); + else + printf(" "); + } if (block == RGLIST_DUMMY_BLOCK) { ret_type = GFS2_METATYPE_RG; struct_len = sizeof(struct gfs2_rgrp); } - else if (*(lpBuffer+0)==0x01 && *(lpBuffer+1)==0x16 && - *(lpBuffer+2)==0x19 && *(lpBuffer+3)==0x70 && - *(lpBuffer+4)==0x00 && *(lpBuffer+5)==0x00 && - *(lpBuffer+6)==0x00) { /* If magic number appears@the start */ - ret_type = *(lpBuffer+7); + else if ((ret_type = get_block_type(lpBuffer))) { switch (*(lpBuffer+7)) { case GFS2_METATYPE_SB: /* 1 */ print_gfs2("(superblock)"); @@ -396,7 +415,7 @@ struct_len = sizeof(struct gfs2_meta_header); break; case GFS2_METATYPE_LF: /* 6 */ - print_gfs2("(leaf dinode blklst)"); + print_gfs2("(directory leaf)"); struct_len = sizeof(struct gfs2_leaf); break; case GFS2_METATYPE_JD: @@ -408,16 +427,30 @@ struct_len = sizeof(struct gfs2_log_header); break; case GFS2_METATYPE_LD: - print_gfs2("(log descriptor)"); - struct_len = sizeof(struct gfs2_log_descriptor); + print_gfs2("(log descriptor)"); + if (gfs1) + struct_len = sizeof(struct gfs_log_descriptor); + else + struct_len = + sizeof(struct gfs2_log_descriptor); break; case GFS2_METATYPE_EA: print_gfs2("(extended attr hdr)"); - struct_len = sizeof(struct gfs2_ea_header); + struct_len = sizeof(struct gfs2_meta_header) + + sizeof(struct gfs2_ea_header); break; case GFS2_METATYPE_ED: print_gfs2("(extended attr data)"); - struct_len = 512; + struct_len = sizeof(struct gfs2_meta_header) + + sizeof(struct gfs2_ea_header); + break; + case GFS2_METATYPE_LB: + print_gfs2("(log buffer)"); + struct_len = sizeof(struct gfs2_meta_header); + break; + case GFS2_METATYPE_QC: + print_gfs2("(quota change)"); + struct_len = sizeof(struct gfs2_quota_change); break; default: print_gfs2("(wtf?)"); @@ -428,6 +461,8 @@ else struct_len = 512; eol(0); + if (from_restore) + return ret_type; if (termlines && dmode == HEX_MODE) { /* calculate how much of the buffer we can fit on screen */ screen_chunk_size = ((termlines - 4) * 16) >> 8 << 8; @@ -583,6 +618,100 @@ } /* ------------------------------------------------------------------------ */ +/* rgcount - return how many rgrps there are. */ +/* ------------------------------------------------------------------------ */ +void rgcount(void) +{ + uint64_t block; + struct gfs2_buffer_head *ribh; + struct gfs2_inode *riinode; + + if (gfs1) + block = sbd1->sb_rindex_di.no_addr; + else + block = masterblock("rindex"); + ribh = bread(&sbd, block); + riinode = inode_get(&sbd, ribh); + printf("%lld RGs in this file system.\n", + riinode->i_di.di_size / sizeof(struct gfs2_rindex)); + inode_put(riinode, not_updated); + exit(EXIT_SUCCESS); +} + +/* ------------------------------------------------------------------------ */ +/* find_rgrp_block - locate the block for a given rgrp number */ +/* ------------------------------------------------------------------------ */ +uint64_t find_rgrp_block(struct gfs2_inode *di, int rg) +{ + char buf[sizeof(struct gfs2_rindex)]; + int amt; + struct gfs2_rindex ri; + + amt = gfs2_readi(di, (void *)&buf, + rg * sizeof(struct gfs2_rindex), + sizeof(struct gfs2_rindex)); + if (!amt) /* end of file */ + return 0; + gfs2_rindex_in(&ri, buf); + return ri.ri_addr; +} + +/* ------------------------------------------------------------------------ */ +/* 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. */ +/* ------------------------------------------------------------------------ */ +void set_rgrp_flags(int rgnum, uint32_t new_flags, int modify, int full) +{ + struct gfs2_rgrp rg; + struct gfs2_buffer_head *bh, *ribh; + uint64_t rgblk, block; + struct gfs2_inode *riinode; + + if (gfs1) + block = sbd1->sb_rindex_di.no_addr; + else + block = masterblock("rindex"); + ribh = bread(&sbd, block); + riinode = inode_get(&sbd, ribh); + if (rgnum >= riinode->i_di.di_size / sizeof(struct gfs2_rindex)) { + fprintf(stderr, "Error: File system only has %lld RGs.\n", + riinode->i_di.di_size / sizeof(struct gfs2_rindex)); + inode_put(riinode, not_updated); + brelse(ribh, not_updated); + return; + } + rgblk = find_rgrp_block(riinode, rgnum); + bh = bread(&sbd, rgblk); + gfs2_rgrp_in(&rg, bh->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.rg_flags, new_flags); + rg.rg_flags = new_flags; + gfs2_rgrp_out(&rg, bh->b_data); + brelse(bh, updated); + } else { + if (full) { + print_gfs2("RG #%d", rgnum); + print_gfs2(" located at: %llu (0x%llx)", rgblk, rgblk); + eol(0); + gfs2_rgrp_print(&rg); + } + else + printf("RG #%d (block %llu / 0x%llx) rg_flags = 0x%08x\n", + rgnum, (unsigned long long)rgblk, + (unsigned long long)rgblk, rg.rg_flags); + brelse(bh, not_updated); + } + inode_put(riinode, not_updated); + if (modify) + bsync(&sbd); +} + +/* ------------------------------------------------------------------------ */ /* parse_rindex - print the rgindex file. */ /* ------------------------------------------------------------------------ */ int parse_rindex(struct gfs2_inode *di, int print_rindex) @@ -603,9 +732,9 @@ error = gfs2_readi(di, (void *)&buf, print_entry_ndx * sizeof(struct gfs2_rindex), sizeof(struct gfs2_rindex)); - gfs2_rindex_in(&ri, buf); if (!error) /* end of file */ break; + gfs2_rindex_in(&ri, buf); if (!termlines || (print_entry_ndx >= start_row[dmode] && ((print_entry_ndx - start_row[dmode])+1) * lines_per_row[dmode] <= @@ -677,7 +806,7 @@ print_gfs2("Journal index entries found: %d.", di->i_di.di_size / sizeof(struct gfs_jindex)); eol(0); - lines_per_row[dmode] = 6; + lines_per_row[dmode] = 4; for (print_entry_ndx=0; ; print_entry_ndx++) { error = gfs2_readi(di, (void *)&buf, print_entry_ndx*sizeof(struct gfs_jindex), @@ -777,8 +906,9 @@ int has_indirect_blocks(void) { if (indirect_blocks || gfs2_struct_type == GFS2_METATYPE_SB || - (gfs2_struct_type == GFS2_METATYPE_DI && - (S_ISDIR(di.di_mode) || (gfs1 && di.__pad1 == GFS_FILE_DIR)))) + gfs2_struct_type == GFS2_METATYPE_LF || + (gfs2_struct_type == GFS2_METATYPE_DI && + (S_ISDIR(di.di_mode) || (gfs1 && di.__pad1 == GFS_FILE_DIR)))) return TRUE; return FALSE; } @@ -820,51 +950,100 @@ } /* ------------------------------------------------------------------------ */ +/* display_leaf - display directory leaf */ +/* ------------------------------------------------------------------------ */ +int display_leaf(struct iinfo *ind) +{ + int start_line, total_dirents = 0; + int d; + + eol(0); + if (gfs2_struct_type == GFS2_METATYPE_SB) + print_gfs2("The superblock has 2 directories"); + else + print_gfs2("This directory contains %d directory entries.", + ind->ii[0].dirents); + + start_line = line; + for (d = 0; d < ind->ii[0].dirents; d++) { + if (termlines && d >= termlines - start_line - 1 + + start_row[dmode]) + break; + total_dirents++; + if (ind->ii[0].dirents > 1) { + eol(5); + if (termlines) { + if (edit_row[dmode] >=0 && + line - start_line - 1 == + edit_row[dmode] - + start_row[dmode]) { + COLORS_HIGHLIGHT; + sprintf(estring, "%"PRIx64, + ind->ii[0].dirent[d].block); + strcpy(edit_fmt, "%"PRIx64); + } + } + print_gfs2("%d. (%d). %lld (0x%llx) / %lld (0x%llx): ", + total_dirents, d + 1, + ind->ii[0].dirent[d].dirent.de_inum.no_formal_ino, + ind->ii[0].dirent[d].dirent.de_inum.no_formal_ino, + ind->ii[0].dirent[d].block, + ind->ii[0].dirent[d].block); + } + print_inode_type(ind->ii[0].dirent[d].dirent.de_type); + print_gfs2(" %s", ind->ii[0].dirent[d].filename); + if (termlines) { + if (edit_row[dmode] >= 0 && + line - start_line - 1 == edit_row[dmode] - + start_row[dmode]) + COLORS_NORMAL; + } + } + if (line >= 4) + last_entry_onscreen[dmode] = line - 4; + eol(0); + end_row[dmode] = ind->ii[0].dirents; + if (end_row[dmode] < last_entry_onscreen[dmode]) + end_row[dmode] = last_entry_onscreen[dmode]; + return 0; +} + +/* ------------------------------------------------------------------------ */ /* display_indirect */ /* ------------------------------------------------------------------------ */ -int display_indirect(void) +int display_indirect(struct iinfo *ind, int indblocks, int level, uint64_t startoff) { - int start_line, total_dirents, indir_blocks; - int i, cur_height = -1; + int start_line, total_dirents; + int i, cur_height = -1, pndx; uint64_t factor[5]={0,0,0,0,0}; int offsets[5]; last_entry_onscreen[dmode] = 0; - eol(0); - start_line = line; + if (!level) + eol(0); if (!has_indirect_blocks()) return -1; - - indir_blocks = indirect_blocks; - if (!indirect_blocks) { - if (gfs2_struct_type == GFS2_METATYPE_SB) - print_gfs2("The superblock has 2 directories"); - else - print_gfs2("This directory contains %d directory entries.", - indirect[0].dirents); - indir_blocks = 1; /* not really an indirect block, but treat it as one */ - } - else { + if (!level) { if (gfs2_struct_type == GFS2_METATYPE_DI) { if (S_ISDIR(di.di_mode)) print_gfs2("This directory contains %d indirect blocks", - indirect_blocks); + indblocks); else print_gfs2("This inode contains %d indirect blocks", - indirect_blocks); + indblocks); } else print_gfs2("This indirect block contains %d indirect blocks", - indirect_blocks); + indblocks); } + eol(0); total_dirents = 0; /* Figure out multiplication factors for indirect pointers. */ - if ((indir_blocks == indirect_blocks) && !S_ISDIR(di.di_mode)) { + if (!S_ISDIR(di.di_mode)) { memset(&offsets, 0, sizeof(offsets)); /* See if we are on an inode or have one in history. */ - cur_height = 0; - if (gfs2_struct_type != GFS2_METATYPE_DI) { - cur_height = 0; + cur_height = level; + if (!level && gfs2_struct_type != GFS2_METATYPE_DI) { for (i = 0; i <= blockhist && i < 5; i++) { offsets[i] = blockstack[(blockhist - i) % BLOCK_STACK_SIZE].edit_row[dmode]; if (blockstack[(blockhist - i) % BLOCK_STACK_SIZE].gfs2_struct_type == GFS2_METATYPE_DI) @@ -890,112 +1069,113 @@ for (i = 0; i < di.di_height; i++) factor[i + 1] = factor[i] * inptrs; } - print_gfs2(" (at height=%d)", cur_height); - } - if (indirect_blocks) { + if (!level) + print_gfs2(" (at height=%d)", cur_height); eol(0); + } + if (!level && indblocks) { print_gfs2("Indirect blocks:"); + eol(0); } - eol(0); - for (print_entry_ndx = start_row[dmode]; - (!termlines || print_entry_ndx < termlines - start_line - 2 - + start_row[dmode]) && print_entry_ndx < indir_blocks; - print_entry_ndx++) { + start_line = line; + for (pndx = start_row[dmode]; + (!termlines || pndx < termlines - start_line - 1 + + start_row[dmode]) && pndx < indblocks; + pndx++) { + uint64_t file_offset; + + print_entry_ndx = pndx; if (termlines) { if (edit_row[dmode] >= 0 && - line - start_line - 2 == edit_row[dmode] - - start_row[dmode]) + line - start_line == + edit_row[dmode] - start_row[dmode]) COLORS_HIGHLIGHT; move(line, 1); } - if (indir_blocks == indirect_blocks) { - print_gfs2("%d => ", print_entry_ndx); - if (termlines) - move(line,9); - print_gfs2("0x%llx / %lld", indirect[print_entry_ndx].block, - indirect[print_entry_ndx].block); - if (termlines) { - if (edit_row[dmode] >= 0 && - line - start_line - 2 == edit_row[dmode] - - start_row[dmode]) { - sprintf(estring, "%"PRIx64, - indirect[print_entry_ndx].block); - strcpy(edit_fmt, "%"PRIx64); - edit_size[dmode] = strlen(estring); - COLORS_NORMAL; - } - } - if (!S_ISDIR(di.di_mode)) { - int hgt; - uint64_t file_offset = 0ull; - float human_off; - char h; - - /* Now divide by how deep we are at the moment. */ - /* This is how much data is represented by each */ - /* indirect pointer for each height we've traversed. */ - offsets[0] = print_entry_ndx; - for (hgt = cur_height; hgt >= 0; hgt--) - file_offset += offsets[cur_height - hgt] * - factor[di.di_height - hgt - 1] * bufsize; - print_gfs2(" "); - h = 'K'; - human_off = (file_offset / 1024.0); - if (human_off > 1024.0) { h = 'M'; human_off /= 1024.0; } - if (human_off > 1024.0) { h = 'G'; human_off /= 1024.0; } - if (human_off > 1024.0) { h = 'T'; human_off /= 1024.0; } - if (human_off > 1024.0) { h = 'P'; human_off /= 1024.0; } - if (human_off > 1024.0) { h = 'E'; human_off /= 1024.0; } - print_gfs2("(data offset 0x%llx / %lld / %6.2f%c)", - file_offset, file_offset, human_off, h); + if (!termlines) { + int h; + + for (h = 0; h < level; h++) print_gfs2(" "); + } + print_gfs2("%d => ", pndx); + if (termlines) + move(line,9); + print_gfs2("0x%llx / %lld", ind->ii[pndx].block, + ind->ii[pndx].block); + if (termlines) { + if (edit_row[dmode] >= 0 && + line - start_line == + edit_row[dmode] - start_row[dmode]) { + sprintf(estring, "%"PRIx64, + ind->ii[print_entry_ndx].block); + strcpy(edit_fmt, "%"PRIx64); + edit_size[dmode] = strlen(estring); + COLORS_NORMAL; } } - if (indirect[print_entry_ndx].is_dir) { - int d; + if (!S_ISDIR(di.di_mode)) { + int hgt; + file_offset = startoff; + float human_off; + char h; + + /* Now divide by how deep we are at the moment. */ + /* This is how much data is represented by each */ + /* indirect pointer for each height we've traversed. */ + offsets[0] = pndx; + for (hgt = cur_height; hgt >= 0; hgt--) + file_offset += offsets[cur_height - hgt] * + factor[di.di_height - hgt - 1] * bufsize; + print_gfs2(" "); + h = 'K'; + human_off = (file_offset / 1024.0); + if (human_off > 1024.0) { h = 'M'; human_off /= 1024.0; } + if (human_off > 1024.0) { h = 'G'; human_off /= 1024.0; } + if (human_off > 1024.0) { h = 'T'; human_off /= 1024.0; } + if (human_off > 1024.0) { h = 'P'; human_off /= 1024.0; } + if (human_off > 1024.0) { h = 'E'; human_off /= 1024.0; } + print_gfs2("(data offset 0x%llx / %lld / %6.2f%c)", + file_offset, file_offset, human_off, h); + print_gfs2(" "); + } + else + file_offset = 0; + if (!termlines && ((level + 1 < di.di_height) || + (S_ISDIR(di.di_mode) && !level))) { + struct iinfo *more_indir; + int more_ind; + char *tmpbuf; - if (indirect[print_entry_ndx].dirents > 1 && - indir_blocks == indirect_blocks) - print_gfs2("(directory leaf with %d entries)", - indirect[print_entry_ndx].dirents); - for (d = 0; d < indirect[print_entry_ndx].dirents; d++) { - total_dirents++; - if (indirect[print_entry_ndx].dirents > 1) { - eol(5); - if (termlines) { - if (edit_row[dmode] >=0 && - line - start_line - 2 == - edit_row[dmode] - - start_row[dmode]) { - COLORS_HIGHLIGHT; - sprintf(estring, "%"PRIx64, - indirect[print_entry_ndx].dirent[d].block); - strcpy(edit_fmt, "%"PRIx64); - } - } - print_gfs2("%d. (%d). %lld (0x%llx) / %lld (0x%llx): ", - total_dirents, d + 1, - indirect[print_entry_ndx].dirent[d].dirent.de_inum.no_formal_ino, - indirect[print_entry_ndx].dirent[d].dirent.de_inum.no_formal_ino, - indirect[print_entry_ndx].dirent[d].block, - indirect[print_entry_ndx].dirent[d].block); - } - print_inode_type(indirect[print_entry_ndx].dirent[d].dirent.de_type); - print_gfs2(" %s", indirect[print_entry_ndx].dirent[d].filename); - if (termlines) { - if (edit_row[dmode] >= 0 && - line - start_line - 2 == edit_row[dmode] - - start_row[dmode]) - COLORS_NORMAL; + more_indir = malloc(sizeof(struct iinfo)); + tmpbuf = malloc(bufsize); + if (tmpbuf) { + do_lseek(sbd.device_fd, + ind->ii[pndx].block * bufsize); + do_read(sbd.device_fd, tmpbuf, + bufsize); /* read in the desired block */ + memset(more_indir, 0, sizeof(struct iinfo)); + if (S_ISDIR(di.di_mode)) { + do_leaf_extended(tmpbuf, more_indir); + display_leaf(more_indir); + } else { + more_ind = do_indirect_extended(tmpbuf, + more_indir); + display_indirect(more_indir, + more_ind, level + 1, + file_offset); } + free(tmpbuf); } - } /* if isdir */ + free(more_indir); + } + print_entry_ndx = pndx; /* restore after recursion */ eol(0); } /* for each display row */ if (line >= 7) /* 7 because it was bumped at the end */ last_entry_onscreen[dmode] = line - 7; eol(0); - end_row[dmode] = (indirect_blocks ? indirect_blocks:indirect[0].dirents); + end_row[dmode] = indblocks; if (end_row[dmode] < last_entry_onscreen[dmode]) end_row[dmode] = last_entry_onscreen[dmode]; lines_per_row[dmode] = 1; @@ -1091,14 +1271,17 @@ struct gfs2_buffer_head *tmp_bh; /* Display any indirect pointers that we have. */ - if (display_indirect() == 0) - return -1; - else if (block_is_rindex()) { + if (block_is_rindex()) { tmp_bh = bread(&sbd, block); tmp_inode = inode_get(&sbd, tmp_bh); parse_rindex(tmp_inode, TRUE); brelse(tmp_bh, not_updated); } + else if (has_indirect_blocks() && !indirect_blocks && + !display_leaf(indirect)) + return -1; + else if (display_indirect(indirect, indirect_blocks, 0, 0) == 0) + return -1; else if (block_is_rglist()) { tmp_bh = bread(&sbd, masterblock("rindex")); tmp_inode = inode_get(&sbd, tmp_bh); @@ -1135,7 +1318,7 @@ /* ------------------------------------------------------------------------ */ /* read_superblock - read the superblock */ /* ------------------------------------------------------------------------ */ -void read_superblock(void) +void read_superblock(int fd) { int x; @@ -1172,7 +1355,9 @@ else gfs1 = FALSE; bufsize = sbd.sd_sb.sb_bsize; - block = 0x10 * (4096 / bufsize); + if (!bufsize) + bufsize = GFS2_DEFAULT_BSIZE; + block = 0x10 * (GFS2_DEFAULT_BSIZE / bufsize); } /* ------------------------------------------------------------------------ */ @@ -1180,9 +1365,9 @@ /* ------------------------------------------------------------------------ */ void read_master_dir(void) { - ioctl(fd, BLKFLSBUF, 0); - do_lseek(fd, sbd.sd_sb.sb_master_dir.no_addr * bufsize); - do_read(fd, buf, bufsize); /* read in the desired block */ + ioctl(sbd.device_fd, BLKFLSBUF, 0); + do_lseek(sbd.device_fd, sbd.sd_sb.sb_master_dir.no_addr * bufsize); + do_read(sbd.device_fd, buf, bufsize); /* read in the desired block */ gfs2_dinode_in(&di, buf); /* parse disk inode into structure */ do_dinode_extended(&di, buf); /* get extended data, if any */ memcpy(&masterdir, &indirect[0], sizeof(struct indirect_info)); @@ -1205,70 +1390,50 @@ } if (block_in_mem != blk) { /* If we changed blocks from the last read */ dev_offset = blk * bufsize; - ioctl(fd, BLKFLSBUF, 0); - do_lseek(fd, dev_offset); - do_read(fd, buf, bufsize); /* read in the desired block */ + ioctl(sbd.device_fd, BLKFLSBUF, 0); + do_lseek(sbd.device_fd, dev_offset); + do_read(sbd.device_fd, buf, bufsize); /* read desired block */ block_in_mem = blk; /* remember which block is in memory */ } line = 1; - gfs2_struct_type = display_block_type(buf); + gfs2_struct_type = display_block_type(buf, FALSE); if (identify_only) return 0; indirect_blocks = 0; lines_per_row[dmode] = 1; if (gfs2_struct_type == GFS2_METATYPE_SB || blk == 0x10 * (4096 / bufsize)) { gfs2_sb_in(&sbd.sd_sb, buf); /* parse it out into the sb structure */ - memset(&indirect, 0, sizeof(indirect)); - indirect[0].block = sbd.sd_sb.sb_master_dir.no_addr; - indirect[0].is_dir = TRUE; - indirect[0].dirents = 2; + memset(indirect, 0, sizeof(indirect)); + 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[0].dirent[0].filename, "root", 4); - indirect[0].dirent[0].dirent.de_inum.no_formal_ino = + 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[0].dirent[0].dirent.de_inum.no_addr = + indirect->ii[0].dirent[0].dirent.de_inum.no_addr = sbd.sd_sb.sb_root_dir.no_addr; - indirect[0].dirent[0].block = sbd.sd_sb.sb_root_dir.no_addr; - indirect[0].dirent[0].dirent.de_type = DT_DIR; + 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[0].dirent[1].filename, "master", 7); - indirect[0].dirent[1].dirent.de_inum.no_formal_ino = + 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[0].dirent[1].dirent.de_inum.no_addr = + indirect->ii[0].dirent[1].dirent.de_inum.no_addr = sbd.sd_sb.sb_master_dir.no_addr; - indirect[0].dirent[1].block = sbd.sd_sb.sb_master_dir.no_addr; - indirect[0].dirent[1].dirent.de_type = DT_DIR; + 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, buf); /* parse disk inode into structure */ do_dinode_extended(&di, buf); /* get extended data, if any */ } else if (gfs2_struct_type == GFS2_METATYPE_IN) { /* indirect block list */ - do_indirect_extended(buf); + do_indirect_extended(buf, indirect); + indirect_blocks = 1; } else if (gfs2_struct_type == GFS2_METATYPE_LF) { /* directory leaf */ - int x; - struct gfs2_dirent de; - - indirect_blocks = 1; - memset(&indirect, 0, sizeof(indirect)); - /* Directory Entries: */ - for (x = sizeof(struct gfs2_leaf); x < bufsize; - x += de.de_rec_len) { - gfs2_dirent_in(&de, buf + x); - if (de.de_inum.no_addr) { - indirect[indirect_blocks].block = de.de_inum.no_addr; - indirect[indirect_blocks].dirent[x].block = de.de_inum.no_addr; - memcpy(&indirect[indirect_blocks].dirent[x].dirent, &de, - sizeof(struct gfs2_dirent)); - memcpy(&indirect[indirect_blocks].dirent[x].filename, - buf + x + sizeof(struct gfs2_dirent), de.de_name_len); - indirect[indirect_blocks].is_dir = TRUE; - indirect[indirect_blocks].dirents++; - } - if (de.de_rec_len <= sizeof(struct gfs2_dirent)) - break; - } + do_leaf_extended(buf, indirect); } last_entry_onscreen[dmode] = 0; if (dmode == EXTENDED_MODE && !block_has_extended_info()) @@ -1377,6 +1542,20 @@ temp_blk = masterblock(string); } } + else if (string[0] == '+') { + if (string[1] == '0' && string[2] == 'x') + sscanf(string, "%"SCNx64, &temp_blk); + else + sscanf(string, "%" PRIu64, &temp_blk); + temp_blk += block; + } + else if (string[0] == '-') { + if (string[1] == '0' && string[2] == 'x') + sscanf(string, "%"SCNx64, &temp_blk); + else + sscanf(string, "%" PRIu64, &temp_blk); + temp_blk -= block; + } else if (string[0] == '0' && string[1] == 'x') sscanf(string, "%"SCNx64, &temp_blk); /* retrieve in hex */ else @@ -1457,9 +1636,9 @@ ch += (estring[i+1] - 'A' + 0x0a); buf[offset + hexoffset] = ch; } - do_lseek(fd, dev_offset); - do_write(fd, buf, bufsize); - fsync(fd); + do_lseek(sbd.device_fd, dev_offset); + do_write(sbd.device_fd, buf, bufsize); + fsync(sbd.device_fd); } } } @@ -1535,9 +1714,11 @@ unsigned int col2; uint64_t *b; - col2 = edit_col[dmode] & 0x08;/* thus 0-7->0, 8-15->8 */ - b = (uint64_t *)&buf[edit_row[dmode]*16 + offset + col2]; - temp_blk=be64_to_cpu(*b); + if (edit_row[dmode] >= 0) { + col2 = edit_col[dmode] & 0x08;/* thus 0-7->0, 8-15->8 */ + b = (uint64_t *)&buf[edit_row[dmode]*16 + offset + col2]; + temp_blk=be64_to_cpu(*b); + } } else sscanf(estring, "%"SCNx64, &temp_blk);/* retrieve in hex */ @@ -1808,6 +1989,189 @@ }/* interactive_mode */ /* ------------------------------------------------------------------------ */ +/* gfs_log_header_in - read in a gfs1-style log header */ +/* ------------------------------------------------------------------------ */ +void gfs_log_header_in(struct gfs_log_header *head, char *buf) +{ + struct gfs_log_header *str = (struct gfs_log_header *) buf; + + gfs2_meta_header_in(&head->lh_header, buf); + + 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(lh, lh_first, "%llu", "%llx"); + pv(lh, lh_sequence, "%llu", "%llx"); + pv(lh, lh_tail, "%llu", "%llx"); + pv(lh, lh_last_dump, "%llu", "%llx"); +} + +/* ------------------------------------------------------------------------ */ +/* dump_journal - dump a journal file's contents. */ +/* ------------------------------------------------------------------------ */ +void dump_journal(const char *journal) +{ + struct gfs2_buffer_head *jindex_bh, *j_bh = NULL; + uint64_t jindex_block, jblock, j_size, jb; + int error, start_line, journal_num; + struct gfs2_dinode jdi; + char jbuf[bufsize]; + struct gfs2_inode *j_inode = NULL; + + start_line = line; + lines_per_row[dmode] = 1; + error = 0; + journal_num = atoi(journal + 7); + print_gfs2("Dumping journal #%d.", journal_num); + eol(0); + /* Figure out the block of the jindex file */ + if (gfs1) + jindex_block = sbd1->sb_jindex_di.no_addr; + else + jindex_block = masterblock("jindex"); + /* read in the block */ + jindex_bh = bread(&sbd, jindex_block); + /* get the dinode data from it. */ + gfs2_dinode_in(&di, jindex_bh->b_data); /* parse disk inode into structure */ + + if (!gfs1) + do_dinode_extended(&di, jindex_bh->b_data); /* parse dir. */ + brelse(jindex_bh, not_updated); + + if (gfs1) { + struct gfs2_inode *jiinode; + struct gfs_jindex ji; + + jiinode = inode_get(&sbd, jindex_bh); + error = gfs2_readi(jiinode, (void *)&jbuf, + journal_num * sizeof(struct gfs_jindex), + sizeof(struct gfs_jindex)); + if (!error) + return; + gfs_jindex_in(&ji, jbuf); + jblock = ji.ji_addr; + j_size = ji.ji_nsegment * 0x10; + } else { + jblock = indirect->ii[0].dirent[journal_num + 2].block; + j_bh = bread(&sbd, jblock); + j_inode = inode_get(&sbd, j_bh); + gfs2_dinode_in(&jdi, j_bh->b_data);/* parse dinode to struct */ + j_size = jdi.di_size; + } + + for (jb = 0; jb < j_size; jb += (gfs1 ? 1:bufsize)) { + if (gfs1) { + if (j_bh) + brelse(j_bh, not_updated); + j_bh = bread(&sbd, jblock + jb); + memcpy(jbuf, j_bh->b_data, bufsize); + } + else + error = gfs2_readi(j_inode, (void *)&jbuf, jb, + bufsize); + if (!error) /* end of file */ + break; + if (get_block_type(jbuf) == GFS2_METATYPE_LD) { + uint64_t *b; + struct gfs2_log_descriptor ld; + int i = 0, ltndx; + uint32_t logtypes[2][6] = { + {GFS2_LOG_DESC_METADATA, + GFS2_LOG_DESC_REVOKE, + GFS2_LOG_DESC_JDATA, + 0, 0, 0}, + {GFS_LOG_DESC_METADATA, + GFS_LOG_DESC_IUL, + GFS_LOG_DESC_IDA, + GFS_LOG_DESC_Q, + GFS_LOG_DESC_LAST, + 0}}; + const char *logtypestr[2][6] = { + {"Metadata", "Revoke", "Jdata", + "Unknown", "Unknown", "Unknown"}, + {"Metadata", "Unlinked inode", "Dealloc inode", + "Quota", "Final Entry", "Unknown"}}; + + print_gfs2("Block #%4llx: Log descriptor, ", + jb / (gfs1 ? 1 : bufsize)); + gfs2_log_descriptor_in(&ld, jbuf); + print_gfs2("type %d ", ld.ld_type); + + for (ltndx = 0;; ltndx++) { + if (ld.ld_type == logtypes[gfs1][ltndx] || + logtypes[gfs1][ltndx] == 0) + break; + } + print_gfs2("(%s) ", logtypestr[gfs1][ltndx]); + print_gfs2("len:%u, data1: %u", + ld.ld_length, ld.ld_data1); + eol(0); + print_gfs2(" "); + if (gfs1) + b = (uint64_t *)(jbuf + + sizeof(struct gfs_log_descriptor)); + else + b = (uint64_t *)(jbuf + + sizeof(struct gfs2_log_descriptor)); + while (*b && (char *)b < (jbuf + bufsize)) { + if (!termlines || + (print_entry_ndx >= start_row[dmode] && + ((print_entry_ndx - start_row[dmode])+1) * + lines_per_row[dmode] <= termlines - start_line - 2)) { + if (i && i % 4 == 0) { + eol(0); + print_gfs2(" "); + } + i++; + print_gfs2("0x%08llx ", be64_to_cpu(*b)); + } + b++; + } + eol(0); + } else if (get_block_type(jbuf) == GFS2_METATYPE_LH) { + struct gfs2_log_header lh; + struct gfs_log_header lh1; + + if (gfs1) { + gfs_log_header_in(&lh1, jbuf); + print_gfs2("Block #%4llx: Log header: Seq" + "= 0x%x, first = 0x%x tail = " + "0x%x, last = 0x%x", + jb, lh1.lh_sequence, lh1.lh_first, + lh1.lh_tail, lh1.lh_last_dump); + } else { + gfs2_log_header_in(&lh, jbuf); + print_gfs2("Block #%4llx: Log header: Seq" + "= 0x%x, tail = 0x%x, blk = 0x%x", + jb / bufsize, lh.lh_sequence, + lh.lh_tail, lh.lh_blkno); + } + eol(0); + } + } + brelse(j_bh, not_updated); + blockhist = -1; /* So we don't print anything else */ +} + +/* ------------------------------------------------------------------------ */ /* usage - print command line usage */ /* ------------------------------------------------------------------------ */ void usage(void) @@ -1815,9 +2179,13 @@ fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-p structures|blocks] /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,"savemeta - save off your metadata for analysis and debugging. The intelligent way (assume bitmap is correct).\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,"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,"-V prints version number.\n"); fprintf(stderr,"-c 1 selects alternate color scheme 1\n"); fprintf(stderr,"-p prints GFS2 structures or blocks to stdout.\n"); @@ -1830,6 +2198,7 @@ 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,"-x print in hexmode.\n"); @@ -1843,6 +2212,12 @@ 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 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\n"); }/* usage */ /* ------------------------------------------------------------------------ */ @@ -1883,12 +2258,21 @@ dmode = GFS2_MODE; } else if (!strcasecmp(argv[i], "savemeta")) - savemeta(argv[i+1], argv[i+2], FALSE); + termlines = 0; else if (!strcasecmp(argv[i], "savemetaslow")) - savemeta(argv[i+1], argv[i+2], TRUE); + termlines = 0; + else if (!strcasecmp(argv[i], "printsavedmeta")) + restoremeta(argv[i+1], argv[i+2], + TRUE); else if (!strcasecmp(argv[i], "restoremeta")) - restoremeta(argv[i+1], argv[i+2]); - else if (strchr(argv[i],'/')) + 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], "rg")) + termlines = 0; + else if (!device[0] && strchr(argv[i],'/')) strcpy(device, argv[i]); } else { /* second pass */ @@ -1943,6 +2327,61 @@ else push_block(masterblock("quota")); } + else if (!strcmp(argv[i], "rgcount")) + rgcount(); + 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]); + 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); + 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]); + exit(EXIT_FAILURE); + } + rg = atoi(argv[i]); + i++; + set_rgrp_flags(rg, 0, FALSE, TRUE); + exit(EXIT_SUCCESS); + } + else if (!strcasecmp(argv[i], "savemeta")) + savemeta(argv[i+2], FALSE); + else if (!strcasecmp(argv[i], "savemetaslow")) + savemeta(argv[i+2], TRUE); else if (argv[i][0]=='0' && argv[i][1]=='x') { /* hex addr */ sscanf(argv[i], "%"SCNx64, &temp_blk);/* retrieve in hex */ push_block(temp_blk); @@ -1951,6 +2390,9 @@ sscanf(argv[i], "%"SCNd64, &temp_blk); push_block(temp_blk); } + else if (!strncmp(argv[i], "journal", 7) && isdigit(argv[i][7])) { + dump_journal(argv[i]); + } else { fprintf(stderr,"I don't know what '%s' means.\n", argv[i]); usage(); @@ -1973,10 +2415,14 @@ ******************************************************************************/ int main(int argc, char *argv[]) { - int i, j; + int i, j, fd; prog_name = argv[0]; + 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)); @@ -1999,16 +2445,19 @@ } } + edit_row[GFS2_MODE] = 10; /* Start off at root inode + pointer in superblock */ memset(device, 0, sizeof(device)); termlines = 30; /* assume interactive mode until we find -p */ process_parameters(argc, argv, 0); fd = open(device, O_RDWR); if (fd < 0) - die("can't open %s: %s\n", argv[1], strerror(errno)); + die("can't open %s: %s\n", device, strerror(errno)); max_block = lseek(fd, 0, SEEK_END) / bufsize; - read_superblock(); + read_superblock(fd); + strcpy(sbd.device_name, device); if (!gfs1) read_master_dir(); block_in_mem = -1; @@ -2020,11 +2469,13 @@ else { /* print all the structures requested */ for (i = 0; i <= blockhist; i++) { block = blockstack[i + 1].block; + if (!block) + break; display(identify); if (!identify) { display_extended(); printf("-------------------------------------" \ - "-----------------"); + "-----------------"); eol(0); } block = pop_block(); @@ -2033,5 +2484,7 @@ close(fd); if (buf) free(buf); + if (indirect) + free(indirect); exit(EXIT_SUCCESS); } --- cluster/gfs2/edit/hexedit.h 2007/11/13 17:06:32 1.4.2.5 +++ cluster/gfs2/edit/hexedit.h 2007/11/16 19:42:34 1.4.2.6 @@ -57,8 +57,14 @@ #define GFS_FILE_FIFO (101) /* fifo/pipe */ #define GFS_FILE_SOCK (102) /* socket */ +/* GFS 1 journal block types: */ +#define GFS_LOG_DESC_METADATA (300) /* metadata */ +#define GFS_LOG_DESC_IUL (400) /* unlinked inode */ +#define GFS_LOG_DESC_IDA (401) /* de-allocated inode */ +#define GFS_LOG_DESC_Q (402) /* quota */ +#define GFS_LOG_DESC_LAST (500) /* final in a logged transaction */ + EXTERN char *prog_name; -EXTERN int fd; EXTERN uint64_t block INIT(0); EXTERN int blockhist INIT(0); EXTERN int edit_mode INIT(0); @@ -96,6 +102,48 @@ EXTERN int editing INIT(0); EXTERN uint64_t temp_blk; +struct gfs_jindex { + uint64_t ji_addr; /* starting block of the journal */ + uint32_t ji_nsegment; /* number (quantity) of segments in journal */ + uint32_t ji_pad; + + char ji_reserved[64]; +}; + +struct gfs_log_descriptor { + struct gfs2_meta_header ld_header; + + uint32_t ld_type; /* GFS_LOG_DESC_... Type of this log chunk */ + uint32_t ld_length; /* Number of buffers in this chunk */ + uint32_t ld_data1; /* descriptor-specific field */ + uint32_t ld_data2; /* descriptor-specific field */ + char ld_reserved[64]; +}; + +struct gfs_log_header { + struct gfs2_meta_header lh_header; + + uint32_t lh_flags; /* GFS_LOG_HEAD_... */ + uint32_t lh_pad; + + uint64_t lh_first; /* Block number of first header in this trans */ + uint64_t lh_sequence; /* Sequence number of this transaction */ + + uint64_t lh_tail; /* Block number of log tail */ + uint64_t lh_last_dump; /* Block number of last dump */ + + char lh_reserved[64]; +}; + +EXTERN int block_is_jindex(void); +EXTERN int block_is_inum_file(void); +EXTERN int block_is_statfs_file(void); +EXTERN int block_is_quota_file(void); +EXTERN int display_block_type(const char *lpBuffer, int from_restore); +EXTERN void gfs_jindex_in(struct gfs_jindex *jindex, char *buf); +EXTERN void gfs_log_header_in(struct gfs_log_header *head, char *buf); +EXTERN void gfs_log_header_print(struct gfs_log_header *lh); + struct gfs2_dirents { uint64_t block; struct gfs2_dirent dirent; @@ -109,6 +157,10 @@ struct gfs2_dirents dirent[64]; }; +struct iinfo { + struct indirect_info ii[512]; +}; + struct gfs_indirect { struct gfs2_meta_header in_header; @@ -159,18 +211,9 @@ char sb_reserved[96]; }; -struct gfs_jindex { - uint64_t ji_addr; /* starting block of the journal */ - uint32_t ji_nsegment; /* number (quantity) of segments in journal */ - uint32_t ji_pad; - - char ji_reserved[64]; -}; - EXTERN struct blkstack_info blockstack[BLOCK_STACK_SIZE]; -EXTERN struct indirect_info indirect[512]; /* more than the most indirect - pointers possible for any given - 4K block */ +EXTERN struct iinfo *indirect; /* more than the most indirect + pointers possible for any given 4K block */ EXTERN struct indirect_info masterdir; /* Master directory info */ EXTERN int indirect_blocks INIT(0); /* count of indirect blocks */ EXTERN enum dsp_mode dmode INIT(HEX_MODE); --- cluster/gfs2/edit/savemeta.c 2007/10/11 20:32:35 1.1.2.2 +++ cluster/gfs2/edit/savemeta.c 2007/11/16 19:42:34 1.1.2.3 @@ -31,11 +31,13 @@ #include #include "osi_list.h" +#include "gfs2hex.h" #include "hexedit.h" #include "libgfs2.h" #define BUFSIZE (4096) #define DFT_SAVE_FILE "/tmp/gfsmeta" +#define MAX_JOURNALS_SAVED 256 struct saved_metablock { uint64_t blk; @@ -46,6 +48,8 @@ struct saved_metablock *savedata; uint64_t last_fs_block, last_reported_block, blks_saved, total_out, pct; struct gfs2_block_list *blocklist = NULL; +uint64_t journal_blocks[MAX_JOURNALS_SAVED]; +int journals_found = 0; extern void read_superblock(void); uint64_t masterblock(const char *fn); @@ -413,13 +417,13 @@ *struct_len = sizeof(struct gfs2_log_header); break; case GFS2_METATYPE_LD: /* 9 (log descriptor) */ - *struct_len = sizeof(struct gfs2_log_descriptor); + *struct_len = bufsize; break; case GFS2_METATYPE_EA: /* 10 (extended attr hdr) */ - *struct_len = sizeof(struct gfs2_ea_header); + *struct_len = bufsize; break; case GFS2_METATYPE_ED: /* 11 (extended attr data) */ - *struct_len = 512; + *struct_len = bufsize; break; default: *struct_len = bufsize; @@ -434,7 +438,7 @@ /* checking every block kills performance. We only report */ /* every second because we don't need 100 extra messages in */ /* logs made from verbose mode. */ -void warm_fuzzy_stuff(uint64_t block, int force) +void warm_fuzzy_stuff(uint64_t block, int force, int save) { static struct timeval tv; static uint32_t seconds = 0; @@ -448,29 +452,67 @@ seconds = tv.tv_sec; if (last_fs_block) { - percent = (block * 100) / last_fs_block; - printf("\r%" PRIu64 " blocks (%" - PRIu64 "%%) processed, ", block, percent); - printf("%" PRIu64 " blocks (%" PRIu64 "MB) saved ", - blks_saved, total_out / (1024*1024)); + printf("\r"); + if (save) { + percent = (block * 100) / last_fs_block; + printf("%" PRIu64 " metadata blocks (%" + PRIu64 "%%) processed, ", block, + percent); + } + if (total_out < 1024 * 1024) + printf("%" PRIu64 " metadata blocks (%" + PRIu64 "KB) %s. ", + blks_saved, total_out / 1024, + save?"saved":"restored"); + else + printf("%" PRIu64 " metadata blocks (%" + PRIu64 "MB) %s. ", + blks_saved, total_out / (1024*1024), + save?"saved":"restored"); + if (force) + printf("\n"); fflush(stdout); } } } -void save_block(int fd, int out_fd, uint64_t blk) +int block_is_a_journal(void) +{ + int j; + + for (j = 0; j < journals_found; j++) + if (block == journal_blocks[j]) + return TRUE; + return FALSE; +} + +int block_is_systemfile(void) +{ + return block_is_jindex() || + block_is_inum_file() || + block_is_statfs_file() || + block_is_quota_file() || + block_is_a_journal(); +} + +int save_block(int fd, int out_fd, uint64_t blk) { int blktype, blklen, outsz; uint16_t trailing0; char *p; - warm_fuzzy_stuff(blk, FALSE); memset(savedata, 0, sizeof(struct saved_metablock)); do_lseek(fd, blk * bufsize); do_read(fd, savedata->buf, bufsize); /* read in the block */ - if (get_gfs_struct_info(savedata->buf, &blktype, &blklen)) - return; /* Not metadata, so skip it */ + /* If this isn't metadata and isn't a system file, we don't want it. + Note that we're checking "block" here rather than blk. That's + because we want to know if the source inode's "block" is a system + inode, not the block within the inode "blk". They may or may not + be the same thing. */ + if (get_gfs_struct_info(savedata->buf, &blktype, &blklen) && + !block_is_systemfile()) + return 0; /* Not metadata, and not system file, so skip it */ trailing0 = 0; p = &savedata->buf[blklen - 1]; while (*p=='\0' && trailing0 < bufsize) { @@ -485,26 +527,198 @@ do_write(out_fd, savedata->buf, outsz); total_out += sizeof(savedata->blk) + sizeof(savedata->siglen) + outsz; blks_saved++; + return blktype; +} + +/* + * save_indirect_blocks - save all indirect blocks for the given buffer + */ +void save_indirect_blocks(int out_fd, osi_list_t *cur_list, + struct gfs2_buffer_head *mybh, int height, int hgt) +{ + uint64_t old_block = 0, starting_block; + uint64_t *ptr; + int head_size; + struct gfs2_buffer_head *nbh; + + starting_block = block; /* remember where we started */ + head_size = (hgt > 1 ? + sizeof(struct gfs2_meta_header) : + sizeof(struct gfs2_dinode)); + + for (ptr = (uint64_t *)(mybh->b_data + head_size); + (char *)ptr < (mybh->b_data + mybh->b_size); ptr++) { + if (!*ptr) + continue; + block = be64_to_cpu(*ptr); + if (block == old_block) + continue; + old_block = block; + save_block(sbd.device_fd, out_fd, block); + if (height != hgt) { /* If not at max height */ + nbh = bread(&sbd, block); + osi_list_add_prev(&nbh->b_altlist, + cur_list); + brelse(nbh, not_updated); + } + } /* for all data on the indirect block */ + block = starting_block; /* go back to where we started */ +} + +/* + * save_inode_data - save off important data associated with an inode + * + * out_fd - destination file descriptor + * block - block number of the inode to save the data for + * + * For user files, we don't want anything except all the indirect block + * pointers that reside on blocks on all but the highest height. + * + * For system files like statfs and inum, we want everything because they + * may contain important clues and no user data. + * + * For file system journals, the "data" is a mixture of metadata and + * journaled data. We want all the metadata and none of the user data. + */ +void save_inode_data(int out_fd) +{ + uint32_t height; + struct gfs2_inode *inode; + osi_list_t metalist[GFS2_MAX_META_HEIGHT]; + osi_list_t *prev_list, *cur_list, *tmp; + struct gfs2_buffer_head *metabh, *mybh; + int i; + char *buf; + + for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) + osi_list_init(&metalist[i]); + buf = malloc(bufsize); + metabh = bread(&sbd, block); + inode = inode_get(&sbd, metabh); + height = inode->i_di.di_height; + /* If this is a user inode, we don't follow to the file height. + We stop one level less. That way we save off the indirect + pointer blocks but not the actual file contents. */ + if (height && !block_is_systemfile()) + height--; + osi_list_add(&metabh->b_altlist, &metalist[0]); + for (i = 1; i <= height; i++){ + prev_list = &metalist[i - 1]; + cur_list = &metalist[i]; + + for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){ + mybh = osi_list_entry(tmp, struct gfs2_buffer_head, + b_altlist); + save_indirect_blocks(out_fd, cur_list, mybh, + height, i); + } /* for blocks at that height */ + } /* for height */ + /* free metalists */ + for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) { + cur_list = &metalist[i]; + while (!osi_list_empty(cur_list)) { + mybh = osi_list_entry(cur_list->next, + struct gfs2_buffer_head, + b_altlist); + osi_list_del(&mybh->b_altlist); + } + } + /* Process directory exhash inodes */ + if (S_ISDIR(inode->i_di.di_mode)) { + if (inode->i_di.di_flags & GFS2_DIF_EXHASH) { + save_indirect_blocks(out_fd, cur_list, mybh, + height, 0); + } + } + if (inode->i_di.di_eattr) { /* if this inode has extended attributes */ + struct gfs2_ea_header ea; + int e; + + metabh = bread(&sbd, inode->i_di.di_eattr); + save_block(sbd.device_fd, out_fd, inode->i_di.di_eattr); + for (e = sizeof(struct gfs2_meta_header); + e < bufsize; e += ea.ea_rec_len) { + uint64_t blk, *b; + int charoff; + + gfs2_ea_header_in(&ea, metabh->b_data + e); + for (i = 0; i < ea.ea_num_ptrs; i++) { + charoff = e + ea.ea_name_len + + sizeof(struct gfs2_ea_header) + + sizeof(uint64_t) - 1; + charoff /= sizeof(uint64_t); + b = (uint64_t *)(metabh->b_data); + b += charoff + i; + blk = be64_to_cpu(*b); + save_block(sbd.device_fd, out_fd, blk); + } + if (!ea.ea_rec_len) + break; + } + brelse(metabh, not_updated); + } + inode_put(inode, not_updated); + free(buf); +} + +void get_journal_inode_blocks(void) +{ + int journal; + struct gfs2_buffer_head *bh; + + journals_found = 0; + memset(journal_blocks, 0, sizeof(journal_blocks)); + /* Save off all the journals--but only the metadata. + * This is confusing so I'll explain. The journals contain important + * metadata. However, in gfs2 the journals are regular files within + * the system directory. Since they're regular files, the blocks + * within the journals are considered data, not metadata. Therefore, + * they won't have been saved by the code above. We want to dump + * these blocks, but we have to be careful. We only care about the + * journal blocks that look like metadata, and we need to not save + * journaled user data that may exist there as well. */ + for (journal = 0; ; journal++) { /* while journals exist */ + uint64_t jblock; + int amt; + struct gfs2_dinode jdi; + struct gfs2_inode *j_inode = NULL; + + if (gfs1) { + struct gfs_jindex ji; + char jbuf[sizeof(struct gfs_jindex)]; + + j_inode = inode_get(&sbd, bh); + amt = gfs2_readi(j_inode, (void *)&jbuf, + journal * sizeof(struct gfs_jindex), + sizeof(struct gfs_jindex)); + if (!amt) + break; + gfs_jindex_in(&ji, jbuf); + jblock = ji.ji_addr; + inode_put(j_inode, not_updated); + } else { + if (journal > indirect->ii[0].dirents - 3) + break; + jblock = indirect->ii[0].dirent[journal + 2].block; + bh = bread(&sbd, jblock); + j_inode = inode_get(&sbd, bh); + gfs2_dinode_in(&jdi, bh->b_data); + inode_put(j_inode, not_updated); + } + journal_blocks[journals_found++] = jblock; + } } -void savemeta(const char *in_fn, const char *out_fn, int slow) +void savemeta(const char *out_fn, int slow) { int out_fd; osi_list_t *tmp; - uint64_t blk; uint64_t memreq; int rgcount; + uint64_t jindex_block; + struct gfs2_buffer_head *bh; - memset(&sbd, 0, sizeof(struct gfs2_sbd)); - strcpy(sbd.device_name, in_fn); - sbd.bsize = GFS2_DEFAULT_BSIZE; - sbd.rgsize = -1; - sbd.jsize = GFS2_DEFAULT_JSIZE; - sbd.qcsize = GFS2_DEFAULT_QCSIZE; sbd.md.journals = 1; - sbd.device_fd = open(in_fn, O_RDONLY); - if (sbd.device_fd < 0) - die("Can't open %s: %s\n", in_fn, strerror(errno)); if (!out_fn) out_fn = DFT_SAVE_FILE; @@ -512,6 +726,8 @@ if (out_fd < 0) die("Can't open %s: %s\n", out_fn, strerror(errno)); + if (ftruncate(out_fd, 0)) + die("Can't truncate %s: %s\n", out_fn, strerror(errno)); savedata = malloc(sizeof(struct saved_metablock)); if (!savedata) die("Can't allocate memory for the operation.\n"); @@ -536,35 +752,49 @@ bufsize = sbd.bsize = sbd.sd_sb.sb_bsize; } last_fs_block = lseek(sbd.device_fd, 0, SEEK_END) / bufsize; - printf("There are %" PRIu64 " blocks of %" PRIu64 " bytes.\n\n", + printf("There are %" PRIu64 " blocks of %" PRIu64 " bytes.\n", last_fs_block, bufsize); if (!slow) { - if (gfs1) + if (gfs1) { sbd.md.riinode = gfs2_load_inode(&sbd, sbd1->sb_rindex_di.no_addr); - else { + jindex_block = sbd1->sb_jindex_di.no_addr; + } else { sbd.master_dir = gfs2_load_inode(&sbd, sbd.sd_sb.sb_master_dir.no_addr); slow = gfs2_lookupi(sbd.master_dir, "rindex", 6, &sbd.md.riinode); + jindex_block = masterblock("jindex"); } + bh = bread(&sbd, jindex_block); + gfs2_dinode_in(&di, bh->b_data); + if (!gfs1) + do_dinode_extended(&di, bh->b_data); + brelse(bh, not_updated); } if (!slow) { + printf("Reading resource groups..."); + fflush(stdout); if (gfs1) slow = gfs1_ri_update(&sbd, 0, &rgcount); else slow = ri_update(&sbd, 0, &rgcount); + printf("Done.\n\n"); + fflush(stdout); } if (!slow) { blocklist = gfs2_block_list_create(last_fs_block + 1, &memreq); if (!blocklist) slow = TRUE; } + get_journal_inode_blocks(); if (!slow) { + /* Save off the superblock */ save_block(sbd.device_fd, out_fd, 0x10 * (4096 / bufsize)); + /* Walk through the resource groups saving everything within */ for (tmp = sbd.rglist.next; tmp != &sbd.rglist; tmp = tmp->next){ struct rgrp_list *rgd; @@ -584,28 +814,37 @@ } first = 1; /* Save off the rg and bitmaps */ - for (blk = rgd->ri.ri_addr; - blk < rgd->ri.ri_data0; blk++) - save_block(sbd.device_fd, out_fd, blk); + for (block = rgd->ri.ri_addr; + block < rgd->ri.ri_data0; block++) { + warm_fuzzy_stuff(block, FALSE, TRUE); + save_block(sbd.device_fd, out_fd, block); + } /* Save off the other metadata: inodes, etc. */ - while (!gfs2_next_rg_meta(rgd, &blk, first)) { - save_block(sbd.device_fd, out_fd, blk); + while (!gfs2_next_rg_meta(rgd, &block, first)) { + int blktype; + + warm_fuzzy_stuff(block, FALSE, TRUE); + blktype = save_block(sbd.device_fd, out_fd, + block); + if (blktype == GFS2_METATYPE_DI) + save_inode_data(out_fd); first = 0; } gfs2_rgrp_relse(rgd, not_updated); } } if (slow) { - for (blk = 0; blk < last_fs_block; blk++) { - save_block(sbd.device_fd, out_fd, blk); + for (block = 0; block < last_fs_block; block++) { + save_block(sbd.device_fd, out_fd, block); } } + /* Clean up */ if (blocklist) gfs2_block_list_destroy(blocklist); /* There may be a gap between end of file system and end of device */ /* so we tell the user that we've processed everything. */ - blk = last_fs_block; - warm_fuzzy_stuff(blk, TRUE); + block = last_fs_block; + warm_fuzzy_stuff(block, TRUE, TRUE); printf("\nMetadata saved to file %s.\n", out_fn); free(savedata); close(out_fd); @@ -613,15 +852,17 @@ exit(0); } -int restore_data(int fd, int in_fd) +int restore_data(int fd, int in_fd, int printblocksonly) { size_t rs; uint64_t buf64, writes = 0; uint16_t buf16; int first = 1; - uint64_t max_fs_size; - do_lseek(fd, 0); + if (!printblocksonly) + do_lseek(fd, 0); + blks_saved = total_out = 0; + last_fs_block = 0; while (TRUE) { memset(savedata, 0, sizeof(struct saved_metablock)); rs = read(in_fd, &buf64, sizeof(uint64_t)); @@ -631,12 +872,14 @@ fprintf(stderr, "Error reading from file.\n"); return -1; } + total_out += bufsize; savedata->blk = be64_to_cpu(buf64); - if (savedata->blk >= max_fs_size) { + if (!printblocksonly && + last_fs_block && savedata->blk >= last_fs_block) { fprintf(stderr, "Error: File system is too small to " "restore this metadata.\n"); fprintf(stderr, "File system is %" PRIu64 " blocks, ", - max_fs_size); + last_fs_block); fprintf(stderr, "Restore block = %" PRIu64 "\n", savedata->blk); return -1; @@ -648,64 +891,100 @@ do_read(in_fd, savedata->buf, savedata->siglen); if (first) { gfs2_sb_in(&sbd.sd_sb, savedata->buf); - if (check_sb(&sbd.sd_sb)) { + sbd1 = (struct gfs_sb *)&sbd.sd_sb; + 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) + ; + else if (check_sb(&sbd.sd_sb)) { fprintf(stderr,"Error: Invalid superblock data.\n"); return -1; } bufsize = sbd.sd_sb.sb_bsize; - last_fs_block = - lseek(fd, 0, SEEK_END) / bufsize; - printf("There are %" PRIu64 " blocks of %" \ - PRIu64 "bytes in the destination file" \ - " system.\n\n", last_fs_block, bufsize); + if (!printblocksonly) { + last_fs_block = + lseek(fd, 0, SEEK_END) / + bufsize; + printf("There are %" PRIu64 " blocks of %" \ + PRIu64 " bytes in the destination" \ + " file system.\n\n", + last_fs_block, bufsize); + } first = 0; } - do_lseek(fd, savedata->blk * bufsize); - do_write(fd, savedata->buf, bufsize); - writes++; + if (printblocksonly) { + print_gfs2("%d (l=0x%x): ", blks_saved, + savedata->siglen); + block = savedata->blk; + display_block_type(savedata->buf, TRUE); + } else { + warm_fuzzy_stuff(savedata->blk, FALSE, FALSE); + if (savedata->blk >= last_fs_block) { + printf("Out of space on the destination " + "device; quitting.\n"); + break; + } + do_lseek(fd, savedata->blk * bufsize); + do_write(fd, savedata->buf, bufsize); + writes++; + } + blks_saved++; } else { fprintf(stderr, "Bad record length: %d for #%" PRIu64".\n", savedata->siglen, savedata->blk); return -1; } } - printf("%" PRIu64 " blocks restored.\n", writes); + if (!printblocksonly) + warm_fuzzy_stuff(savedata->blk, TRUE, FALSE); return 0; } -void restoremeta(const char *in_fn, const char *out_device) +void complain(const char *complaint) { - int in_fd; + fprintf(stderr, "%s\n", complaint); + die("Format is: \ngfs2_edit restoremeta " + "\n"); +} + +void restoremeta(const char *in_fn, const char *out_device, + int printblocksonly) +{ + int in_fd, error; + termlines = 0; if (!in_fn) - die("No source file specified. Format is: \ngfs2_edit " - "restoremeta \n"); - if (!out_device) - die("No destination file system specified. Format is: \n" - "gfs2_edit restoremeta \n"); + complain("No source file specified."); + if (!printblocksonly && !out_device) + complain("No destination file system specified."); in_fd = open(in_fn, O_RDONLY); if (in_fd < 0) die("Can't open source file %s: %s\n", in_fn, strerror(errno)); - fd = open(out_device, O_RDWR); - if (fd < 0) - die("Can't open destination file system %s: %s\n", - out_device, strerror(errno)); - + if (!printblocksonly) { + sbd.device_fd = open(out_device, O_RDWR); + if (sbd.device_fd < 0) + die("Can't open destination file system %s: %s\n", + out_device, strerror(errno)); + } savedata = malloc(sizeof(struct saved_metablock)); if (!savedata) die("Can't allocate memory for the restore operation.\n"); - blks_saved = total_out = 0; - if (restore_data(fd, in_fd) == 0) - printf("File %s restore successful.\n", in_fn); - else - printf("File %s restore error.\n", in_fn); + blks_saved = 0; + error = restore_data(sbd.device_fd, in_fd, printblocksonly); + printf("File %s %s %s.\n", in_fn, + (printblocksonly ? "print" : "restore"), + (error ? "error" : "successful")); free(savedata); close(in_fd); - close(fd); + if (!printblocksonly) + close(sbd.device_fd); exit(0); } --- cluster/gfs2/libgfs2/ondisk.c 2007/10/11 20:32:36 1.5.2.3 +++ cluster/gfs2/libgfs2/ondisk.c 2007/11/16 19:42:35 1.5.2.4 @@ -386,7 +386,7 @@ memset(buf, 0, GFS2_FNAMESIZE + 1); memcpy(buf, name, de->de_name_len); - printf(" name = %s\n", buf); + print_it(" name", "%s", NULL, buf); } void gfs2_leaf_in(struct gfs2_leaf *lf, char *buf) @@ -462,7 +462,7 @@ memset(buf, 0, GFS2_EA_MAX_NAME_LEN + 1); memcpy(buf, name, ea->ea_name_len); - printf(" name = %s\n", buf); + print_it(" name", "%s", NULL, buf); } void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf) --- cluster/gfs2/libgfs2/ondisk.h 2006/06/14 13:55:11 1.2 +++ cluster/gfs2/libgfs2/ondisk.h 2007/11/16 19:42:35 1.2.2.1 @@ -35,6 +35,8 @@ extern void gfs2_ea_header_out(struct gfs2_ea_header *ea, char *buf); extern void gfs2_log_header_in(struct gfs2_log_header *lh, char *buf); extern void gfs2_log_header_out(struct gfs2_log_header *lh, char *buf); +extern void gfs2_log_descriptor_in(struct gfs2_log_descriptor *ld, char *buf); +extern void gfs2_log_descriptor_out(struct gfs2_log_descriptor *ld, char *buf); extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, char *buf); extern void gfs2_inum_range_out(struct gfs2_inum_range *ir, char *buf); extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, char *buf);