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