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
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