Skip to content

Add JSON support for uhubctl - addresses all PR #575 feedback #575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

benroeder
Copy link

@benroeder benroeder commented Aug 2, 2024

Summary

This PR addresses all feedback from mvp on PR #575 and implements comprehensive JSON support for uhubctl.

Major Changes

Library Replacement

  • Replace cJSON with mkjson - Achieved 10x size reduction (~400 lines vs ~3,400 lines)
  • Remove git submodule dependency - mkjson files now embedded directly in repository
  • Add mkjson_array() wrapper - Eliminates manual parameter counting with null-terminated arrays

JSON Output Features

  • JSON support for all power actions - Works with on/off/toggle/cycle/flash operations
  • Real-time JSON event streaming - Live events during power operations with success/failure status
  • Pretty-printing always enabled - 2-space indentation for human readability
  • Comprehensive status decoding - Raw hex, decoded state, and individual bit breakdown
  • Human-readable descriptions - Clear explanations for all status flags

Technical Improvements

  • Rename is_usb3_hub → super_speed - Clearer parameter naming
  • Rename speed_bits → speed_bps - Consistent naming convention
  • Add memory management documentation - Clear documentation for all JSON functions
  • Convert all // comments to / / C-style - Consistent code formatting
  • Remove trailing whitespace - Clean code formatting
  • Move help option to end - Proper command line parser organization
  • Output optimization - Only output true boolean flags to minimize JSON size
  • Remove verbose fields - Removed nconfigs and interfaces from default output

JSON Output Structure

Status Queries

{
  "hubs": [
    {
      "location": "3-1.4",
      "description": "05e3:0610 GenesysLogic USB2.1 Hub, USB 2.10, 4 ports, ppps",
      "hub_info": {
        "vid": "0x05e3",
        "pid": "0x0610",
        "usb_version": "2.10",
        "nports": 4,
        "ppps": "ppps"
      },
      "ports": [
        {
          "port": 1,
          "status": {
            "raw": "0x0103",
            "decoded": "device_active",
            "bits": {
              "connection": true,
              "enabled": true,
              "powered": true,
              "suspended": false,
              "overcurrent": false,
              "reset": false,
              "highspeed": false,
              "lowspeed": false
            }
          },
          "flags": {
            "connection": true,
            "enable": true,
            "power": true
          },
          "human_readable": {
            "connection": "Device is connected",
            "enable": "Port is enabled",
            "power": "Port power is enabled"
          },
          "speed": "USB1.1 Full Speed 12Mbps",
          "speed_bps": 12000000,
          "vid": "0x0403",
          "pid": "0x6001",
          "vendor": "FTDI",
          "product": "FT232R USB UART",
          "device_class": 0,
          "class_name": "Composite Device",
          "usb_version": "2.00",
          "device_version": "6.00",
          "serial": "A10KZP45",
          "description": "0403:6001 FTDI FT232R USB UART A10KZP45"
        }
      ]
    }
  ]
}

Power Action Events

uhubctl -j -a cycle -l 3-1.4 -p 1 -d 2

Outputs real-time events:

{"event": "hub_status", "hub": "3-1.4", "description": "05e3:0610 GenesysLogic USB2.1 Hub, USB 2.10, 4 ports, ppps"}
{"event": "power_change", "hub": "3-1.4", "port": 1, "action": "off", "from_state": true, "to_state": false, "success": true}
{"event": "delay", "reason": "power_cycle", "duration_seconds": 2.0}
{"event": "power_change", "hub": "3-1.4", "port": 1, "action": "on", "from_state": false, "to_state": true, "success": true}

Usage Examples

# List all hubs in JSON format
uhubctl -j

# Control specific port and get JSON output
uhubctl -j -l 1-1 -p 2 -a off

# Find all FTDI devices
uhubctl -j | jq '.hubs[] | . as $hub | .ports[] | select(.vendor == "FTDI") | "Device: \(.description)\nControl: uhubctl -l \($hub.location) -p \(.port) -a off\n"'

# Monitor power cycling with events
uhubctl -j -a cycle -l 3-1.4 -p 1 -d 2

Testing

  • Memory leak free - Valgrind testing shows no memory leaks
  • Complex topology support - Works with deep USB hub chains
  • Cross-platform - Tested on Linux and macOS
  • Backwards compatible - All existing command-line functionality preserved
  • Opt-in JSON - JSON is enabled only with -j flag

Implementation Notes

  • mkjson integration - No external dependencies, library embedded directly
  • Memory management - All JSON functions properly documented for memory handling
  • Error handling - Comprehensive error checking and reporting
  • Performance - Optimized for minimal JSON output size
  • Security - Proper string escaping and validation

This implementation provides a complete JSON interface for uhubctl while maintaining full backwards compatibility and addressing all feedback from the initial review.

@benroeder benroeder mentioned this pull request Aug 2, 2024
Copy link
Owner

@mvp mvp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your submission @benroeder!

Overall great job, but it needs some work to move on with this - please read comments below.

But main points are:

  1. Consider using encoder-only json C library that is as small as possible, e.g. mkjson - it is 10x smaller than cJSON.
  2. Try making emitted json as small as possible: avoid emitting empty or false values. E.g. always emitting "indicator": false in list of flags is hardly useful. Try using shorter field names (but still make them understandable) - e.g. consider using nports instead of num_ports - this will make json smaller.
  3. Retain backwards compatibility as much as possible - e.g. existing code is using ppps for per-port power switching mode supported - consider using it instead of per-port.
  4. For json generating functions, avoid copying large blocks from old non-json functions.
  5. Try to make output json as small as possible and don't emit info that is rarely used - basically anything that is not related to current port power state. If you want it to be still available, consider adding --verbose/-V flag that would make it really verbose.

Makefile Outdated
$(RM) $(PROGRAM).o $(PROGRAM).dSYM $(PROGRAM)
$(RM) $(OBJECTS) $(PROGRAM).dSYM $(PROGRAM)

.PHONY: all install clean
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing last newline

cJSON.h Outdated
@@ -0,0 +1,300 @@
/*
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cJSON supports both encoding and decoding, and is relatively large (96KB c+h combined).
Since we only need json encoder, perhaps we should use encoder only library? mkjson seems like great alternative (less than 10KB c+h combined).

uhubctl.c Outdated
@@ -18,6 +18,10 @@
#include <getopt.h>
#include <errno.h>
#include <ctype.h>
#include <stdbool.h>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need stdbool.h - commenting this out still works - please remove.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still don't need stdbool.h

@@ -180,6 +184,38 @@ struct usb_port_status {
#define HUB_CHAR_TTTT 0x0060 /* TT Think Time mask */
#define HUB_CHAR_PORTIND 0x0080 /* per-port indicators (LEDs) */

/*
* USB Speed definitions
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please link source where you got these speed definitions from? Perhaps USB spec or something?

uhubctl.c Outdated
int is_mass_storage_device(struct libusb_device *dev)
{
struct libusb_config_descriptor *config;
int ret = 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use rc instead of ret to be consistent with other code

uhubctl.c Outdated
const char* power_switching_mode;
switch (hub->lpsm) {
case HUB_CHAR_INDV_PORT_LPSM:
power_switching_mode = "per-port";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mode is already set to ppps in get_device_description, make it consistent?

uhubctl.c Outdated
power_switching_mode = "ganged";
break;
default:
power_switching_mode = "unknown";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is set to nops in get_device_description (no power switching).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is still set to nops when running without -j. Better to make it consistent.
But is ok to set it to none in both places.

struct libusb_device_handle* devh = NULL;
int rc = libusb_open(hub->dev, &devh);
if (rc == 0) {
for (int port = 1; port <= hub->nports; port++) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code has big copy/paste chunk from get_device_description(). Is there a way to avoid this? Ideally make it into one function?

uhubctl.c Outdated
int mask;
const char* name;
} flag_defs[] = {
{USB_PORT_STAT_CONNECTION, "connection"},
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For brevity, I would not emit any flag that has false value - it would considerably reduce output size

uhubctl.c Outdated
}

// Helper function to determine port speed
void get_port_speed(int port_status, char** speed_str, int64_t* speed_bits)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

speed_bits should be speed_bps (bits per second). That should be in emitted json as well.

@gillg
Copy link

gillg commented Feb 3, 2025

Hello ! What are the missing steps to merge ?
Any chance to get it soon ?

@piit79
Copy link

piit79 commented Feb 24, 2025

@gillg Looks like the author of the PR never followed up on the comments... Someone would probably need to take over and implement the requested changes. They are quite straightforward, so I might take it up to contribute to this awesome project at least a bit :)

@piit79
Copy link

piit79 commented Feb 24, 2025

2. consider using nports instead of num_ports - this will make json smaller

While brevity is good in general, I wonder if saving 3 bytes per key at the expense of (a little bit of) clarity make sense :)

@bradeyh
Copy link

bradeyh commented Jul 4, 2025

@piit79 Did you get anywhere on this? Don't see a uhubctl fork in your repos, but maybe you have something locally--was thinking of working on it myself, since I have some free time.

benroeder added a commit to benroeder/uhubctl that referenced this pull request Jul 4, 2025
Based on PR mvp#575 feedback, this commit replaces the large cJSON library
with the much smaller mkjson library for JSON output generation.

Changes:
- Replace cJSON (3,443 lines) with mkjson (357 lines) - ~10x reduction
- Optimize JSON output to only emit true boolean flags
- Use shorter field names (vid, pid, nports, ppps)
- Fix code style issues (remove stdbool.h, change ret to rc)
- Fix USB Full Speed detection for USB 2.0 devices
- Add USB speed reference citation
- Add missing newline at end of Makefile

The JSON output format remains compatible while significantly reducing
the library size as requested.
benroeder added a commit to benroeder/uhubctl that referenced this pull request Jul 4, 2025
- Replace cJSON library (3,443 lines) with lightweight mkjson (357 lines)
- Fix mkjson bug: change %Ld to %lld for proper 64-bit integer handling
- Add missing JSON fields: device descriptions, USB3 link states, serial numbers
- Fix USB3 detection by checking hub->super_speed flag instead of port status bits
- Fix buffer allocations with proper size calculations
- Handle all alternate settings in interfaces array
- Replace unsafe string operations (strcpy/strcat) with snprintf
- Change 'speed_bits' field to 'speed_bps' for consistency
- Document JSON output option (-j) in README

Addresses feedback from PR mvp#575. Tested on macOS and Linux.
@benroeder
Copy link
Author

I've completely reworked this PR based on your feedback. Major changes:

Critical Bug Fix in mkjson

I discovered and fixed a critical bug in mkjson library: The library was using %Ld format specifier for long long integers, which caused 64-bit values to be truncated. For example, USB 3.0 speeds of 5,000,000,000 bps were being displayed as 705,032,704. I fixed this by changing the format specifier to %lld in mkjson.c line 205.

Changes Made

  1. Replaced cJSON with mkjson - Reduced JSON library size from 3,443 lines to 357 lines (~10x reduction)
  2. Fixed all missing JSON fields - Added device names, USB3 link states, serial numbers
  3. Fixed USB3 detection - Now uses hub->super_speed flag instead of port status bits
  4. Fixed all code quality issues:
    • Replaced hardcoded buffer sizes with calculated values
    • Fixed interfaces array to include ALL alternate settings
    • Replaced unsafe string operations (strcpy/strcat) with snprintf
    • Removed duplicated USB3 detection logic
  5. Changed 'speed_bits' to 'speed_bps' as requested
  6. Added JSON documentation to README.md

Testing

  • Tested on macOS and Linux (Debian ARM64)
  • Clean compilation with -Wall -Wextra -std=c99 -pedantic
  • All functionality verified working correctly

The code is ready for review.

benroeder added 5 commits July 5, 2025 01:12
I have added cjson to to the repo
This is my first pass of adding -j, there is more work to do
Based on PR mvp#575 feedback, this commit replaces the large cJSON library
with the much smaller mkjson library for JSON output generation.

Changes:
- Replace cJSON (3,443 lines) with mkjson (357 lines) - ~10x reduction
- Optimize JSON output to only emit true boolean flags
- Use shorter field names (vid, pid, nports, ppps)
- Fix code style issues (remove stdbool.h, change ret to rc)
- Fix USB Full Speed detection for USB 2.0 devices
- Add USB speed reference citation
- Add missing newline at end of Makefile

The JSON output format remains compatible while significantly reducing
the library size as requested.
- Fix missing device descriptions by correcting mkjson parameter count
- Add USB3 link states (U0, U1, U2, Rx.Detect, etc.) to JSON output
- Fix USB Full Speed detection for USB 2.0 devices

These changes ensure JSON output includes all information shown in text output.
Serial numbers are now included in the JSON output for devices that have them.
This completes the JSON output enhancements to match the text output.

Example:
  "serial": "00015919101424154549"
- Replace cJSON library (3,443 lines) with lightweight mkjson (357 lines)
- Fix mkjson bug: change %Ld to %lld for proper 64-bit integer handling
- Add missing JSON fields: device descriptions, USB3 link states, serial numbers
- Fix USB3 detection by checking hub->super_speed flag instead of port status bits
- Fix buffer allocations with proper size calculations
- Handle all alternate settings in interfaces array
- Replace unsafe string operations (strcpy/strcat) with snprintf
- Change 'speed_bits' field to 'speed_bps' for consistency
- Document JSON output option (-j) in README

Addresses feedback from PR mvp#575. Tested on macOS and Linux.
Add comprehensive examples showing how to use uhubctl's JSON output
with jq for various use cases:
- Finding devices by vendor, serial, or class
- Generating control commands
- Monitoring device changes
- Creating device maps
- Finding empty ports
- Exporting to CSV

The examples demonstrate the power and flexibility of the JSON output
format for automation and scripting.
@pabs3
Copy link

pabs3 commented Jul 5, 2025

@mvp @benroeder

I note that mkjson is unmaintained (repo is archived, no commits to the two forks), so it might not be a good choice for this. cJSON is at least maintained and available in Linux distros like Debian.

If you want to keep mkjson, please at least make a fork of the main repo that has the fixes you added, so the project can be maintained and depended on by uhubctl.

benroeder added 2 commits July 5, 2025 14:10
- Original mkjson repository was archived on Apr 19, 2025
- Created fork at https://github.com/benroeder/mkjson
- Fixed critical bug: %Ld -> %lld format specifier for 64-bit integers
- Converted to git submodule for easier maintenance
- Updated build process and documentation

The bug fix prevents truncation of large 64-bit values such as
USB 3.0 speeds (5 Gbps = 5,000,000,000 bps).
@benroeder
Copy link
Author

I've updated this PR based on your feedback:

  1. Replaced cJSON with mkjson as suggested - this achieves a ~10x size reduction
  2. Fixed critical security vulnerabilities in mkjson by adding proper string escaping
  3. Maintaining a fork of mkjson since the original was archived
  4. Added comprehensive examples in examples/json_usage_examples.sh
  5. All tests pass and JSON output is validated

The implementation is now complete and ready for review. All JSON output is properly escaped and secure.

@benroeder
Copy link
Author

As they say no good deed goes un punished :-)

@piit79
Copy link

piit79 commented Jul 6, 2025

@bradeyh I sadly never found the time...

Great work, @benroeder, thank you! 👌

Copy link
Owner

@mvp mvp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for second round of this @benroeder!

I still have few high level issues with your new approach.

  1. Originally, I was under impression that -j would support all actions and emit all messages it emits today in json format, including power transitions. However, as far as I can tell, with your approach, -j is not compatible with any power actions. As you wrote this, it only supports showing status, making uhubctl very convenient exploration tool for USB devices and hubs, and print everything that one may need to know about USB in JSON format.
    This may not be bad idea in its own right, but it also means uhubctl integrations (e.g. pyhubctl python integration) cannot really use -j for easier parsing - they still need to parse existing non-json interface to actually provide full power switching support.
  2. Great job on importing mkjson and interfacing with it. However, I don't support idea of importing it as submodule. I want to make sure that all downstream uhubctl users (which is most Linux distros, homebrew, etc) can easily update to new uhubctl version without much trouble. Importing submodule is not exactly straightforward for them, and I'd rather avoid this issue completely by copying mkson.[c,h] verbatim in uhubctl repo. It can still receive updates from your forked mkjson repo, but manually. Note that I don't really care if mkjson original repo is no longer supported by original maintainer, as long as we carry it over and support it ourselves for our quite limited purpose.
  3. (Minor) I am not sure if it is good idea to have separate README and json_usage_examples. I am leaning towards adding json section in main README (but make it shorter than yours).
  4. I do like mkjson a lot more that cjson (mostly due to small size and ability to carry it over as a whole), but I have to admit that it is very painful to prepare list of arguments for mkjson() varags calls, especially when it comes to counting parameters. I would like to add different non-varargs function of similar nature to mkjson which would use null terminated array instead to eliminate a need for counting in first place - I will play with this myself.
  5. (Minor) Another issue with mkjson() is json output is not pretty - everything is packed in one line. It is not an issue for API usage, but if we are to ever support power transitions with json output it will be quite annoying because it is not really human readable. I wonder if we can patch mkjson to support pretty printing.

.gitmodules Outdated
Comment on lines 1 to 3
[submodule "mkjson"]
path = mkjson
url = https://github.com/benroeder/mkjson.git
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am against using submodule for this. I would rather copy 2 tiny .c and .h files into uhubctl repo. Its ok to keep updating it manually if mkjson changes.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mkjson has been archived, which why I forked and fixed it

@@ -14,7 +14,7 @@ PKG_CONFIG ?= pkg-config

CC ?= gcc
CFLAGS ?= -g -O0
CFLAGS += -Wall -Wextra -Wno-zero-length-array -std=c99 -pedantic
CFLAGS += -Wall -Wextra -Wno-zero-length-array -std=c99 -pedantic -I.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would not be needed if we keep mkjson local copy

README.md Outdated
Comment on lines 202 to 205
git clone https://github.com/mvp/uhubctl
cd uhubctl
git submodule init
git submodule update
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets not use submodule. But if we did, perhaps cleaner approach is

git clone --recurse-submodules https://github.com/mvp/uhubctl

uhubctl.c Outdated
@@ -18,6 +18,10 @@
#include <getopt.h>
#include <errno.h>
#include <ctype.h>
#include <stdbool.h>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still don't need stdbool.h

@@ -273,6 +312,8 @@ static const struct option long_options[] = {
{ "reset", no_argument, NULL, 'R' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ "json", no_argument, NULL, 'j' },
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

help should be the last option

uhubctl.c Outdated
Comment on lines 2084 to 2085
// If no action is specified or JSON output is requested, just print status
if (opt_action == POWER_KEEP || opt_json) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please enforce check that -j is only compatible with action POWER_KEEP before doing anything - we should print error message if say -j -a 0 is requested.
Then this if can be left as is

continue;
if (k == 1 && opt_action == POWER_KEEP)
continue;
/* if toggle requested, do it only once when `k == 0` */
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why removing comment about toggle?

if (k==0 && hubs[i].super_speed)
sleep_ms(150);

if (!opt_json) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you enforce -j incompatibility check with -a, you would not need these ifs

uhubctl.c Outdated
char* create_status_flags_json(int port_status, int is_usb3_hub)
{
// Use the provided hub USB version information
int is_usb3 = is_usb3_hub;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why create another variable which is simply a copy of the same thing?

Comment on lines +1887 to +1889



Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

many superficial empty lines

@pabs3
Copy link

pabs3 commented Jul 8, 2025

FTR, distros strongly prefer to not have embedded code copies, for example the Debian advice. The same can apply to git submodules but to a lesser extent, since the GitHub tarballs don't have the code copy, but then distros still have to patch the build system to work with the separately packaged version.

@gillg
Copy link

gillg commented Jul 8, 2025

FTR, distros strongly prefer to not have embedded code copies, for example the Debian advice. The same can apply to git submodules but to a lesser extent, since the GitHub tarballs don't have the code copy, but then distros still have to patch the build system to work with the separately packaged version.

Or best of both worlds, subrepo ? https://github.com/ingydotnet/git-subrepo

No submodule, no git reference, the code is locally copied, but subrepo adds a manifest to make easy a rebase or other things. In the end, it's just a local commit of all the files from the target version but you can track from where it's coming.

This PR addresses all feedback from mvp on PR mvp#575 and implements comprehensive JSON support for uhubctl.

Major changes:
- Replace cJSON with mkjson (10x smaller library, ~400 lines vs ~3,400)
- Add JSON support for all power actions (on/off/toggle/cycle/flash)
- Implement real-time JSON event streaming for power operations
- Add pretty-printing with 2-space indentation (always enabled)
- Create mkjson_array() wrapper to eliminate manual parameter counting
- Add comprehensive status decoding with human-readable descriptions

Technical improvements:
- Remove git submodule dependency, embed mkjson directly
- Rename is_usb3_hub → super_speed for clarity
- Rename speed_bits → speed_bps for consistency
- Add memory management documentation for JSON functions
- Convert all // comments to /* */ C-style
- Remove trailing whitespace and fix code formatting
- Move help option to end of command line parser
- Only output true boolean flags to minimize JSON size
- Remove verbose fields (nconfigs, interfaces) from default output

JSON output features:
- Hub information with VID/PID, USB version, port count
- Port status with raw hex, decoded state, and bit breakdown
- Connected device details (vendor, product, serial, class)
- Real-time power action events with success/failure status
- Human-readable flag descriptions
- Consistent field naming and structure

Testing:
- Valgrind clean (no memory leaks)
- Works with complex USB hub topologies
- All existing command-line functionality preserved
- JSON is opt-in via -j flag

Documentation:
- Added JSON section to README.md with examples
- Included jq usage examples for common tasks
- Memory management documented in function headers
@benroeder benroeder changed the title initial update for -j json Add JSON support for uhubctl - addresses all PR #575 feedback Jul 8, 2025
benroeder added 3 commits July 8, 2025 23:34
This function was created but never used since we removed the interfaces
field from JSON output per mvp's feedback. Removing it cleans up the code
and reduces binary size.
This addresses mvp's feedback about 'big copy/paste chunk from
get_device_description()'. The solution:

1. Extended descriptor_strings struct to include additional fields
   needed for JSON output (vid, pid, device_class, etc.)
2. Updated get_device_description() to populate these fields
3. Removed duplicate libusb_get_device_descriptor() call and
   parsing logic from create_port_status_json()
4. Added forward declarations for helper functions

This eliminates ~30 lines of duplicate code while making the
JSON output more efficient by reusing already-parsed device info.
This eliminates duplicate device enumeration loops that were repeated
throughout the codebase. The new find_device_on_hub_port() helper
function consolidates the logic for finding devices connected to
specific hub ports.

Changes:
- Added find_device_on_hub_port() helper function
- Replaced 3 duplicate enumeration loops with helper calls
- Reduced code duplication by ~40 lines
- Improved maintainability and consistency

Testing:
- Builds cleanly on both macOS and Linux
- JSON and text output work correctly
- Valgrind shows no memory leaks
benroeder added 2 commits July 8, 2025 23:50
This eliminates duplicate hex formatting code scattered throughout
the codebase. The new format_hex_id() helper function ensures
consistent formatting of VID/PID values.

Changes:
- Added format_hex_id() helper function
- Replaced 5 duplicate snprintf calls with helper
- Consistent "0x%04x" formatting throughout codebase
- Improved maintainability and consistency

Testing:
- Builds cleanly on both platforms
- JSON output format unchanged
- All hex values formatted correctly
This eliminates duplicate USB version formatting code that was
repeated multiple times throughout the codebase. The new
format_usb_version() helper ensures consistent formatting.

Changes:
- Added format_usb_version() helper function
- Replaced 3 duplicate snprintf calls with helper
- Consistent "x.xx" version formatting throughout
- Improved maintainability and consistency

Testing:
- Builds cleanly on both platforms
- USB version formatting works correctly
- JSON output shows proper version strings
@pabs3
Copy link

pabs3 commented Jul 8, 2025

From a distro point of view, git-subrepo sounds the ultimately same, copying code instead of it remaining an external dependency, which is packaged separately in distros.

Also, mkjson uses static linking, which is almost as bad from a distro point of view, slightly better though, since distros don't have to patch all reverse dependencies, but just rebuild them, that process takes manual distro work though, while shared libraries just need one distro update, and users to restart processes or reboot.

The mkjson security bug @benroeder found and fixed illustrates this problem, if things that use it had copies of it, some of them probably would not find out about the security problem, and some of them probably would not fix the issue in their copy, and users could be affected by the issue. With a shared library, distros patch that once, and every mkjson user is automatically fixed soon enough.

Also, @benroeder you might want to consider getting a CVE for the mkjson security issue (IIRC GitHub makes that easy).

All that said, no distros have mkjson packaged, and there are no copies of it in other source code in Debian, and it is mostly just one small function, so maybe it is fine. OTOH there has already been one security issue.

Also, there is a naming conflict with a mkjson command-line tool written in Haskell, might be worth renaming the mkjson C lib to libmkjson-c or similar instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants