From: Ahmad Fatoum <a.fatoum@barebox.org>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@barebox.org>
Subject: [PATCH 43/44] commands: introduce bfetch command
Date: Mon, 11 Aug 2025 14:28:23 +0200 [thread overview]
Message-ID: <20250811122824.1667791-44-a.fatoum@barebox.org> (raw)
In-Reply-To: <20250811122824.1667791-1-a.fatoum@barebox.org>
Inspired by U-Boot's addition of the ufetch command and the neofetch
utility for Linux[1], add a similar command to barebox.
The command is meant to simplify showing off a barebox port with some
colored ASCII art. The usual alternative is a screenshot of a barebox
boot up and prompt, which for a fresh port usually will contain some
>= warning messages, which is not as pleasant to look at compared to:
:##: :##: none@virt64
-%%: =#####. :%%- -----------
#@@@@@. Kernel: barebox 2025.07.0-<snip>
*@@@@@. Model: ARM QEMU virt64 (linux,dummy-virt)
*@@@@@. Config: arm64 multi_v8_defconfig
*@@@@@. :=##=. CPU: Cortex-A57 r1p0 at EL1
*@@@@@. :+%@@@@@@#+: Memory: 1 GiB
*@@@@@:-*@@@@@@@@@@@@@%*-. Uptime: 1 second
*@@@@@@@@@@@@@@%%@@@@@@@@@#=. Shell: Hush with 155 commands and 8 aliases
*@@@@@@@@@@@%**+=+*%@@@@@@@@@%+. Consoles: input0 cs0 netconsole-1
*@@@@@@@%#*++++++===+*#%@@@@@@@+ Features: FW_CFG HWRNG PCI VIRTIO
*@@@@@#*+++++++++++++===+#@@@@@+ barebox: /dev 9P BTHREAD DEEP RATP W^X
*@@@@@*+++++++++++++++++=*@@@@@+ Network: 1 interface, 1 up
*@@@@@*+++++++++++++++++=*@@@@@+ eth0: 0.0.0.0/0
*@@@@@*+++++++++++++++++=*@@@@@+ Hardening: init-stack
*@@@@@*+++++++++++++++++=*@@@@@+ Devices: 85 with 17 bound
*@@@@@*++++++++++++++++==*@@@@@+ Drivers: 220 drivers across 16 busses
*@@@@@%#*+++++++++++===+*%@@@@@+ Storage: 1x MTD (128 MiB)
*@@@@@@@@%#*++++===+*#%@@@@@@@@+ Environment: 28 bytes
-*%@@@@@@@@@%*++*%@@@@@@@@@%+: Firmware:
:+#@@@@@@@@@@@@@@@@@@#=: PSCI: v1.1 over hvc
.=*@@@@@@@@@@@%*-.
-+%@@@@%+:
-@@- :==. :@@-
:**. .**:
[1]: https://en.wikipedia.org/wiki/Neofetch
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
commands/Kconfig | 11 +
commands/Makefile | 1 +
commands/bfetch.c | 752 +++++++++++++++++++++++++++++++++
include/linux/string_choices.h | 18 +
include/stringlist.h | 6 +
5 files changed, 788 insertions(+)
create mode 100644 commands/bfetch.c
create mode 100644 include/linux/string_choices.h
diff --git a/commands/Kconfig b/commands/Kconfig
index 16b995cb3b7c..02b45d8cbe09 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -308,6 +308,17 @@ config CMD_VERSION
barebox 2014.05.0-00142-gb289373 #177 Mon May 12 20:35:55 CEST 2014
+config CMD_BFETCH
+ tristate
+ depends on BANNER
+ select STRUCTIO
+ imply CMD_UPTIME
+ imply CMD_ARM_CPUINFO if ARM
+ imply CMD_DEVINFO
+ prompt "bfetch"
+ help
+ Print system information from barebox point of view. Fancily.
+
config CMD_MMC
tristate
prompt "mmc command allowing to set enhanced area"
diff --git a/commands/Makefile b/commands/Makefile
index 9247287ed53a..fadf9e7cc7e0 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_CMD_TRUE) += true.o
obj-$(CONFIG_CMD_FALSE) += false.o
obj-$(CONFIG_CMD_VARINFO) += varinfo.o
obj-$(CONFIG_CMD_VERSION) += version.o
+obj-$(CONFIG_CMD_BFETCH) += bfetch.o
obj-$(CONFIG_CMD_HELP) += help.o
obj-$(CONFIG_CMD_LSMOD) += lsmod.o
obj-$(CONFIG_CMD_INSMOD) += insmod.o
diff --git a/commands/bfetch.c b/commands/bfetch.c
new file mode 100644
index 000000000000..8f78a6fa8652
--- /dev/null
+++ b/commands/bfetch.c
@@ -0,0 +1,752 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <barebox-info.h>
+#include <bbu.h>
+#include <blobgen.h>
+#include <block.h>
+#include <command.h>
+#include <complete.h>
+#include <dsa.h>
+#include <envfs.h>
+#include <environment.h>
+#include <fb.h>
+#include <featctrl.h>
+#include <firmware.h>
+#include <getopt.h>
+#include <globalvar.h>
+#include <machine_id.h>
+#include <memory.h>
+#include <net.h>
+#include <pm_domain.h>
+#include <sound.h>
+#include <stdio.h>
+#include <structio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <watchdog.h>
+
+#include <efi/efi-mode.h>
+#include <efi/efi-device.h>
+
+#include <generated/utsrelease.h>
+#include <linux/clk.h>
+#include <linux/device/bus.h>
+#include <linux/hw_random.h>
+#include <linux/kasan.h>
+#include <linux/kernel.h>
+#include <linux/mtd/mtd.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/pci.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pstore.h>
+#include <linux/reboot-mode.h>
+#include <linux/rtc.h>
+#include <linux/scmi_protocol.h>
+#include <linux/string_choices.h>
+#include <linux/tee_drv.h>
+#include <linux/usb/usb.h>
+
+#define BFETCH_TMP_ENV "/tmp/.bfetch.env.tmp"
+
+#define LINE_WIDTH 40
+#define WHITE "\033[1;37m"
+#define YELLOW "\033[33m"
+#define BOLD "\033[1m"
+#define RED "\033[31m"
+#define LIGHT_RED "\033[1;91m"
+#define DARK_RED "\033[0;31m"
+#define PURPLE "\033[35m"
+#define RESET "\033[0m"
+#define BOLD_RESET RESET BOLD
+
+#define LOGO_WIDTH 44
+#define LOGO_HEIGHT 25
+
+static const char logo_lines[LOGO_HEIGHT][LOGO_WIDTH] = {
+ ":##: :##:",
+ "-%%: =#####. :%%-",
+ " #@@@@@. ",
+ " *@@@@@. ",
+ " *@@@@@. ",
+ " *@@@@@. :=##=. ",
+ " *@@@@@. :+%@@@@@@#+: ",
+ " *@@@@@:-*@@@@@@@@@@@@@%*-. ",
+ " *@@@@@@@@@@@@@@%%@@@@@@@@@#=. ",
+ " *@@@@@@@@@@@%**+=+*%@@@@@@@@@%+. ",
+ " *@@@@@@@%#*++++++===+*#%@@@@@@@+ ",
+ " *@@@@@#*+++++++++++++===+#@@@@@+ ",
+ " *@@@@@*+++++++++++++++++=*@@@@@+ ",
+ " *@@@@@*+++++++++++++++++=*@@@@@+ ",
+ " *@@@@@*+++++++++++++++++=*@@@@@+ ",
+ " *@@@@@*+++++++++++++++++=*@@@@@+ ",
+ " *@@@@@*++++++++++++++++==*@@@@@+ ",
+ " *@@@@@%#*+++++++++++===+*%@@@@@+ ",
+ " *@@@@@@@@%#*++++===+*#%@@@@@@@@+ ",
+ " -*%@@@@@@@@@%*++*%@@@@@@@@@%+: ",
+ " :+#@@@@@@@@@@@@@@@@@@#=: ",
+ " .=*@@@@@@@@@@@%*-. ",
+ " -+%@@@@%+: ",
+ "-@@- :==. :@@-",
+ ":**. .**:",
+};
+
+static const char style_lines[LOGO_HEIGHT][LOGO_WIDTH] = {
+ "*@@* *@@*",
+ "*@@* ******* *@@*",
+ " *@@@@@* ",
+ " *@@@@@* ",
+ " *@@@@@* ",
+ " *@@@@@* ****** ",
+ " *@@@@@* ***@@@@@@*** ",
+ " *@@@@@***@@@@@@@@@@@@@**** ",
+ " *@@@@@@@@@@@@@@rR@@@@@@@@@*** ",
+ " *@@@@@@@@@@@rrrrRRRR@@@@@@@@@*** ",
+ " *@@@@@@@rrrrrrrrRRRRRRRR@@@@@@@* ",
+ " *@@@@@rrrrrrrrrrRRRRRRRRRR@@@@@* ",
+ " *@@@@@rrrrrrrrrrRRRRRRRRRR@@@@@* ",
+ " *@@@@@rrrrrrrrrrRRRRRRRRRR@@@@@* ",
+ " *@@@@@rrrrrrrrrrRRRRRRRRRR@@@@@* ",
+ " *@@@@@rrrrrrrrrrRRRRRRRRRR@@@@@* ",
+ " *@@@@@rrrrrrrrrrRRRRRRRRRR@@@@@* ",
+ " *@@@@@rrrrrrrrrrRRRRRRRRRR@@@@@* ",
+ " *@@@@@@@@rrrrrrrRRRRRRR@@@@@@@@* ",
+ " ***@@@@@@@@@rrrRRR@@@@@@@@@*** ",
+ " ***@@@@@@@@@@@@@@@@@@*** ",
+ " ***@@@@@@@@@@@**** ",
+ " ***@@@@*** ",
+ "*@@* **** *@@*",
+ "*@@* *@@*",
+};
+
+static_assert(sizeof(logo_lines) == sizeof(style_lines));
+
+static bool skip_logo;
+
+static bool logo(unsigned *lineidx)
+{
+ const char *c, *s;
+ char last_style = '\0';
+
+ if (skip_logo)
+ return false;
+
+ if (*lineidx >= LOGO_HEIGHT) {
+ printf("%*s" " ", LOGO_WIDTH, "");
+ return false;
+ }
+
+ c = logo_lines[*lineidx];
+ s = style_lines[*lineidx];
+
+ while (*c) {
+ if (last_style != *s) {
+ switch (*s) {
+ case '*': puts(RESET); break;
+ case '@': puts(RESET BOLD); break;
+ case 'r': puts(LIGHT_RED); break;
+ case 'R': puts(DARK_RED); break;
+ case ' ': break;
+ default: BUG();
+ }
+
+ last_style = *s;
+ }
+
+ putchar(*c);
+
+ c++;
+ s++;
+ }
+
+ printf(RESET " ");
+ ++*lineidx;
+ return true;
+}
+
+#define print_line(key, fmt, ...) do { \
+ logo(line); printf(DARK_RED "%s" RESET ": " fmt "\n", key, ##__VA_ARGS__); \
+} while (0)
+
+static inline bool __print_string_list(unsigned *line, const char *key,
+ struct string_list *sl,
+ const char *joinstr)
+{
+ if (string_list_empty(sl))
+ return false;
+ print_line(key, "%s", string_list_join(sl, joinstr));
+ return true;
+}
+#define print_string_list(k, sl, js) __print_string_list(line, k, sl, js)
+
+static inline bool bus_has_devices(const char *name)
+{
+ struct bus_type *bus;
+ struct device *dev;
+
+ bus = get_bus_by_name("virtio");
+ if (!bus)
+ return false;
+
+ bus_for_each_device(bus, dev)
+ return true;
+
+ return false;
+}
+
+static void print_header(unsigned *line)
+{
+ int size = 0;
+
+ if (!IS_ENABLED(CONFIG_GLOBALVAR))
+ return;
+
+ logo(line);
+ printf(DARK_RED "%s" RESET "@" DARK_RED "%s" RESET "\n",
+ globalvar_get("user"), globalvar_get("hostname"));
+ size += strlen(globalvar_get("user") ?: "");
+ size++;
+ size += strlen(globalvar_get("hostname") ?: "");
+ logo(line);
+
+ for (int i = 0; i < size; i++)
+ putchar('-');
+ putchar('\n');
+}
+
+static void print_barebox_info(unsigned *line)
+{
+ const char *compat = NULL, *model;
+
+ print_line("Kernel", "barebox " UTS_RELEASE);
+
+ model = globalvar_get("model");
+ of_property_read_string(of_get_root_node(), "compatible", &compat);
+ if (compat)
+ print_line("Model", "%s (%s)", model, compat);
+ else if (model)
+ print_line("Model", "%s", model);
+
+ if (*CONFIG_NAME)
+ print_line("Config", "%s %s", CONFIG_ARCH_LINUX_NAME, CONFIG_NAME);
+ else
+ print_line("Architecture", "%s", CONFIG_ARCH_LINUX_NAME);
+}
+
+static void print_cpu_mem_info(unsigned *line)
+{
+ struct bobject *bret;
+ struct memory_bank *mem;
+ unsigned long memsize = 0;
+ int nbanks = 0;
+ int ret;
+
+ /* TODO: show info for other arches, e.g. RISC-V S-Mode/M-Mode */
+ if (IS_ENABLED(CONFIG_ARM)) {
+ ret = structio_run_command(&bret, "cpuinfo");
+ if (!ret) {
+ if (IS_ENABLED(CONFIG_ARM64))
+ print_line("CPU", "%s at EL%s",
+ bobject_get_param(bret, "core"),
+ bobject_get_param(bret, "exception_level"));
+ else if (IS_ENABLED(CONFIG_ARM32))
+ print_line("CPU", "%s", bobject_get_param(bret, "core"));
+
+ bobject_free(bret);
+ }
+ } else if (IS_ENABLED(CONFIG_GLOBALVAR)) {
+ print_line("CPU", "%s-endian", globalvar_get("endianness"));
+ }
+
+ for_each_memory_bank(mem) {
+ memsize += mem->size;
+ nbanks++;
+ }
+
+ if (nbanks > 1)
+ print_line("Memory", "%s across %u banks",
+ size_human_readable(memsize), nbanks);
+ else if (nbanks == 1)
+ print_line("Memory", "%s",
+ size_human_readable(memsize));
+}
+
+static void print_shell_console(unsigned *line)
+{
+ const char *shell;
+ struct command *cmd;
+ struct string_list sl;
+ struct console_device *console;
+
+ if (IS_ENABLED(CONFIG_SHELL_HUSH))
+ shell = "Hush";
+ else if (IS_ENABLED(CONFIG_SHELL_SIMPLE))
+ shell = "Simple";
+ else
+ shell = "None";
+
+ if (IS_ENABLED(CONFIG_COMMAND_SUPPORT)) {
+ int ncmds = 0, naliases = 0;
+
+ for_each_command(cmd) {
+ ncmds++;
+ naliases += strv_length(cmd->aliases);
+ }
+
+ print_line("Shell", "%s with %u commands and %u aliases",
+ shell, ncmds, naliases);
+ } else {
+ print_line("Shell", "%s", shell);
+ }
+
+ string_list_init(&sl);
+
+ for_each_console(console)
+ string_list_add(&sl, console->devfs.name);
+ if (!string_list_empty(&sl))
+ print_line("Consoles", "%s", string_list_join(&sl, " "));
+
+ string_list_free(&sl);
+}
+
+static void print_framebuffers(unsigned *line)
+{
+ struct string_list sl;
+ struct fb_info *info;
+
+ if (!IS_ENABLED(CONFIG_VIDEO))
+ return;
+
+ string_list_init(&sl);
+
+ class_for_each_container_of_device(&fb_class, info, dev) {
+ string_list_add_asprintf(&sl, "%s: %ux%ux%u",
+ dev_name(&info->dev),
+ info->xres, info->yres,
+ info->bits_per_pixel);
+ }
+
+ if (!string_list_empty(&sl))
+ print_line("Framebuffers", "%s", string_list_join(&sl, ", "));
+
+ string_list_free(&sl);
+}
+
+static void print_features(unsigned *line)
+{
+ struct stat st;
+ struct string_list sl;
+ bool features = false;
+ size_t tmp;
+
+ string_list_init(&sl);
+
+ if (blobgen_get(NULL))
+ string_list_add(&sl, "BLOBGEN");
+ if (clk_have_nonfixed_providers())
+ string_list_add(&sl, "CLK");
+ if (IS_ENABLED(CONFIG_DSA) && !list_empty(&dsa_switch_list))
+ string_list_add(&sl, "DSA");
+ if (IS_ENABLED(CONFIG_FEATURE_CONTROLLER) &&
+ !list_empty(&of_feature_controllers))
+ string_list_add(&sl, "FEATCTL");
+ if (!stat("/dev/fw_cfg", &st))
+ string_list_add(&sl, "FW_CFG");
+ if (firmwaremgr_find_by_node(NULL))
+ string_list_add(&sl, "FWMGR");
+ if (genpd_is_active())
+ string_list_add(&sl, "GENPD");
+ if (hwrng_get_first())
+ string_list_add(&sl, "HWRNG");
+ if (machine_id_get_hashable(&tmp))
+ string_list_add(&sl, "MACHINE-ID");
+ if (IS_ENABLED(CONFIG_MCI_TUNING)) {
+ string_list_add(&sl, "MCI-TUNING");
+ // TODO: check that loaded driver supports it
+ }
+ if (IS_ENABLED(CONFIG_PCI) && !list_empty(&pci_root_buses))
+ string_list_add(&sl, "PCI");
+ if (IS_ENABLED(CONFIG_PINCTRL) && !list_empty(&pinctrl_list))
+ string_list_add(&sl, "PINCTRL");
+ if (pstore_is_ready())
+ string_list_add(&sl, "PSTORE");
+ if (reboot_mode_get())
+ string_list_add(&sl, "REBOOT-MODE");
+ if (IS_ENABLED(CONFIG_RTC) && !list_empty(&rtc_class.list))
+ string_list_add(&sl, "RTC");
+ if (IS_ENABLED(CONFIG_SOUND) && sound_card_get_default())
+ string_list_add(&sl, "SOUND");
+ if (IS_ENABLED(CONFIG_SDL))
+ string_list_add(&sl, "USB");
+ if (bus_has_devices("virtio"))
+ string_list_add(&sl, "VIRTIO");
+ if (watchdog_get_default())
+ string_list_add(&sl, "WDOG");
+
+ if (print_string_list("Features", &sl, " "))
+ features = true;
+
+ string_list_reinit(&sl);
+
+ if (IS_ENABLED(CONFIG_FS_DEVFS))
+ string_list_add(&sl, "/dev");
+ if (IS_ENABLED(CONFIG_9P_FS))
+ string_list_add(&sl, "9P");
+ if (efi_is_loader())
+ string_list_add(&sl, "EFI");
+ if (bbu_handlers_available())
+ string_list_add(&sl, "BBU");
+ if (IS_ENABLED(CONFIG_BTHREAD))
+ string_list_add(&sl, "BTHREAD");
+ if (deep_probe_is_supported())
+ string_list_add(&sl, "DEEP");
+ if (IS_ENABLED(CONFIG_GCOV))
+ string_list_add(&sl, "GCOV");
+ if (IS_ENABLED(CONFIG_RISCV_ICACHE))
+ string_list_add(&sl, "I$");
+ if (IS_ENABLED(CONFIG_JWT))
+ string_list_add(&sl, "JWT");
+ if (IS_ENABLED(CONFIG_RATP))
+ string_list_add(&sl, "RATP");
+ if (IS_ENABLED(CONFIG_CRYPTO_RSA))
+ string_list_add(&sl, "RSA");
+ if (IS_ENABLED(CONFIG_CRYPTO_ECDSA))
+ string_list_add(&sl, "ECDSA");
+ if (IS_ENABLED(CONFIG_SDL))
+ string_list_add(&sl, "SDL");
+ if (IS_ENABLED(CONFIG_ARM_MMU_PERMISSIONS))
+ string_list_add(&sl, "W^X");
+
+ if (IS_ENABLED(CONFIG_FS_UBOOTVARFS) && !stat("/dev/ubootvar", &st))
+ string_list_add(&sl, "UBOOTVARFS");
+
+ /* TODO: detect semihosting */
+
+ print_string_list(features ? " barebox" : "Features", &sl, " ");
+
+ string_list_free(&sl);
+}
+
+static void print_netdevs(unsigned *line)
+{
+ struct eth_device *edev;
+ int nif = 0, nifup = 0;
+
+ if (!IS_ENABLED(CONFIG_NET))
+ return;
+
+ for_each_netdev(edev) {
+ nif++;
+ if (edev->active)
+ nifup++;
+ }
+
+ print_line("Network", "%u interface%s, %u up",
+ nif, str_plural(nif), nifup);
+ if (nifup) {
+ for_each_netdev(edev) {
+ IPaddr_t ipaddr;
+
+ if (!edev->active)
+ continue;
+
+ ipaddr = net_get_ip(edev);
+
+ logo(line);
+ printf(DARK_RED " %s" RESET ": %pI4/%u\n",
+ eth_name(edev), &ipaddr,
+ netmask_to_prefix(edev->netmask));
+ }
+ }
+}
+
+static void print_hardening(unsigned *line)
+{
+ struct string_list sl;
+
+ string_list_init(&sl);
+
+ if (kasan_enabled())
+ string_list_add(&sl, IS_ENABLED(CONFIG_KASAN) ? "KASAN" : "ASAN");
+ if (IS_ENABLED(CONFIG_UBSAN))
+ string_list_add(&sl, "UBSAN");
+ if (IS_ENABLED(CONFIG_DMA_API_DEBUG))
+ string_list_add(&sl, "DMA-API");
+
+ print_string_list("Debugging", &sl, " ");
+
+ string_list_reinit(&sl);
+
+ if (!IS_ENABLED(CONFIG_INIT_STACK_NONE) &&
+ IS_ENABLED(CONFIG_INIT_ON_ALLOC_DEFAULT_ON) &&
+ IS_ENABLED(CONFIG_INIT_ON_FREE_DEFAULT_ON) &&
+ IS_ENABLED(CONFIG_ZERO_CALL_USED_REGS)) {
+ string_list_add(&sl, "init-all");
+ } else {
+ if (!IS_ENABLED(CONFIG_INIT_STACK_NONE))
+ string_list_add(&sl, "init-stack");
+ if (IS_ENABLED(CONFIG_INIT_ON_ALLOC_DEFAULT_ON))
+ string_list_add(&sl, "init-alloc");
+ if (IS_ENABLED(CONFIG_INIT_ON_FREE_DEFAULT_ON))
+ string_list_add(&sl, "init-free");
+ if (IS_ENABLED(CONFIG_ZERO_CALL_USED_REGS))
+ string_list_add(&sl, "init-regs");
+ }
+ if (IS_ENABLED(CONFIG_FORTIFY_SOURCE))
+ string_list_add(&sl, "fortify");
+ if (IS_ENABLED(CONFIG_STACK_GUARD_PAGE))
+ string_list_add(&sl, "stack-guard");
+ if (!IS_ENABLED(CONFIG_STACKPROTECTOR_NONE))
+ string_list_add(&sl, "stack-prot");
+ if (!IS_ENABLED(CONFIG_PBL_STACKPROTECTOR_NONE))
+ string_list_add(&sl, "stack-prot-pbl");
+
+ print_string_list("Hardening", &sl, " ");
+
+ string_list_free(&sl);
+}
+
+static void print_devices_drivers(unsigned *line)
+{
+ struct bus_type *bus;
+ struct device *dev;
+ int nbusses = 0, ndevs = 0, ndrvs = 0, nbound = 0;
+
+ for_each_device(dev) {
+ ndevs++;
+ if (dev->driver)
+ nbound++;
+ }
+
+ print_line("Devices", "%u with %u bound", ndevs, nbound);
+
+ for_each_bus(bus) {
+ struct driver *drv;
+ bool has_drivers = false;
+
+ bus_for_each_driver(bus, drv) {
+ has_drivers = true;
+ ndrvs++;
+ }
+
+ nbusses++;
+ }
+
+ print_line("Drivers", "%u drivers across %u busses", ndrvs, nbusses);
+}
+
+static void print_storage(unsigned *line)
+{
+ const char *other_key;
+ unsigned nmtds = 0, nnvmem =0;
+ struct block_device *blk;
+ unsigned nblkdevs[BLK_TYPE_COUNT] = {};
+ unsigned blkdev_sizes[BLK_TYPE_COUNT] = {};
+ struct mtd_info *mtd;
+ size_t mtd_size = 0, nvmem_size = 0;
+ struct string_list sl;
+ struct device *dev;
+
+ if (IS_ENABLED(CONFIG_BLOCK)) {
+ for_each_block_device(blk) {
+ if (blk->type >= BLK_TYPE_COUNT)
+ continue;
+
+ nblkdevs[blk->type]++;
+ blkdev_sizes[blk->type] += blk->num_blocks * BLOCKSIZE(blk);
+ }
+ }
+
+ string_list_init(&sl);
+
+ for (int i = 0; i < BLK_TYPE_COUNT; i++) {
+ if (!nblkdevs[i])
+ continue;
+
+ string_list_add_asprintf(&sl, "%ux %s (%s)", nblkdevs[i],
+ blk_type_str(i),
+ size_human_readable(blkdev_sizes[i]));
+ }
+
+ if (print_string_list("Block devices", &sl, ", "))
+ other_key = "Other storage";
+ else
+ other_key = "Storage";
+
+ string_list_reinit(&sl);
+
+ if (IS_ENABLED(CONFIG_MTD)) {
+ class_for_each_container_of_device(&mtd_class, mtd, dev) {
+ if (mtd->parent)
+ continue;
+
+ nmtds++;
+ mtd_size += mtd->size;
+ }
+
+ if (nmtds)
+ string_list_add_asprintf(&sl, "%ux MTD (%s)", nmtds,
+ size_human_readable(mtd_size));
+ }
+
+ if (IS_ENABLED(CONFIG_NVMEM)) {
+ class_for_each_device(&nvmem_class, dev) {
+ nnvmem++;
+ nvmem_size += nvmem_device_size(nvmem_from_device(dev));
+ }
+
+ if (nnvmem)
+ string_list_add_asprintf(&sl, "%ux NVMEM (%s)", nnvmem,
+ size_human_readable(nvmem_size));
+ }
+
+ print_string_list(other_key, &sl, ", ");
+
+ string_list_free(&sl);
+}
+
+static void print_env(unsigned *line)
+{
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_ENV_HANDLING))
+ return;
+
+ ret = envfs_save(BFETCH_TMP_ENV, NULL, 0);
+ if (!ret) {
+ struct stat st;
+
+ if (!stat(BFETCH_TMP_ENV, &st))
+ print_line("Environment", "%llu bytes", st.st_size);
+
+ unlink(BFETCH_TMP_ENV);
+ }
+}
+
+static int tee_devinfo(struct bobject **bret)
+{
+ struct device *dev;
+
+ if (!IS_ENABLED(CONFIG_TEE))
+ return -ENOSYS;
+
+ bus_for_each_device(&tee_bus_type, dev)
+ return structio_devinfo(bret, dev);
+
+ return -ENODEV;
+}
+
+static void print_firmware(unsigned *line)
+{
+ const char *psci_version;
+ struct bobject *bret;
+ bool have_scmi = false, have_tee = false;
+
+ psci_version = getenv("psci.version");
+
+ if (IS_ENABLED(CONFIG_ARM_SCMI_PROTOCOL) && !list_empty(&scmi_list))
+ have_scmi = true;
+ if (tee_devinfo(&bret) == 0)
+ have_tee = true;
+
+ if (!psci_version && !have_scmi && !have_tee && !efi_is_payload())
+ return;
+
+ print_line("Firmware", "");
+
+ if (psci_version)
+ print_line(" PSCI", "v%s over %s",
+ psci_version, getenv("psci.method"));
+
+ if (have_scmi)
+ print_line(" SCMI", "yes\n");
+
+ /* TODO: RISC-V SBI version */
+
+ if (have_tee) {
+ const char *name = bobject_get_param(bret, "impl.name");
+ if (name)
+ print_line(" TEE", "%s rev. %s",
+ name, bobject_get_param(bret, "impl.rev"));
+ else
+ print_line(" TEE", "impementation ID %s",
+ bobject_get_param(bret, "impl.id"));
+ bobject_free(bret);
+ }
+
+ if (efi_is_payload()) {
+ print_line(" UEFI", "v%s.%s by %s v%s\n",
+ dev_get_param(&efi_bus.dev, "major"),
+ dev_get_param(&efi_bus.dev, "minor"),
+ dev_get_param(&efi_bus.dev, "fw_vendor"),
+ dev_get_param(&efi_bus.dev, "fw_revision"));
+ }
+}
+
+static int do_bfetch(int argc, char *argv[])
+{
+ struct bobject *bret;
+ unsigned _line, *line = &_line;
+ int opt;
+ int ret;
+
+ skip_logo = false;
+ while((opt = getopt(argc, argv, "n")) > 0) {
+ switch(opt) {
+ case 'n':
+ skip_logo = true;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ print_header(line);
+
+ print_barebox_info(line);
+ print_cpu_mem_info(line);
+
+ ret = structio_run_command(&bret, "uptime");
+ if (!ret) {
+ print_line("Uptime", "%s", bobject_get_param(bret, "uptime"));
+ bobject_free(bret);
+ }
+
+ print_shell_console(line);
+ print_framebuffers(line);
+ print_features(line);
+ print_netdevs(line);
+
+ /* print_line("Compiled by", "TODO"); */
+
+ if (*buildsystem_version_string)
+ print_line("Buildsystem Version", "%s", buildsystem_version_string);
+
+ print_hardening(line);
+ print_devices_drivers(line);
+ print_storage(line);
+ print_env(line);
+ print_firmware(line);
+
+ while (logo(line))
+ putchar('\n');
+
+ if (!skip_logo)
+ printf(RESET "\n\n");
+
+ return 0;
+}
+
+BAREBOX_CMD_HELP_START(bfetch)
+BAREBOX_CMD_HELP_TEXT("Print system information from barebox point of view")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-n", "Don't print the ASCII logo")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(bfetch)
+ .cmd = do_bfetch,
+ BAREBOX_CMD_DESC("Print device info")
+ BAREBOX_CMD_OPTS("[-n]")
+ BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+ BAREBOX_CMD_COMPLETE(empty_complete)
+BAREBOX_CMD_END
diff --git a/include/linux/string_choices.h b/include/linux/string_choices.h
new file mode 100644
index 000000000000..265573343f54
--- /dev/null
+++ b/include/linux/string_choices.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_STRING_CHOICES_H_
+#define _LINUX_STRING_CHOICES_H_
+
+#include <linux/types.h>
+
+/**
+ * str_plural - Return the simple pluralization based on English counts
+ * @num: Number used for deciding pluralization
+ *
+ * If @num is 1, returns empty string, otherwise returns "s".
+ */
+static inline const char *str_plural(size_t num)
+{
+ return num == 1 ? "" : "s";
+}
+
+#endif
diff --git a/include/stringlist.h b/include/stringlist.h
index 9a982f2ad685..707a776d919c 100644
--- a/include/stringlist.h
+++ b/include/stringlist.h
@@ -46,6 +46,12 @@ static inline void string_list_free(struct string_list *sl)
}
}
+static inline void string_list_reinit(struct string_list *sl)
+{
+ string_list_free(sl);
+ string_list_init(sl);
+}
+
#define string_list_for_each_entry(entry, sl) \
list_for_each_entry(entry, &(sl)->list, list)
--
2.39.5
next prev parent reply other threads:[~2025-08-11 12:31 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-11 12:27 [PATCH 00/44] commands: add bfetch/buds of command redirection Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 01/44] driver: move device name definition into device.h Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 02/44] driver: introduce common struct bobject Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 03/44] lib: param: rename dev_remove_param to param_remove Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 04/44] param: implement dev_remove_parameters using param_remove Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 05/44] lib: param: add dev_for_each_param helpers Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 06/44] driver: initialize device parameters as part of bobject Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 07/44] param: operate on bobjects instead of full devices Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 08/44] commands: version: print value of CONFIG_NAME Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 09/44] treewide: populate CONFIG_NAME for all configs in-tree Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 10/44] test: py: change barebox_config from set to dict Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 11/44] test: add heuristic for guessing labgrid environment YAML Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 12/44] usb: drop dead iSerialNumber parameter addition Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 13/44] drivers: use dev_add_param_uint32_fixed for IDs Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 14/44] param: make bobject_add_param_fixed variadic Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 15/44] param: handle NULL gracefully in bobject_get_param Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 16/44] common: introduce structured I/O Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 17/44] ARM: cpuinfo: support structio output Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 18/44] commands: uptime: enable structured I/O Ahmad Fatoum
2025-08-11 12:27 ` [PATCH 19/44] string: implement strv_length helper Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 20/44] ARM: psci: client: add PSCI version/method parameters Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 21/44] net: move netmask_to_prefix into header Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 22/44] stringlist: implement string_list_empty Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 23/44] optee: add revision info to tee devinfo output Ahmad Fatoum
2025-08-12 9:35 ` Sascha Hauer
2025-08-12 9:44 ` Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 24/44] tee: enable structured I/O in devinfo handler Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 25/44] mtd: add devices to new mtd class Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 26/44] nvmem: add devices to new nvmem class Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 27/44] nvmem: export functions to query NVMEM size Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 28/44] video: add devices to new fb class Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 29/44] security: blobgen: add easy way to check for existent providers Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 30/44] pmdomain: add easy way to check for provider support Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 31/44] bbu: add easy way to check for existent providers Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 32/44] firmware: " Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 33/44] rtc: export rtc_class in header Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 34/44] driver: featctrl: export of_feature_controllers Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 35/44] net: dsa: export dsa_switch_list Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 36/44] usb: export usb_host_list Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 37/44] pstore: export pstore_is_ready Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 38/44] pinctrl: export pinctrl_list Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 39/44] clk: implement clk_have_nonfixed_providers Ahmad Fatoum
2025-08-13 5:38 ` Sascha Hauer
2025-08-11 12:28 ` [PATCH 40/44] driver: bus: export get_bus_by_name Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 41/44] fimware: arm_scmi: export scmi_list Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 42/44] block: define BLK_TYPE_COUNT as last enum blk_type value Ahmad Fatoum
2025-08-11 12:28 ` Ahmad Fatoum [this message]
2025-08-12 10:39 ` [PATCH 43/44] commands: introduce bfetch command Sascha Hauer
2025-08-12 11:09 ` Ahmad Fatoum
2025-08-11 12:28 ` [PATCH 44/44] configs: enable bfetch in some popular defconfigs Ahmad Fatoum
2025-08-12 10:29 ` [PATCH 00/44] commands: add bfetch/buds of command redirection Sascha Hauer
2025-08-12 11:23 ` Ahmad Fatoum
2025-08-13 5:48 ` (subset) " Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250811122824.1667791-44-a.fatoum@barebox.org \
--to=a.fatoum@barebox.org \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox