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