[Toybox] lsusb: add -t option for tree format display

Rob Landley rob at landley.net
Mon Jul 21 18:13:34 PDT 2025


On 7/20/25 21:25, Rob Landley wrote:
> I can change it here, let me take a closer look this evening. (I'm in 
> tokyo at the moment juggling other commitments...)

"git am" warned of a bunch of trailing whitespace errors, so I did a
sed -i 's/ *$//' toys/*/lsusb.c

Why did you change id1 and id2 to unsigned in get_names()? (The protocol 
fields are 16 bit, int is 32 bit, how can it be negative? Do you have a 
test case this changed the behavior for?)

Since unsigned defaults to int (in C99, probably C89 too) you can just 
say "unsigned" without having to say "unsigned int". (Code style: 
shortest representation for consistency, you only have to specify 
non-default attributes.)

> toys/other/lsusb.c: In function 'create_device':
> toys/other/lsusb.c:207:44: warning: '%s' directive output may be truncated writing 6 bytes into a region of size between 0 and 255 [-Wformat-truncation=]
>   207 |   snprintf(fullpath, sizeof(fullpath), "%s/%s", path, file);
>       |                                            ^~
> In function 'read_sysfs_uint',
>     inlined from 'create_device' at toys/other/lsusb.c:284:17:
> toys/other/lsusb.c:207:3: note: 'snprintf' output between 8 and 263 bytes into a destination of size 256
>   207 |   snprintf(fullpath, sizeof(fullpath), "%s/%s", path, file);
>       |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I generally try to have it compile without warnings, even silly ones.

Hmmm, "diff -u <(lsusb -t) <(./lsusb -t)" doesn't share a single common 
line of output. I ran it through "sort" and did "diff -bu" and it's 
still not matching anything. So what's different...

/usr/bin/lsusb -t says:
-/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M

toybox lsusb -t says:
+/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=hub/0p, 480M

I dunno what the "driver" field should be, but it's not the same info.

> // Tree display functions
> static struct usb_bus *usb_buses = NULL;

Globals go in the GLOBALS() block, it's a memory efficiency thing. (See 
https://landley.net/toybox/code.html#toy_union .)

You don't need to initialize global or static variables, ELF insures 
they default to null/zero when sticking them in the .bss section.

Speaking of your struct types with the fixed size buffers, notice the 
difference between:

struct usb_bus {
   struct usb_bus *next;
   struct usb_device *first_child;
   unsigned busnum;
   char name[64];
};

struct dev_ids {
   struct dev_ids *next, *child;
   int id;
   char name[];
};

Two things:

1) Those are functionally the same struct, tree of int with string, you 
could presumably have reused dev_ids. (Ok, avoids a typecast for the 
child...)

2) Mine had a dynamically sized string field at the end so malloc() can 
measure the string it's about to copy and allocate enough space. Yours 
is doing a fixed length buffer which you trust /proc never to provide 
too much data to. (I don't trust /proc not to have random crap --bind 
mounted over it in container du jour, things like scan_uevent() trusting 
new->name to fit in 256 bytes with the null terminator is because that 
data came from readdir() which came getdents() which came from the VFS 
which limits each path component size to a max length of 255 bytes and 
says it can't contain / or NUL.)

Gotta come back to this later...

> Thanks,
> 
> Rob

Rob


More information about the Toybox mailing list