1    	#include "clusterautoconfig.h"
2    	
3    	#include <stdio.h>
4    	#include <stdlib.h>
5    	#include <ctype.h>
6    	#include <string.h>
7    	#include <inttypes.h>
8    	#include <sys/types.h>
9    	#include <sys/stat.h>
10   	#include <fcntl.h>
11   	#include <unistd.h>
12   	#include <errno.h>
13   	#include <curses.h>
14   	#include <term.h>
15   	#include <signal.h>
16   	#include <sys/ioctl.h>
17   	#include <sys/mount.h>
18   	#include <dirent.h>
19   	
20   	#include "copyright.cf"
21   	
22   	#include "hexedit.h"
23   	#include "libgfs2.h"
24   	#include "gfs2hex.h"
25   	#include "extended.h"
26   	#include "journal.h"
27   	#include "struct_print.h"
28   	
29   	const char *mtypes[] = {"none", "sb", "rg", "rb", "di", "in", "lf", "jd",
30   				"lh", "ld", "ea", "ed", "lb", "13", "qc"};
31   	
32   	static struct lgfs2_buffer_head *bh;
33   	static int pgnum;
34   	static long int gziplevel = 9;
35   	static int termcols;
36   	
37   	int details = 0;
38   	char *device = NULL;
39   	
40   	/* ------------------------------------------------------------------------- */
41   	/* erase - clear the screen */
42   	/* ------------------------------------------------------------------------- */
43   	static void Erase(void)
44   	{
45   		bkgd(A_NORMAL|COLOR_PAIR(COLOR_NORMAL));
46   		/* clear();*/ /* doesn't set background correctly */
47   		erase();
48   		/*bkgd(bg);*/
49   	}
50   	
51   	/* ------------------------------------------------------------------------- */
52   	/* display_title_lines */
53   	/* ------------------------------------------------------------------------- */
54   	static void display_title_lines(void)
55   	{
56   		Erase();
57   		COLORS_TITLE;
58   		move(0, 0);
59   		printw("%-80s",TITLE1);
60   		move(termlines, 0);
61   		printw("%-79s",TITLE2);
62   		COLORS_NORMAL;
63   	}
64   	
65   	/* ------------------------------------------------------------------------- */
66   	/* bobgets - get a string                                                    */
67   	/* returns: 1 if user exited by hitting enter                                */
68   	/*          0 if user exited by hitting escape                               */
69   	/* ------------------------------------------------------------------------- */
70   	static int bobgets(char string[],int x,int y,int sz,int *ch)
71   	{
72   		int done,runningy,rc;
73   	
74   		move(x,y);
75   		done=FALSE;
76   		COLORS_INVERSE;
77   		move(x,y);
78   		addstr(string);
79   		move(x,y);
80   		curs_set(2);
81   		refresh();
82   		runningy=y;
83   		rc=0;
84   		while (!done) {
85   			*ch = getch();
86   			
87   			if(*ch < 0x0100 && isprint(*ch)) {
88   				char *p=string+strlen(string); // end of the string
89   	
90   				*(p+1)='\0';
91   				while (insert && p > &string[runningy-y]) {
92   					*p=*(p-1);
93   					p--;
94   				}
95   				string[runningy-y]=*ch;
96   				runningy++;
97   				move(x,y);
98   				addstr(string);
99   				if (runningy-y >= sz) {
100  					rc=1;
101  					*ch = KEY_RIGHT;
102  					done = TRUE;
103  				}
104  			}
105  			else {
106  				// special character, is it one we recognize?
107  				switch(*ch)
108  				{
109  				case(KEY_ENTER):
110  				case('\n'):
111  				case('\r'):
112  					rc=1;
113  					done=TRUE;
114  					string[runningy-y] = '\0';
115  					break;
116  				case(KEY_CANCEL):
117  				case(0x01B):
118  					rc=0;
119  					done=TRUE;
120  					break;
121  				case(KEY_LEFT):
122  					if (dmode == HEX_MODE) {
123  						done = TRUE;
124  						rc = 1;
125  					}
126  					else
127  						runningy--;
128  					break;
129  				case(KEY_RIGHT):
130  					if (dmode == HEX_MODE) {
131  						done = TRUE;
132  						rc = 1;
133  					}
134  					else
135  						runningy++;
136  					break;
137  				case(KEY_DC):
138  				case(0x07F):
139  					if (runningy>=y) {
140  						char *p;
141  						p = &string[runningy - y];
142  						while (*p) {
143  							*p = *(p + 1);
144  							p++;
145  						}
146  						*p = '\0';
147  						runningy--;
148  						// remove the character from the string 
149  						move(x,y);
150  						addstr(string);
151  						COLORS_NORMAL;
152  						addstr(" ");
153  						COLORS_INVERSE;
154  						runningy++;
155  					}
156  					break;
157  				case(KEY_BACKSPACE):
158  					if (runningy>y) {
159  						char *p;
160  	
161  						p = &string[runningy - y - 1];
162  						while (*p) {
163  							*p = *(p + 1);
164  							p++;
165  						}
166  						*p='\0';
167  						runningy--;
168  						// remove the character from the string 
169  						move(x,y);
170  						addstr(string);
171  						COLORS_NORMAL;
172  						addstr(" ");
173  						COLORS_INVERSE;
174  					}
175  					break;
176  				case KEY_DOWN:	// Down
177  					rc=0x5000U;
178  					done=TRUE;
179  					break;
180  				case KEY_UP:	// Up
181  					rc=0x4800U;
182  					done=TRUE;
183  					break;
184  				case 0x014b:
185  					insert=!insert;
186  					move(0,68);
187  					if (insert)
188  						printw("insert ");
189  					else
190  						printw("replace");
191  					break;
192  				default:
193  					move(0,70);
194  					printw("%08x",*ch);
195  					// ignore all other characters
196  					break;
197  				} // end switch on non-printable character
198  			} // end non-printable character
199  			move(x,runningy);
200  			refresh();
201  		} // while !done
202  		if (sz>0)
203  			string[sz]='\0';
204  		COLORS_NORMAL;
205  		return rc;
206  	}/* bobgets */
207  	
208  	/******************************************************************************
209  	** instr - instructions
210  	******************************************************************************/
211  	static void gfs2instr(const char *s1, const char *s2)
212  	{
213  		COLORS_HIGHLIGHT;
214  		move(line,0);
215  		printw("%s", s1);
216  		COLORS_NORMAL;
217  		move(line,17);
218  		printw("%s", s2);
219  		line++;
220  	}
221  	
222  	/******************************************************************************
223  	*******************************************************************************
224  	**
225  	** void print_usage()
226  	**
227  	** Description:
228  	**   This routine prints out the appropriate commands for this application.
229  	**
230  	*******************************************************************************
231  	******************************************************************************/
232  	
233  	static void print_usage(void)
234  	{
235  		line = 2;
236  		Erase();
237  		display_title_lines();
238  		move(line++,0);
239  		printw("Supported commands: (roughly conforming to the rules of 'less')");
240  		line++;
241  		move(line++,0);
242  		printw("Navigation:");
243  		gfs2instr("<pg up>/<down>","Move up or down one screen full");
244  		gfs2instr("<up>/<down>","Move up or down one line");
245  		gfs2instr("<left>/<right>","Move left or right one byte");
246  		gfs2instr("<home>","Return to the superblock.");
247  		gfs2instr("   f","Forward one 4K block");
248  		gfs2instr("   b","Backward one 4K block");
249  		gfs2instr("   g","Goto a given block (number, master, root, rindex, jindex, etc)");
250  		gfs2instr("   j","Jump to the highlighted 64-bit block number.");
251  		gfs2instr("    ","(You may also arrow up to the block number and hit enter)");
252  		gfs2instr("<backspace>","Return to a previous block (a block stack is kept)");
253  		gfs2instr("<space>","Jump forward to block before backspace (opposite of backspace)");
254  		line++;
255  		move(line++, 0);
256  		printw("Other commands:");
257  		gfs2instr("   h","This Help display");
258  		gfs2instr("   c","Toggle the color scheme");
259  		gfs2instr("   m","Switch display mode: hex -> GFS2 structure -> Extended");
260  		gfs2instr("   q","Quit (same as hitting <escape> key)");
261  		gfs2instr("<enter>","Edit a value (enter to save, esc to discard)");
262  		gfs2instr("       ","(Currently only works on the hex display)");
263  		gfs2instr("<escape>","Quit the program");
264  		line++;
265  		move(line++, 0);
266  		printw("Notes: Areas shown in red are outside the bounds of the struct/file.");
267  		move(line++, 0);
268  		printw("       Areas shown in blue are file contents.");
269  		move(line++, 0);
270  		printw("       Characters shown in green are selected for edit on <enter>.");
271  		move(line++, 0);
272  		move(line++, 0);
273  		printw("Press any key to return.");
274  		refresh();
275  		getch(); // wait for input
276  		Erase();
277  	}
278  	
279  	const struct lgfs2_metadata *get_block_type(char *buf)
280  	{
281  		uint32_t t = lgfs2_get_block_type(buf);
282  	
283  		if (t != 0)
284  			return lgfs2_find_mtype(t);
285  		return NULL;
286  	}
287  	
288  	/**
289  	 * returns: metatype if block is a GFS2 structure block type
290  	 *          0 if block is not a GFS2 structure
291  	 */
292  	int display_block_type(char *buf, uint64_t addr, int from_restore)
293  	{
294  		const struct lgfs2_metadata *mtype;
295  		const struct gfs2_meta_header *mh;
296  		int ret_type = 0; /* return type */
297  	
298  		/* first, print out the kind of GFS2 block this is */
299  		if (termlines) {
300  			line = 1;
301  			move(line, 0);
302  		}
303  		print_gfs2("Block #");
304  		if (termlines) {
305  			if (edit_row[dmode] == -1)
306  				COLORS_HIGHLIGHT;
307  		}
308  		if (block == RGLIST_DUMMY_BLOCK)
309  			print_gfs2("RG List       ");
310  		else if (block == JOURNALS_DUMMY_BLOCK)
311  			print_gfs2("Journal Status:      ");
312  		else
313  			print_gfs2("%"PRIu64"    (0x%"PRIx64")", addr, addr);
314  		if (termlines) {
315  			if (edit_row[dmode] == -1)
316  				COLORS_NORMAL;
317  		}
318  		print_gfs2(" ");
319  		if (!from_restore)
320  			print_gfs2("of %"PRIu64" (0x%"PRIx64") ", max_block, max_block);
321  		if (block == RGLIST_DUMMY_BLOCK) {
322  			ret_type = GFS2_METATYPE_RG;
323  			struct_len = sizeof(struct gfs2_rgrp);
324  		} else if (block == JOURNALS_DUMMY_BLOCK) {
325  			ret_type = GFS2_METATYPE_DI;
326  			struct_len = 0;
327  		} else {
328  			mtype = get_block_type(buf);
329  			if (mtype != NULL) {
330  				print_gfs2("(%s)", mtype->display);
331  				struct_len = mtype->size;
332  				ret_type = mtype->mh_type;
333  			} else {
334  				struct_len = sbd.sd_bsize;
335  				ret_type = 0;
336  			}
337  		}
338  		mh = (void *)buf;
339  		eol(0);
340  		if (from_restore)
341  			return ret_type;
342  		if (termlines && dmode == HEX_MODE) {
343  			int type;
344  			struct lgfs2_rgrp_tree *rgd;
345  	
346  			rgd = lgfs2_blk2rgrpd(&sbd, block);
347  			if (rgd) {
348  				lgfs2_rgrp_read(&sbd, rgd);
349  				if ((be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RG) ||
350  				    (be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RB))
351  					type = 4;
352  				else {
353  					type = lgfs2_get_bitmap(&sbd, block, rgd);
354  				}
355  			} else
356  				type = 4;
357  			screen_chunk_size = ((termlines - 4) * 16) >> 8 << 8;
358  			if (!screen_chunk_size)
359  				screen_chunk_size = 256;
360  			pgnum = (offset / screen_chunk_size);
361  			if (type >= 0) {
362  				print_gfs2("(p.%d of %d--%s)", pgnum + 1,
363  					   (sbd.sd_bsize % screen_chunk_size) > 0 ?
364  					   sbd.sd_bsize / screen_chunk_size + 1 : sbd.sd_bsize /
365  					   screen_chunk_size, lgfs2_blkst_str(type));
366  			}
367  			/*eol(9);*/
368  			if ((be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RG)) {
369  				int ptroffset = edit_row[dmode] * 16 + edit_col[dmode];
370  	
371  				if (rgd && (ptroffset >= struct_len || pgnum)) {
372  					int blknum, b, btype;
373  	
374  					blknum = pgnum * screen_chunk_size;
375  					blknum += (ptroffset - struct_len);
376  					blknum *= 4;
377  					blknum += rgd->rt_data0;
378  	
379  					print_gfs2(" blk ");
380  					for (b = blknum; b < blknum + 4; b++) {
381  						btype = lgfs2_get_bitmap(&sbd, b, rgd);
382  						print_gfs2("0x%x-%s  ", b, lgfs2_blkst_str(btype));
383  					}
384  				}
385  			} else if ((be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RB)) {
386  				int ptroffset = edit_row[dmode] * 16 + edit_col[dmode];
387  	
388  				if (rgd && (ptroffset >= struct_len || pgnum)) {
389  					int blknum, b, btype, rb_number;
390  	
391  					rb_number = block - rgd->rt_addr;
392  					blknum = 0;
393  					/* count the number of bytes representing
394  					   blocks prior to the displayed screen. */
395  					for (b = 0; b < rb_number; b++) {
396  						struct_len = (b ?
397  						      sizeof(struct gfs2_meta_header) :
398  						      sizeof(struct gfs2_rgrp));
399  						blknum += (sbd.sd_bsize - struct_len);
400  					}
401  					struct_len = sizeof(struct gfs2_meta_header);
402  					/* add the number of bytes on this screen */
403  					blknum += (ptroffset - struct_len);
404  					/* factor in the page number */
405  					blknum += pgnum * screen_chunk_size;
406  					/* convert bytes to blocks */
407  					blknum *= GFS2_NBBY;
408  					/* add the starting offset for this rgrp */
409  					blknum += rgd->rt_data0;
410  					print_gfs2(" blk ");
411  					for (b = blknum; b < blknum + 4; b++) {
412  						btype = lgfs2_get_bitmap(&sbd, b, rgd);
413  						print_gfs2("0x%x-%s  ", b, lgfs2_blkst_str(btype));
414  					}
415  				}
416  			}
417  			if (rgd)
418  				lgfs2_rgrp_relse(&sbd, rgd);
419  	 	}
420  		if (block == sbd.sd_root_dir.in_addr)
421  			print_gfs2("--------------- Root directory ------------------");
422  		else if (block == sbd.sd_meta_dir.in_addr)
423  			print_gfs2("-------------- Master directory -----------------");
424  		else if (block == RGLIST_DUMMY_BLOCK)
425  			print_gfs2("------------------ RG List ----------------------");
426  		else if (block == JOURNALS_DUMMY_BLOCK)
427  			print_gfs2("-------------------- Journal List --------------------");
428  		else {
429  			int d;
430  	
431  			for (d = 2; d < 8; d++) {
432  				if (block == masterdir.dirent[d].inum.in_addr) {
433  					if (!strncmp(masterdir.dirent[d].filename, "jindex", 6))
434  						print_gfs2("--------------- Journal Index ------------------");
435  					else if (!strncmp(masterdir.dirent[d].filename, "per_node", 8))
436  						print_gfs2("--------------- Per-node Dir -------------------");
437  					else if (!strncmp(masterdir.dirent[d].filename, "inum", 4))
438  						print_gfs2("---------------- Inum file ---------------------");
439  					else if (!strncmp(masterdir.dirent[d].filename, "statfs", 6))
440  						print_gfs2("---------------- statfs file -------------------");
441  					else if (!strncmp(masterdir.dirent[d].filename, "rindex", 6))
442  						print_gfs2("---------------- rindex file -------------------");
443  					else if (!strncmp(masterdir.dirent[d].filename, "quota", 5))
444  						print_gfs2("---------------- Quota file --------------------");
445  				}
446  			}
447  		}
448  		eol(0);
449  		return ret_type;
450  	}
451  	
452  	static int get_pnum(int ptroffset)
453  	{
454  		int pnum;
455  	
456  		pnum = pgnum * screen_chunk_size;
457  		pnum += (ptroffset - struct_len);
458  		pnum /= sizeof(uint64_t);
459  	
460  		return pnum;
461  	}
462  	
463  	/* ------------------------------------------------------------------------ */
464  	/* hexdump - hex dump the filesystem block to the screen                    */
465  	/* ------------------------------------------------------------------------ */
466  	static int hexdump(uint64_t startaddr, uint64_t len, int trunc_zeros,
467  			   uint64_t flagref, uint64_t ref_blk)
468  	{
469  		const unsigned char *pointer, *ptr2;
470  		int i;
471  		uint64_t l;
472  		const char *lpBuffer = bh->b_data;
473  		const char *zeros_strt = lpBuffer + sbd.sd_bsize;
474  		int print_field, cursor_line;
475  		const struct lgfs2_metadata *m = get_block_type(bh->b_data);
476  		__be64 *ref;
477  		int ptroffset = 0;
478  	
479  		strcpy(edit_fmt,"%02x");
480  		pointer = (unsigned char *)lpBuffer + offset;
481  		ptr2 = (unsigned char *)lpBuffer + offset;
482  		ref = (__be64 *)lpBuffer + offset;
483  		if (trunc_zeros) {
484  			while (zeros_strt > lpBuffer && (*(zeros_strt - 1) == 0))
485  				zeros_strt--;
486  		}
487  		l = offset;
488  		print_entry_ndx = 0;
489  		while (((termlines && line < termlines &&
490  			 line <= ((screen_chunk_size / 16) + 2)) ||
491  			(!termlines && l < len)) && l < sbd.sd_bsize) {
492  			int ptr_not_null = 0;
493  	
494  			if (termlines) {
495  				move(line, 0);
496  				COLORS_OFFSETS; /* cyan for offsets */
497  			}
498  			if (startaddr < 0xffffffff)
499  				print_gfs2("%.8"PRIx64, startaddr + l);
500  			else
501  				print_gfs2("%.16"PRIx64, startaddr + l);
502  			if (termlines) {
503  				if (l < struct_len)
504  					COLORS_NORMAL; /* normal part of structure */
505  				else if (gfs2_struct_type == GFS2_METATYPE_DI &&
506  						 l < struct_len + be64_to_cpu(di->di_size))
507  					COLORS_CONTENTS; /* after struct but not eof */
508  				else
509  					COLORS_SPECIAL; /* beyond end of the struct */
510  			}
511  			print_field = -1;
512  			cursor_line = 0;
513  			for (i = 0; i < 16; i++) { /* first print it in hex */
514  				/* Figure out if we have a null pointer--for colors */
515  				if (((gfs2_struct_type == GFS2_METATYPE_IN) ||
516  				     (gfs2_struct_type == GFS2_METATYPE_DI &&
517  				      l < struct_len + be64_to_cpu(di->di_size) &&
518  				      (be16_to_cpu(di->di_height) > 0 ||
519  				      !S_ISREG(be32_to_cpu(di->di_mode))))) &&
520  				    (i==0 || i==8)) {
521  					int j;
522  	
523  					ptr_not_null = 0;
524  					for (j = 0; j < 8; j++) {
525  						if (*(pointer + j)) {
526  							ptr_not_null = 1;
527  							break;
528  						}
529  					}
530  				}
531  				if (termlines) {
532  					if (l + i < struct_len)
533  						COLORS_NORMAL; /* in the structure */
534  					else if (gfs2_struct_type == GFS2_METATYPE_DI
535  						 && l + i < struct_len + be64_to_cpu(di->di_size)) {
536  						if ((!di->di_height &&
537  						     S_ISREG(be32_to_cpu(di->di_mode))) ||
538  						    !ptr_not_null)
539  							COLORS_CONTENTS;/*stuff data */
540  						else
541  							COLORS_SPECIAL;/* non-null */
542  					}
543  					else if (gfs2_struct_type == GFS2_METATYPE_IN){
544  						if (ptr_not_null)
545  							COLORS_SPECIAL;/* non-null */
546  						else
547  							COLORS_CONTENTS;/* null */
548  					} else
549  						COLORS_SPECIAL; /* past the struct */
550  				}
551  				if (i%4 == 0)
552  					print_gfs2(" ");
553  				if (termlines && line == edit_row[dmode] + 3 &&
554  					i == edit_col[dmode]) {
555  					COLORS_HIGHLIGHT; /* in the structure */
556  					memset(estring,0,3);
557  					sprintf(estring,"%02x",*pointer);
558  					cursor_line = 1;
559  					print_field = (char *)pointer - bh->b_data;
560  				}
561  				print_gfs2("%02x",*pointer);
562  				if (termlines && line == edit_row[dmode] + 3 &&
563  					i == edit_col[dmode]) {
564  					if (l < struct_len + offset)
565  						COLORS_NORMAL; /* in the structure */
566  					else
567  						COLORS_SPECIAL; /* beyond structure */
568  				}
569  				pointer++;
570  			}
571  			print_gfs2(" [");
572  			for (i=0; i<16; i++) { /* now print it in character format */
573  				if ((*ptr2 >=' ') && (*ptr2 <= '~'))
574  					print_gfs2("%c",*ptr2);
575  				else
576  					print_gfs2(".");
577  				ptr2++;
578  			}
579  			print_gfs2("] ");
580  			if (print_field >= 0) {
581  				if (m) {
582  					const struct lgfs2_metafield *f;
583  					unsigned n;
584  					for (n = 0; n < m->nfields; n++) {
585  						f = &m->fields[n];
586  						if (print_field >= f->offset &&
587  						    print_field < (f->offset + f->length)) {
588  							print_gfs2("%s", m->fields[n].name);
589  							break;
590  						}
591  					}
592  				}
593  	
594  			}
595  			if (m && cursor_line) {
596  				const uint32_t block_type = m->mh_type;
597  				int isdir;
598  	
599  				isdir = ((block_type == GFS2_METATYPE_DI) &&
600  				         (((struct gfs2_dinode*)bh->b_data)->di_height ||
601  					  S_ISDIR(be32_to_cpu(di->di_mode))));
602  	
603  				if (block_type == GFS2_METATYPE_IN ||
604  				    block_type == GFS2_METATYPE_LD || isdir) {
605  	
606  					ptroffset = edit_row[dmode] * 16 +
607  						edit_col[dmode];
608  	
609  					if (ptroffset >= struct_len || pgnum) {
610  						int pnum = get_pnum(ptroffset);
611  						if (block_type == GFS2_METATYPE_LD)
612  							print_gfs2("*");
613  						print_gfs2("pointer 0x%x", pnum);
614  					}
615  				}
616  			}
617  			if (line - 3 > last_entry_onscreen[dmode])
618  				last_entry_onscreen[dmode] = line - 3;
619  			if (flagref && be64_to_cpu(*ref) == flagref)
620  				print_gfs2("<------------------------- ref in 0x%"PRIx64" "
621  					   "to 0x%"PRIx64, ref_blk, flagref);
622  			ref++;
623  			if (flagref && be64_to_cpu(*ref) == flagref)
624  				print_gfs2("<------------------------- ref in 0x%"PRIx64" "
625  					   "to 0x%"PRIx64, ref_blk, flagref);
626  			ref++;
627  			eol(0);
628  			l += 16;
629  			print_entry_ndx++;
630  			/* This should only happen if trunc_zeros is specified: */
631  			if ((const char *)pointer >= zeros_strt)
632  				break;
633  		} /* while */
634  		if (m && m->mh_type == GFS2_METATYPE_LD && ptroffset >= struct_len) {
635  			COLORS_NORMAL;
636  			eol(0);
637  			print_gfs2("         * 'j' will jump to the journaled block, "
638  				   "not the absolute block.");
639  			eol(0);
640  		}
641  		return (offset+len);
642  	}/* hexdump */
643  	
644  	/* ------------------------------------------------------------------------ */
645  	/* masterblock - find a file (by name) in the master directory and return   */
646  	/*               its block number.                                          */
647  	/* ------------------------------------------------------------------------ */
648  	uint64_t masterblock(const char *fn)
649  	{
650  		int d;
651  		
652  		for (d = 2; d < 8; d++)
653  			if (!strncmp(masterdir.dirent[d].filename, fn, strlen(fn)))
654  				return (masterdir.dirent[d].inum.in_addr);
655  		return 0;
656  	}
657  	
658  	/* ------------------------------------------------------------------------ */
659  	/* rgcount - return how many rgrps there are.                               */
660  	/* ------------------------------------------------------------------------ */
661  	static void rgcount(void)
662  	{
663  		printf("%"PRId64" RGs in this file system.\n",
664  		       sbd.md.riinode->i_size / sizeof(struct gfs2_rindex));
665  		lgfs2_inode_put(&sbd.md.riinode);
666  		lgfs2_rgrp_free(&sbd, &sbd.rgtree);
667  		exit(EXIT_SUCCESS);
668  	}
669  	
670  	/* ------------------------------------------------------------------------ */
671  	/* find_rgrp_block - locate the block for a given rgrp number               */
672  	/* ------------------------------------------------------------------------ */
673  	static uint64_t find_rgrp_block(struct lgfs2_inode *dif, int rg)
674  	{
675  		int amt;
676  		struct gfs2_rindex ri;
677  		uint64_t foffset;
678  	
679  		foffset = rg * sizeof(struct gfs2_rindex);
680  		amt = lgfs2_readi(dif, &ri, foffset, sizeof(ri));
681  		if (!amt) /* end of file */
682  			return 0;
683  		return be64_to_cpu(ri.ri_addr);
684  	}
685  	
686  	/* ------------------------------------------------------------------------ */
687  	/* get_rg_addr                                                              */
688  	/* ------------------------------------------------------------------------ */
689  	static uint64_t get_rg_addr(int rgnum)
690  	{
691  		uint64_t rgblk = 0, gblock;
692  		struct lgfs2_inode *riinode;
693  	
694  		gblock = masterblock("rindex");
695  		riinode = lgfs2_inode_read(&sbd, gblock);
696  		if (riinode == NULL)
697  			return 0;
698  		if (rgnum < riinode->i_size / sizeof(struct gfs2_rindex))
699  			rgblk = find_rgrp_block(riinode, rgnum);
700  		else
701  			fprintf(stderr, "Error: File system only has %"PRId64" RGs.\n",
702  				riinode->i_size / sizeof(struct gfs2_rindex));
703  		lgfs2_inode_put(&riinode);
704  		return rgblk;
705  	}
706  	
707  	/* ------------------------------------------------------------------------ */
708  	/* set_rgrp_flags - Set an rgrp's flags to a given value                    */
709  	/* rgnum: which rg to print or modify flags for (0 - X)                     */
710  	/* new_flags: value to set new rg_flags to (if modify == TRUE)              */
711  	/* modify: TRUE if the value is to be modified, FALSE if it's to be printed */
712  	/* full: TRUE if the full RG should be printed.                             */
713  	/* ------------------------------------------------------------------------ */
714  	static void set_rgrp_flags(int rgnum, uint32_t new_flags, int modify, int full)
715  	{
716  		struct lgfs2_buffer_head *rbh;
717  		struct gfs2_rgrp *rg;
718  		uint64_t rgblk;
719  	
720  		rgblk = get_rg_addr(rgnum);
721  		rbh = lgfs2_bread(&sbd, rgblk);
722  		rg = (void *)rbh->b_data;
723  	
724  		if (modify) {
725  			uint32_t flags = be32_to_cpu(rg->rg_flags);
726  	
727  			printf("RG #%d (block %"PRIu64" / 0x%"PRIx64") rg_flags changed from 0x%08x to 0x%08x\n",
728  			       rgnum, rgblk, rgblk, flags, new_flags);
729  			rg->rg_flags = cpu_to_be32(new_flags);
730  			lgfs2_bmodified(rbh);
731  		} else {
732  			if (full) {
733  				print_gfs2("RG #%d", rgnum);
734  				print_gfs2(" located at: %"PRIu64" (0x%"PRIx64")", rgblk, rgblk);
735  	                        eol(0);
736  				rgrp_print(rg);
737  			}
738  			else
739  				printf("RG #%d (block %"PRIu64" / 0x%"PRIx64") rg_flags = 0x%08x\n",
740  				       rgnum, rgblk, rgblk, be32_to_cpu(rg->rg_flags));
741  		}
742  		lgfs2_brelse(rbh);
743  		if (modify)
744  			fsync(sbd.device_fd);
745  	}
746  	
747  	int has_indirect_blocks(void)
748  	{
749  		if (indirect_blocks || gfs2_struct_type == GFS2_METATYPE_SB ||
750  		    gfs2_struct_type == GFS2_METATYPE_LF ||
751  		    (gfs2_struct_type == GFS2_METATYPE_DI &&
752  		     (S_ISDIR(be32_to_cpu(di->di_mode)))))
753  			return TRUE;
754  		return FALSE;
755  	}
756  	
757  	int block_is_rindex(uint64_t blk)
758  	{
759  		return blk == masterblock("rindex");
760  	}
761  	
762  	int block_is_inum_file(uint64_t blk)
763  	{
764  		return blk == masterblock("inum");
765  	}
766  	
767  	int block_is_statfs_file(uint64_t blk)
768  	{
769  		return blk == masterblock("statfs");
770  	}
771  	
772  	int block_is_quota_file(uint64_t blk)
773  	{
774  		return blk == masterblock("quota");
775  	}
776  	
777  	int block_is_per_node(uint64_t blk)
778  	{
779  		return blk == masterblock("per_node");
780  	}
781  	
782  	/* ------------------------------------------------------------------------ */
783  	/* block_has_extended_info                                                  */
784  	/* ------------------------------------------------------------------------ */
785  	static int block_has_extended_info(void)
786  	{
787  		if (has_indirect_blocks() ||
788  		    block_is_rindex(block) ||
789  		    block_is_rgtree(block) ||
790  		    block_is_journals(block) ||
791  		    block_is_inum_file(block) ||
792  		    block_is_statfs_file(block) ||
793  		    block_is_quota_file(block))
794  			return TRUE;
795  		return FALSE;
796  	}
797  	
798  	static void read_superblock(int fd)
799  	{
800  		struct gfs2_meta_header *mh;
801  	
802  		ioctl(fd, BLKFLSBUF, 0);
803  		memset(&sbd, 0, sizeof(struct lgfs2_sbd));
804  		sbd.sd_bsize = LGFS2_DEFAULT_BSIZE;
805  		sbd.device_fd = fd;
806  		bh = lgfs2_bread(&sbd, 0x10);
807  		sbd.rgtree.osi_node = NULL;
808  		lgfs2_sb_in(&sbd, bh->b_data);
809  		mh = (struct gfs2_meta_header *)bh->b_data;
810  		if (!sbd.sd_bsize)
811  			sbd.sd_bsize = LGFS2_DEFAULT_BSIZE;
812  		if (lgfs2_get_dev_info(fd, &sbd.dinfo)) {
813  			perror(device);
814  			exit(-1);
815  		}
816  		if (lgfs2_compute_constants(&sbd)) {
817  			fprintf(stderr, "Failed to compute constants.\n");
818  			exit(-1);
819  		}
820  		if (be32_to_cpu(mh->mh_magic) == GFS2_MAGIC &&
821  		    be32_to_cpu(mh->mh_type) == GFS2_METATYPE_SB)
822  			block = 0x10 * (LGFS2_DEFAULT_BSIZE / sbd.sd_bsize);
823  		else
824  			block = starting_blk = 0;
825  		lgfs2_fix_device_geometry(&sbd);
826  		sbd.sd_inptrs = (sbd.sd_bsize - sizeof(struct gfs2_meta_header)) /
827  			sizeof(uint64_t);
828  		sbd.sd_diptrs = (sbd.sd_bsize - sizeof(struct gfs2_dinode)) /
829  			sizeof(uint64_t);
830  		sbd.master_dir = lgfs2_inode_read(&sbd, sbd.sd_meta_dir.in_addr);
831  		if (sbd.master_dir == NULL) {
832  			sbd.md.riinode = NULL;
833  		} else {
834  			sbd.md.riinode = lgfs2_lookupi(sbd.master_dir, "rindex", 6);
835  		}
836  		lgfs2_brelse(bh);
837  		bh = NULL;
838  	}
839  	
840  	static int read_rindex(void)
841  	{
842  		uint64_t count;
843  		int ok;
844  	
845  		sbd.fssize = sbd.device.length;
846  		if (sbd.md.riinode) /* If we found the rindex */
847  			lgfs2_rindex_read(&sbd, &count, &ok);
848  	
(64) Event example_checked: Example 2: "sbd.rgtree.osi_node" has its value checked in "sbd.rgtree.osi_node == NULL".
Also see events: [null_field][example_checked][example_checked][example_checked][example_checked][dereference]
849  		if (!OSI_EMPTY_ROOT(&sbd.rgtree)) {
850  			struct lgfs2_rgrp_tree *rg = (struct lgfs2_rgrp_tree *)osi_last(&sbd.rgtree);
851  			sbd.fssize = rg->rt_data0 + rg->rt_data;
852  		}
853  		return 0;
854  	}
855  	
856  	static int read_master_dir(void)
857  	{
858  		ioctl(sbd.device_fd, BLKFLSBUF, 0);
859  	
860  		bh = lgfs2_bread(&sbd, sbd.sd_meta_dir.in_addr);
861  		if (bh == NULL)
862  			return 1;
863  		di = (struct gfs2_dinode *)bh->b_data;
864  		do_dinode_extended(bh->b_data); /* get extended data, if any */
865  		memcpy(&masterdir, &indirect[0], sizeof(struct indirect_info));
866  		return 0;
867  	}
868  	
869  	int display(int identify_only, int trunc_zeros, uint64_t flagref,
870  		    uint64_t ref_blk)
871  	{
872  		uint64_t blk;
873  	
874  		if (block == RGLIST_DUMMY_BLOCK) {
875  			blk = masterblock("rindex");
876  		} else if (block == JOURNALS_DUMMY_BLOCK) {
877  			blk = masterblock("jindex");
878  		} else
879  			blk = block;
880  		if (termlines) {
881  			display_title_lines();
882  			move(2,0);
883  		}
884  		if (bh == NULL || bh->b_blocknr != blk) { /* If we changed blocks from the last read */
885  			if (bh != NULL)
886  				lgfs2_brelse(bh);
887  			dev_offset = blk * sbd.sd_bsize;
888  			ioctl(sbd.device_fd, BLKFLSBUF, 0);
889  			if (!(bh = lgfs2_bread(&sbd, blk))) {
890  				fprintf(stderr, "read error: %s from %s:%d: "
891  					"offset %"PRIu64" (0x%"PRIx64")\n",
892  					strerror(errno), __FUNCTION__, __LINE__,
893  					dev_offset, dev_offset);
894  				exit(-1);
895  			}
896  		}
897  		line = 1;
898  		gfs2_struct_type = display_block_type(bh->b_data, bh->b_blocknr, FALSE);
899  		if (identify_only)
900  			return 0;
901  		indirect_blocks = 0;
902  		lines_per_row[dmode] = 1;
903  		if (gfs2_struct_type == GFS2_METATYPE_SB || blk == 0x10 * (4096 / sbd.sd_bsize)) {
904  			struct indirect_info *ii = &indirect->ii[0];
905  			struct idirent *id;
906  	
907  			lgfs2_sb_in(&sbd, bh->b_data);
908  			memset(indirect, 0, sizeof(struct iinfo));
909  			ii->block = sbd.sd_meta_dir.in_addr;
910  			ii->is_dir = TRUE;
911  			ii->dirents = 2;
912  	
913  			id = &ii->dirent[0];
914  			memcpy(id->filename, "root", 4);
915  			id->inum = sbd.sd_root_dir;
916  			id->type = DT_DIR;
917  	
918  			id = &ii->dirent[1];
919  			memcpy(id->filename, "master", 7);
920  			id->inum = sbd.sd_meta_dir;
921  			id->type = DT_DIR;
922  		}
923  		else if (gfs2_struct_type == GFS2_METATYPE_DI) {
924  			di = (struct gfs2_dinode *)bh->b_data;
925  			do_dinode_extended(bh->b_data); /* get extended data, if any */
926  		}
927  		else if (gfs2_struct_type == GFS2_METATYPE_IN) { /* indirect block list */
928  			if (blockhist) {
929  				int i;
930  	
931  				for (i = 0; i < 512; i++)
932  					memcpy(&indirect->ii[i].mp,
933  					       &blockstack[blockhist - 1].mp,
934  					       sizeof(struct lgfs2_metapath));
935  			}
936  			indirect_blocks = do_indirect_extended(bh->b_data, indirect);
937  		}
938  		else if (gfs2_struct_type == GFS2_METATYPE_LF) { /* directory leaf */
939  			do_leaf_extended(bh->b_data, indirect);
940  		}
941  	
942  		last_entry_onscreen[dmode] = 0;
943  		if (dmode == EXTENDED_MODE && !block_has_extended_info())
944  			dmode = HEX_MODE;
945  		if (termlines) {
946  			move(termlines, 63);
947  			if (dmode==HEX_MODE)
948  				printw("Mode: Hex %s", (editing?"edit ":"view "));
949  			else
950  				printw("Mode: %s", (dmode==GFS2_MODE?"Structure":
951  						    "Pointers "));
952  			move(line, 0);
953  		}
954  		if (dmode == HEX_MODE) {         /* if hex display mode           */
955  			uint64_t len = sbd.sd_bsize;
956  	
957  			if (gfs2_struct_type == GFS2_METATYPE_DI)
958  				len = struct_len + be64_to_cpu(di->di_size);
959  	
960  			hexdump(dev_offset, len, trunc_zeros, flagref, ref_blk);
961  		} else if (dmode == GFS2_MODE) { /* if structure display */
962  			if (block != JOURNALS_DUMMY_BLOCK)
963  				display_gfs2(bh->b_data);
964  		} else
965  			display_extended();        /* display extended blocks       */
966  		/* No else here because display_extended can switch back to hex mode */
967  		if (termlines)
968  			refresh();
969  		return(0);
970  	}
971  	
972  	/* ------------------------------------------------------------------------ */
973  	/* push_block - push a block onto the block stack                           */
974  	/* ------------------------------------------------------------------------ */
975  	static void push_block(uint64_t blk)
976  	{
977  		int i, bhst;
978  	
979  		bhst = blockhist % BLOCK_STACK_SIZE;
980  		if (blk) {
981  			blockstack[bhst].dmode = dmode;
982  			for (i = 0; i < DMODES; i++) {
983  				blockstack[bhst].start_row[i] = start_row[i];
984  				blockstack[bhst].end_row[i] = end_row[i];
985  				blockstack[bhst].edit_row[i] = edit_row[i];
986  				blockstack[bhst].edit_col[i] = edit_col[i];
987  				blockstack[bhst].lines_per_row[i] = lines_per_row[i];
988  			}
989  			blockstack[bhst].gfs2_struct_type = gfs2_struct_type;
990  			if (edit_row[dmode] >= 0 && !block_is_rindex(block))
991  				memcpy(&blockstack[bhst].mp,
992  				       &indirect->ii[edit_row[dmode]].mp,
993  				       sizeof(struct lgfs2_metapath));
994  			blockhist++;
995  			blockstack[blockhist % BLOCK_STACK_SIZE].block = blk;
996  		}
997  	}
998  	
999  	/* ------------------------------------------------------------------------ */
1000 	/* pop_block - pop a block off the block stack                              */
1001 	/* ------------------------------------------------------------------------ */
1002 	static uint64_t pop_block(void)
1003 	{
1004 		int i, bhst;
1005 	
1006 		if (!blockhist)
1007 			return block;
1008 		blockhist--;
1009 		bhst = blockhist % BLOCK_STACK_SIZE;
1010 		dmode = blockstack[bhst].dmode;
1011 		for (i = 0; i < DMODES; i++) {
1012 			start_row[i] = blockstack[bhst].start_row[i];
1013 			end_row[i] = blockstack[bhst].end_row[i];
1014 			edit_row[i] = blockstack[bhst].edit_row[i];
1015 			edit_col[i] = blockstack[bhst].edit_col[i];
1016 			lines_per_row[i] = blockstack[bhst].lines_per_row[i];
1017 		}
1018 		gfs2_struct_type = blockstack[bhst].gfs2_struct_type;
1019 		return blockstack[bhst].block;
1020 	}
1021 	
1022 	/* ------------------------------------------------------------------------ */
1023 	/* Find next metadata block of a given type AFTER a given point in the fs   */
1024 	/*                                                                          */
1025 	/* This is used to find blocks that aren't represented in the bitmaps, such */
1026 	/* as the RGs and bitmaps or the superblock.                                */
1027 	/* ------------------------------------------------------------------------ */
1028 	static uint64_t find_metablockoftype_slow(uint64_t startblk, int metatype, int print)
1029 	{
1030 		uint64_t blk, last_fs_block;
1031 		int found = 0;
1032 		struct lgfs2_buffer_head *lbh;
1033 	
1034 		last_fs_block = lseek(sbd.device_fd, 0, SEEK_END) / sbd.sd_bsize;
1035 		for (blk = startblk + 1; blk < last_fs_block; blk++) {
1036 			lbh = lgfs2_bread(&sbd, blk);
1037 			/* Can't use get_block_type here (returns false "none") */
1038 			if (lbh->b_data[0] == 0x01 && lbh->b_data[1] == 0x16 &&
1039 			    lbh->b_data[2] == 0x19 && lbh->b_data[3] == 0x70 &&
1040 			    lbh->b_data[4] == 0x00 && lbh->b_data[5] == 0x00 &&
1041 			    lbh->b_data[6] == 0x00 && lbh->b_data[7] == metatype) {
1042 				found = 1;
1043 				lgfs2_brelse(lbh);
1044 				break;
1045 			}
1046 			lgfs2_brelse(lbh);
1047 		}
1048 		if (!found)
1049 			blk = 0;
1050 		if (print) {
1051 			if (dmode == HEX_MODE)
1052 				printf("0x%"PRIx64"\n", blk);
1053 			else
1054 				printf("%"PRIu64"\n", blk);
1055 		}
1056 		lgfs2_rgrp_free(&sbd, &sbd.rgtree);
1057 		if (print)
1058 			exit(0);
1059 		return blk;
1060 	}
1061 	
1062 	static int find_rg_metatype(struct lgfs2_rgrp_tree *rgd, uint64_t *blk, uint64_t startblk, int mtype)
1063 	{
1064 		int found;
1065 		unsigned i, j, m;
1066 		struct lgfs2_buffer_head *bhp = NULL;
1067 		uint64_t *ibuf = malloc(sbd.sd_bsize * GFS2_NBBY * sizeof(uint64_t));
1068 	
1069 		for (i = 0; i < rgd->rt_length; i++) {
1070 			m = lgfs2_bm_scan(rgd, i, ibuf, GFS2_BLKST_DINODE);
1071 	
1072 			for (j = 0; j < m; j++) {
1073 				*blk = ibuf[j];
1074 				bhp = lgfs2_bread(&sbd, *blk);
1075 				found = (*blk > startblk) && !lgfs2_check_meta(bhp->b_data, mtype);
1076 				lgfs2_brelse(bhp);
1077 				if (found) {
1078 					free(ibuf);
1079 					return 0;
1080 				}
1081 			}
1082 		}
1083 		free(ibuf);
1084 		return -1;
1085 	}
1086 	
1087 	/* ------------------------------------------------------------------------ */
1088 	/* Find next "metadata in use" block AFTER a given point in the fs          */
1089 	/*                                                                          */
1090 	/* This version does its magic by searching the bitmaps of the RG.  After   */
1091 	/* all, if we're searching for a dinode, we want a real allocated inode,    */
1092 	/* not just some block that used to be an inode in a previous incarnation.  */
1093 	/* ------------------------------------------------------------------------ */
1094 	static uint64_t find_metablockoftype_rg(uint64_t startblk, int metatype, int print)
1095 	{
1096 		struct osi_node *next = NULL;
1097 		uint64_t blk, errblk;
1098 		int first = 1, found = 0;
1099 		struct lgfs2_rgrp_tree *rgd = NULL;
1100 	
1101 		blk = 0;
1102 		/* Skip the rgs prior to the block we've been given */
1103 		for (next = osi_first(&sbd.rgtree); next; next = osi_next(next)) {
1104 			rgd = (struct lgfs2_rgrp_tree *)next;
1105 			if (first && startblk <= rgd->rt_data0) {
1106 				startblk = rgd->rt_data0;
1107 				break;
1108 			} else if (rgd->rt_addr <= startblk &&
1109 				 startblk < rgd->rt_data0 + rgd->rt_data)
1110 				break;
1111 			else
1112 				rgd = NULL;
1113 			first = 0;
1114 		}
1115 		if (!rgd) {
1116 			if (print)
1117 				printf("0\n");
1118 			lgfs2_rgrp_free(&sbd, &sbd.rgtree);
1119 			if (print)
1120 				exit(-1);
1121 		}
1122 		for (; !found && next; next = osi_next(next)){
1123 			rgd = (struct lgfs2_rgrp_tree *)next;
1124 			errblk = lgfs2_rgrp_read(&sbd, rgd);
1125 			if (errblk)
1126 				continue;
1127 	
1128 			found = !find_rg_metatype(rgd, &blk, startblk, metatype);
1129 			if (found)
1130 				break;
1131 	
1132 			lgfs2_rgrp_relse(&sbd, rgd);
1133 		}
1134 	
1135 		if (!found)
1136 			blk = 0;
1137 		if (print) {
1138 			if (dmode == HEX_MODE)
1139 				printf("0x%"PRIx64"\n", blk);
1140 			else
1141 				printf("%"PRIu64"\n", blk);
1142 		}
1143 		lgfs2_rgrp_free(&sbd, &sbd.rgtree);
1144 		if (print)
1145 			exit(0);
1146 		return blk;
1147 	}
1148 	
1149 	/* ------------------------------------------------------------------------ */
1150 	/* Find next metadata block AFTER a given point in the fs                   */
1151 	/* ------------------------------------------------------------------------ */
1152 	static uint64_t find_metablockoftype(const char *strtype, int print)
1153 	{
1154 		int mtype = 0;
1155 		uint64_t startblk, blk = 0;
1156 	
1157 		if (print)
1158 			startblk = blockstack[blockhist % BLOCK_STACK_SIZE].block;
1159 		else
1160 			startblk = block;
1161 	
1162 		for (mtype = GFS2_METATYPE_NONE;
1163 		     mtype <= GFS2_METATYPE_QC; mtype++)
1164 			if (!strcasecmp(strtype, mtypes[mtype]))
1165 				break;
1166 		if (!strcmp(strtype, "dinode"))
1167 			mtype = GFS2_METATYPE_DI;
1168 		if (mtype >= GFS2_METATYPE_NONE && mtype <= GFS2_METATYPE_RB)
1169 			blk = find_metablockoftype_slow(startblk, mtype, print);
1170 		else if (mtype >= GFS2_METATYPE_DI && mtype <= GFS2_METATYPE_QC)
1171 			blk = find_metablockoftype_rg(startblk, mtype, print);
1172 		else if (print) {
1173 			fprintf(stderr, "Error: metadata type not "
1174 				"specified: must be one of:\n");
1175 			fprintf(stderr, "sb rg rb di in lf jd lh ld"
1176 				" ea ed lb 13 qc\n");
1177 			lgfs2_rgrp_free(&sbd, &sbd.rgtree);
1178 			exit(-1);
1179 		}
1180 		return blk;
1181 	}
1182 	
1183 	/* ------------------------------------------------------------------------ */
1184 	/* Check if the word is a keyword such as "sb" or "rindex"                  */
1185 	/* Returns: block number if it is, else 0                                   */
1186 	/* ------------------------------------------------------------------------ */
1187 	uint64_t check_keywords(const char *kword)
1188 	{
1189 		uint64_t blk = 0;
1190 	
1191 		if (!strcmp(kword, "sb") ||!strcmp(kword, "superblock"))
1192 			blk = 0x10 * (4096 / sbd.sd_bsize); /* superblock */
1193 		else if (!strcmp(kword, "root") || !strcmp(kword, "rootdir"))
1194 			blk = sbd.sd_root_dir.in_addr;
1195 		else if (!strcmp(kword, "master")) {
1196 			if (!sbd.sd_meta_dir.in_addr) {
1197 				fprintf(stderr, "GFS2 master directory not found on %s\n", device);
1198 				exit(-1);
1199 			} else
1200 				blk = sbd.sd_meta_dir.in_addr;
1201 		}
1202 		else if (!strcmp(kword, "jindex"))
1203 			blk = masterblock("jindex");
1204 		else if (!strcmp(kword, "per_node"))
1205 			blk = masterblock("per_node");
1206 		else if (!strcmp(kword, "inum"))
1207 			blk = masterblock("inum");
1208 		else if (!strcmp(kword, "statfs"))
1209 			blk = masterblock("statfs");
1210 		else if (!strcmp(kword, "rindex") || !strcmp(kword, "rgindex")) {
1211 			blk = masterblock("rindex");
1212 		} else if (!strcmp(kword, "rgs")) {
1213 			blk = RGLIST_DUMMY_BLOCK;
1214 		} else if (!strcmp(kword, "quota")) {
1215 			blk = masterblock("quota");
1216 		} else if (!strncmp(kword, "rg ", 3)) {
1217 			int rgnum = 0;
1218 	
1219 			rgnum = atoi(kword + 3);
1220 			blk = get_rg_addr(rgnum);
1221 		} else if (!strncmp(kword, "journals", 8)) {
1222 			blk = JOURNALS_DUMMY_BLOCK;
1223 		} else if (strlen(kword) > 7 && !strncmp(kword, "journal", 7) && isdigit(kword[7])) {
1224 			uint64_t j_size;
1225 	
1226 			blk = find_journal_block(kword, &j_size);
1227 		} else if (kword[0]=='/') /* search */
1228 			blk = find_metablockoftype(&kword[1], 0);
1229 		else if (kword[0]=='0' && kword[1]=='x') /* hex addr */
1230 			sscanf(kword, "%"SCNx64, &blk);/* retrieve in hex */
1231 		else
1232 			sscanf(kword, "%"SCNu64, &blk); /* retrieve decimal */
1233 	
1234 		return blk;
1235 	}
1236 	
1237 	/* ------------------------------------------------------------------------ */
1238 	/* goto_block - go to a desired block entered by the user                   */
1239 	/* ------------------------------------------------------------------------ */
1240 	static uint64_t goto_block(void)
1241 	{
1242 		char string[256];
1243 		int ch, delta;
1244 	
1245 		memset(string, 0, sizeof(string));
1246 		sprintf(string,"%lld", (long long)block);
1247 		if (bobgets(string, 1, 7, 16, &ch)) {
1248 			if (isalnum(string[0]) || string[0] == '/')
1249 				temp_blk = check_keywords(string);
1250 			else if (string[0] == '+' || string[0] == '-') {
1251 				if (string[1] == '0' && string[2] == 'x')
1252 					sscanf(string, "%x", &delta);
1253 				else
1254 					sscanf(string, "%d", &delta);
1255 				temp_blk = block + delta;
1256 			}
1257 	
1258 			if (temp_blk == RGLIST_DUMMY_BLOCK ||
1259 			    temp_blk == JOURNALS_DUMMY_BLOCK || temp_blk < max_block) {
1260 				offset = 0;
1261 				block = temp_blk;
1262 				push_block(block);
1263 			}
1264 		}
1265 		return block;
1266 	}
1267 	
1268 	/* ------------------------------------------------------------------------ */
1269 	/* init_colors                                                              */
1270 	/* ------------------------------------------------------------------------ */
1271 	static void init_colors(void)
1272 	{
1273 	
1274 		if (color_scheme) {
1275 			init_pair(COLOR_TITLE, COLOR_BLACK,  COLOR_CYAN);
1276 			init_pair(COLOR_NORMAL, COLOR_WHITE,  COLOR_BLACK);
1277 			init_pair(COLOR_INVERSE, COLOR_BLACK,  COLOR_WHITE);
1278 			init_pair(COLOR_SPECIAL, COLOR_RED,    COLOR_BLACK);
1279 			init_pair(COLOR_HIGHLIGHT, COLOR_GREEN, COLOR_BLACK);
1280 			init_pair(COLOR_OFFSETS, COLOR_CYAN,   COLOR_BLACK);
1281 			init_pair(COLOR_CONTENTS, COLOR_YELLOW, COLOR_BLACK);
1282 		}
1283 		else {
1284 			init_pair(COLOR_TITLE, COLOR_BLACK,  COLOR_CYAN);
1285 			init_pair(COLOR_NORMAL, COLOR_BLACK,  COLOR_WHITE);
1286 			init_pair(COLOR_INVERSE, COLOR_WHITE,  COLOR_BLACK);
1287 			init_pair(COLOR_SPECIAL, COLOR_MAGENTA, COLOR_WHITE);
1288 			init_pair(COLOR_HIGHLIGHT, COLOR_RED, COLOR_WHITE); /*cursor*/
1289 			init_pair(COLOR_OFFSETS, COLOR_CYAN,   COLOR_WHITE);
1290 			init_pair(COLOR_CONTENTS, COLOR_BLUE, COLOR_WHITE);
1291 		}
1292 	}
1293 	
1294 	/* ------------------------------------------------------------------------ */
1295 	/* hex_edit - Allow the user to edit the page by entering hex digits        */
1296 	/* ------------------------------------------------------------------------ */
1297 	static void hex_edit(int *exitch)
1298 	{
1299 		int left_off;
1300 		int ch;
1301 	
1302 		left_off = ((block * sbd.sd_bsize) < 0xffffffff) ? 9 : 17;
1303 		/* 8 and 16 char addresses on screen */
1304 		
1305 		if (bobgets(estring, edit_row[HEX_MODE] + 3,
1306 			    (edit_col[HEX_MODE] * 2) + (edit_col[HEX_MODE] / 4) +
1307 			    left_off, 2, exitch)) {
1308 			if (strstr(edit_fmt,"X") || strstr(edit_fmt,"x")) {
1309 				int hexoffset;
1310 				int i, sl = strlen(estring);
1311 				
1312 				for (i = 0; i < sl; i+=2) {
1313 					hexoffset = (edit_row[HEX_MODE] * 16) +
1314 						edit_col[HEX_MODE] + (i / 2);
1315 					ch = 0x00;
1316 					if (isdigit(estring[i]))
1317 						ch = (estring[i] - '0') * 0x10;
1318 					else if (estring[i] >= 'a' &&
1319 						 estring[i] <= 'f')
1320 						ch = (estring[i]-'a' + 0x0a)*0x10;
1321 					else if (estring[i] >= 'A' &&
1322 						 estring[i] <= 'F')
1323 						ch = (estring[i] - 'A' + 0x0a) * 0x10;
1324 					if (isdigit(estring[i+1]))
1325 						ch += (estring[i+1] - '0');
1326 					else if (estring[i+1] >= 'a' &&
1327 						 estring[i+1] <= 'f')
1328 						ch += (estring[i+1] - 'a' + 0x0a);
1329 					else if (estring[i+1] >= 'A' &&
1330 						 estring[i+1] <= 'F')
1331 						ch += (estring[i+1] - 'A' + 0x0a);
1332 					bh->b_data[offset + hexoffset] = ch;
1333 				}
1334 				if (pwrite(sbd.device_fd, bh->b_data, sbd.sd_bsize, dev_offset) !=
1335 				    sbd.sd_bsize) {
1336 					fprintf(stderr, "write error: %s from %s:%d: "
1337 						"offset %"PRIu64" (0x%"PRIx64")\n",
1338 						strerror(errno),
1339 						__FUNCTION__, __LINE__,
1340 						dev_offset, dev_offset);
1341 					exit(-1);
1342 				}
1343 				fsync(sbd.device_fd);
1344 			}
1345 		}
1346 	}
1347 	
1348 	/* ------------------------------------------------------------------------ */
1349 	/* page up                                                                  */
1350 	/* ------------------------------------------------------------------------ */
1351 	static void pageup(void)
1352 	{
1353 		if (dmode == EXTENDED_MODE) {
1354 			if (edit_row[dmode] - (dsplines / lines_per_row[dmode]) > 0)
1355 				edit_row[dmode] -= (dsplines / lines_per_row[dmode]);
1356 			else
1357 				edit_row[dmode] = 0;
1358 			if (start_row[dmode] - (dsplines / lines_per_row[dmode]) > 0)
1359 				start_row[dmode] -= (dsplines / lines_per_row[dmode]);
1360 			else
1361 				start_row[dmode] = 0;
1362 		}
1363 		else {
1364 			start_row[dmode] = edit_row[dmode] = 0;
1365 			if (dmode == GFS2_MODE || offset==0) {
1366 				block--;
1367 				if (dmode == HEX_MODE)
1368 					offset = (sbd.sd_bsize % screen_chunk_size) > 0 ?
1369 						screen_chunk_size *
1370 						(sbd.sd_bsize / screen_chunk_size) :
1371 						sbd.sd_bsize - screen_chunk_size;
1372 				else
1373 					offset = 0;
1374 			} else
1375 				offset -= screen_chunk_size;
1376 		}
1377 	}
1378 	
1379 	/* ------------------------------------------------------------------------ */
1380 	/* page down                                                                */
1381 	/* ------------------------------------------------------------------------ */
1382 	static void pagedn(void)
1383 	{
1384 		if (dmode == EXTENDED_MODE) {
1385 			if ((edit_row[dmode] + dsplines) / lines_per_row[dmode] + 1 <=
1386 			    end_row[dmode]) {
1387 				start_row[dmode] += dsplines / lines_per_row[dmode];
1388 				edit_row[dmode] += dsplines / lines_per_row[dmode];
1389 			} else {
1390 				edit_row[dmode] = end_row[dmode] - 1;
1391 				while (edit_row[dmode] - start_row[dmode]
1392 				       + 1 > last_entry_onscreen[dmode])
1393 					start_row[dmode]++;
1394 			}
1395 		}
1396 		else {
1397 			start_row[dmode] = edit_row[dmode] = 0;
1398 			if (dmode == GFS2_MODE ||
1399 			    offset + screen_chunk_size >= sbd.sd_bsize) {
1400 				block++;
1401 				offset = 0;
1402 			} else
1403 				offset += screen_chunk_size;
1404 		}
1405 	}
1406 	
1407 	/* ------------------------------------------------------------------------ */
1408 	/* jump - jump to the address the cursor is on                              */
1409 	/*                                                                          */
1410 	/* If the cursor is in a log descriptor, jump to the log-descriptor version */
1411 	/* of the block instead of the "real" block.                                */
1412 	/* ------------------------------------------------------------------------ */
1413 	static void jump(void)
1414 	{
1415 		if (dmode == HEX_MODE) {
1416 			unsigned int col2;
1417 			__be64 *b;
1418 			const struct lgfs2_metadata *mtype = get_block_type(bh->b_data);
1419 			uint32_t block_type = 0;
1420 	
1421 			if (mtype != NULL)
1422 				block_type = mtype->mh_type;
1423 	
1424 			/* special exception for log descriptors: jump the journaled
1425 			   version of the block, not the "real" block */
1426 			if (block_type == GFS2_METATYPE_LD) {
1427 				int ptroffset = edit_row[dmode] * 16 + edit_col[dmode];
1428 				int pnum = get_pnum(ptroffset);
1429 				temp_blk = bh->b_blocknr + pnum + 1;
1430 			} else if (edit_row[dmode] >= 0) {
1431 				col2 = edit_col[dmode] & 0x08;/* thus 0-7->0, 8-15->8 */
1432 				b = (__be64 *)&bh->b_data[edit_row[dmode]*16 +
1433 							    offset + col2];
1434 				temp_blk = be64_to_cpu(*b);
1435 			}
1436 		}
1437 		else
1438 			sscanf(estring, "%"SCNx64, &temp_blk);/* retrieve in hex */
1439 		if (temp_blk < max_block) { /* if the block number is valid */
1440 			int i;
1441 			
1442 			offset = 0;
1443 			push_block(temp_blk);
1444 			block = temp_blk;
1445 			for (i = 0; i < DMODES; i++) {
1446 				start_row[i] = end_row[i] = edit_row[i] = 0;
1447 				edit_col[i] = 0;
1448 			}
1449 		}
1450 	}
1451 	
1452 	static void print_block_type(uint64_t tblock, const struct lgfs2_metadata *type)
1453 	{
1454 		if (type == NULL)
1455 			return;
1456 		if (type->nfields > 0)
1457 			printf("%d (Block %"PRIu64" is type %d: %s)\n", type->mh_type,
1458 			       tblock, type->mh_type, type->display);
1459 		else
1460 			printf("%d (Block %"PRIu64" is type %d: unknown)\n", type->mh_type,
1461 			       tblock, type->mh_type);
1462 	}
1463 	
1464 	static void find_print_block_type(void)
1465 	{
1466 		uint64_t tblock;
1467 		struct lgfs2_buffer_head *lbh;
1468 		const struct lgfs2_metadata *type;
1469 	
1470 		tblock = blockstack[blockhist % BLOCK_STACK_SIZE].block;
1471 		lbh = lgfs2_bread(&sbd, tblock);
1472 		type = get_block_type(lbh->b_data);
1473 		print_block_type(tblock, type);
1474 		lgfs2_brelse(lbh);
1475 		lgfs2_rgrp_free(&sbd, &sbd.rgtree);
1476 		exit(0);
1477 	}
1478 	
1479 	/**
1480 	 * Find and print the resource group associated with a given block
1481 	 */
1482 	static void find_print_block_rg(int bitmap)
1483 	{
1484 		uint64_t rblock, rgblock;
1485 		int i;
1486 		struct lgfs2_rgrp_tree *rgd;
1487 	
1488 		rblock = blockstack[blockhist % BLOCK_STACK_SIZE].block;
1489 		if (rblock == LGFS2_SB_ADDR(&sbd)) {
1490 			printf("0 (the superblock is not in the bitmap)\n");
1491 			goto out;
1492 		}
1493 		rgd = lgfs2_blk2rgrpd(&sbd, rblock);
1494 		if (rgd == NULL) {
1495 			printf("-1 (block invalid or part of an rgrp).\n");
1496 			goto out;
1497 		}
1498 		rgblock = rgd->rt_addr;
1499 		if (!bitmap)
1500 			goto print;
1501 	
1502 		for (i = 0; i < rgd->rt_length; i++) {
1503 			struct lgfs2_bitmap *bits = &(rgd->rt_bits[i]);
1504 			uint64_t end = ((uint64_t)bits->bi_start + bits->bi_len) * GFS2_NBBY;
1505 	
1506 			if (rblock - rgd->rt_data0 < end)
1507 				break;
1508 		}
1509 		if (i < rgd->rt_length)
1510 			rgblock += i;
1511 	print:
1512 		if (dmode == HEX_MODE)
1513 			printf("0x%"PRIx64"\n", rgblock);
1514 		else
1515 			printf("%"PRIu64"\n", rgblock);
1516 	out:
1517 		lgfs2_rgrp_free(&sbd, &sbd.rgtree);
1518 		exit(0);
1519 	}
1520 	
1521 	/* ------------------------------------------------------------------------ */
1522 	/* find/change/print block allocation (what the bitmap says about block)    */
1523 	/* ------------------------------------------------------------------------ */
1524 	static void find_change_block_alloc(int *newval)
1525 	{
1526 		uint64_t ablock;
1527 		int type;
1528 		struct lgfs2_rgrp_tree *rgd;
1529 	
1530 		if (newval &&
1531 		    (*newval < GFS2_BLKST_FREE || *newval > GFS2_BLKST_DINODE)) {
1532 			int i;
1533 	
1534 			printf("Error: value %d is not valid.\nValid values are:\n",
1535 			       *newval);
1536 			for (i = GFS2_BLKST_FREE; i <= GFS2_BLKST_DINODE; i++)
1537 				printf("%d - %s\n", i, lgfs2_blkst_str(i));
1538 			lgfs2_rgrp_free(&sbd, &sbd.rgtree);
1539 			exit(-1);
1540 		}
1541 		ablock = blockstack[blockhist % BLOCK_STACK_SIZE].block;
1542 		if (ablock == LGFS2_SB_ADDR(&sbd))
1543 			printf("3 (the superblock is not in the bitmap)\n");
1544 		else {
1545 			rgd = lgfs2_blk2rgrpd(&sbd, ablock);
1546 			if (rgd) {
1547 				lgfs2_rgrp_read(&sbd, rgd);
1548 				if (newval) {
1549 					if (lgfs2_set_bitmap(rgd, ablock, *newval))
1550 						printf("-1 (block invalid or part of an rgrp).\n");
1551 					else
1552 						printf("%d\n", *newval);
1553 				} else {
1554 					type = lgfs2_get_bitmap(&sbd, ablock, rgd);
1555 					if (type < 0) {
1556 						printf("-1 (block invalid or part of "
1557 						       "an rgrp).\n");
1558 						exit(-1);
1559 					}
1560 					printf("%d (%s)\n", type, lgfs2_blkst_str(type));
1561 				}
1562 				lgfs2_rgrp_relse(&sbd, rgd);
1563 			} else {
1564 				lgfs2_rgrp_free(&sbd, &sbd.rgtree);
1565 				printf("-1 (block invalid or part of an rgrp).\n");
1566 				exit(-1);
1567 			}
1568 		}
1569 		lgfs2_rgrp_free(&sbd, &sbd.rgtree);
1570 		if (newval)
1571 			fsync(sbd.device_fd);
1572 		exit(0);
1573 	}
1574 	
1575 	/**
1576 	 * process request to print a certain field from a previously pushed block
1577 	 */
1578 	static void process_field(const char *field, const char *nstr)
1579 	{
1580 		uint64_t fblock;
1581 		struct lgfs2_buffer_head *rbh;
1582 		const struct lgfs2_metadata *mtype;
1583 		const struct lgfs2_metafield *mfield;
1584 	
1585 		fblock = blockstack[blockhist % BLOCK_STACK_SIZE].block;
1586 		rbh = lgfs2_bread(&sbd, fblock);
1587 		mtype = get_block_type(rbh->b_data);
1588 		if (mtype == NULL) {
1589 			fprintf(stderr, "Metadata type of block %"PRIx64" not recognised\n",
1590 			        fblock);
1591 			exit(1);
1592 		}
1593 	
1594 		mfield = lgfs2_find_mfield_name(field, mtype);
1595 		if (mfield == NULL) {
1596 			fprintf(stderr, "No field '%s' in block type '%s'\n", field, mtype->name);
1597 			exit(1);
1598 		}
1599 	
1600 		if (nstr != device) {
1601 			int err = 0;
1602 			if (mfield->flags & (LGFS2_MFF_UUID|LGFS2_MFF_STRING)) {
1603 				err = lgfs2_field_assign(rbh->b_data, mfield, nstr);
1604 			} else {
1605 				uint64_t val = 0;
1606 				err = sscanf(nstr, "%"SCNi64, &val);
1607 				if (err == 1)
1608 					/* coverity[overrun-buffer-val:SUPPRESS] False positive */
1609 					err = lgfs2_field_assign(rbh->b_data, mfield, &val);
1610 				else
1611 					err = -1;
1612 			}
1613 			if (err != 0) {
1614 				fprintf(stderr, "Could not set '%s' to '%s': %s\n", field, nstr,
1615 				        strerror(errno));
1616 				exit(1);
1617 			}
1618 			lgfs2_bmodified(rbh);
1619 		}
1620 	
1621 		if (!termlines) {
1622 			char str[GFS2_LOCKNAME_LEN] = "";
1623 			lgfs2_field_str(str, GFS2_LOCKNAME_LEN, rbh->b_data, mfield, (dmode == HEX_MODE));
1624 			printf("%s\n", str);
1625 		}
1626 	
1627 		lgfs2_brelse(rbh);
1628 		fsync(sbd.device_fd);
1629 		exit(0);
1630 	}
1631 	
1632 	/* ------------------------------------------------------------------------ */
1633 	/* interactive_mode - accept keystrokes from user and display structures    */
1634 	/* ------------------------------------------------------------------------ */
1635 	static void interactive_mode(void)
1636 	{
1637 		int ch = 0, Quit;
1638 	
1639 		if ((wind = initscr()) == NULL) {
1640 			fprintf(stderr, "Error: unable to initialize screen.");
1641 			eol(0);
1642 			exit(-1);
1643 		}
1644 		getmaxyx(stdscr, termlines, termcols);
1645 		termlines--;
1646 		/* Do our initial screen stuff: */
1647 		clear(); /* don't use Erase */
1648 		start_color();
1649 		noecho();
1650 		keypad(stdscr, TRUE);
1651 		raw();
1652 		curs_set(0);
1653 		init_colors();
1654 		/* Accept keystrokes and act on them accordingly */
1655 		Quit = FALSE;
1656 		editing = FALSE;
1657 		while (!Quit) {
1658 			display(FALSE, 0, 0, 0);
1659 			if (editing) {
1660 				if (edit_row[dmode] == -1)
1661 					block = goto_block();
1662 				else {
1663 					if (dmode == HEX_MODE)
1664 						hex_edit(&ch);
1665 					else if (dmode == GFS2_MODE) {
1666 						bobgets(estring, edit_row[dmode]+4, 24,
1667 							10, &ch);
1668 						process_field(efield, estring);
1669 					} else
1670 						bobgets(estring, edit_row[dmode]+6, 14,
1671 							edit_size[dmode], &ch);
1672 				}
1673 			}
1674 			else
1675 				while ((ch=getch()) == 0); // wait for input
1676 	
1677 			switch (ch)
1678 			{
1679 			/* --------------------------------------------------------- */
1680 			/* escape or 'q' */
1681 			/* --------------------------------------------------------- */
1682 			case 0x1b:
1683 			case 0x03:
1684 			case 'q':
1685 				if (editing)
1686 					editing = FALSE;
1687 				else
1688 					Quit=TRUE;
1689 				break;
1690 			/* --------------------------------------------------------- */
1691 			/* home - return to the superblock                           */
1692 			/* --------------------------------------------------------- */
1693 			case KEY_HOME:
1694 				if (dmode == EXTENDED_MODE) {
1695 					start_row[dmode] = end_row[dmode] = 0;
1696 					edit_row[dmode] = 0;
1697 				}
1698 				else {
1699 					block = 0x10 * (4096 / sbd.sd_bsize);
1700 					push_block(block);
1701 					offset = 0;
1702 				}
1703 				break;
1704 			/* --------------------------------------------------------- */
1705 			/* backspace - return to the previous block on the stack     */
1706 			/* --------------------------------------------------------- */
1707 			case KEY_BACKSPACE:
1708 			case 0x7f:
1709 				block = pop_block();
1710 				offset = 0;
1711 				break;
1712 			/* --------------------------------------------------------- */
1713 			/* space - go down the block stack (opposite of backspace)   */
1714 			/* --------------------------------------------------------- */
1715 			case ' ':
1716 				blockhist++;
1717 				block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
1718 				offset = 0;
1719 				break;
1720 			/* --------------------------------------------------------- */
1721 			/* arrow up */
1722 			/* --------------------------------------------------------- */
1723 			case KEY_UP:
1724 			case '-':
1725 				if (dmode == EXTENDED_MODE) {
1726 					if (edit_row[dmode] > 0)
1727 						edit_row[dmode]--;
1728 					if (edit_row[dmode] < start_row[dmode])
1729 						start_row[dmode] = edit_row[dmode];
1730 				}
1731 				else {
1732 					if (edit_row[dmode] >= 0)
1733 						edit_row[dmode]--;
1734 				}
1735 				break;
1736 			/* --------------------------------------------------------- */
1737 			/* arrow down */
1738 			/* --------------------------------------------------------- */
1739 			case KEY_DOWN:
1740 			case '+':
1741 				if (dmode == EXTENDED_MODE) {
1742 					if (edit_row[dmode] + 1 < end_row[dmode]) {
1743 						if (edit_row[dmode] - start_row[dmode]
1744 						    + 1 > last_entry_onscreen[dmode])
1745 							start_row[dmode]++;
1746 						edit_row[dmode]++;
1747 					}
1748 				}
1749 				else {
1750 					if (edit_row[dmode] < last_entry_onscreen[dmode])
1751 						edit_row[dmode]++;
1752 				}
1753 				break;
1754 			/* --------------------------------------------------------- */
1755 			/* arrow left */
1756 			/* --------------------------------------------------------- */
1757 			case KEY_LEFT:
1758 				if (dmode == HEX_MODE) {
1759 					if (edit_col[dmode] > 0)
1760 						edit_col[dmode]--;
1761 					else
1762 						edit_col[dmode] = 15;
1763 				}
1764 				break;
1765 			/* --------------------------------------------------------- */
1766 			/* arrow right */
1767 			/* --------------------------------------------------------- */
1768 			case KEY_RIGHT:
1769 				if (dmode == HEX_MODE) {
1770 					if (edit_col[dmode] < 15)
1771 						edit_col[dmode]++;
1772 					else
1773 						edit_col[dmode] = 0;
1774 				}
1775 				break;
1776 			/* --------------------------------------------------------- */
1777 			/* m - change display mode key */
1778 			/* --------------------------------------------------------- */
1779 			case 'm':
1780 				dmode = ((dmode + 1) % DMODES);
1781 				break;
1782 			/* --------------------------------------------------------- */
1783 			/* J - Jump to highlighted block number */
1784 			/* --------------------------------------------------------- */
1785 			case 'j':
1786 				jump();
1787 				break;
1788 			/* --------------------------------------------------------- */
1789 			/* g - goto block */
1790 			/* --------------------------------------------------------- */
1791 			case 'g':
1792 				block = goto_block();
1793 				break;
1794 			/* --------------------------------------------------------- */
1795 			/* h - help key */
1796 			/* --------------------------------------------------------- */
1797 			case 'h':
1798 				print_usage();
1799 				break;
1800 			/* --------------------------------------------------------- */
1801 			/* e - change to extended mode */
1802 			/* --------------------------------------------------------- */
1803 			case 'e':
1804 				dmode = EXTENDED_MODE;
1805 				break;
1806 			/* --------------------------------------------------------- */
1807 			/* b - Back one 4K block */
1808 			/* --------------------------------------------------------- */
1809 			case 'b':
1810 				start_row[dmode] = end_row[dmode] = edit_row[dmode] = 0;
1811 				if (block > 0)
1812 					block--;
1813 				offset = 0;
1814 				break;
1815 			/* --------------------------------------------------------- */
1816 			/* c - Change color scheme */
1817 			/* --------------------------------------------------------- */
1818 			case 'c':
1819 				color_scheme = !color_scheme;
1820 				init_colors();
1821 				break;
1822 			/* --------------------------------------------------------- */
1823 			/* page up key */
1824 			/* --------------------------------------------------------- */
1825 			case 0x19:                    // ctrl-y for vt100
1826 			case KEY_PPAGE:		      // PgUp
1827 			case 0x15:                    // ctrl-u for vi compat.
1828 			case 0x02:                   // ctrl-b for less compat.
1829 				pageup();
1830 				break;
1831 			/* --------------------------------------------------------- */
1832 			/* end - Jump to the end of the list */
1833 			/* --------------------------------------------------------- */
1834 			case 0x168:
1835 				if (dmode == EXTENDED_MODE) {
1836 					int ents_per_screen = dsplines /
1837 						lines_per_row[dmode];
1838 	
1839 					edit_row[dmode] = end_row[dmode] - 1;
1840 					if ((edit_row[dmode] - ents_per_screen)+1 > 0)
1841 						start_row[dmode] = edit_row[dmode] - 
1842 							ents_per_screen + 1;
1843 					else
1844 						start_row[dmode] = 0;
1845 				}
1846 				/* TODO: Make end key work for other display modes. */
1847 				break;
1848 			/* --------------------------------------------------------- */
1849 			/* f - Forward one 4K block */
1850 			/* --------------------------------------------------------- */
1851 			case 'f':
1852 				start_row[dmode]=end_row[dmode]=edit_row[dmode] = 0;
1853 				lines_per_row[dmode] = 1;
1854 				block++;
1855 				offset = 0;
1856 				break;
1857 			/* --------------------------------------------------------- */
1858 			/* page down key */
1859 			/* --------------------------------------------------------- */
1860 			case 0x16:                    // ctrl-v for vt100
1861 			case KEY_NPAGE:		      // PgDown
1862 			case 0x04:                    // ctrl-d for vi compat.
1863 				pagedn();
1864 				break;
1865 			/* --------------------------------------------------------- */
1866 			/* enter key - change a value */
1867 			/* --------------------------------------------------------- */
1868 			case KEY_ENTER:
1869 			case('\n'):
1870 			case('\r'):
1871 				editing = !editing;
1872 				break;
1873 			case KEY_RESIZE:
1874 				getmaxyx(stdscr, termlines, termcols);
1875 				termlines--;
1876 				break;
1877 			default:
1878 				move(termlines - 1, 0);
1879 				printw("Keystroke not understood: 0x%03x",ch);
1880 				refresh();
1881 				usleep(50000);
1882 				break;
1883 			} /* switch */
1884 		} /* while !Quit */
1885 	
1886 	    Erase();
1887 	    refresh();
1888 	    endwin();
1889 	}/* interactive_mode */
1890 	
1891 	/* ------------------------------------------------------------------------ */
1892 	/* usage - print command line usage                                         */
1893 	/* ------------------------------------------------------------------------ */
1894 	static void usage(void)
1895 	{
1896 		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 <f>[val]] /dev/device\n\n");
1897 		fprintf(stderr,"If only the device is specified, it enters into hexedit mode.\n");
1898 		fprintf(stderr,"identify - prints out only the block type, not the details.\n");
1899 		fprintf(stderr,"printsavedmeta - prints out the saved metadata blocks from a savemeta file.\n");
1900 		fprintf(stderr,"savemeta <file_system> <file.gz> - save off your metadata for analysis and debugging.\n");
1901 		fprintf(stderr,"   (The intelligent way: assume bitmap is correct).\n");
1902 		fprintf(stderr,"savemetaslow - save off your metadata for analysis and debugging.  The SLOW way (block by block).\n");
1903 		fprintf(stderr,"savergs - save off only the resource group information (rindex and rgs).\n");
1904 		fprintf(stderr,"restoremeta - restore metadata for debugging (DANGEROUS).\n");
1905 		fprintf(stderr,"rgcount - print how many RGs in the file system.\n");
1906 		fprintf(stderr,"rgflags rgnum [new flags] - print or modify flags for rg #rgnum (0 - X)\n");
1907 		fprintf(stderr,"rgbitmaps <rgnum> - print out the bitmaps for rgrp "
1908 			"rgnum.\n");
1909 		fprintf(stderr,"rgrepair - find and repair damaged rgrp.\n");
1910 		fprintf(stderr,"-V   prints version number.\n");
1911 		fprintf(stderr,"-c 1 selects alternate color scheme 1\n");
1912 		fprintf(stderr,"-d   prints details (for printing journals)\n");
1913 		fprintf(stderr,"-p   prints GFS2 structures or blocks to stdout.\n");
1914 		fprintf(stderr,"     sb - prints the superblock.\n");
1915 		fprintf(stderr,"     size - prints the filesystem size.\n");
1916 		fprintf(stderr,"     master - prints the master directory.\n");
1917 		fprintf(stderr,"     root - prints the root directory.\n");
1918 		fprintf(stderr,"     jindex - prints the journal index directory.\n");
1919 		fprintf(stderr,"     journals - prints the journal status.\n");
1920 		fprintf(stderr,"     per_node - prints the per_node directory.\n");
1921 		fprintf(stderr,"     inum - prints the inum file.\n");
1922 		fprintf(stderr,"     statfs - prints the statfs file.\n");
1923 		fprintf(stderr,"     rindex - prints the rindex file.\n");
1924 		fprintf(stderr,"     rg X - print resource group X.\n");
1925 		fprintf(stderr,"     rgs - prints all the resource groups (rgs).\n");
1926 		fprintf(stderr,"     quota - prints the quota file.\n");
1927 		fprintf(stderr,"     0x1234 - prints the specified block\n");
1928 		fprintf(stderr,"-p   <block> blocktype - prints the type "
1929 			"of the specified block\n");
1930 		fprintf(stderr,"-p   <block> blockrg - prints the resource group "
1931 			"block corresponding to the specified block\n");
1932 		fprintf(stderr,"-p   <block> blockbits - prints the block with "
1933 			"the bitmap corresponding to the specified block\n");
1934 		fprintf(stderr,"-p   <block> blockalloc [0|1|2|3] - print or change "
1935 			"the allocation type of the specified block\n");
1936 		fprintf(stderr,"-p   <block> field [new_value] - prints or change the "
1937 			"structure field\n");
1938 		fprintf(stderr,"-p   <b> find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|"
1939 			"13|qc - find block of given type after block <b>\n");
1940 		fprintf(stderr,"     <b> specifies the starting block for search\n");
1941 		fprintf(stderr,"-z 1 use gzip compression level 1 for savemeta (default 9)\n");
1942 		fprintf(stderr,"-z 0 do not use compression\n");
1943 		fprintf(stderr,"-s   specifies a starting block such as root, rindex, quota, inum.\n");
1944 		fprintf(stderr,"-x   print in hexmode.\n");
1945 		fprintf(stderr,"-h   prints this help.\n\n");
1946 		fprintf(stderr,"Examples:\n");
1947 		fprintf(stderr,"   To run in interactive mode:\n");
1948 		fprintf(stderr,"     gfs2_edit /dev/bobs_vg/lvol0\n");
1949 		fprintf(stderr,"   To print out the superblock and master directory:\n");
1950 		fprintf(stderr,"     gfs2_edit -p sb master /dev/bobs_vg/lvol0\n");
1951 		fprintf(stderr,"   To print out the master directory in hex:\n");
1952 		fprintf(stderr,"     gfs2_edit -x -p master /dev/bobs_vg/lvol0\n");
1953 		fprintf(stderr,"   To print out the block-type for block 0x27381:\n");
1954 		fprintf(stderr,"     gfs2_edit identify -p 0x27381 /dev/bobs_vg/lvol0\n");
1955 		fprintf(stderr,"   To print out the fourth Resource Group. (the first R is #0)\n");
1956 		fprintf(stderr,"     gfs2_edit -p rg 3 /dev/sdb1\n");
1957 		fprintf(stderr,"   To print out the metadata type of block 1234\n");
1958 		fprintf(stderr,"     gfs2_edit -p 1234 blocktype /dev/roth_vg/roth_lb\n");
1959 		fprintf(stderr,"   To print out the allocation type of block 2345\n");
1960 		fprintf(stderr,"     gfs2_edit -p 2345 blockalloc /dev/vg/lv\n");
1961 		fprintf(stderr,"   To change the allocation type of block 2345 to a 'free block'\n");
1962 		fprintf(stderr,"     gfs2_edit -p 2345 blockalloc 0 /dev/vg/lv\n");
1963 		fprintf(stderr,"   To print out the file size of the dinode at block 0x118\n");
1964 		fprintf(stderr,"     gfs2_edit -p 0x118 field di_size /dev/roth_vg/roth_lb\n");
1965 		fprintf(stderr,"   To find any dinode higher than the quota file dinode:\n");
1966 		fprintf(stderr,"     gfs2_edit -p quota find di /dev/x/y\n");
1967 		fprintf(stderr,"   To set the Resource Group flags for rg #7 to 3.\n");
1968 		fprintf(stderr,"     gfs2_edit rgflags 7 3 /dev/sdc2\n");
1969 		fprintf(stderr,"   To save off all metadata for /dev/vg/lv:\n");
1970 		fprintf(stderr,"     gfs2_edit savemeta /dev/vg/lv /tmp/metasave.gz\n");
1971 	}/* usage */
1972 	
1973 	/**
1974 	 * getgziplevel - Process the -z parameter to savemeta operations
1975 	 * argv - argv
1976 	 * i    - a pointer to the argv index at which to begin processing
1977 	 * The index pointed to by i will be incremented past the -z option if found
1978 	 */
1979 	static void getgziplevel(char *argv[], int *i)
1980 	{
1981 		char *opt, *arg;
1982 		char *endptr;
1983 	
1984 		arg = argv[1 + *i];
1985 		if (strncmp(arg, "-z", 2)) {
1986 			return;
1987 		} else if (arg[2] != '\0') {
1988 			opt = &arg[2];
1989 		} else {
1990 			(*i)++;
1991 			opt = argv[1 + *i];
1992 		}
1993 		errno = 0;
1994 		gziplevel = strtol(opt, &endptr, 10);
1995 		if (errno || endptr == opt || gziplevel < 0 || gziplevel > 9) {
1996 			fprintf(stderr, "Compression level out of range: %s\n", opt);
1997 			exit(-1);
1998 		}
1999 		(*i)++;
2000 	}
2001 	
2002 	static int count_dinode_blks(struct lgfs2_rgrp_tree *rgd, int bitmap,
2003 				     struct lgfs2_buffer_head *rbh)
2004 	{
2005 		struct lgfs2_buffer_head *tbh;
2006 		uint64_t b;
2007 		int dinodes = 0;
2008 		char *byte, cur_state, new_state;
2009 		int bit, off;
2010 	
2011 		if (bitmap)
2012 			off = sizeof(struct gfs2_meta_header);
2013 		else
2014 			off = sizeof(struct gfs2_rgrp);
2015 	
2016 		for (b = 0; b < rgd->rt_bits[bitmap].bi_len << GFS2_BIT_SIZE; b++) {
2017 			tbh = lgfs2_bread(&sbd, rgd->rt_data0 +
2018 				    rgd->rt_bits[bitmap].bi_start + b);
2019 			byte = rbh->b_data + off + (b / GFS2_NBBY);
2020 			bit = (b % GFS2_NBBY) * GFS2_BIT_SIZE;
2021 			if (lgfs2_check_meta(tbh->b_data, GFS2_METATYPE_DI) == 0) {
2022 				dinodes++;
2023 				new_state = GFS2_BLKST_DINODE;
2024 			} else {
2025 				new_state = GFS2_BLKST_USED;
2026 			}
2027 			cur_state = (*byte >> bit) & GFS2_BIT_MASK;
2028 			*byte ^= cur_state << bit;
2029 			*byte |= new_state << bit;
2030 			lgfs2_brelse(tbh);
2031 		}
2032 		lgfs2_bmodified(rbh);
2033 		return dinodes;
2034 	}
2035 	
2036 	static int count_dinode_bits(struct lgfs2_buffer_head *rbh)
2037 	{
2038 		uint64_t blk;
2039 		struct gfs2_meta_header *mh = (struct gfs2_meta_header *)rbh->b_data;
2040 		char *byte;
2041 		int bit;
2042 		int dinodes = 0;
2043 	
2044 		if (be32_to_cpu(mh->mh_type) == GFS2_METATYPE_RG)
2045 			blk = sizeof(struct gfs2_rgrp);
2046 		else
2047 			blk = sizeof(struct gfs2_meta_header);
2048 	
2049 		for (; blk < sbd.sd_bsize; blk++) {
2050 			byte = rbh->b_data + (blk / GFS2_NBBY);
2051 			bit = (blk % GFS2_NBBY) * GFS2_BIT_SIZE;
2052 			if (((*byte >> bit) & GFS2_BIT_MASK) == GFS2_BLKST_DINODE)
2053 				dinodes++;
2054 		}
2055 		return dinodes;
2056 	}
2057 	
2058 	static void rg_repair(void)
2059 	{
2060 		struct lgfs2_buffer_head *rbh;
2061 		struct lgfs2_rgrp_tree *rgd;
2062 		struct osi_node *n;
2063 		int b;
2064 		int rgs_fixed = 0;
2065 		int dinodes_found = 0, dinodes_total = 0;
2066 	
2067 		/* Walk through the resource groups saving everything within */
2068 		for (n = osi_first(&sbd.rgtree); n; n = osi_next(n)) {
2069 			rgd = (struct lgfs2_rgrp_tree *)n;
2070 			if (lgfs2_rgrp_read(&sbd, rgd) == 0) { /* was read in okay */
2071 				lgfs2_rgrp_relse(&sbd, rgd);
2072 				continue; /* ignore it */
2073 			}
2074 			/* If we get here, it's because we have an rgrp in the rindex
2075 			   file that can't be read in. So attempt to repair it.
2076 			   If we find a damaged rgrp or bitmap, fix the metadata.
2077 			   Then scan all its blocks: if we find a dinode, set the
2078 			   repaired bitmap to GFS2_BLKST_DINODE. Set all others to
2079 			   GFS2_BLKST_USED so fsck can sort it out. If we set them
2080 			   to FREE, fsck would just nuke it all. */
2081 			printf("Resource group at block %"PRIu64" (0x%"PRIx64") appears to be "
2082 			       "damaged. Attempting to fix it (in reverse order).\n",
2083 			       rgd->rt_addr, rgd->rt_addr);
2084 	
2085 			for (b = rgd->rt_length - 1; b >= 0; b--) {
2086 				int mtype = (b ? GFS2_METATYPE_RB : GFS2_METATYPE_RG);
2087 				struct gfs2_meta_header *mh;
2088 	
2089 				printf("Bitmap #%d:", b);
2090 				rbh = lgfs2_bread(&sbd, rgd->rt_addr + b);
2091 				if (lgfs2_check_meta(rbh->b_data, mtype)) { /* wrong type */
2092 					printf("Damaged. Repairing...");
2093 					/* Fix the meta header */
2094 					memset(rbh->b_data, 0, sbd.sd_bsize);
2095 					mh = (struct gfs2_meta_header *)rbh->b_data;
2096 					mh->mh_magic = cpu_to_be32(GFS2_MAGIC);
2097 					mh->mh_type = cpu_to_be32(mtype);
2098 					if (b)
2099 						mh->mh_format =
2100 							cpu_to_be32(GFS2_FORMAT_RB);
2101 					else
2102 						mh->mh_format =
2103 							cpu_to_be32(GFS2_FORMAT_RG);
2104 					lgfs2_bmodified(rbh);
2105 					/* Count the dinode blocks */
2106 					dinodes_found = count_dinode_blks(rgd, b, rbh);
2107 				} else { /* bitmap info is okay: tally it. */
2108 					printf("Undamaged. Analyzing...");
2109 					dinodes_found = count_dinode_bits(rbh);
2110 				}
2111 				printf("Dinodes found: %d\n", dinodes_found);
2112 				dinodes_total += dinodes_found;
2113 				if (b == 0) { /* rgrp itself was damaged */
2114 					rgd->rt_dinodes = dinodes_total;
2115 					rgd->rt_free = 0;
2116 				}
2117 				lgfs2_brelse(rbh);
2118 			}
2119 			rgs_fixed++;
2120 		}
2121 		if (rgs_fixed)
2122 			printf("%d resource groups fixed.\n"
2123 			       "You should run fsck.gfs2 to reconcile the bitmaps.\n",
2124 			       rgs_fixed);
2125 		else
2126 			printf("All resource groups are okay. No repairs needed.\n");
2127 		exit(0);
2128 	}
2129 	
2130 	/* ------------------------------------------------------------------------ */
2131 	/* parameterpass1 - pre-processing for command-line parameters              */
2132 	/* ------------------------------------------------------------------------ */
2133 	static void parameterpass1(int argc, char *argv[], int i)
2134 	{
2135 		if (!strcasecmp(argv[i], "-V")) {
2136 			printf("gfs2_edit " VERSION "\n");
2137 			printf("%s\n", REDHAT_COPYRIGHT);
2138 			exit(0);
2139 		}
2140 		else if (!strcasecmp(argv[i], "-h") ||
2141 			 !strcasecmp(argv[i], "-help") ||
2142 			 !strcasecmp(argv[i], "-usage")) {
2143 			usage();
2144 			exit(0);
2145 		}
2146 		else if (!strcasecmp(argv[i], "-c")) {
2147 			i++;
2148 			color_scheme = atoi(argv[i]);
2149 		}
2150 		else if (!strcasecmp(argv[i], "-p") ||
2151 			 !strcasecmp(argv[i], "-print")) {
2152 			termlines = 0; /* initial value--we'll figure
2153 					  it out later */
2154 			dmode = GFS2_MODE;
2155 		}
2156 		else if (!strcasecmp(argv[i], "-d") ||
2157 			 !strcasecmp(argv[i], "-details"))
2158 			details = 1;
2159 		else if (!strcasecmp(argv[i], "savemeta"))
2160 			termlines = 0;
2161 		else if (!strcasecmp(argv[i], "savemetaslow"))
2162 			termlines = 0;
2163 		else if (!strcasecmp(argv[i], "savergs"))
2164 			termlines = 0;
2165 		else if (!strcasecmp(argv[i], "printsavedmeta")) {
2166 			if (dmode == INIT_MODE)
2167 				dmode = GFS2_MODE;
2168 			restoremeta(argv[i+1], argv[i+2], TRUE);
2169 		} else if (!strcasecmp(argv[i], "restoremeta")) {
2170 			if (dmode == INIT_MODE)
2171 				dmode = HEX_MODE; /* hopefully not used */
2172 			restoremeta(argv[i+1], argv[i+2], FALSE);
2173 		} else if (!strcmp(argv[i], "rgcount"))
2174 			termlines = 0;
2175 		else if (!strcmp(argv[i], "rgflags"))
2176 			termlines = 0;
2177 		else if (!strcmp(argv[i], "rgrepair"))
2178 			termlines = 0;
2179 		else if (!strcmp(argv[i], "rg"))
2180 			termlines = 0;
2181 		else if (!strcasecmp(argv[i], "-x"))
2182 			dmode = HEX_MODE;
2183 		else if (device == NULL && strchr(argv[i],'/')) {
2184 			device = argv[i];
2185 		}
2186 	}
2187 	
2188 	/* ------------------------------------------------------------------------ */
2189 	/* process_parameters - process commandline parameters                      */
2190 	/* pass - we make two passes through the parameters; the first pass gathers */
2191 	/*        normals parameters, device name, etc.  The second pass is for     */
2192 	/*        figuring out what structures to print out.                        */
2193 	/* ------------------------------------------------------------------------ */
2194 	static void process_parameters(int argc, char *argv[], int pass)
2195 	{
2196 		int i;
2197 		uint64_t keyword_blk;
2198 	
2199 		if (argc < 2) {
2200 			fprintf(stderr, "No device specified\n");
2201 			exit(1);
2202 		}
2203 		for (i = 1; i < argc; i++) {
2204 			if (!pass) { /* first pass */
2205 				parameterpass1(argc, argv, i);
2206 				continue;
2207 			}
2208 			/* second pass */
2209 			if (!strcasecmp(argv[i], "-s")) {
2210 				i++;
2211 				if (i >= argc - 1) {
2212 					printf("Error: starting block not specified "
2213 					       "with -s.\n");
2214 					printf("%s -s [starting block | keyword] "
2215 					       "<device>\n", argv[0]);
2216 					printf("For example: %s -s \"rg 3\" "
2217 					       "/dev/exxon_vg/exxon_lv\n", argv[0]);
2218 					exit(EXIT_FAILURE);
2219 				}
2220 				starting_blk = check_keywords(argv[i]);
2221 				continue;
2222 			}
2223 			if (termlines || strchr(argv[i],'/')) /* if print or slash */
2224 				continue;
2225 	
2226 			if (!strncmp(argv[i], "journal", 7) && isdigit(argv[i][7]) &&
2227 			    strcmp(argv[i+1], "field")) {
2228 				uint64_t blk = 0;
2229 	
2230 				if (i < argc - 1 && isdigit(argv[i + 1][0])) {
2231 					if (argv[i + 1][0]=='0' && argv[i + 1][1]=='x')
2232 						sscanf(argv[i + 1], "%"SCNx64, &blk);
2233 					else
2234 						sscanf(argv[i + 1], "%"SCNu64, &blk);
2235 				}
2236 				dump_journal(argv[i], blk);
2237 				continue;
2238 			}
2239 			keyword_blk = check_keywords(argv[i]);
2240 			if (keyword_blk)
2241 				push_block(keyword_blk);
2242 			else if (!strcasecmp(argv[i], "-x"))
2243 				dmode = HEX_MODE;
2244 			else if (argv[i][0] == '-') /* if it starts with a dash */
2245 				; /* ignore it--meant for pass == 0 */
2246 			else if (!strcmp(argv[i], "identify"))
2247 				identify = TRUE;
2248 			else if (!strcmp(argv[i], "size")) {
2249 				printf("Device size: %"PRIu64" blocks\n", max_block);
2250 				exit(EXIT_SUCCESS);
2251 			} else if (!strcmp(argv[i], "rgcount"))
2252 				rgcount();
2253 			else if (!strcmp(argv[i], "field")) {
2254 				i++;
2255 				if (i >= argc - 1) {
2256 					printf("Error: field not specified.\n");
2257 					printf("Format is: %s -p <block> field "
2258 					       "<field> [newvalue]\n", argv[0]);
2259 					lgfs2_rgrp_free(&sbd, &sbd.rgtree);
2260 					exit(EXIT_FAILURE);
2261 				}
2262 				process_field(argv[i], argv[i + 1]);
2263 			} else if (!strcmp(argv[i], "blocktype")) {
2264 				find_print_block_type();
2265 			} else if (!strcmp(argv[i], "blockrg")) {
2266 				find_print_block_rg(0);
2267 			} else if (!strcmp(argv[i], "blockbits")) {
2268 				find_print_block_rg(1);
2269 			} else if (!strcmp(argv[i], "blockalloc")) {
2270 				if (isdigit(argv[i + 1][0])) {
2271 					int newval;
2272 	
2273 					if (argv[i + 1][0]=='0' && argv[i + 1][1]=='x')
2274 						sscanf(argv[i + 1], "%x", &newval);
2275 					else
2276 						newval = (uint64_t)atoi(argv[i + 1]);
2277 					find_change_block_alloc(&newval);
2278 				} else {
2279 					find_change_block_alloc(NULL);
2280 				}
2281 			} else if (!strcmp(argv[i], "find")) {
2282 				find_metablockoftype(argv[i + 1], 1);
2283 			} else if (!strcmp(argv[i], "rgflags")) {
2284 				int rg, set = FALSE;
2285 				uint32_t new_flags = 0;
2286 	
2287 				i++;
2288 				if (i >= argc - 1) {
2289 					printf("Error: rg # not specified.\n");
2290 					printf("Format is: %s rgflags rgnum"
2291 					       "[newvalue]\n", argv[0]);
2292 					lgfs2_rgrp_free(&sbd, &sbd.rgtree);
2293 					exit(EXIT_FAILURE);
2294 				}
2295 				if (argv[i][0]=='0' && argv[i][1]=='x')
2296 					sscanf(argv[i], "%"SCNx32, &rg);
2297 				else
2298 					rg = atoi(argv[i]);
2299 				i++;
2300 				if (i < argc - 1 &&
2301 				    isdigit(argv[i][0])) {
2302 					set = TRUE;
2303 					if (argv[i][0]=='0' && argv[i][1]=='x')
2304 						sscanf(argv[i], "%"SCNx32, &new_flags);
2305 					else
2306 						new_flags = atoi(argv[i]);
2307 				}
2308 				set_rgrp_flags(rg, new_flags, set, FALSE);
2309 				lgfs2_rgrp_free(&sbd, &sbd.rgtree);
2310 				exit(EXIT_SUCCESS);
2311 			} else if (!strcmp(argv[i], "rg")) {
2312 				int rg;
2313 	
2314 				i++;
2315 				if (i >= argc - 1) {
2316 					printf("Error: rg # not specified.\n");
2317 					printf("Format is: %s rg rgnum\n", argv[0]);
2318 					lgfs2_rgrp_free(&sbd, &sbd.rgtree);
2319 					exit(EXIT_FAILURE);
2320 				}
2321 				rg = atoi(argv[i]);
2322 				if (!strcasecmp(argv[i + 1], "find")) {
2323 					temp_blk = get_rg_addr(rg);
2324 					push_block(temp_blk);
2325 				} else {
2326 					set_rgrp_flags(rg, 0, FALSE, TRUE);
2327 					lgfs2_rgrp_free(&sbd, &sbd.rgtree);
2328 					exit(EXIT_SUCCESS);
2329 				}
2330 			} else if (!strcmp(argv[i], "rgbitmaps")) {
2331 				int rg, bmap;
2332 				uint64_t rgblk;
2333 				struct lgfs2_rgrp_tree *rgd;
2334 	
2335 				i++;
2336 				if (i >= argc - 1) {
2337 					printf("Error: rg # not specified.\n");
2338 					printf("Format is: %s rgbitmaps rgnum\n",
2339 					       argv[0]);
2340 					lgfs2_rgrp_free(&sbd, &sbd.rgtree);
2341 					exit(EXIT_FAILURE);
2342 				}
2343 				rg = atoi(argv[i]);
2344 				rgblk = get_rg_addr(rg);
2345 				rgd = lgfs2_blk2rgrpd(&sbd, rgblk);
2346 				if (rgd == NULL) {
2347 					printf("Error: rg # is invalid.\n");
2348 					lgfs2_rgrp_free(&sbd, &sbd.rgtree);
2349 					exit(EXIT_FAILURE);
2350 				}
2351 				for (bmap = 0; bmap < rgd->rt_length; bmap++)
2352 					push_block(rgblk + bmap);
2353 			}
2354 			else if (!strcmp(argv[i], "rgrepair"))
2355 				rg_repair();
2356 			else if (!strcasecmp(argv[i], "savemeta")) {
2357 				getgziplevel(argv, &i);
2358 				savemeta(argv[i+2], 0, gziplevel);
2359 			} else if (!strcasecmp(argv[i], "savemetaslow")) {
2360 				getgziplevel(argv, &i);
2361 				savemeta(argv[i+2], 1, gziplevel);
2362 			} else if (!strcasecmp(argv[i], "savergs")) {
2363 				getgziplevel(argv, &i);
2364 				savemeta(argv[i+2], 2, gziplevel);
2365 			} else if (isdigit(argv[i][0])) { /* decimal addr */
2366 				sscanf(argv[i], "%"SCNd64, &temp_blk);
2367 				push_block(temp_blk);
2368 			} else {
2369 				fprintf(stderr,"I don't know what '%s' means.\n",
2370 					argv[i]);
2371 				usage();
2372 				exit(EXIT_FAILURE);
2373 			}
2374 		} /* for */
2375 	}/* process_parameters */
2376 	
2377 	#ifndef UNITTESTS
2378 	int main(int argc, char *argv[])
2379 	{
2380 		int i, j, fd;
2381 	
2382 		indirect = malloc(sizeof(struct iinfo));
2383 		if (indirect == NULL) {
2384 			perror("Failed to allocate indirect info");
2385 			exit(1);
2386 		}
2387 		memset(indirect, 0, sizeof(struct iinfo));
2388 		memset(start_row, 0, sizeof(start_row));
2389 		memset(lines_per_row, 0, sizeof(lines_per_row));
2390 		memset(end_row, 0, sizeof(end_row));
2391 		memset(edit_row, 0, sizeof(edit_row));
2392 		memset(edit_col, 0, sizeof(edit_col));
2393 		memset(edit_size, 0, sizeof(edit_size));
2394 		memset(last_entry_onscreen, 0, sizeof(last_entry_onscreen));
2395 		dmode = INIT_MODE;
2396 		sbd.sd_bsize = 4096;
2397 		block = starting_blk = 0x10;
2398 		for (i = 0; i < BLOCK_STACK_SIZE; i++) {
2399 			blockstack[i].dmode = HEX_MODE;
2400 			blockstack[i].block = block;
2401 			for (j = 0; j < DMODES; j++) {
2402 				blockstack[i].start_row[j] = 0;
2403 				blockstack[i].end_row[j] = 0;
2404 				blockstack[i].edit_row[j] = 0;
2405 				blockstack[i].edit_col[j] = 0;
2406 				blockstack[i].lines_per_row[j] = 0;
2407 			}
2408 		}
2409 	
2410 		edit_row[GFS2_MODE] = 10; /* Start off at root inode
2411 					     pointer in superblock */
2412 		termlines = 30;  /* assume interactive mode until we find -p */
2413 		process_parameters(argc, argv, 0);
2414 		if (dmode == INIT_MODE)
2415 			dmode = HEX_MODE;
2416 	
2417 		fd = open(device, O_RDWR);
2418 		if (fd < 0) {
2419 			fprintf(stderr, "Failed to open '%s': %s\n", device, strerror(errno));
2420 			exit(1);
2421 		}
2422 		max_block = lseek(fd, 0, SEEK_END) / sbd.sd_bsize;
2423 	
2424 		read_superblock(fd);
2425 		if (read_rindex())
2426 			exit(-1);
2427 		max_block = lseek(fd, 0, SEEK_END) / sbd.sd_bsize;
2428 		if (read_master_dir() != 0)
2429 			exit(-1);
2430 	
2431 		process_parameters(argc, argv, 1); /* get what to print from cmdline */
2432 	
2433 		block = blockstack[0].block = starting_blk * (4096 / sbd.sd_bsize);
2434 	
2435 		if (termlines)
2436 			interactive_mode();
2437 		else { /* print all the structures requested */
2438 			i = 0;
2439 			while (blockhist > 0) {
2440 				block = blockstack[i + 1].block;
2441 				if (!block)
2442 					break;
2443 				display(identify, 0, 0, 0);
2444 				if (!identify) {
2445 					display_extended();
2446 					printf("-------------------------------------" \
2447 					       "-----------------");
2448 					eol(0);
2449 				}
2450 				block = pop_block();
2451 				i++;
2452 			}
2453 		}
2454 		close(fd);
2455 		if (indirect)
2456 			free(indirect);
2457 		lgfs2_rgrp_free(&sbd, &sbd.rgtree);
2458 	 	exit(EXIT_SUCCESS);
2459 	}
2460 	#endif /* UNITTESTS */
2461