Skip to content

Commit

Permalink
fallback to libusb if system_profiler returns non-zero not parsing error
Browse files Browse the repository at this point in the history
  • Loading branch information
tuna-f1sh committed Jan 31, 2023
1 parent af12877 commit dec5573
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 27 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "List system USB buses and devices; a modern and compatible `lsusb
repository = "https://github.com/tuna-f1sh/cyme"
readme = "README.md"
license = "GPL-3.0-or-later"
version = "1.2.6"
version = "1.2.7"
edition = "2021"
keywords = ["usb", "lsusb", "system_profiler", "macos", "libusb"]
categories = ["command-line-utilities"]
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,21 @@ For usage as a library for profiling system USB devices, the crate is 100% docum

`cyme` will check for a 'cyme.json' config file in:

* Linux: "$XDG_CONFIG_HOME or $HOME/.config"
* Linux: "$XDG\_CONFIG\_HOME or $HOME/.config"
* macOS: "$HOME/Library/Application Support"
* Windows: "{FOLDERID_RoamingAppData}"
* Windows: "{FOLDERID\_RoamingAppData}"

One can also be supplied with `--config`. Copy or refer to './doc/cyme_example_config.json' for configurables. Tthe file is essentially the default args; supplied args will override these. Use `--debug` to see where it is looking or if it's not loading.
One can also be supplied with `--config`. Copy or refer to './doc/cyme\_example\_config.json' for configurables. Tthe file is essentially the default args; supplied args will override these. Use `--debug` to see where it is looking or if it's not loading.

### Custom Icons and Colours

See './doc/cyme_example_config.json' for an example of how icons can be defined and also the [docs](https://docs.rs/cyme/latest/cyme/icon/enum.Icon.html). The config can exclude the "user"/"colours" keys if one wishes not to define any new icons/colours.
See './doc/cyme\_example\_config.json' for an example of how icons can be defined and also the [docs](https://docs.rs/cyme/latest/cyme/icon/enum.Icon.html). The config can exclude the "user"/"colours" keys if one wishes not to define any new icons/colours.

Icons are looked up in an order of User -> Default. For devices: `VidPid` -> `VidPidMsb` -> `Vid` -> `UnknownVendor` -> `get_default_vidpid_icon`, classes: `ClassifierSubProtocol` -> `Classifier` -> `UndefinedClassifier` -> `get_default_classifier_icon`. User supplied colours override all internal; if a key is missing, it will be `None`.

# Known Issues

* Version major BCD Device difference between libusb and macOS `system_profiler`: If the major version is large, libusb seems to read a different value to macOS. I don't think it's a parsing error but open to ideas.
* libusb cannot read special non-user Apple buses; T2 chip for example. These will still be listed by `system_profiler`. The result is that when merging for verbose data, these will not print verbose information. Use `--force-libusb` to ignore them.
* `sudo` is required to read Linux root_hub string descriptors - a stderr will be printed regarding this. The program works fine without these however.
* `sudo` is required to read Linux root\_hub string descriptors - a stderr will be printed regarding this. The program works fine without these however.
* Tested with macOS 13 ->. I'm not sure when the `-json` flag was added to `system_profiler`; whether it exists on all macOS versions.
23 changes: 18 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,17 +444,30 @@ fn main() {
&& !((args.tree && args.lsusb) || args.verbose > 0 || args.more)
{
system_profiler::get_spusb().unwrap_or_else(|e| {
eprintexit!(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to parse system_profiler output: Error({})", e)
));
// Other is for non-zero return, report but continue in this case
if e.kind() == std::io::ErrorKind::Other {
eprintln!("Failed to run 'system_profiler -json SPUSBDataType', fallback to pure libusb: Error({})", e.to_string());
get_libusb_spusb(&args)
// parsing error abort
} else {
eprintexit!(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Failed to parse 'system_profiler -json SPUSBDataType': Error({})", e)
));
}
})
} else {
// if not forcing libusb, get system_profiler and the merge with libusb
if cfg!(target_os = "macos") && !args.force_libusb {
log::warn!("Merging macOS system_profiler output with libusb for verbose data. Apple internal devices will not be obtained");
system_profiler::get_spusb_with_extra().unwrap_or_else(|e| {
eprintexit!(e);
// Other is for non-zero return, report but continue in this case
if e.kind() == std::io::ErrorKind::Other {
eprintln!("Failed to run 'system_profiler -json SPUSBDataType', fallback to pure libusb: Error({})", e.to_string());
get_libusb_spusb(&args)
} else {
eprintexit!(e);
}
})
} else {
get_libusb_spusb(&args)
Expand Down
48 changes: 33 additions & 15 deletions src/system_profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1380,9 +1380,10 @@ pub fn get_spusb() -> Result<SPUSBDataType, io::Error> {
serde_json::from_str(String::from_utf8(output.stdout).unwrap().as_str())
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))
} else {
log::error!("system_profiler returned non-zero stderr: {:?}, stdout: {:?}", String::from_utf8(output.stderr).unwrap_or(String::from("Failed to parse stderr")), String::from_utf8(output.stdout).unwrap_or(String::from("Failed to parse stdout")));
return Err(io::Error::new(
io::ErrorKind::Other,
format!("system_profiler returned non-zero, use '--force-libusb' to bypass: stderr: {:?}, stdout: {:?}", output.stderr, output.stdout),
"system_profiler returned non-zero, use '--force-libusb' to bypass"
));
}
}
Expand All @@ -1395,20 +1396,37 @@ pub fn get_spusb() -> Result<SPUSBDataType, io::Error> {
/// Runs `get_spusb` and then adds in data obtained from libusb. Requires 'libusb' feature.
#[cfg(feature = "libusb")]
pub fn get_spusb_with_extra() -> Result<SPUSBDataType, io::Error> {
let mut spusb = get_spusb().map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("Failed to parse system_profiler output: Error({})", e),
)
})?;
crate::lsusb::profiler::fill_spusb(&mut spusb).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("Failed to gather system USB data from libusb: Error({})", e),
)
})?;

Ok(spusb)
get_spusb().and_then(|mut spusb| {
crate::lsusb::profiler::fill_spusb(&mut spusb).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("Failed to gather system USB data from libusb: Error({})", e),
)
})?;
Ok(spusb)
})

// allow fallback if non-zero return
// match spusb {
// Ok(spusb) => Ok(spusb),
// Err(e) => {
// if e.kind() == std::io::ErrorKind::Other {
// eprintln!("Failed to run 'system_profiler -json SPUSBDataType', fallback to pure libusb: Error({})", e.to_string());
// crate::lsusb::profiler::get_spusb_with_extra().map_err(|e| {
// io::Error::new(
// io::ErrorKind::Other,
// format!("Failed to gather system USB data from libusb: Error({})", e),
// )
// })
// // parsing error abort
// } else {
// Err(io::Error::new(
// io::ErrorKind::InvalidData,
// format!("Failed to parse 'system_profiler -json SPUSBDataType': Error({})", e)
// ))
// }
// }
// }
}

/// Cannot run this function without libusb feature
Expand Down

0 comments on commit dec5573

Please sign in to comment.