diff --git a/MAINTAINERS b/MAINTAINERS index 1c9939e331..cb4d44584d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1519,6 +1519,13 @@ M: Max Filippov S: Maintained F: arch/xtensa/ +XXD +M: Roger Knecht +S: Maintained +F: cmd/xxd.c +F: doc/usage/cmd/xxd.rst +F: test/py/tests/test_xxd/ + THE REST M: Tom Rini L: u-boot@lists.denx.de diff --git a/cmd/Kconfig b/cmd/Kconfig index 3267811b25..8eeb7ea081 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -469,6 +469,11 @@ config CMD_XIMG help Extract a part of a multi-image. +config CMD_XXD + bool "xxd" + help + Print file as hexdump to standard output + config CMD_SPL bool "spl export - Export boot information for Falcon boot" depends on SPL diff --git a/cmd/Makefile b/cmd/Makefile index 4bd52bb257..d9bbd0b9fd 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -185,6 +185,7 @@ obj-$(CONFIG_CMD_USB_SDP) += usb_gadget_sdp.o obj-$(CONFIG_CMD_THOR_DOWNLOAD) += thordown.o obj-$(CONFIG_CMD_VBE) += vbe.o obj-$(CONFIG_CMD_XIMG) += ximg.o +obj-$(CONFIG_CMD_XXD) += xxd.o obj-$(CONFIG_CMD_YAFFS2) += yaffs2.o obj-$(CONFIG_CMD_SPL) += spl.o obj-$(CONFIG_CMD_W1) += w1.o diff --git a/cmd/xxd.c b/cmd/xxd.c new file mode 100644 index 0000000000..742a85c7a9 --- /dev/null +++ b/cmd/xxd.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022 + * Roger Knecht + */ + +#include +#include +#include +#include +#include +#include + +static int do_xxd(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + char *ifname; + char *dev; + char *file; + char *buffer; + phys_addr_t addr; + loff_t file_size; + + if (argc < 4) + return CMD_RET_USAGE; + + ifname = argv[1]; + dev = argv[2]; + file = argv[3]; + + // check file exists + if (fs_set_blk_dev(ifname, dev, FS_TYPE_ANY)) + return CMD_RET_FAILURE; + + if (!fs_exists(file)) { + log_err("File does not exist: ifname=%s dev=%s file=%s\n", ifname, dev, file); + return CMD_RET_FAILURE; + } + + // get file size + if (fs_set_blk_dev(ifname, dev, FS_TYPE_ANY)) + return CMD_RET_FAILURE; + + if (fs_size(file, &file_size)) { + log_err("Cannot read file size: ifname=%s dev=%s file=%s\n", ifname, dev, file); + return CMD_RET_FAILURE; + } + + // allocate memory for file content + buffer = calloc(sizeof(char), file_size); + if (!buffer) { + log_err("Out of memory\n"); + return CMD_RET_FAILURE; + } + + // map pointer to system memory + addr = map_to_sysmem(buffer); + + // read file to memory + if (fs_set_blk_dev(ifname, dev, FS_TYPE_ANY)) + return CMD_RET_FAILURE; + + if (fs_read(file, addr, 0, 0, &file_size)) { + log_err("Cannot read file: ifname=%s dev=%s file=%s\n", ifname, dev, file); + return CMD_RET_FAILURE; + } + + // print file content + print_buffer(0, buffer, sizeof(char), file_size, 0); + + free(buffer); + + return 0; +} + +#ifdef CONFIG_SYS_LONGHELP +static char xxd_help_text[] = + " \n" + " - Print file from 'dev' on 'interface' as hexdump to standard output\n"; +#endif + +U_BOOT_CMD(xxd, 4, 1, do_xxd, + "Print file as hexdump to standard output", + xxd_help_text +); diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 0926e9213e..ade1505439 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -55,6 +55,7 @@ CONFIG_CMD_READ=y CONFIG_CMD_REMOTEPROC=y CONFIG_CMD_SPI=y CONFIG_CMD_USB=y +CONFIG_CMD_XXD=y CONFIG_BOOTP_DNS2=y CONFIG_CMD_TFTPPUT=y CONFIG_CMD_TFTPSRV=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index e1832295dc..195271463b 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -61,6 +61,7 @@ CONFIG_CMD_MEM_SEARCH=y CONFIG_CMD_MX_CYCLIC=y CONFIG_CMD_MEMTEST=y CONFIG_CMD_UNZIP=y +CONFIG_CMD_XXD=y CONFIG_CMD_BIND=y CONFIG_CMD_DEMO=y CONFIG_CMD_GPIO=y diff --git a/doc/usage/cmd/xxd.rst b/doc/usage/cmd/xxd.rst new file mode 100644 index 0000000000..0de1223dce --- /dev/null +++ b/doc/usage/cmd/xxd.rst @@ -0,0 +1,50 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +xxd command +=============== + +Synopsis +-------- + +:: + + xxd + +Description +----------- + +The xxd command prints the file content as hexdump to standard out. + +interface + interface for accessing the block device (mmc, sata, scsi, usb, ....) + +dev + device number + +part + partition number, defaults to 1 + +file + path to file + +Example +------- + +Here is the output for a example text file: + +:: + + => xxd mmc 0:1 hello + 00000000: 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a 00 01 02 03 hello world..... + 00000010: 04 05 .. + => + +Configuration +------------- + +The xxd command is only available if CONFIG_CMD_XXD=y. + +Return value +------------ + +The return value $? is set to 0 (true) if the file is readable, otherwise it returns a non-zero error code. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index a05aa42485..64a265879d 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -72,6 +72,7 @@ Shell commands cmd/true cmd/ums cmd/wdt + cmd/xxd Booting OS ---------- diff --git a/test/py/tests/test_xxd/conftest.py b/test/py/tests/test_xxd/conftest.py new file mode 100644 index 0000000000..59285aadf4 --- /dev/null +++ b/test/py/tests/test_xxd/conftest.py @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0+ + +"""Fixture for xxd command test +""" + +import os +import shutil +from subprocess import check_call, CalledProcessError +import pytest + +@pytest.fixture(scope='session') +def xxd_data(u_boot_config): + """Set up a file system to be used in xxd tests + + Args: + u_boot_config -- U-boot configuration. + """ + mnt_point = u_boot_config.persistent_data_dir + '/test_xxd' + image_path = u_boot_config.persistent_data_dir + '/xxd.img' + + try: + os.mkdir(mnt_point, mode = 0o755) + + with open(mnt_point + '/hello', 'w', encoding = 'ascii') as file: + file.write('hello world\n\x00\x01\x02\x03\x04\x05') + + check_call(f'virt-make-fs --partition=gpt --size=+1M --type=vfat {mnt_point} {image_path}', + shell=True) + + yield image_path + except CalledProcessError: + pytest.skip('Setup failed') + finally: + shutil.rmtree(mnt_point) + os.remove(image_path) diff --git a/test/py/tests/test_xxd/test_xxd.py b/test/py/tests/test_xxd/test_xxd.py new file mode 100644 index 0000000000..06b9cfc000 --- /dev/null +++ b/test/py/tests/test_xxd/test_xxd.py @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0+ + +""" Unit test for xxd command +""" + +import pytest + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_xxd') +def test_xxd(u_boot_console, xxd_data): + """ Unit test for xxd + + Args: + u_boot_console -- U-Boot console + xxd_data -- Path to the disk image used for testing. + """ + response = u_boot_console.run_command_list([ + f'host bind 0 {xxd_data}', + 'xxd host 0 hello']) + + assert '00000000: 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a 00 01 02 03 hello world.....\r\r\n' + \ + '00000010: 04 05 ..' \ + in response