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