From patchwork Mon Jul 7 07:24:48 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: hujianyang X-Patchwork-Id: 367442 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2001:1868:205::9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 159791400A3 for ; Mon, 7 Jul 2014 17:27:41 +1000 (EST) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1X43J9-0001oo-DA; Mon, 07 Jul 2014 07:25:51 +0000 Received: from szxga02-in.huawei.com ([119.145.14.65]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1X43J6-0000vr-2o for linux-mtd@lists.infradead.org; Mon, 07 Jul 2014 07:25:49 +0000 Received: from 172.24.2.119 (EHLO SZXEML414-HUB.china.huawei.com) ([172.24.2.119]) by szxrg02-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id BWJ03186; Mon, 07 Jul 2014 15:25:03 +0800 (CST) Received: from [127.0.0.1] (10.111.68.144) by SZXEML414-HUB.china.huawei.com (10.82.67.153) with Microsoft SMTP Server id 14.3.158.1; Mon, 7 Jul 2014 15:24:52 +0800 Message-ID: <53BA4B40.70902@huawei.com> Date: Mon, 7 Jul 2014 15:24:48 +0800 From: hujianyang User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20130801 Thunderbird/17.0.8 MIME-Version: 1.0 To: linux-mtd Subject: [PATCH 5/7] Add libubifs.c References: <53BA491E.8060502@huawei.com> In-Reply-To: <53BA491E.8060502@huawei.com> X-Originating-IP: [10.111.68.144] X-CFilter-Loop: Reflected X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140707_002548_881277_23E5584A X-CRM114-Status: GOOD ( 20.07 ) X-Spam-Score: -1.4 (-) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-1.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [119.145.14.65 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain Cc: Artem Bityutskiy X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org These functions are copied from fs/ubifs/scan.c and fs/ubifs/debug.c with some small changes. We don't have 'ubifs_info *c' in user space and we don't need to check NODEs, just print what they are. I think if data is corrupted, kernel will warn it and we can't check it here because the checking codes are to heavy. case SCANNED_A_NODE: We will get the whole detailed info about this node if we set '-i'. I just dump detailed info with some kinds of NODEs because I think others are useless for debugging and you can simply add what you need if it is necessary. Signed-off-by: hujianyang --- ubi-utils/libubifs.c | 399 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 ubi-utils/libubifs.c diff --git a/ubi-utils/libubifs.c b/ubi-utils/libubifs.c new file mode 100644 index 0000000..86517fa --- /dev/null +++ b/ubi-utils/libubifs.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * Author: Hu Jianyang + * + * UBIFS library. + */ + +#define PROGRAM_NAME "libubifs" + +#include +#include +#include +#include +#include "common.h" + +static const char *get_key_fmt(int fmt) +{ + switch (fmt) { + case UBIFS_SIMPLE_KEY_FMT: + return "simple"; + default: + return "unknown/invalid format"; + } +} + +static const char *get_key_hash(int hash) +{ + switch (hash) { + case UBIFS_KEY_HASH_R5: + return "R5"; + case UBIFS_KEY_HASH_TEST: + return "test"; + default: + return "unknown/invalid name hash"; + } +} + +static const char *node_ntype(int type) +{ + switch (type) { + case UBIFS_PAD_NODE: + return "padding node"; + case UBIFS_SB_NODE: + return "superblock node"; + case UBIFS_MST_NODE: + return "master node"; + case UBIFS_REF_NODE: + return "reference node"; + case UBIFS_INO_NODE: + return "inode node"; + case UBIFS_DENT_NODE: + return "direntry node"; + case UBIFS_XENT_NODE: + return "xentry node"; + case UBIFS_DATA_NODE: + return "data node"; + case UBIFS_TRUN_NODE: + return "truncate node"; + case UBIFS_IDX_NODE: + return "indexing node"; + case UBIFS_CS_NODE: + return "commit start node"; + case UBIFS_ORPH_NODE: + return "orphan node"; + default: + return "unknown node"; + } +} + +static const char *node_gtype(int type) +{ + switch (type) { + case UBIFS_NO_NODE_GROUP: + return "no node group"; + case UBIFS_IN_NODE_GROUP: + return "in node group"; + case UBIFS_LAST_OF_NODE_GROUP: + return "last of node group"; + default: + return "unknown"; + } +} + +static void dump_ch(const struct ubifs_ch *ch) +{ + printf("\tmagic %#x\n", le32_to_cpu(ch->magic)); + printf("\tcrc %#x\n", le32_to_cpu(ch->crc)); + printf("\tnode_type %d (%s)\n", ch->node_type, + node_ntype(ch->node_type)); + printf("\tgroup_type %d (%s)\n", ch->group_type, + node_gtype(ch->group_type)); + printf("\tsqnum %llu\n", + (unsigned long long)le64_to_cpu(ch->sqnum)); + printf("\tlen %u\n", le32_to_cpu(ch->len)); +} + +void ubifs_dump_node(const void *node) +{ + const struct ubifs_ch *ch = node; + + if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) { + printf("Not a node, first %zu bytes:\n", UBIFS_CH_SZ); + return; + } + + dump_ch(node); + + switch (ch->node_type) { + case UBIFS_PAD_NODE: + { + const struct ubifs_pad_node *pad = node; + + printf("\tpad_len %u\n", le32_to_cpu(pad->pad_len)); + break; + } + case UBIFS_SB_NODE: + { + const struct ubifs_sb_node *sup = node; + unsigned int sup_flags = le32_to_cpu(sup->flags); + + printf("\tkey_hash %d (%s)\n", + (int)sup->key_hash, get_key_hash(sup->key_hash)); + printf("\tkey_fmt %d (%s)\n", + (int)sup->key_fmt, get_key_fmt(sup->key_fmt)); + printf("\tflags %#x\n", sup_flags); + printf("\tbig_lpt %u\n", + !!(sup_flags & UBIFS_FLG_BIGLPT)); + printf("\tspace_fixup %u\n", + !!(sup_flags & UBIFS_FLG_SPACE_FIXUP)); + printf("\tmin_io_size %u\n", le32_to_cpu(sup->min_io_size)); + printf("\tleb_size %u\n", le32_to_cpu(sup->leb_size)); + printf("\tleb_cnt %u\n", le32_to_cpu(sup->leb_cnt)); + printf("\tmax_leb_cnt %u\n", le32_to_cpu(sup->max_leb_cnt)); + printf("\tmax_bud_bytes %llu\n", + (unsigned long long)le64_to_cpu(sup->max_bud_bytes)); + printf("\tlog_lebs %u\n", le32_to_cpu(sup->log_lebs)); + printf("\tlpt_lebs %u\n", le32_to_cpu(sup->lpt_lebs)); + printf("\torph_lebs %u\n", le32_to_cpu(sup->orph_lebs)); + printf("\tjhead_cnt %u\n", le32_to_cpu(sup->jhead_cnt)); + printf("\tfanout %u\n", le32_to_cpu(sup->fanout)); + printf("\tlsave_cnt %u\n", le32_to_cpu(sup->lsave_cnt)); + printf("\tdefault_compr %u\n", + (int)le16_to_cpu(sup->default_compr)); + printf("\trp_size %llu\n", + (unsigned long long)le64_to_cpu(sup->rp_size)); + printf("\trp_uid %u\n", le32_to_cpu(sup->rp_uid)); + printf("\trp_gid %u\n", le32_to_cpu(sup->rp_gid)); + printf("\tfmt_version %u\n", le32_to_cpu(sup->fmt_version)); + printf("\ttime_gran %u\n", le32_to_cpu(sup->time_gran)); + printf("\tUUID %pUB\n", sup->uuid); + break; + } + case UBIFS_MST_NODE: + { + const struct ubifs_mst_node *mst = node; + + printf("\thighest_inum %llu\n", + (unsigned long long)le64_to_cpu(mst->highest_inum)); + printf("\tcommit number %llu\n", + (unsigned long long)le64_to_cpu(mst->cmt_no)); + printf("\tflags %#x\n", le32_to_cpu(mst->flags)); + printf("\tlog_lnum %u\n", le32_to_cpu(mst->log_lnum)); + printf("\troot_lnum %u\n", le32_to_cpu(mst->root_lnum)); + printf("\troot_offs %u\n", le32_to_cpu(mst->root_offs)); + printf("\troot_len %u\n", le32_to_cpu(mst->root_len)); + printf("\tgc_lnum %u\n", le32_to_cpu(mst->gc_lnum)); + printf("\tihead_lnum %u\n", le32_to_cpu(mst->ihead_lnum)); + printf("\tihead_offs %u\n", le32_to_cpu(mst->ihead_offs)); + printf("\tindex_size %llu\n", + (unsigned long long)le64_to_cpu(mst->index_size)); + printf("\tlpt_lnum %u\n", le32_to_cpu(mst->lpt_lnum)); + printf("\tlpt_offs %u\n", le32_to_cpu(mst->lpt_offs)); + printf("\tnhead_lnum %u\n", le32_to_cpu(mst->nhead_lnum)); + printf("\tnhead_offs %u\n", le32_to_cpu(mst->nhead_offs)); + printf("\tltab_lnum %u\n", le32_to_cpu(mst->ltab_lnum)); + printf("\tltab_offs %u\n", le32_to_cpu(mst->ltab_offs)); + printf("\tlsave_lnum %u\n", le32_to_cpu(mst->lsave_lnum)); + printf("\tlsave_offs %u\n", le32_to_cpu(mst->lsave_offs)); + printf("\tlscan_lnum %u\n", le32_to_cpu(mst->lscan_lnum)); + printf("\tleb_cnt %u\n", le32_to_cpu(mst->leb_cnt)); + printf("\tempty_lebs %u\n", le32_to_cpu(mst->empty_lebs)); + printf("\tidx_lebs %u\n", le32_to_cpu(mst->idx_lebs)); + printf("\ttotal_free %llu\n", + (unsigned long long)le64_to_cpu(mst->total_free)); + printf("\ttotal_dirty %llu\n", + (unsigned long long)le64_to_cpu(mst->total_dirty)); + printf("\ttotal_used %llu\n", + (unsigned long long)le64_to_cpu(mst->total_used)); + printf("\ttotal_dead %llu\n", + (unsigned long long)le64_to_cpu(mst->total_dead)); + printf("\ttotal_dark %llu\n", + (unsigned long long)le64_to_cpu(mst->total_dark)); + break; + } + case UBIFS_REF_NODE: + { + const struct ubifs_ref_node *ref = node; + + printf("\tlnum %u\n", le32_to_cpu(ref->lnum)); + printf("\toffs %u\n", le32_to_cpu(ref->offs)); + printf("\tjhead %u\n", le32_to_cpu(ref->jhead)); + break; + } + case UBIFS_CS_NODE: + break; + case UBIFS_INO_NODE: + case UBIFS_DENT_NODE: + case UBIFS_XENT_NODE: + case UBIFS_DATA_NODE: + case UBIFS_TRUN_NODE: + case UBIFS_IDX_NODE: + case UBIFS_ORPH_NODE: + printf("cannot dump node, type not support\n"); + default: + printf("node type %d was not recognized\n", + (int)ch->node_type); + } +} + +/** + * scan_padding_bytes - scan for padding bytes. + * @buf: buffer to scan + * @len: length of buffer + * + * This function returns the number of padding bytes on success and + * %SCANNED_GARBAGE on failure. + */ +static int scan_padding_bytes(void *buf, int len) +{ + int pad_len = 0, max_pad_len = min_t(int, UBIFS_PAD_NODE_SZ, len); + uint8_t *p = buf; + + printf("not a node\n"); + + while (pad_len < max_pad_len && *p++ == UBIFS_PADDING_BYTE) + pad_len += 1; + + if (!pad_len || (pad_len & 7)) + return SCANNED_GARBAGE; + + printf("%d padding bytes\n", pad_len); + + return pad_len; +} + +/** + * ubifs_scan_a_node - scan for a node or padding. + * @buf: buffer to scan + * @size: logical eraseblock size + * @len: length of buffer + * @lnum: logical eraseblock number + * @offs: offset within the logical eraseblock + * + * This function returns a scanning code to indicate what was scanned. + */ +int ubifs_scan_a_node(void *buf, int leb_size, int len, int lnum, int offs) +{ + struct ubifs_ch *ch = buf; + uint32_t magic; + + magic = le32_to_cpu(ch->magic); + + if (magic == 0xFFFFFFFF) { + printf("hit empty space at LEB %d:%d\n", lnum, offs); + return SCANNED_EMPTY_SPACE; + } + + if (magic != UBIFS_NODE_MAGIC) + return scan_padding_bytes(buf, len); + + if (len < UBIFS_CH_SZ) + return SCANNED_GARBAGE; + + printf("scanning %s at LEB %d:%d\n", + node_ntype(ch->node_type), lnum, offs); + + /* No ubifs_check_nodei() perform here */ + + if (ch->node_type == UBIFS_PAD_NODE) { + struct ubifs_pad_node *pad = buf; + int pad_len = le32_to_cpu(pad->pad_len); + int node_len = le32_to_cpu(ch->len); + + /* Validate the padding node */ + if (pad_len < 0 || + offs + node_len + pad_len > leb_size) { + printf("bad pad node at LEB %d:%d\n", lnum, offs); + ubifs_dump_node(pad); + return SCANNED_A_BAD_PAD_NODE; + } + + /* Make the node pads to 8-byte boundary */ + if ((node_len + pad_len) & 7) { + printf("bad padding length %d - %d\n", + offs, offs + node_len + pad_len); + return SCANNED_A_BAD_PAD_NODE; + } + + printf("%d bytes padded at LEB %d:%d, offset now %d\n", pad_len, + lnum, offs, ALIGN(offs + node_len + pad_len, 8)); + + return node_len + pad_len; + } + + return SCANNED_A_NODE; +} + +/** + * ubifs_scan - scan a logical eraseblock. + * @lnum: logical eraseblock number + * @sbuf: scan buffer + * @size: size of @buf in bytes + * @offs: offset to start at (usually zero) + * @detailed: print NODEs detailed info + * + * This function scans LEB and prints complete information about + * its contents. + */ +void ubifs_scan(int lnum, void *sbuf, int leb_size, int offs, int detailed) +{ + void *buf = sbuf + offs; + int err, len = leb_size - offs; + + printf("scan LEB %d:%d\n", lnum, offs); + + while (len >= 8) { + struct ubifs_ch *ch = buf; + int node_len, ret; + + printf("look at LEB %d:%d (%d bytes left)\n", + lnum, offs, len); + + ret = ubifs_scan_a_node(buf, leb_size, len, lnum, offs); + if (ret > 0) { + /* Padding bytes or a valid padding node */ + offs += ret; + buf += ret; + len -= ret; + continue; + } + + if (ret == SCANNED_EMPTY_SPACE) + /* Empty space is checked later */ + break; + + switch (ret) { + case SCANNED_GARBAGE: + printf("garbage\n"); + goto corrupted; + case SCANNED_A_NODE: + if (detailed) + ubifs_dump_node(buf); + break; + case SCANNED_A_CORRUPT_NODE: + case SCANNED_A_BAD_PAD_NODE: + printf("bad node\n"); + goto corrupted; + default: + printf("unknown\n"); + err = -EINVAL; + goto error; + } + + node_len = ALIGN(le32_to_cpu(ch->len), 8); + offs += node_len; + buf += node_len; + len -= node_len; + } + + for (; len > 4; offs += 4, buf = buf + 4, len -= 4) + if (*(uint32_t *)buf != 0xffffffff) + break; + for (; len; offs++, buf++, len--) + if (*(uint8_t *)buf != 0xff) { + printf("corrupt empty space at LEB %d:%d\n", + lnum, offs); + goto corrupted; + } + + printf("stop scanning LEB %d at offset %d\n", lnum, offs); + return; + +corrupted: + printf("corruption at LEB %d:%d\n", lnum, offs); + err = -EUCLEAN; +error: + printf("LEB %d scanning failed, error %d\n", lnum, err); +}