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