1pub const BUSY_HINT: &str = "\
8Another program already claimed the USB interface.
9
10On Linux that's almost always gvfs: run `gio mount -l` to find the device,
11then `gio mount -u <mount-uri>` to release it. To stop gvfs from grabbing
12devices at all: `systemctl --user mask gvfs-mtp-volume-monitor`.
13
14On macOS it's `ptpcamerad`: stop it with `sudo killall ptpcamerad`, then
15reconnect the device (launchd starts it again on the next connect).";
16
17pub const PERMISSION_HINT: &str = "\
19The OS denied access to the USB device.
20
21On Linux this is a missing udev rule: your user has no write access to
22/dev/bus/usb/*. Add yourself to the `plugdev` group, or install a udev rule
23for the device's vendor ID.
24See: https://github.com/vdavid/mtp-mount#requirements";
25
26pub fn open_failure_hint(e: &mtp_rs::Error) -> Option<&'static str> {
28 if e.is_exclusive_access() {
29 Some(BUSY_HINT)
30 } else if e.is_permission_denied() {
31 Some(PERMISSION_HINT)
32 } else {
33 None
34 }
35}
36
37pub fn indent(text: &str, prefix: &str) -> String {
39 text.lines()
40 .map(|line| {
41 if line.is_empty() {
42 String::new()
43 } else {
44 format!("{prefix}{line}")
45 }
46 })
47 .collect::<Vec<_>>()
48 .join("\n")
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn busy_gets_the_release_the_device_remedy() {
57 let e = mtp_rs::Error::ExclusiveAccess;
60 assert!(e.is_exclusive_access(), "precondition: {e}");
61 let hint = open_failure_hint(&e).expect("busy needs a hint");
62 assert!(hint.contains("gio mount -l"));
63 assert!(hint.contains("gvfs-mtp-volume-monitor"));
64 assert!(hint.contains("ptpcamerad"));
65 }
66
67 #[test]
68 fn permission_denied_points_at_udev() {
69 let e = mtp_rs::Error::PermissionDenied;
70 assert!(e.is_permission_denied(), "precondition: {e}");
71 let hint = open_failure_hint(&e).expect("permission denied needs a hint");
72 assert!(hint.contains("udev"));
73 }
74
75 #[test]
76 fn other_failures_get_no_hint() {
77 let e = mtp_rs::Error::NotFound;
78 assert!(!e.is_exclusive_access());
79 assert!(!e.is_permission_denied());
80 assert!(open_failure_hint(&e).is_none());
81 }
82
83 #[test]
84 fn indent_prefixes_content_lines_only() {
85 assert_eq!(indent("a\n\nb", " "), " a\n\n b");
86 }
87}