diff --git a/Cargo.lock b/Cargo.lock index e149ce0e..4844736d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,37 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +[[package]] +name = "argh" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7af5ba06967ff7214ce4c7419c7d185be7ecd6cc4965a8f6e1d8ce0398aad219" +dependencies = [ + "argh_derive", + "argh_shared", +] + +[[package]] +name = "argh_derive" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56df0aeedf6b7a2fc67d06db35b09684c3e8da0c95f8f27685cb17e08413d87a" +dependencies = [ + "argh_shared", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "argh_shared" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5693f39141bda5760ecc4111ab08da40565d1771038c4a0250f03457ec707531" +dependencies = [ + "serde", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -89,9 +120,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "built" @@ -103,11 +134,17 @@ dependencies = [ "git2", ] +[[package]] +name = "bytecount" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" + [[package]] name = "bytemuck" -version = "1.16.0" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" +checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" [[package]] name = "bytemuck_derive" @@ -117,7 +154,7 @@ checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -141,7 +178,7 @@ version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ac2a4d0e69036cf0062976f6efcba1aaee3e448594e6514bb2ddf87acce562" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cairo-sys-rs", "glib", "libc", @@ -173,13 +210,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.99" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" dependencies = [ "jobserver", "libc", - "once_cell", ] [[package]] @@ -204,6 +240,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "convert_case" version = "0.4.0" @@ -263,7 +305,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.66", + "syn 2.0.72", +] + +[[package]] +name = "ctrlc" +version = "3.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" +dependencies = [ + "nix", + "windows-sys 0.52.0", ] [[package]] @@ -287,14 +339,14 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" @@ -424,7 +476,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -449,9 +501,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.19.2" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6a23f8a0b5090494fd04924662d463f8386cc678dd3915015a838c1a3679b92" +checksum = "624eaba126021103c7339b2e179ae4ee8cdab842daab419040710f38ed9f8699" dependencies = [ "gdk-pixbuf-sys", "gio", @@ -461,9 +513,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" -version = "0.19.5" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fdbf021f8b9d19e30fb9ea6d6e5f2b6a712fe4645417c69f86f6ff1e1444a8f" +checksum = "4efa05a4f83c8cc50eb4d883787b919b85e5f1d8dd10b5a1df53bf5689782379" dependencies = [ "gio-sys", "glib-sys", @@ -534,9 +586,9 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gio" -version = "0.19.5" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be548be810e45dd31d3bbb89c6210980bb7af9bca3ea1292b5f16b75f8e394a7" +checksum = "4c49f117d373ffcc98a35d114db5478bc223341cff53e39a5d6feced9e2ddffe" dependencies = [ "futures-channel", "futures-core", @@ -552,9 +604,9 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.19.5" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4bdbef451b0f0361e7f762987cc6bebd5facab1d535e85a3cf1115dfb08db40" +checksum = "2cd743ba4714d671ad6b6234e8ab2a13b42304d0e13ab7eba1dcdd78a7d6d4ef" dependencies = [ "glib-sys", "gobject-sys", @@ -569,7 +621,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", "libgit2-sys", "log", @@ -578,11 +630,11 @@ dependencies = [ [[package]] name = "glib" -version = "0.19.7" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e52355166df21c7ed16b6a01f615669c7911ed74e27ef60eba339c0d2da12490" +checksum = "39650279f135469465018daae0ba53357942a5212137515777d5fdca74984a44" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "futures-channel", "futures-core", "futures-executor", @@ -600,22 +652,22 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.19.7" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70025dbfa1275cf7d0531c3317ba6270dae15d87e63342229d638246ff45202e" +checksum = "4429b0277a14ae9751350ad9b658b1be0abb5b54faa5bcdf6e74a3372582fad7" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "glib-sys" -version = "0.19.5" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767d23ead9bbdfcbb1c2242c155c8128a7d13dde7bf69c176f809546135e2282" +checksum = "5c2dc18d3a82b0006d470b13304fbbb3e0a9bd4884cf985a60a7ed733ac2c4a5" dependencies = [ "libc", "system-deps", @@ -623,9 +675,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.19.5" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3787b0bfacca12bb25f8f822b0dbee9f7e4a86e6469a29976d332d2c14c945b" +checksum = "2e697e252d6e0416fd1d9e169bda51c0f1c926026c39ca21fbe8b1bb5c3b8b9e" dependencies = [ "glib-sys", "libc", @@ -634,9 +686,9 @@ dependencies = [ [[package]] name = "graphene-rs" -version = "0.19.2" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4d388e96c5f29e2b2f67045d229ddf826d0a8d6d282f94ed3b34452222c91" +checksum = "f5fb86031d24d9ec0a2a15978fc7a65d545a2549642cf1eb7c3dda358da42bcf" dependencies = [ "glib", "graphene-sys", @@ -645,9 +697,9 @@ dependencies = [ [[package]] name = "graphene-sys" -version = "0.19.5" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60e7381afdd7be43bd10a89d3b6741d162aabbca3a8db73505afb6a3aea59d" +checksum = "2f530e0944bccba4b55065e9c69f4975ad691609191ebac16e13ab8e1f27af05" dependencies = [ "glib-sys", "libc", @@ -716,7 +768,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -744,6 +796,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -771,9 +829,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown", @@ -834,9 +892,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -853,9 +911,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -901,9 +959,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lrumap" @@ -952,9 +1010,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -1001,6 +1059,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.6.0", + "cfg-if 1.0.0", + "cfg_aliases", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -1023,23 +1093,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -1061,9 +1131,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" dependencies = [ "memchr", ] @@ -1080,12 +1150,14 @@ version = "0.1.0" dependencies = [ "anyhow", "arc-swap", + "argh", "bitfield", "built", "bytemuck", "bytemuck_derive", "crc", "ctor", + "ctrlc", "derive_more", "futures-channel", "futures-lite", @@ -1106,6 +1178,7 @@ dependencies = [ "rand_xorshift", "serde", "serde_json", + "tabled", "tempfile", "usb-ids", "winapi 0.3.9", @@ -1123,9 +1196,9 @@ dependencies = [ [[package]] name = "pango" -version = "0.19.5" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504ce6e805439ea2c6791168fe7ef8e3da0c1b2ef82c44bc450dbc330592920d" +checksum = "3f0d328648058085cfd6897c9ae4272884098a926f3a833cd50c8c73e6eccecd" dependencies = [ "gio", "glib", @@ -1135,9 +1208,9 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.19.5" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4829555bdbb83692ddeaf5a6927fb2d025c8131e5ecaa4f7619fff6985d3505" +checksum = "ff03da4fa086c0b244d4a4587d3e20622a3ecdb21daea9edf66597224c634ba0" dependencies = [ "glib-sys", "gobject-sys", @@ -1145,6 +1218,17 @@ dependencies = [ "system-deps", ] +[[package]] +name = "papergrid" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad43c07024ef767f9160710b3a6773976194758c7919b17e63b863db0bdf7fb" +dependencies = [ + "bytecount", + "fnv", + "unicode-width", +] + [[package]] name = "parking" version = "2.2.0" @@ -1226,9 +1310,12 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro-crate" @@ -1239,11 +1326,35 @@ dependencies = [ "toml_edit 0.21.1", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1372,7 +1483,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -1396,40 +1507,41 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -1468,9 +1580,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -1484,48 +1596,73 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ "cfg-expr", - "heck", + "heck 0.5.0", "pkg-config", - "toml 0.8.14", + "toml 0.8.19", "version-compare", ] +[[package]] +name = "tabled" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c998b0c8b921495196a48aabaf1901ff28be0760136e31604f7967b0792050e" +dependencies = [ + "papergrid", + "tabled_derive", + "unicode-width", +] + +[[package]] +name = "tabled_derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c138f99377e5d653a371cdad263615634cfc8467685dfe8e73e2b8e98f44b17" +dependencies = [ + "heck 0.4.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" dependencies = [ "cfg-if 1.0.0", "fastrand", + "once_cell", "rustix", "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -1557,21 +1694,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.14" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.14", + "toml_edit 0.22.20", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -1602,15 +1739,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.14" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.13", + "winnow 0.6.18", ] [[package]] @@ -1634,6 +1771,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + [[package]] name = "url" version = "2.5.2" @@ -1660,9 +1803,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom 0.2.15", ] @@ -1679,6 +1822,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -1740,7 +1889,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -1760,18 +1909,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1782,9 +1931,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -1794,9 +1943,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -1806,15 +1955,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -1824,9 +1973,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -1836,9 +1985,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -1848,9 +1997,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -1860,9 +2009,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -1875,9 +2024,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.13" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -1891,3 +2040,24 @@ dependencies = [ "winapi 0.2.8", "winapi-build", ] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] diff --git a/Cargo.toml b/Cargo.toml index 069e66e0..4915e29e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,9 @@ page_size = "0.6.0" anyhow = { version = "1.0.79", features = ["backtrace"] } crc = "3.2.1" usb-ids = "1.2024.4" +argh = "0.1.12" +tabled = "0.15.0" +ctrlc = "3.4.4" [dev-dependencies] serde = { version = "1.0.196", features = ["derive"] } diff --git a/src/backend/cynthion.rs b/src/backend/cynthion.rs index 76a6264e..a6e8b9a6 100644 --- a/src/backend/cynthion.rs +++ b/src/backend/cynthion.rs @@ -36,7 +36,7 @@ const ENDPOINT: u8 = 0x81; const READ_LEN: usize = 0x4000; const NUM_TRANSFERS: usize = 4; -#[derive(Copy, Clone, FromPrimitive, IntoPrimitive)] +#[derive(Copy, Clone, FromPrimitive, IntoPrimitive, Eq, PartialEq)] #[repr(u8)] pub enum Speed { #[default] @@ -68,6 +68,33 @@ impl Speed { } } +impl std::str::FromStr for Speed { + type Err = Error; + + fn from_str(s: &str) -> Result { + use Speed::*; + match s { + "auto" => Ok(Auto), + "high" => Ok(High), + "full" => Ok(Full), + "low" => Ok(Low), + _ => bail!("Invalid speed: {}", s) + } + } +} + +impl std::fmt::Display for Speed { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.description()) + } +} + +impl std::fmt::Debug for Speed { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.description()) + } +} + bitfield! { #[derive(Copy, Clone)] struct State(u8); @@ -366,13 +393,13 @@ impl CynthionHandle { fn start_capture(&mut self, speed: Speed) -> Result<(), Error> { self.write_request(1, State::new(true, speed).0)?; - println!("Capture enabled, speed: {}", speed.description()); + eprintln!("Capture enabled, speed: {}", speed.description()); Ok(()) } fn stop_capture(&mut self) -> Result<(), Error> { self.write_request(1, State::new(false, Speed::High).0)?; - println!("Capture disabled"); + eprintln!("Capture disabled"); Ok(()) } @@ -545,7 +572,7 @@ impl CynthionStream { impl CynthionStop { pub fn stop(self) -> Result<(), Error> { - println!("Requesting capture stop"); + eprintln!("Requesting capture stop"); self.stop_request.send(()) .or_else(|_| bail!("Failed sending stop request"))?; handle_thread_panic(self.worker.join())?; diff --git a/src/cli.rs b/src/cli.rs index d8150953..ba28b654 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,43 +1,256 @@ -use std::process::{Command, ExitCode}; +use std::process::ExitCode; -#[cfg(unix)] -use std::os::unix::process::ExitStatusExt; +#[macro_use] +extern crate bitfield; -#[cfg(windows)] -const MAIN_BINARY: &str = "packetry.exe"; -#[cfg(not(windows))] -const MAIN_BINARY: &str = "packetry"; +mod backend; +mod pcap; +mod version; + +use crate::backend::cynthion::{CynthionDevice, CynthionUsability::*, Speed}; +use crate::pcap::Writer; +use version::{version, version_info}; + +// Include build-time info. +pub mod built { + // The file has been placed there by the build script. + include!(concat!(env!("OUT_DIR"), "/built.rs")); +} + +use anyhow::Error; +use std::fs::File; +use std::io::{self, Write}; +use std::sync::{Arc, Mutex}; +use tabled::{Table, Tabled}; + +use argh::FromArgs; +#[derive(FromArgs, PartialEq, Debug)] +/// packetry - a fast, intuitive USB 2.0 protocol analysis application for use with Cynthion +struct Args { + #[argh(subcommand)] + sub_commands: Option, +} + +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand)] +enum SubcommandEnum { + One(SubCommandCliCapture), + Two(SubCommandDevices), + Three(SubCommandVersion), +} + +#[derive(FromArgs, PartialEq, Debug)] +/// Start packetry in CLI mode +#[argh(subcommand, name = "capture")] +struct SubCommandCliCapture { + /// device (default: auto) + #[argh( + option, + short = 'd', + long = "device", + default = "String::from(\"auto\")" + )] + device_serial: String, + /// usb speed (default: low) + #[argh(option, short = 's', long = "speed", default = "Speed::Low")] + usb_speed: Speed, + /// output file (use '-' for stdout, default: cynthion.pcap) + #[argh( + option, + short = 'o', + long = "output", + default = "String::from(\"cynthion.pcap\")" + )] + output_file: String, +} + +#[derive(FromArgs, PartialEq, Debug)] +/// List capture devices +#[argh(subcommand, name = "devices")] +struct SubCommandDevices {} + +#[derive(FromArgs, PartialEq, Debug)] +/// Print version information +#[argh(subcommand, name = "version")] +struct SubCommandVersion { + /// print dependency information with version + #[argh(switch, long = "dependencies")] + print_dependencies: bool, +} + +#[derive(Tabled)] +pub struct DeviceInfo { + name: String, + serial: String, + useable: String, + bus: String, + address: String, + speeds: String, +} fn main() -> ExitCode { - // Find the main Packetry executable. - let packetry_binary_path = std::env::current_exe() - .expect("Failed to find path to current executable") - .parent() - .expect("Failed to find parent directory of current executable") - .join(MAIN_BINARY); - - // Prepare to call it, passing through all arguments we were passed. - let mut command = Command::new(packetry_binary_path); - command.args(std::env::args().skip(1)); - - // If on Windows, tell the child that it needs to attach to our console. - #[cfg(windows)] - command.env("PACKETRY_ATTACH_CONSOLE", "1"); - - // Spawn the main binary as a child process, and wait for its exit status. - let exit_status = command - .status() - .expect("Failed to start main packetry binary"); - - // Try to exit with the same code the child did. - match exit_status.code() { - Some(code) => ExitCode::from(code as u8), - None => { - #[cfg(unix)] - if let Some(signal) = exit_status.signal() { - panic!("Packetry was terminated by signal {signal}"); + let args: Args = argh::from_env(); + + let exit_code = if let Some(subcmd) = args.sub_commands { + match subcmd { + SubcommandEnum::One(captureoptions) => { + if let Err(e) = headless_capture(captureoptions) { + eprintln!("Error capturing packets: {}", e); + ExitCode::FAILURE + } else { + ExitCode::SUCCESS + } + } + + SubcommandEnum::Two(_) => { + if let Err(e) = list_devices() { + eprintln!("Error listing devices: {}", e); + ExitCode::FAILURE + } else { + ExitCode::SUCCESS + } + } + + SubcommandEnum::Three(versionoptions) => { + println!("Packetry version {}\n\n{}", + version(), + version_info(versionoptions.print_dependencies)); + ExitCode::SUCCESS + } + } + } else { + ExitCode::SUCCESS + }; + + exit_code +} + +fn headless_capture(options: SubCommandCliCapture) -> Result<(), Error> { + let device = select_device(&options.device_serial, options.usb_speed)?; + + let output_writer: Box = if options.output_file == "-" { + Box::new(io::stdout()) + } else { + Box::new(File::create(&options.output_file)?) + }; + let mut writer = Writer::open(output_writer)?; + + let cynthion = device.open()?; + let (stream_handle, stop_handle) = + cynthion.start(options.usb_speed, |e| eprintln!("{:?}", e))?; + + let stop_handle = Arc::new(Mutex::new(Some(stop_handle))); + ctrlc::set_handler(move || { + let mut handle_opt = stop_handle.lock().unwrap(); + if let Some(handle) = handle_opt.take() { + if let Err(e) = handle.stop() { + eprintln!("Failed to stop Cynthion: {}", e); } - panic!("Packetry was terminated without an exit code"); } + }) + .expect("Error setting CTRL+C handler"); + + for packet in stream_handle { + writer.add_packet(&packet.bytes, packet.timestamp_ns)?; } + + writer.close()?; + + Ok(()) +} + +fn select_device(serial: &str, speed: Speed) -> Result { + let mut devices = CynthionDevice::scan()?; + + if devices.is_empty() { + return Err(anyhow::anyhow!("No devices found")); + } + + let device_index = if serial == "auto" { + // Select the first device + Some(0) + } else { + // Find the device with the requested serial number + devices + .iter() + .position(|d| d.device_info.serial_number() == Some(&serial.to_string())) + }; + + // Check if the device was found + let device_index = match device_index { + Some(index) => index, + None => return Err(anyhow::anyhow!("Device with serial {} not found", serial)), + }; + + // Remove the device from the list to get ownership + let device = devices.remove(device_index); + + // Check if the device is usable and supports the requested speed + match &device.usability { + Usable(_, speeds) => { + if !speeds.contains(&speed) { + return Err(anyhow::anyhow!("Device does not support speed {:?}", speed)); + } + } + + Unusable(reason) => { + return Err(anyhow::anyhow!("Device is not usable: {}", reason)); + } + } + + Ok(device) +} + +pub fn list_devices() -> Result<(), Error> { + let devices = CynthionDevice::scan()?; + + if devices.is_empty() { + println!("No devices found."); + return Ok(()); + } + + let device_table: Vec = devices + .iter() + .map(|device| { + let info = &device.device_info; + + // Maybe in the future there are more devices to support. Hardcode the name for now. + let name = "Cynthion".to_string(); + + let serial = info + .serial_number() + .map_or("None".to_string(), |s| s.to_string()); + let bus = info.bus_number().to_string(); + let address = info.device_address().to_string(); + + let (useable, speeds) = match &device.usability { + Usable(_, speeds) => ( + "Yes".to_string(), + speeds + .iter() + .map(|speed| { + let desc = speed.description(); + desc.split(' ').next().unwrap_or("").to_string() + }) + .collect::>() + .join(", "), + ), + Unusable(reason) => (reason.to_string(), String::new()), + }; + + DeviceInfo { + name, + serial, + useable, + bus, + address, + speeds, + } + }) + .collect(); + + let table = Table::new(device_table).to_string(); + println!("{}", table); + + Ok(()) } diff --git a/src/main.rs b/src/main.rs index 090abe34..347c753d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,7 +66,7 @@ fn main() { #[cfg(windows)] if std::env::var("PACKETRY_ATTACH_CONSOLE").is_ok() { use winapi::um::wincon::{AttachConsole, ATTACH_PARENT_PROCESS}; - unsafe {AttachConsole(ATTACH_PARENT_PROCESS)}; + unsafe { AttachConsole(ATTACH_PARENT_PROCESS) }; } if have_argument("--version") { diff --git a/wix/rust_licenses.py b/wix/rust_licenses.py index 9523eee0..c029c76c 100644 --- a/wix/rust_licenses.py +++ b/wix/rust_licenses.py @@ -24,7 +24,7 @@ # These packages have been validated for conditionally accepted licenses. validated = ( - ('target-lexicon', '0.12.14'), + ('target-lexicon', '0.12.16'), ('unicode-ident', '1.0.12'), ) @@ -119,6 +119,7 @@ def validate_license(package, version, expr): file_paths = ( ['LICENSE-MIT'], ['LICENSE-MIT.md'], + ['LICENSE.MIT'], ['license-mit'], ['LICENSES', 'MIT.txt'], ['LICENSE'],