]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/btdump.c
xfs_db: identify attr dabtree field types correctly
[thirdparty/xfsprogs-dev.git] / db / btdump.c
1 /*
2 * Copyright (C) 2017 Oracle. All Rights Reserved.
3 *
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 #include "libxfs.h"
21 #include "command.h"
22 #include "output.h"
23 #include "init.h"
24 #include "io.h"
25 #include "type.h"
26 #include "input.h"
27
28 static void
29 btdump_help(void)
30 {
31 dbprintf(_(
32 "\n"
33 " If the cursor points to a btree block, 'btdump' dumps the btree\n"
34 " downward from that block. If the cursor points to an inode,\n"
35 " the data fork btree root is selected by default.\n"
36 "\n"
37 " Options:\n"
38 " -a -- Display an inode's extended attribute fork btree.\n"
39 " -i -- Print internal btree nodes.\n"
40 "\n"
41 ));
42
43 }
44
45 static int
46 eval(
47 const char *fmt, ...)
48 {
49 va_list ap;
50 char buf[PATH_MAX];
51 char **v;
52 int c;
53 int ret;
54
55 va_start(ap, fmt);
56 vsnprintf(buf, sizeof(buf), fmt, ap);
57 va_end(ap);
58
59 v = breakline(buf, &c);
60 ret = command(c, v);
61 free(v);
62 return ret;
63 }
64
65 static bool
66 btblock_has_rightsib(
67 struct xfs_btree_block *block,
68 bool long_format)
69 {
70 if (long_format)
71 return block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK);
72 return block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK);
73 }
74
75 static int
76 dump_btlevel(
77 int level,
78 bool long_format)
79 {
80 xfs_daddr_t orig_daddr = iocur_top->bb;
81 xfs_daddr_t last_daddr;
82 unsigned int nr;
83 int ret;
84
85 ret = eval("push");
86 if (ret)
87 return ret;
88
89 nr = 1;
90 do {
91 last_daddr = iocur_top->bb;
92 dbprintf(_("%s level %u block %u daddr %llu\n"),
93 iocur_top->typ->name, level, nr, last_daddr);
94 if (level > 0) {
95 ret = eval("print keys");
96 if (ret)
97 goto err;
98 ret = eval("print ptrs");
99 } else {
100 ret = eval("print recs");
101 }
102 if (ret)
103 goto err;
104 if (btblock_has_rightsib(iocur_top->data, long_format)) {
105 ret = eval("addr rightsib");
106 if (ret)
107 goto err;
108 }
109 nr++;
110 } while (iocur_top->bb != orig_daddr && iocur_top->bb != last_daddr);
111
112 ret = eval("pop");
113 return ret;
114 err:
115 eval("pop");
116 return ret;
117 }
118
119 static int
120 dump_btree(
121 bool dump_node_blocks,
122 bool long_format)
123 {
124 xfs_daddr_t orig_daddr = iocur_top->bb;
125 xfs_daddr_t last_daddr;
126 int level;
127 int ret;
128
129 ret = eval("push");
130 if (ret)
131 return ret;
132
133 cur_agno = XFS_FSB_TO_AGNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb));
134 level = xfs_btree_get_level(iocur_top->data);
135 do {
136 last_daddr = iocur_top->bb;
137 if (level > 0) {
138 if (dump_node_blocks) {
139 ret = dump_btlevel(level, long_format);
140 if (ret)
141 goto err;
142 }
143 ret = eval("addr ptrs[1]");
144 } else {
145 ret = dump_btlevel(level, long_format);
146 }
147 if (ret)
148 goto err;
149 level--;
150 } while (level >= 0 &&
151 iocur_top->bb != orig_daddr &&
152 iocur_top->bb != last_daddr);
153
154 ret = eval("pop");
155 return ret;
156 err:
157 eval("pop");
158 return ret;
159 }
160
161 static inline int dump_btree_short(bool dump_node_blocks)
162 {
163 return dump_btree(dump_node_blocks, false);
164 }
165
166 static inline int dump_btree_long(bool dump_node_blocks)
167 {
168 return dump_btree(dump_node_blocks, true);
169 }
170
171 static int
172 dump_inode(
173 bool dump_node_blocks,
174 bool attrfork)
175 {
176 char *prefix;
177 struct xfs_dinode *dip;
178 int ret;
179
180 if (attrfork)
181 prefix = "a.bmbt";
182 else if (xfs_sb_version_hascrc(&mp->m_sb))
183 prefix = "u3.bmbt";
184 else
185 prefix = "u.bmbt";
186
187 dip = iocur_top->data;
188 if (attrfork) {
189 if (!dip->di_anextents ||
190 dip->di_aformat != XFS_DINODE_FMT_BTREE) {
191 dbprintf(_("attr fork not in btree format\n"));
192 return 0;
193 }
194 } else {
195 if (!dip->di_nextents ||
196 dip->di_format != XFS_DINODE_FMT_BTREE) {
197 dbprintf(_("data fork not in btree format\n"));
198 return 0;
199 }
200 }
201
202 ret = eval("push");
203 if (ret)
204 return ret;
205
206 if (dump_node_blocks) {
207 ret = eval("print %s.keys", prefix);
208 if (ret)
209 goto err;
210 ret = eval("print %s.ptrs", prefix);
211 if (ret)
212 goto err;
213 }
214
215 ret = eval("addr %s.ptrs[1]", prefix);
216 if (ret)
217 goto err;
218
219 ret = dump_btree_long(dump_node_blocks);
220 if (ret)
221 goto err;
222
223 ret = eval("pop");
224 return ret;
225 err:
226 eval("pop");
227 return ret;
228 }
229
230 static int
231 btdump_f(
232 int argc,
233 char **argv)
234 {
235 bool aflag = false;
236 bool iflag = false;
237 int c;
238
239 if (cur_typ == NULL) {
240 dbprintf(_("no current type\n"));
241 return 0;
242 }
243 while ((c = getopt(argc, argv, "ai")) != EOF) {
244 switch (c) {
245 case 'a':
246 aflag = true;
247 break;
248 case 'i':
249 iflag = true;
250 break;
251 default:
252 dbprintf(_("bad option for btdump command\n"));
253 return 0;
254 }
255 }
256
257 if (optind != argc) {
258 dbprintf(_("bad options for btdump command\n"));
259 return 0;
260 }
261 if (aflag && cur_typ->typnm != TYP_INODE) {
262 dbprintf(_("attrfork flag doesn't apply here\n"));
263 return 0;
264 }
265
266 switch (cur_typ->typnm) {
267 case TYP_BNOBT:
268 case TYP_CNTBT:
269 case TYP_INOBT:
270 case TYP_FINOBT:
271 case TYP_RMAPBT:
272 case TYP_REFCBT:
273 return dump_btree_short(iflag);
274 case TYP_BMAPBTA:
275 case TYP_BMAPBTD:
276 return dump_btree_long(iflag);
277 case TYP_INODE:
278 return dump_inode(iflag, aflag);
279 default:
280 dbprintf(_("type \"%s\" is not a btree type or inode\n"),
281 cur_typ->name);
282 return 0;
283 }
284 }
285
286 static const cmdinfo_t btdump_cmd =
287 { "btdump", "b", btdump_f, 0, 2, 0, "[-a] [-i]",
288 N_("dump btree"), btdump_help };
289
290 void
291 btdump_init(void)
292 {
293 add_command(&btdump_cmd);
294 }