Update clap to remove suppressions (#2856)

A Friday afternoon jaunt.

To be merged after #2855; does the remaining work to close #2277 (and closes off some things that Dependabot was trying to upgrade).

Tested by manually running the commands; we don't have good coverage for this kind of stuff. OTOH, most of these commands are for the experimental local fuzzing mode, which is not fully supported yet. I did specifically test the `onefuzz-task managed` command which is the one used in production.

## Details

- Bump `clap` to 4.1.6
  - Remove `structopt` as this is subsumed by clap now
- Bump `envlogger` to 0.10 (removes problematic dependency)
- Set `default-features=false` on `proc-maps` (removes a feature which is only needed to support FreeBSD), and bump it to 0.3

The main changes migrating `clap` are:

- `value_t!` is gone; now use `matches.get_one::<T>`. If `T` is not `String` then a parser must have been registered on the `Arg` when it was created, with `arg.value_parser(value_parser!(T))`.
- `Command::with_name` and `Arg::with_name` are now called `new`.
- `Command` and `Subcommand` were unified, and `App` is removed.
- `arg.takes_value(true)` is gone; it is the default. For flags use `arg.action(ArgAction::SetTrue)` and then retrieve the flag value with `matches.get_flag`.

This code would be simplified a lot by using the `clap::Parser` on structs, but that requires reworking the code significantly as we cannot dynamically add/remove arguments the way that this is currently done.

## Also found

Found one bug while manually testing the `onefuzz-task local` commands; see comment below.
This commit is contained in:
George Pollard
2023-02-20 10:45:15 +13:00
committed by GitHub
parent 1b07b7df25
commit cd18c6066d
32 changed files with 642 additions and 806 deletions

300
src/agent/Cargo.lock generated
View File

@ -32,15 +32,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.51" version = "1.0.51"
@ -122,17 +113,6 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -266,25 +246,21 @@ dependencies = [
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.59.1" version = "0.59.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cexpr", "cexpr",
"clang-sys", "clang-sys",
"clap 2.34.0",
"env_logger 0.8.4",
"lazy_static", "lazy_static",
"lazycell", "lazycell",
"log",
"peeking_take_while", "peeking_take_while",
"proc-macro2 1.0.47", "proc-macro2 1.0.47",
"quote 1.0.9", "quote 1.0.9",
"regex", "regex",
"rustc-hash", "rustc-hash",
"shlex", "shlex",
"which",
] ]
[[package]] [[package]]
@ -293,28 +269,16 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitvec"
version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33"
dependencies = [
"funty 1.1.0",
"radium 0.5.3",
"tap",
"wyz 0.2.0",
]
[[package]] [[package]]
name = "bitvec" name = "bitvec"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b"
dependencies = [ dependencies = [
"funty 2.0.0", "funty",
"radium 0.7.0", "radium",
"tap", "tap",
"wyz 0.5.0", "wyz",
] ]
[[package]] [[package]]
@ -376,11 +340,11 @@ checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
[[package]] [[package]]
name = "cexpr" name = "cexpr"
version = "0.5.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [ dependencies = [
"nom 6.1.2", "nom 7.1.0",
] ]
[[package]] [[package]]
@ -421,86 +385,32 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.34.0" version = "4.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
dependencies = [ dependencies = [
"ansi_term",
"atty",
"bitflags", "bitflags",
"strsim 0.8.0", "clap_derive",
"textwrap 0.11.0", "clap_lex",
"unicode-width", "is-terminal",
"vec_map",
]
[[package]]
name = "clap"
version = "3.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d20de3739b4fb45a17837824f40aa1769cc7655d7a83e68739a77fe7b30c87a"
dependencies = [
"atty",
"bitflags",
"clap_derive 3.2.4",
"clap_lex 0.2.2",
"indexmap",
"once_cell", "once_cell",
"strsim 0.10.0", "strsim",
"termcolor",
"textwrap 0.15.0",
]
[[package]]
name = "clap"
version = "4.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e"
dependencies = [
"atty",
"bitflags",
"clap_derive 4.0.21",
"clap_lex 0.3.0",
"once_cell",
"strsim 0.10.0",
"termcolor", "termcolor",
] ]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "3.2.4" version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "026baf08b89ffbd332836002ec9378ef0e69648cbfadd68af7cd398ca5bf98f7" checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
dependencies = [ dependencies = [
"heck 0.4.0", "heck",
"proc-macro-error", "proc-macro-error",
"proc-macro2 1.0.47", "proc-macro2 1.0.47",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.103", "syn 1.0.103",
] ]
[[package]]
name = "clap_derive"
version = "4.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
dependencies = [
"heck 0.4.0",
"proc-macro-error",
"proc-macro2 1.0.47",
"quote 1.0.9",
"syn 1.0.103",
]
[[package]]
name = "clap_lex"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5538cd660450ebeb4234cfecf8f2284b844ffc4c50531e66d584ad5b91293613"
dependencies = [
"os_str_bytes",
]
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.3.0" version = "0.3.0"
@ -559,11 +469,11 @@ name = "coverage"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap 4.0.26", "clap",
"cobertura", "cobertura",
"debuggable-module", "debuggable-module",
"debugger", "debugger",
"env_logger 0.10.0", "env_logger",
"iced-x86", "iced-x86",
"log", "log",
"pete", "pete",
@ -753,7 +663,7 @@ name = "debuggable-module"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap 4.0.26", "clap",
"elsa", "elsa",
"gimli", "gimli",
"goblin 0.6.0", "goblin 0.6.0",
@ -853,10 +763,10 @@ name = "dynamic-library"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap",
"debugger", "debugger",
"lazy_static", "lazy_static",
"regex", "regex",
"structopt",
"thiserror", "thiserror",
"winapi", "winapi",
"winreg 0.10.1", "winreg 0.10.1",
@ -895,32 +805,6 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
[[package]]
name = "env_logger"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "env_logger"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]] [[package]]
name = "env_logger" name = "env_logger"
version = "0.10.0" version = "0.10.0"
@ -1078,12 +962,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "funty"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
[[package]] [[package]]
name = "funty" name = "funty"
version = "2.0.0" version = "2.0.0"
@ -1304,30 +1182,12 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.2.6" version = "0.2.6"
@ -1581,7 +1441,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
dependencies = [ dependencies = [
"hermit-abi 0.2.6", "hermit-abi",
"io-lifetimes", "io-lifetimes",
"rustix", "rustix",
"windows-sys 0.42.0", "windows-sys 0.42.0",
@ -1692,10 +1552,11 @@ dependencies = [
[[package]] [[package]]
name = "libproc" name = "libproc"
version = "0.10.0" version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6466fc1f834276563fbbd4be1c24236ef92bb9efdbd4691e07f1cf85a0b407f0" checksum = "0b799ad155d75ce914c467ee5627b62247c20d4aedbd446f821484cebf3cded7"
dependencies = [ dependencies = [
"bindgen",
"errno", "errno",
"libc", "libc",
] ]
@ -1914,18 +1775,6 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "nom"
version = "6.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
dependencies = [
"bitvec 0.19.6",
"funty 1.1.0",
"memchr",
"version_check",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "7.1.0" version = "7.1.0"
@ -2002,7 +1851,7 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [ dependencies = [
"hermit-abi 0.2.6", "hermit-abi",
"libc", "libc",
] ]
@ -2039,6 +1888,7 @@ dependencies = [
"backoff", "backoff",
"base64", "base64",
"bytes", "bytes",
"clap",
"cpp_demangle 0.3.5", "cpp_demangle 0.3.5",
"debugger", "debugger",
"dunce", "dunce",
@ -2067,7 +1917,6 @@ dependencies = [
"sha2", "sha2",
"stacktrace-parser", "stacktrace-parser",
"storage-queue", "storage-queue",
"structopt",
"strum", "strum",
"strum_macros", "strum_macros",
"tempfile", "tempfile",
@ -2089,9 +1938,9 @@ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
"backtrace", "backtrace",
"clap 3.2.4", "clap",
"downcast-rs", "downcast-rs",
"env_logger 0.9.0", "env_logger",
"futures", "futures",
"log", "log",
"nix", "nix",
@ -2135,11 +1984,11 @@ dependencies = [
"azure_storage_blobs", "azure_storage_blobs",
"backoff", "backoff",
"chrono", "chrono",
"clap 2.34.0", "clap",
"cobertura", "cobertura",
"coverage", "coverage",
"crossterm 0.22.1", "crossterm 0.22.1",
"env_logger 0.9.0", "env_logger",
"flume", "flume",
"futures", "futures",
"hex", "hex",
@ -2514,12 +2363,11 @@ dependencies = [
[[package]] [[package]]
name = "proc-maps" name = "proc-maps"
version = "0.2.1" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2f62c16ccc63ce2f590b17b8b9b33616f59631b8982ad52ed21e7f6d936c409" checksum = "2c790484f98e8b00e2385ebde989077698f99417307a74361001ada102f8c2ce"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bindgen",
"libc", "libc",
"libproc", "libproc",
"mach2", "mach2",
@ -2588,12 +2436,6 @@ dependencies = [
"proc-macro2 1.0.47", "proc-macro2 1.0.47",
] ]
[[package]]
name = "radium"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]] [[package]]
name = "radium" name = "radium"
version = "0.7.0" version = "0.7.0"
@ -3102,7 +2944,7 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "410b26ed97440d90ced3e2488c868d56a86e2064f5d7d6f417909b286afe25e5" checksum = "410b26ed97440d90ced3e2488c868d56a86e2064f5d7d6f417909b286afe25e5"
dependencies = [ dependencies = [
"heck 0.4.0", "heck",
"proc-macro2 1.0.47", "proc-macro2 1.0.47",
"quote 1.0.9", "quote 1.0.9",
"syn 1.0.103", "syn 1.0.103",
@ -3132,14 +2974,14 @@ name = "srcview"
version = "0.1.2" version = "0.1.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"env_logger 0.9.0", "clap",
"env_logger",
"log", "log",
"nom 7.1.0", "nom 7.1.0",
"pdb", "pdb",
"quick-xml", "quick-xml",
"regex", "regex",
"serde", "serde",
"structopt",
] ]
[[package]] [[package]]
@ -3207,42 +3049,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "structopt"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
dependencies = [
"clap 2.34.0",
"lazy_static",
"structopt-derive",
]
[[package]]
name = "structopt-derive"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck 0.3.3",
"proc-macro-error",
"proc-macro2 1.0.47",
"quote 1.0.9",
"syn 1.0.103",
]
[[package]] [[package]]
name = "strum" name = "strum"
version = "0.24.0" version = "0.24.0"
@ -3255,7 +3067,7 @@ version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef" checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef"
dependencies = [ dependencies = [
"heck 0.4.0", "heck",
"proc-macro2 1.0.47", "proc-macro2 1.0.47",
"quote 1.0.9", "quote 1.0.9",
"rustversion", "rustversion",
@ -3298,7 +3110,7 @@ version = "10.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f94766a96b5834eaf72f9cb99a5a45e63fa44f1084705b705d9d31bb6455434" checksum = "8f94766a96b5834eaf72f9cb99a5a45e63fa44f1084705b705d9d31bb6455434"
dependencies = [ dependencies = [
"bitvec 1.0.0", "bitvec",
"dmsort", "dmsort",
"elementtree", "elementtree",
"elsa", "elsa",
@ -3415,21 +3227,6 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.37" version = "1.0.37"
@ -3753,12 +3550,6 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.3" version = "0.9.3"
@ -3905,15 +3696,6 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "which"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "win-util" name = "win-util"
version = "0.1.0" version = "0.1.0"
@ -4119,12 +3901,6 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "wyz"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]] [[package]]
name = "wyz" name = "wyz"
version = "0.5.0" version = "0.5.0"

View File

@ -6,9 +6,9 @@ license = "MIT"
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
clap = { version = "4.1.6", features = ["derive"] }
lazy_static = "1.4" lazy_static = "1.4"
regex = "1.6" regex = "1.6"
structopt = "0.3"
thiserror = "1.0" thiserror = "1.0"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]

View File

@ -4,22 +4,22 @@
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use anyhow::Result; use anyhow::Result;
use structopt::StructOpt; use clap::Parser;
#[derive(Debug, StructOpt)] #[derive(Parser, Debug)]
struct Opt { struct Opt {
#[structopt(min_values = 1)] #[arg(required = true, num_args = 1..)]
argv: Vec<String>, argv: Vec<String>,
#[structopt(short, long)] #[arg(short, long)]
quiet: bool, quiet: bool,
#[structopt(short, long)] #[arg(short, long)]
ld_library_path: Option<String>, ld_library_path: Option<String>,
} }
fn main() -> Result<()> { fn main() -> Result<()> {
let opt = Opt::from_args(); let opt = Opt::parse();
let exe = &opt.argv[0]; let exe = &opt.argv[0];
let mut cmd = Command::new(exe); let mut cmd = Command::new(exe);

View File

@ -10,7 +10,7 @@ license = "MIT"
anyhow = { version = "1.0", features = ["backtrace"] } anyhow = { version = "1.0", features = ["backtrace"] }
async-trait = "0.1" async-trait = "0.1"
downcast-rs = "1.2" downcast-rs = "1.2"
env_logger = "0.9" env_logger = "0.10"
futures = "0.3" futures = "0.3"
log = "0.4" log = "0.4"
onefuzz = { path = "../onefuzz" } onefuzz = { path = "../onefuzz" }
@ -25,7 +25,7 @@ storage-queue = { path = "../storage-queue" }
tokio = { version = "1.24", features = ["full"] } tokio = { version = "1.24", features = ["full"] }
url = { version = "2.3", features = ["serde"] } url = { version = "2.3", features = ["serde"] }
uuid = { version = "0.8", features = ["serde", "v4"] } uuid = { version = "0.8", features = ["serde", "v4"] }
clap = { version = "3.2.4", features = ["derive", "cargo"] } clap = { version = "4", features = ["derive", "cargo"] }
reqwest-retry = { path = "../reqwest-retry" } reqwest-retry = { path = "../reqwest-retry" }
onefuzz-telemetry = { path = "../onefuzz-telemetry" } onefuzz-telemetry = { path = "../onefuzz-telemetry" }
backtrace = "0.3" backtrace = "0.3"

View File

@ -54,20 +54,21 @@ enum Opt {
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
struct RunOpt { struct RunOpt {
#[clap(short, long = "--config", parse(from_os_str))] #[arg(short, long = "config")]
config_path: Option<PathBuf>, config_path: Option<PathBuf>,
/// re-executes as a child process, recording stdout/stderr to files in /// re-executes as a child process, recording stdout/stderr to files in
/// the specified directory /// the specified directory
#[clap(short, long = "--redirect-output", parse(from_os_str))] #[arg(short, long = "redirect-output")]
redirect_output: Option<PathBuf>, redirect_output: Option<PathBuf>,
#[clap(long = "--machine_id")] #[arg(long = "machine_id")]
machine_id: Option<Uuid>, machine_id: Option<Uuid>,
#[clap(long = "--machine_name")] #[arg(long = "machine_name")]
machine_name: Option<String>, machine_name: Option<String>,
#[clap(long = "--reset_lock", takes_value = false, action = ArgAction::SetTrue )] #[arg(long = "reset_lock", action = ArgAction::SetTrue )]
reset_node_lock: bool, reset_node_lock: bool,
} }

View File

@ -15,11 +15,11 @@ arraydeque = "0.5"
async-trait = "0.1" async-trait = "0.1"
atexit = { path = "../atexit" } atexit = { path = "../atexit" }
backoff = { version = "0.4", features = ["tokio"] } backoff = { version = "0.4", features = ["tokio"] }
clap = "2.34" clap = { version = "4", features = ["cargo", "string"] }
cobertura = { path = "../cobertura" } cobertura = { path = "../cobertura" }
coverage = { path = "../coverage" } coverage = { path = "../coverage" }
crossterm = "0.22" crossterm = "0.22"
env_logger = "0.9" env_logger = "0.10"
flume = "0.10" flume = "0.10"
futures = "0.3" futures = "0.3"
hex = "0.4" hex = "0.4"

View File

@ -9,7 +9,7 @@ use crate::local::{
libfuzzer_test_input, radamsa, test_input, tui::TerminalUi, libfuzzer_test_input, radamsa, test_input, tui::TerminalUi,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::{App, Arg, SubCommand}; use clap::{Arg, ArgAction, Command};
use std::str::FromStr; use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
@ -37,17 +37,22 @@ enum Commands {
const TIMEOUT: &str = "timeout"; const TIMEOUT: &str = "timeout";
const TUI: &str = "tui"; const TUI: &str = "tui";
pub async fn run(args: clap::ArgMatches<'static>) -> Result<()> { pub async fn run(args: clap::ArgMatches) -> Result<()> {
let running_duration = value_t!(args, TIMEOUT, u64).ok(); let running_duration = args.get_one::<u64>(TIMEOUT).copied();
let start_ui = args.is_present(TUI);
let (cmd, sub_args) = args.subcommand(); let start_ui = args.get_flag(TUI);
let command =
Commands::from_str(cmd).with_context(|| format!("unexpected subcommand: {cmd}"))?;
let sub_args = sub_args let (cmd, sub_args) = args.subcommand().ok_or_else(|| {
.ok_or_else(|| anyhow!("missing subcommand arguments"))? format_err!(
.to_owned(); "Expected subcommand for 'local'. Use 'local help' to see available subcommands."
)
})?;
let command = Commands::from_str(cmd).with_context(|| {
format!("Unexpected subcommand: {cmd}. Use 'local help' to see available subcommands.")
})?;
let sub_args = sub_args.clone();
let terminal = if start_ui { let terminal = if start_ui {
Some(TerminalUi::init()?) Some(TerminalUi::init()?)
@ -104,20 +109,20 @@ pub async fn run(args: clap::ArgMatches<'static>) -> Result<()> {
} }
} }
pub fn args(name: &str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
let mut cmd = SubCommand::with_name(name) let mut cmd = Command::new(name)
.about("pre-release local fuzzing") .about("pre-release local fuzzing")
.arg( .arg(
Arg::with_name(TIMEOUT) Arg::new(TIMEOUT)
.long(TIMEOUT) .long(TIMEOUT)
.help("The maximum running time in seconds") .value_parser(value_parser!(u64))
.takes_value(true), .help("The maximum running time in seconds"),
) )
.arg( .arg(
Arg::with_name(TUI) Arg::new(TUI)
.long(TUI) .long(TUI)
.help("Enable the terminal UI") .help("Enable the terminal UI")
.takes_value(false), .action(ArgAction::SetTrue),
); );
for subcommand in Commands::iter() { for subcommand in Commands::iter() {

View File

@ -7,7 +7,7 @@ use std::{
use anyhow::Result; use anyhow::Result;
use backoff::{future::retry, Error as BackoffError, ExponentialBackoff}; use backoff::{future::retry, Error as BackoffError, ExponentialBackoff};
use clap::{App, Arg, ArgMatches}; use clap::{Arg, ArgAction, ArgMatches, Command};
use flume::Sender; use flume::Sender;
use onefuzz::{ use onefuzz::{
blob::url::BlobContainerUrl, machine_id::MachineIdentity, monitor::DirectoryMonitor, blob::url::BlobContainerUrl, machine_id::MachineIdentity, monitor::DirectoryMonitor,
@ -76,40 +76,41 @@ pub struct LocalContext {
pub event_sender: Option<Sender<UiEvent>>, pub event_sender: Option<Sender<UiEvent>>,
} }
pub fn get_hash_map(args: &clap::ArgMatches<'_>, name: &str) -> Result<HashMap<String, String>> { pub fn get_hash_map(args: &clap::ArgMatches, name: &str) -> Result<HashMap<String, String>> {
let mut env = HashMap::new(); let mut env = HashMap::new();
for opt in args.values_of_lossy(name).unwrap_or_default() { for opt in args.get_many::<String>(name).unwrap_or_default() {
let (k, v) = parse_key_value(opt)?; let (k, v) = parse_key_value(opt)?;
env.insert(k, v); env.insert(k, v);
} }
Ok(env) Ok(env)
} }
pub fn get_cmd_exe(cmd_type: CmdType, args: &clap::ArgMatches<'_>) -> Result<String> { pub fn get_cmd_exe(cmd_type: CmdType, args: &clap::ArgMatches) -> Result<String> {
let name = match cmd_type { let name = match cmd_type {
CmdType::Target => TARGET_EXE, CmdType::Target => TARGET_EXE,
// CmdType::Supervisor => SUPERVISOR_EXE, // CmdType::Supervisor => SUPERVISOR_EXE,
CmdType::Generator => GENERATOR_EXE, CmdType::Generator => GENERATOR_EXE,
}; };
let exe = value_t!(args, name, String)?; args.get_one::<String>(name)
Ok(exe) .cloned()
.ok_or_else(|| format_err!("missing argument {name}"))
} }
pub fn get_cmd_arg(cmd_type: CmdType, args: &clap::ArgMatches<'_>) -> Vec<String> { pub fn get_cmd_arg(cmd_type: CmdType, args: &clap::ArgMatches) -> Vec<String> {
let name = match cmd_type { let name = match cmd_type {
CmdType::Target => TARGET_OPTIONS, CmdType::Target => TARGET_OPTIONS,
// CmdType::Supervisor => SUPERVISOR_OPTIONS, // CmdType::Supervisor => SUPERVISOR_OPTIONS,
CmdType::Generator => GENERATOR_OPTIONS, CmdType::Generator => GENERATOR_OPTIONS,
}; };
args.values_of_lossy(name).unwrap_or_default() args.get_many::<String>(name)
.unwrap_or_default()
.cloned()
.collect()
} }
pub fn get_cmd_env( pub fn get_cmd_env(cmd_type: CmdType, args: &clap::ArgMatches) -> Result<HashMap<String, String>> {
cmd_type: CmdType,
args: &clap::ArgMatches<'_>,
) -> Result<HashMap<String, String>> {
let env_name = match cmd_type { let env_name = match cmd_type {
CmdType::Target => TARGET_ENV, CmdType::Target => TARGET_ENV,
// CmdType::Supervisor => SUPERVISOR_ENV, // CmdType::Supervisor => SUPERVISOR_ENV,
@ -118,58 +119,58 @@ pub fn get_cmd_env(
get_hash_map(args, env_name) get_hash_map(args, env_name)
} }
pub fn add_common_config(app: App<'static, 'static>) -> App<'static, 'static> { pub fn add_common_config(app: Command) -> Command {
app.arg( app.arg(
Arg::with_name("job_id") Arg::new("job_id")
.long("job_id") .long("job_id")
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(uuid::Uuid)),
) )
.arg( .arg(
Arg::with_name("task_id") Arg::new("task_id")
.long("task_id") .long("task_id")
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(uuid::Uuid)),
) )
.arg( .arg(
Arg::with_name("instance_id") Arg::new("instance_id")
.long("instance_id") .long("instance_id")
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(uuid::Uuid)),
) )
.arg( .arg(
Arg::with_name("setup_dir") Arg::new("setup_dir")
.long("setup_dir") .long("setup_dir")
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(PathBuf)),
) )
.arg( .arg(
Arg::with_name(CREATE_JOB_DIR) Arg::new(CREATE_JOB_DIR)
.long(CREATE_JOB_DIR) .long(CREATE_JOB_DIR)
.action(ArgAction::SetTrue)
.required(false) .required(false)
.help("create a local job directory to sync the files"), .help("create a local job directory to sync the files"),
) )
} }
fn get_uuid(name: &str, args: &ArgMatches<'_>) -> Result<Uuid> { fn get_uuid(name: &str, args: &ArgMatches) -> Result<Uuid> {
value_t!(args, name, String).map(|x| { args.get_one::<Uuid>(name)
Uuid::parse_str(&x).map_err(|x| format_err!("invalid {}. uuid expected. {})", name, x)) .copied()
})? .ok_or_else(|| format_err!("missing argument {name}"))
} }
pub fn get_synced_dirs( pub fn get_synced_dirs(
name: &str, name: &str,
job_id: Uuid, job_id: Uuid,
task_id: Uuid, task_id: Uuid,
args: &ArgMatches<'_>, args: &ArgMatches,
) -> Result<Vec<SyncedDir>> { ) -> Result<Vec<SyncedDir>> {
let create_job_dir = args.is_present(CREATE_JOB_DIR); let create_job_dir = args.get_flag(CREATE_JOB_DIR);
let current_dir = std::env::current_dir()?; let current_dir = std::env::current_dir()?;
args.values_of_os(name) args.get_many::<PathBuf>(name)
.ok_or_else(|| anyhow!("argument '{}' not specified", name))? .ok_or_else(|| anyhow!("argument '{}' not specified", name))?
.enumerate() .enumerate()
.map(|(index, remote_path)| { .map(|(index, path)| {
let path = PathBuf::from(remote_path);
if create_job_dir { if create_job_dir {
let remote_path = path.absolutize()?; let remote_path = path.absolutize()?;
let remote_url = Url::from_file_path(remote_path).expect("invalid file path"); let remote_url = Url::from_file_path(remote_path).expect("invalid file path");
@ -182,7 +183,7 @@ pub fn get_synced_dirs(
} else { } else {
Ok(SyncedDir { Ok(SyncedDir {
remote_path: None, remote_path: None,
local_path: path, local_path: path.clone(),
}) })
} }
}) })
@ -193,10 +194,14 @@ pub fn get_synced_dir(
name: &str, name: &str,
job_id: Uuid, job_id: Uuid,
task_id: Uuid, task_id: Uuid,
args: &ArgMatches<'_>, args: &ArgMatches,
) -> Result<SyncedDir> { ) -> Result<SyncedDir> {
let remote_path = value_t!(args, name, PathBuf)?.absolutize()?.into_owned(); let remote_path = args
if args.is_present(CREATE_JOB_DIR) { .get_one::<PathBuf>(name)
.ok_or_else(|| format_err!("missing argument {name}"))?
.absolutize()?
.into_owned();
if args.get_flag(CREATE_JOB_DIR) {
let remote_url = let remote_url =
Url::from_file_path(remote_path).map_err(|_| anyhow!("invalid file path"))?; Url::from_file_path(remote_path).map_err(|_| anyhow!("invalid file path"))?;
let remote_blob_url = BlobContainerUrl::new(remote_url)?; let remote_blob_url = BlobContainerUrl::new(remote_url)?;
@ -218,11 +223,11 @@ pub fn get_synced_dir(
// enables making the one-shot crash report generation, which isn't really a task, // enables making the one-shot crash report generation, which isn't really a task,
// consistent across multiple runs. // consistent across multiple runs.
pub async fn build_local_context( pub async fn build_local_context(
args: &ArgMatches<'_>, args: &ArgMatches,
generate_task_id: bool, generate_task_id: bool,
event_sender: Option<Sender<UiEvent>>, event_sender: Option<Sender<UiEvent>>,
) -> Result<LocalContext> { ) -> Result<LocalContext> {
let job_id = get_uuid("job_id", args).unwrap_or_else(|_| Uuid::nil()); let job_id = get_uuid("job_id", args).unwrap_or_default();
let task_id = get_uuid("task_id", args).unwrap_or_else(|_| { let task_id = get_uuid("task_id", args).unwrap_or_else(|_| {
if generate_task_id { if generate_task_id {
Uuid::new_v4() Uuid::new_v4()
@ -230,12 +235,12 @@ pub async fn build_local_context(
Uuid::nil() Uuid::nil()
} }
}); });
let instance_id = get_uuid("instance_id", args).unwrap_or_else(|_| Uuid::nil()); let instance_id = get_uuid("instance_id", args).unwrap_or_default();
let setup_dir = if args.is_present(SETUP_DIR) { let setup_dir = if let Some(setup_dir) = args.get_one::<PathBuf>(SETUP_DIR) {
value_t!(args, SETUP_DIR, PathBuf)? setup_dir.clone()
} else if args.is_present(TARGET_EXE) { } else if let Some(target_exe) = args.get_one::<String>(TARGET_EXE) {
value_t!(args, TARGET_EXE, PathBuf)? PathBuf::from(target_exe)
.parent() .parent()
.map(|x| x.to_path_buf()) .map(|x| x.to_path_buf())
.unwrap_or_default() .unwrap_or_default()

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use std::path::PathBuf;
use crate::{ use crate::{
local::common::{ local::common::{
build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir,
@ -13,14 +15,14 @@ use crate::{
}, },
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, ArgAction, Command};
use flume::Sender; use flume::Sender;
use storage_queue::QueueClient; use storage_queue::QueueClient;
use super::common::{SyncCountDirMonitor, UiEvent}; use super::common::{SyncCountDirMonitor, UiEvent};
pub fn build_coverage_config( pub fn build_coverage_config(
args: &clap::ArgMatches<'_>, args: &clap::ArgMatches,
local_job: bool, local_job: bool,
input_queue: Option<QueueClient>, input_queue: Option<QueueClient>,
common: CommonConfig, common: CommonConfig,
@ -29,7 +31,7 @@ pub fn build_coverage_config(
let target_exe = get_cmd_exe(CmdType::Target, args)?.into(); let target_exe = get_cmd_exe(CmdType::Target, args)?.into();
let target_env = get_cmd_env(CmdType::Target, args)?; let target_env = get_cmd_env(CmdType::Target, args)?;
let mut target_options = get_cmd_arg(CmdType::Target, args); let mut target_options = get_cmd_arg(CmdType::Target, args);
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok(); let target_timeout = args.get_one::<u64>(TARGET_TIMEOUT).copied();
let readonly_inputs = if local_job { let readonly_inputs = if local_job {
vec![ vec![
@ -67,7 +69,7 @@ pub fn build_coverage_config(
Ok(config) Ok(config)
} }
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let config = build_coverage_config( let config = build_coverage_config(
args, args,
@ -81,54 +83,47 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
task.run().await task.run().await
} }
pub fn build_shared_args(local_job: bool) -> Vec<Arg<'static, 'static>> { pub fn build_shared_args(local_job: bool) -> Vec<Arg> {
let mut args = vec![ let mut args = vec![
Arg::with_name(TARGET_EXE) Arg::new(TARGET_EXE).long(TARGET_EXE).required(true),
.long(TARGET_EXE) Arg::new(TARGET_ENV).long(TARGET_ENV).num_args(0..),
.takes_value(true) Arg::new(TARGET_OPTIONS)
.required(true),
Arg::with_name(TARGET_ENV)
.long(TARGET_ENV)
.takes_value(true)
.multiple(true),
Arg::with_name(TARGET_OPTIONS)
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.default_value("{input}") .default_value("{input}")
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(TARGET_TIMEOUT) Arg::new(TARGET_TIMEOUT)
.takes_value(true) .value_parser(value_parser!(u64))
.long(TARGET_TIMEOUT), .long(TARGET_TIMEOUT),
Arg::with_name(COVERAGE_DIR) Arg::new(COVERAGE_DIR)
.takes_value(true)
.required(!local_job) .required(!local_job)
.value_parser(value_parser!(PathBuf))
.long(COVERAGE_DIR), .long(COVERAGE_DIR),
Arg::with_name(CHECK_FUZZER_HELP) Arg::new(CHECK_FUZZER_HELP)
.takes_value(false) .action(ArgAction::SetTrue)
.long(CHECK_FUZZER_HELP), .long(CHECK_FUZZER_HELP),
]; ];
if local_job { if local_job {
args.push( args.push(
Arg::with_name(INPUTS_DIR) Arg::new(INPUTS_DIR)
.long(INPUTS_DIR) .long(INPUTS_DIR)
.takes_value(true) .required(true)
.required(true), .value_parser(value_parser!(PathBuf)),
) )
} else { } else {
args.push( args.push(
Arg::with_name(READONLY_INPUTS) Arg::new(READONLY_INPUTS)
.takes_value(true)
.required(true) .required(true)
.long(READONLY_INPUTS) .long(READONLY_INPUTS)
.multiple(true), .value_parser(value_parser!(PathBuf))
.num_args(1..),
) )
} }
args args
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("execute a local-only coverage task") .about("execute a local-only coverage task")
.args(&build_shared_args(false)) .args(&build_shared_args(false))
} }

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use std::path::PathBuf;
use crate::{ use crate::{
local::common::{ local::common::{
build_local_context, get_cmd_arg, get_cmd_exe, get_hash_map, get_synced_dir, CmdType, build_local_context, get_cmd_arg, get_cmd_exe, get_hash_map, get_synced_dir, CmdType,
@ -14,12 +16,12 @@ use crate::{
}, },
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, Command};
use flume::Sender; use flume::Sender;
use storage_queue::QueueClient; use storage_queue::QueueClient;
pub fn build_analysis_config( pub fn build_analysis_config(
args: &clap::ArgMatches<'_>, args: &clap::ArgMatches,
input_queue: Option<QueueClient>, input_queue: Option<QueueClient>,
common: CommonConfig, common: CommonConfig,
event_sender: Option<Sender<UiEvent>>, event_sender: Option<Sender<UiEvent>>,
@ -27,8 +29,17 @@ pub fn build_analysis_config(
let target_exe = get_cmd_exe(CmdType::Target, args)?.into(); let target_exe = get_cmd_exe(CmdType::Target, args)?.into();
let target_options = get_cmd_arg(CmdType::Target, args); let target_options = get_cmd_arg(CmdType::Target, args);
let analyzer_exe = value_t!(args, ANALYZER_EXE, String)?; let analyzer_exe = args
let analyzer_options = args.values_of_lossy(ANALYZER_OPTIONS).unwrap_or_default(); .get_one::<String>(ANALYZER_EXE)
.cloned()
.ok_or_else(|| format_err!("expected {ANALYZER_EXE}"))?;
let analyzer_options = args
.get_many::<String>(ANALYZER_OPTIONS)
.unwrap_or_default()
.map(|x| x.to_string())
.collect();
let analyzer_env = get_hash_map(args, ANALYZER_ENV)?; let analyzer_env = get_hash_map(args, ANALYZER_ENV)?;
let analysis = get_synced_dir(ANALYSIS_DIR, common.job_id, common.task_id, args)? let analysis = get_synced_dir(ANALYSIS_DIR, common.job_id, common.task_id, args)?
.monitor_count(&event_sender)?; .monitor_count(&event_sender)?;
@ -69,61 +80,54 @@ pub fn build_analysis_config(
Ok(config) Ok(config)
} }
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let config = build_analysis_config(args, None, context.common_config.clone(), event_sender)?; let config = build_analysis_config(args, None, context.common_config.clone(), event_sender)?;
run_analysis(config).await run_analysis(config).await
} }
pub fn build_shared_args(required_task: bool) -> Vec<Arg<'static, 'static>> { pub fn build_shared_args(required_task: bool) -> Vec<Arg> {
vec![ vec![
Arg::with_name(TARGET_EXE) Arg::new(TARGET_EXE).long(TARGET_EXE).required(true),
.long(TARGET_EXE) Arg::new(TARGET_ENV)
.takes_value(true)
.required(true),
Arg::with_name(TARGET_ENV)
.long(TARGET_ENV) .long(TARGET_ENV)
.requires(TARGET_EXE) .requires(TARGET_EXE)
.takes_value(true) .num_args(0..),
.multiple(true), Arg::new(TARGET_OPTIONS)
Arg::with_name(TARGET_OPTIONS)
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.takes_value(true)
.default_value("{input}") .default_value("{input}")
.value_delimiter(" ") .value_delimiter(' ')
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(CRASHES_DIR) Arg::new(CRASHES_DIR)
.long(CRASHES_DIR) .long(CRASHES_DIR)
.takes_value(true), .value_parser(value_parser!(PathBuf)),
Arg::with_name(ANALYZER_OPTIONS) Arg::new(ANALYZER_OPTIONS)
.long(ANALYZER_OPTIONS) .long(ANALYZER_OPTIONS)
.requires(ANALYZER_EXE) .requires(ANALYZER_EXE)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(ANALYZER_ENV) Arg::new(ANALYZER_ENV)
.long(ANALYZER_ENV) .long(ANALYZER_ENV)
.requires(ANALYZER_EXE) .requires(ANALYZER_EXE)
.takes_value(true) .num_args(0..),
.multiple(true), Arg::new(TOOLS_DIR)
Arg::with_name(TOOLS_DIR).long(TOOLS_DIR).takes_value(true), .long(TOOLS_DIR)
Arg::with_name(ANALYZER_EXE) .value_parser(value_parser!(PathBuf)),
Arg::new(ANALYZER_EXE)
.long(ANALYZER_EXE) .long(ANALYZER_EXE)
.takes_value(true)
.requires(ANALYSIS_DIR) .requires(ANALYSIS_DIR)
.requires(CRASHES_DIR) .requires(CRASHES_DIR)
.required(required_task), .required(required_task),
Arg::with_name(ANALYSIS_DIR) Arg::new(ANALYSIS_DIR)
.long(ANALYSIS_DIR) .long(ANALYSIS_DIR)
.takes_value(true)
.requires(ANALYZER_EXE) .requires(ANALYZER_EXE)
.requires(CRASHES_DIR) .requires(CRASHES_DIR)
.required(required_task), .required(required_task),
] ]
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("execute a local-only generic analysis") .about("execute a local-only generic analysis")
.args(&build_shared_args(true)) .args(&build_shared_args(true))
} }

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use std::path::PathBuf;
use crate::{ use crate::{
local::common::{ local::common::{
build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType, build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType,
@ -14,12 +16,12 @@ use crate::{
}, },
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, ArgAction, Command};
use flume::Sender; use flume::Sender;
use storage_queue::QueueClient; use storage_queue::QueueClient;
pub fn build_report_config( pub fn build_report_config(
args: &clap::ArgMatches<'_>, args: &clap::ArgMatches,
input_queue: Option<QueueClient>, input_queue: Option<QueueClient>,
common: CommonConfig, common: CommonConfig,
event_sender: Option<Sender<UiEvent>>, event_sender: Option<Sender<UiEvent>>,
@ -50,12 +52,16 @@ pub fn build_report_config(
)?) )?)
.monitor_count(&event_sender)?; .monitor_count(&event_sender)?;
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok(); let target_timeout = args.get_one::<u64>(TARGET_TIMEOUT).copied();
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?; let check_retry_count = args
let check_queue = !args.is_present(DISABLE_CHECK_QUEUE); .get_one::<u64>(CHECK_RETRY_COUNT)
let check_asan_log = args.is_present(CHECK_ASAN_LOG); .copied()
let check_debugger = !args.is_present(DISABLE_CHECK_DEBUGGER); .expect("has a default");
let check_queue = !args.get_flag(DISABLE_CHECK_QUEUE);
let check_asan_log = args.get_flag(CHECK_ASAN_LOG);
let check_debugger = !args.get_flag(DISABLE_CHECK_DEBUGGER);
let config = Config { let config = Config {
target_exe, target_exe,
@ -78,66 +84,59 @@ pub fn build_report_config(
Ok(config) Ok(config)
} }
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let config = build_report_config(args, None, context.common_config.clone(), event_sender)?; let config = build_report_config(args, None, context.common_config.clone(), event_sender)?;
ReportTask::new(config).managed_run().await ReportTask::new(config).managed_run().await
} }
pub fn build_shared_args() -> Vec<Arg<'static, 'static>> { pub fn build_shared_args() -> Vec<Arg> {
vec![ vec![
Arg::with_name(TARGET_EXE) Arg::new(TARGET_EXE).long(TARGET_EXE).required(true),
.long(TARGET_EXE) Arg::new(TARGET_ENV).long(TARGET_ENV).num_args(0..),
.takes_value(true) Arg::new(TARGET_OPTIONS)
.required(true),
Arg::with_name(TARGET_ENV)
.long(TARGET_ENV)
.takes_value(true)
.multiple(true),
Arg::with_name(TARGET_OPTIONS)
.default_value("{input}") .default_value("{input}")
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(CRASHES_DIR) Arg::new(CRASHES_DIR)
.long(CRASHES_DIR) .long(CRASHES_DIR)
.takes_value(true) .required(true)
.required(true), .value_parser(value_parser!(PathBuf)),
Arg::with_name(REPORTS_DIR) Arg::new(REPORTS_DIR)
.long(REPORTS_DIR) .long(REPORTS_DIR)
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(PathBuf)),
Arg::with_name(NO_REPRO_DIR) Arg::new(NO_REPRO_DIR)
.long(NO_REPRO_DIR) .long(NO_REPRO_DIR)
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(PathBuf)),
Arg::with_name(UNIQUE_REPORTS_DIR) Arg::new(UNIQUE_REPORTS_DIR)
.long(UNIQUE_REPORTS_DIR) .long(UNIQUE_REPORTS_DIR)
.takes_value(true) .value_parser(value_parser!(PathBuf))
.required(true), .required(true),
Arg::with_name(TARGET_TIMEOUT) Arg::new(TARGET_TIMEOUT)
.takes_value(true)
.long(TARGET_TIMEOUT) .long(TARGET_TIMEOUT)
.value_parser(value_parser!(u64))
.default_value("30"), .default_value("30"),
Arg::with_name(CHECK_RETRY_COUNT) Arg::new(CHECK_RETRY_COUNT)
.takes_value(true)
.long(CHECK_RETRY_COUNT) .long(CHECK_RETRY_COUNT)
.value_parser(value_parser!(u64))
.default_value("0"), .default_value("0"),
Arg::with_name(DISABLE_CHECK_QUEUE) Arg::new(DISABLE_CHECK_QUEUE)
.takes_value(false) .action(ArgAction::SetTrue)
.long(DISABLE_CHECK_QUEUE), .long(DISABLE_CHECK_QUEUE),
Arg::with_name(CHECK_ASAN_LOG) Arg::new(CHECK_ASAN_LOG)
.takes_value(false) .action(ArgAction::SetTrue)
.long(CHECK_ASAN_LOG), .long(CHECK_ASAN_LOG),
Arg::with_name(DISABLE_CHECK_DEBUGGER) Arg::new(DISABLE_CHECK_DEBUGGER)
.takes_value(false) .action(ArgAction::SetTrue)
.long(DISABLE_CHECK_DEBUGGER), .long(DISABLE_CHECK_DEBUGGER),
] ]
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("execute a local-only generic crash report") .about("execute a local-only generic crash report")
.args(&build_shared_args()) .args(&build_shared_args())
} }

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use std::path::PathBuf;
use crate::{ use crate::{
local::common::{ local::common::{
build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir,
@ -15,11 +17,11 @@ use crate::{
}, },
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, ArgAction, Command};
use flume::Sender; use flume::Sender;
pub fn build_fuzz_config( pub fn build_fuzz_config(
args: &clap::ArgMatches<'_>, args: &clap::ArgMatches,
common: CommonConfig, common: CommonConfig,
event_sender: Option<Sender<UiEvent>>, event_sender: Option<Sender<UiEvent>>,
) -> Result<Config> { ) -> Result<Config> {
@ -37,11 +39,20 @@ pub fn build_fuzz_config(
.map(|sd| sd.monitor_count(&event_sender)) .map(|sd| sd.monitor_count(&event_sender))
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
let rename_output = args.is_present(RENAME_OUTPUT); let rename_output = args.get_flag(RENAME_OUTPUT);
let check_asan_log = args.is_present(CHECK_ASAN_LOG); let check_asan_log = args.get_flag(CHECK_ASAN_LOG);
let check_debugger = !args.is_present(DISABLE_CHECK_DEBUGGER); let check_debugger = !args.get_flag(DISABLE_CHECK_DEBUGGER);
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?;
let target_timeout = Some(value_t!(args, TARGET_TIMEOUT, u64)?); let check_retry_count = args
.get_one::<u64>(CHECK_RETRY_COUNT)
.copied()
.expect("has a default");
let target_timeout = Some(
args.get_one::<u64>(TARGET_TIMEOUT)
.copied()
.expect("has a default"),
);
let tools = get_synced_dir(TOOLS_DIR, common.job_id, common.task_id, args) let tools = get_synced_dir(TOOLS_DIR, common.job_id, common.task_id, args)
.ok() .ok()
@ -71,75 +82,65 @@ pub fn build_fuzz_config(
Ok(config) Ok(config)
} }
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let config = build_fuzz_config(args, context.common_config.clone(), event_sender)?; let config = build_fuzz_config(args, context.common_config.clone(), event_sender)?;
GeneratorTask::new(config).run().await GeneratorTask::new(config).run().await
} }
pub fn build_shared_args() -> Vec<Arg<'static, 'static>> { pub fn build_shared_args() -> Vec<Arg> {
vec![ vec![
Arg::with_name(TARGET_EXE) Arg::new(TARGET_EXE).long(TARGET_EXE).required(true),
.long(TARGET_EXE) Arg::new(TARGET_ENV).long(TARGET_ENV).num_args(0..),
.takes_value(true) Arg::new(TARGET_OPTIONS)
.required(true),
Arg::with_name(TARGET_ENV)
.long(TARGET_ENV)
.takes_value(true)
.multiple(true),
Arg::with_name(TARGET_OPTIONS)
.default_value("{input}") .default_value("{input}")
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(GENERATOR_EXE) Arg::new(GENERATOR_EXE)
.long(GENERATOR_EXE) .long(GENERATOR_EXE)
.default_value("radamsa") .default_value("radamsa")
.takes_value(true)
.required(true), .required(true),
Arg::with_name(GENERATOR_ENV) Arg::new(GENERATOR_ENV).long(GENERATOR_ENV).num_args(0..),
.long(GENERATOR_ENV) Arg::new(GENERATOR_OPTIONS)
.takes_value(true)
.multiple(true),
Arg::with_name(GENERATOR_OPTIONS)
.long(GENERATOR_OPTIONS) .long(GENERATOR_OPTIONS)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.default_value("-H sha256 -o {generated_inputs}/input-%h.%s -n 100 -r {input_corpus}") .default_value("-H sha256 -o {generated_inputs}/input-%h.%s -n 100 -r {input_corpus}")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(CRASHES_DIR) Arg::new(CRASHES_DIR)
.takes_value(true)
.required(true) .required(true)
.long(CRASHES_DIR), .long(CRASHES_DIR)
Arg::with_name(READONLY_INPUTS) .value_parser(value_parser!(PathBuf)),
.takes_value(true) Arg::new(READONLY_INPUTS)
.required(true) .required(true)
.multiple(true) .num_args(1..)
.value_parser(value_parser!(PathBuf))
.long(READONLY_INPUTS), .long(READONLY_INPUTS),
Arg::with_name(TOOLS_DIR).takes_value(true).long(TOOLS_DIR), Arg::new(TOOLS_DIR)
Arg::with_name(CHECK_RETRY_COUNT) .long(TOOLS_DIR)
.takes_value(true) .value_parser(value_parser!(PathBuf)),
Arg::new(CHECK_RETRY_COUNT)
.long(CHECK_RETRY_COUNT) .long(CHECK_RETRY_COUNT)
.value_parser(value_parser!(u64))
.default_value("0"), .default_value("0"),
Arg::with_name(CHECK_ASAN_LOG) Arg::new(CHECK_ASAN_LOG)
.takes_value(false) .action(ArgAction::SetTrue)
.long(CHECK_ASAN_LOG), .long(CHECK_ASAN_LOG),
Arg::with_name(RENAME_OUTPUT) Arg::new(RENAME_OUTPUT)
.takes_value(false) .action(ArgAction::SetTrue)
.long(RENAME_OUTPUT), .long(RENAME_OUTPUT),
Arg::with_name(TARGET_TIMEOUT) Arg::new(TARGET_TIMEOUT)
.takes_value(true)
.long(TARGET_TIMEOUT) .long(TARGET_TIMEOUT)
.value_parser(value_parser!(u64))
.default_value("30"), .default_value("30"),
Arg::with_name(DISABLE_CHECK_DEBUGGER) Arg::new(DISABLE_CHECK_DEBUGGER)
.takes_value(false) .action(ArgAction::SetTrue)
.long(DISABLE_CHECK_DEBUGGER), .long(DISABLE_CHECK_DEBUGGER),
] ]
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("execute a local-only generator fuzzing task") .about("execute a local-only generator fuzzing task")
.args(&build_shared_args()) .args(&build_shared_args())
} }

View File

@ -26,14 +26,14 @@ use crate::{
}, },
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, SubCommand}; use clap::Command;
use flume::Sender; use flume::Sender;
use onefuzz::utils::try_wait_all_join_handles; use onefuzz::utils::try_wait_all_join_handles;
use std::collections::HashSet; use std::collections::HashSet;
use tokio::task::spawn; use tokio::task::spawn;
use uuid::Uuid; use uuid::Uuid;
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let fuzz_config = build_fuzz_config(args, context.common_config.clone(), event_sender.clone())?; let fuzz_config = build_fuzz_config(args, context.common_config.clone(), event_sender.clone())?;
let crash_dir = fuzz_config let crash_dir = fuzz_config
@ -51,7 +51,7 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
task_handles.push(fuzz_task); task_handles.push(fuzz_task);
if args.is_present(UNIQUE_REPORTS_DIR) { if args.contains_id(UNIQUE_REPORTS_DIR) {
let crash_report_input_monitor = let crash_report_input_monitor =
DirectoryMonitorQueue::start_monitoring(crash_dir.clone()).await?; DirectoryMonitorQueue::start_monitoring(crash_dir.clone()).await?;
@ -73,7 +73,7 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
} }
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
if args.is_present(COVERAGE_DIR) { if args.contains_id(COVERAGE_DIR) {
let coverage_input_monitor = let coverage_input_monitor =
DirectoryMonitorQueue::start_monitoring(crash_dir.clone()).await?; DirectoryMonitorQueue::start_monitoring(crash_dir.clone()).await?;
let coverage_config = coverage::build_coverage_config( let coverage_config = coverage::build_coverage_config(
@ -94,7 +94,7 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
task_handles.push(coverage_input_monitor.handle); task_handles.push(coverage_input_monitor.handle);
} }
if args.is_present(ANALYZER_EXE) { if args.contains_id(ANALYZER_EXE) {
let analysis_input_monitor = DirectoryMonitorQueue::start_monitoring(crash_dir).await?; let analysis_input_monitor = DirectoryMonitorQueue::start_monitoring(crash_dir).await?;
let analysis_config = build_analysis_config( let analysis_config = build_analysis_config(
args, args,
@ -111,7 +111,7 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
task_handles.push(analysis_input_monitor.handle); task_handles.push(analysis_input_monitor.handle);
} }
if args.is_present(REGRESSION_REPORTS_DIR) { if args.contains_id(REGRESSION_REPORTS_DIR) {
let regression_config = build_regression_config( let regression_config = build_regression_config(
args, args,
CommonConfig { CommonConfig {
@ -130,12 +130,12 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
Ok(()) Ok(())
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
let mut app = SubCommand::with_name(name).about("run a local libfuzzer & crash reporting task"); let mut app = Command::new(name).about("run a local libfuzzer & crash reporting task");
let mut used = HashSet::new(); let mut used = HashSet::new();
for args in [ for args in &[
build_fuzz_args(), build_fuzz_args(),
build_crash_args(), build_crash_args(),
build_analysis_args(false), build_analysis_args(false),
@ -144,11 +144,9 @@ pub fn args(name: &'static str) -> App<'static, 'static> {
build_regression_args(false), build_regression_args(false),
] { ] {
for arg in args { for arg in args {
if used.contains(arg.b.name) { if used.insert(arg.get_id()) {
continue; app = app.arg(arg);
} }
used.insert(arg.b.name.to_string());
app = app.arg(arg);
} }
} }

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use std::path::PathBuf;
use crate::{ use crate::{
local::common::{ local::common::{
build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType, build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType,
@ -14,12 +16,12 @@ use crate::{
}, },
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, ArgAction, Command};
use flume::Sender; use flume::Sender;
use storage_queue::QueueClient; use storage_queue::QueueClient;
pub fn build_report_config( pub fn build_report_config(
args: &clap::ArgMatches<'_>, args: &clap::ArgMatches,
input_queue: Option<QueueClient>, input_queue: Option<QueueClient>,
common: CommonConfig, common: CommonConfig,
event_sender: Option<Sender<UiEvent>>, event_sender: Option<Sender<UiEvent>>,
@ -43,13 +45,16 @@ pub fn build_report_config(
.ok() .ok()
.monitor_count(&event_sender)?; .monitor_count(&event_sender)?;
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok(); let target_timeout = args.get_one::<u64>(TARGET_TIMEOUT).copied();
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?; let check_retry_count = args
.get_one::<u64>(CHECK_RETRY_COUNT)
.copied()
.expect("has a default");
let check_queue = !args.is_present(DISABLE_CHECK_QUEUE); let check_queue = !args.get_flag(DISABLE_CHECK_QUEUE);
let check_fuzzer_help = args.is_present(CHECK_FUZZER_HELP); let check_fuzzer_help = args.get_flag(CHECK_FUZZER_HELP);
let crashes = if input_queue.is_none() { crashes } else { None }; let crashes = if input_queue.is_none() { crashes } else { None };
@ -73,61 +78,54 @@ pub fn build_report_config(
Ok(config) Ok(config)
} }
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let config = build_report_config(args, None, context.common_config.clone(), event_sender)?; let config = build_report_config(args, None, context.common_config.clone(), event_sender)?;
ReportTask::new(config).managed_run().await ReportTask::new(config).managed_run().await
} }
pub fn build_shared_args() -> Vec<Arg<'static, 'static>> { pub fn build_shared_args() -> Vec<Arg> {
vec![ vec![
Arg::with_name(TARGET_EXE) Arg::new(TARGET_EXE).long(TARGET_EXE).required(true),
.long(TARGET_EXE) Arg::new(TARGET_ENV).long(TARGET_ENV).num_args(0..),
.takes_value(true) Arg::new(TARGET_OPTIONS)
.required(true),
Arg::with_name(TARGET_ENV)
.long(TARGET_ENV)
.takes_value(true)
.multiple(true),
Arg::with_name(TARGET_OPTIONS)
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(CRASHES_DIR) Arg::new(CRASHES_DIR)
.long(CRASHES_DIR) .long(CRASHES_DIR)
.takes_value(true) .required(true)
.required(true), .value_parser(value_parser!(PathBuf)),
Arg::with_name(REPORTS_DIR) Arg::new(REPORTS_DIR)
.long(REPORTS_DIR) .long(REPORTS_DIR)
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(PathBuf)),
Arg::with_name(NO_REPRO_DIR) Arg::new(NO_REPRO_DIR)
.long(NO_REPRO_DIR) .long(NO_REPRO_DIR)
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(PathBuf)),
Arg::with_name(UNIQUE_REPORTS_DIR) Arg::new(UNIQUE_REPORTS_DIR)
.long(UNIQUE_REPORTS_DIR) .long(UNIQUE_REPORTS_DIR)
.takes_value(true) .required(true)
.required(true), .value_parser(value_parser!(PathBuf)),
Arg::with_name(TARGET_TIMEOUT) Arg::new(TARGET_TIMEOUT)
.takes_value(true) .value_parser(value_parser!(u64))
.long(TARGET_TIMEOUT), .long(TARGET_TIMEOUT),
Arg::with_name(CHECK_RETRY_COUNT) Arg::new(CHECK_RETRY_COUNT)
.takes_value(true)
.long(CHECK_RETRY_COUNT) .long(CHECK_RETRY_COUNT)
.value_parser(value_parser!(u64))
.default_value("0"), .default_value("0"),
Arg::with_name(DISABLE_CHECK_QUEUE) Arg::new(DISABLE_CHECK_QUEUE)
.takes_value(false) .action(ArgAction::SetTrue)
.long(DISABLE_CHECK_QUEUE), .long(DISABLE_CHECK_QUEUE),
Arg::with_name(CHECK_FUZZER_HELP) Arg::new(CHECK_FUZZER_HELP)
.takes_value(false) .action(ArgAction::SetTrue)
.long(CHECK_FUZZER_HELP), .long(CHECK_FUZZER_HELP),
] ]
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("execute a local-only libfuzzer crash report task") .about("execute a local-only libfuzzer crash report task")
.args(&build_shared_args()) .args(&build_shared_args())
} }

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use std::path::PathBuf;
use crate::{ use crate::{
local::common::{ local::common::{
build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType, build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType,
@ -13,13 +15,13 @@ use crate::{
}, },
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, ArgAction, Command};
use flume::Sender; use flume::Sender;
const EXPECT_CRASH_ON_FAILURE: &str = "expect_crash_on_failure"; const EXPECT_CRASH_ON_FAILURE: &str = "expect_crash_on_failure";
pub fn build_fuzz_config( pub fn build_fuzz_config(
args: &clap::ArgMatches<'_>, args: &clap::ArgMatches,
common: CommonConfig, common: CommonConfig,
event_sender: Option<Sender<UiEvent>>, event_sender: Option<Sender<UiEvent>>,
) -> Result<Config> { ) -> Result<Config> {
@ -32,10 +34,14 @@ pub fn build_fuzz_config(
let target_env = get_cmd_env(CmdType::Target, args)?; let target_env = get_cmd_env(CmdType::Target, args)?;
let target_options = get_cmd_arg(CmdType::Target, args); let target_options = get_cmd_arg(CmdType::Target, args);
let target_workers = value_t!(args, "target_workers", usize).unwrap_or_default(); let target_workers = args
.get_one::<usize>("target_workers")
.copied()
.unwrap_or_default();
let readonly_inputs = None; let readonly_inputs = None;
let check_fuzzer_help = args.is_present(CHECK_FUZZER_HELP); let check_fuzzer_help = args.get_flag(CHECK_FUZZER_HELP);
let expect_crash_on_failure = args.is_present(EXPECT_CRASH_ON_FAILURE); let expect_crash_on_failure = args.get_flag(EXPECT_CRASH_ON_FAILURE);
let ensemble_sync_delay = None; let ensemble_sync_delay = None;
@ -57,49 +63,42 @@ pub fn build_fuzz_config(
Ok(config) Ok(config)
} }
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let config = build_fuzz_config(args, context.common_config.clone(), event_sender)?; let config = build_fuzz_config(args, context.common_config.clone(), event_sender)?;
LibFuzzerFuzzTask::new(config)?.run().await LibFuzzerFuzzTask::new(config)?.run().await
} }
pub fn build_shared_args() -> Vec<Arg<'static, 'static>> { pub fn build_shared_args() -> Vec<Arg> {
vec![ vec![
Arg::with_name(TARGET_EXE) Arg::new(TARGET_EXE).long(TARGET_EXE).required(true),
.long(TARGET_EXE) Arg::new(TARGET_ENV).long(TARGET_ENV).num_args(0..),
.takes_value(true) Arg::new(TARGET_OPTIONS)
.required(true),
Arg::with_name(TARGET_ENV)
.long(TARGET_ENV)
.takes_value(true)
.multiple(true),
Arg::with_name(TARGET_OPTIONS)
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(INPUTS_DIR) Arg::new(INPUTS_DIR)
.long(INPUTS_DIR) .long(INPUTS_DIR)
.takes_value(true) .required(true)
.required(true), .value_parser(value_parser!(PathBuf)),
Arg::with_name(CRASHES_DIR) Arg::new(CRASHES_DIR)
.long(CRASHES_DIR) .long(CRASHES_DIR)
.takes_value(true) .required(true)
.required(true), .value_parser(value_parser!(PathBuf)),
Arg::with_name(TARGET_WORKERS) Arg::new(TARGET_WORKERS)
.long(TARGET_WORKERS) .long(TARGET_WORKERS)
.takes_value(true), .value_parser(value_parser!(u64)),
Arg::with_name(CHECK_FUZZER_HELP) Arg::new(CHECK_FUZZER_HELP)
.takes_value(false) .action(ArgAction::SetTrue)
.long(CHECK_FUZZER_HELP), .long(CHECK_FUZZER_HELP),
Arg::with_name(EXPECT_CRASH_ON_FAILURE) Arg::new(EXPECT_CRASH_ON_FAILURE)
.takes_value(false) .action(ArgAction::SetTrue)
.long(EXPECT_CRASH_ON_FAILURE), .long(EXPECT_CRASH_ON_FAILURE),
] ]
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("execute a local-only libfuzzer fuzzing task") .about("execute a local-only libfuzzer fuzzing task")
.args(&build_shared_args()) .args(&build_shared_args())
} }

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use std::path::PathBuf;
use crate::{ use crate::{
local::common::{ local::common::{
build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir,
@ -14,12 +16,12 @@ use crate::{
}, },
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, ArgAction, Command};
use flume::Sender; use flume::Sender;
use storage_queue::QueueClient; use storage_queue::QueueClient;
pub fn build_merge_config( pub fn build_merge_config(
args: &clap::ArgMatches<'_>, args: &clap::ArgMatches,
input_queue: Option<QueueClient>, input_queue: Option<QueueClient>,
common: CommonConfig, common: CommonConfig,
event_sender: Option<Sender<UiEvent>>, event_sender: Option<Sender<UiEvent>>,
@ -27,7 +29,7 @@ pub fn build_merge_config(
let target_exe = get_cmd_exe(CmdType::Target, args)?.into(); let target_exe = get_cmd_exe(CmdType::Target, args)?.into();
let target_env = get_cmd_env(CmdType::Target, args)?; let target_env = get_cmd_env(CmdType::Target, args)?;
let target_options = get_cmd_arg(CmdType::Target, args); let target_options = get_cmd_arg(CmdType::Target, args);
let check_fuzzer_help = args.is_present(CHECK_FUZZER_HELP); let check_fuzzer_help = args.get_flag(CHECK_FUZZER_HELP);
let inputs = get_synced_dirs(ANALYSIS_INPUTS, common.job_id, common.task_id, args)? let inputs = get_synced_dirs(ANALYSIS_INPUTS, common.job_id, common.task_id, args)?
.into_iter() .into_iter()
.map(|sd| sd.monitor_count(&event_sender)) .map(|sd| sd.monitor_count(&event_sender))
@ -35,7 +37,10 @@ pub fn build_merge_config(
let unique_inputs = let unique_inputs =
get_synced_dir(ANALYSIS_UNIQUE_INPUTS, common.job_id, common.task_id, args)? get_synced_dir(ANALYSIS_UNIQUE_INPUTS, common.job_id, common.task_id, args)?
.monitor_count(&event_sender)?; .monitor_count(&event_sender)?;
let preserve_existing_outputs = value_t!(args, PRESERVE_EXISTING_OUTPUTS, bool)?; let preserve_existing_outputs = args
.get_one::<bool>(PRESERVE_EXISTING_OUTPUTS)
.copied()
.unwrap_or_default();
let config = Config { let config = Config {
target_exe, target_exe,
@ -52,39 +57,32 @@ pub fn build_merge_config(
Ok(config) Ok(config)
} }
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let config = build_merge_config(args, None, context.common_config.clone(), event_sender)?; let config = build_merge_config(args, None, context.common_config.clone(), event_sender)?;
spawn(std::sync::Arc::new(config)).await spawn(std::sync::Arc::new(config)).await
} }
pub fn build_shared_args() -> Vec<Arg<'static, 'static>> { pub fn build_shared_args() -> Vec<Arg> {
vec![ vec![
Arg::with_name(TARGET_EXE) Arg::new(TARGET_EXE).long(TARGET_EXE).required(true),
.long(TARGET_EXE) Arg::new(TARGET_ENV).long(TARGET_ENV).num_args(0..),
.takes_value(true) Arg::new(TARGET_OPTIONS)
.required(true),
Arg::with_name(TARGET_ENV)
.long(TARGET_ENV)
.takes_value(true)
.multiple(true),
Arg::with_name(TARGET_OPTIONS)
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(CHECK_FUZZER_HELP) Arg::new(CHECK_FUZZER_HELP)
.takes_value(false) .action(ArgAction::SetTrue)
.long(CHECK_FUZZER_HELP), .long(CHECK_FUZZER_HELP),
Arg::with_name(INPUTS_DIR) Arg::new(INPUTS_DIR)
.long(INPUTS_DIR) .long(INPUTS_DIR)
.takes_value(true) .value_parser(value_parser!(PathBuf))
.multiple(true), .num_args(0..),
] ]
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("execute a local-only libfuzzer crash report task") .about("execute a local-only libfuzzer crash report task")
.args(&build_shared_args()) .args(&build_shared_args())
} }

View File

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use std::path::PathBuf;
use crate::{ use crate::{
local::common::{ local::common::{
build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType, build_local_context, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType,
@ -14,26 +16,29 @@ use crate::{
}, },
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, ArgAction, Command};
use flume::Sender; use flume::Sender;
const REPORT_NAMES: &str = "report_names"; const REPORT_NAMES: &str = "report_names";
pub fn build_regression_config( pub fn build_regression_config(
args: &clap::ArgMatches<'_>, args: &clap::ArgMatches,
common: CommonConfig, common: CommonConfig,
event_sender: Option<Sender<UiEvent>>, event_sender: Option<Sender<UiEvent>>,
) -> Result<Config> { ) -> Result<Config> {
let target_exe = get_cmd_exe(CmdType::Target, args)?.into(); let target_exe = get_cmd_exe(CmdType::Target, args)?.into();
let target_env = get_cmd_env(CmdType::Target, args)?; let target_env = get_cmd_env(CmdType::Target, args)?;
let target_options = get_cmd_arg(CmdType::Target, args); let target_options = get_cmd_arg(CmdType::Target, args);
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok(); let target_timeout = args.get_one::<u64>(TARGET_TIMEOUT).copied();
let crashes = get_synced_dir(CRASHES_DIR, common.job_id, common.task_id, args)? let crashes = get_synced_dir(CRASHES_DIR, common.job_id, common.task_id, args)?
.monitor_count(&event_sender)?; .monitor_count(&event_sender)?;
let regression_reports = let regression_reports =
get_synced_dir(REGRESSION_REPORTS_DIR, common.job_id, common.task_id, args)? get_synced_dir(REGRESSION_REPORTS_DIR, common.job_id, common.task_id, args)?
.monitor_count(&event_sender)?; .monitor_count(&event_sender)?;
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?; let check_retry_count = args
.get_one::<u64>(CHECK_RETRY_COUNT)
.copied()
.expect("has a default value");
let reports = get_synced_dir(REPORTS_DIR, common.job_id, common.task_id, args) let reports = get_synced_dir(REPORTS_DIR, common.job_id, common.task_id, args)
.ok() .ok()
@ -45,13 +50,11 @@ pub fn build_regression_config(
.ok() .ok()
.monitor_count(&event_sender)?; .monitor_count(&event_sender)?;
let report_list = if args.is_present(REPORT_NAMES) { let report_list: Option<Vec<String>> = args
Some(values_t!(args, REPORT_NAMES, String)?) .get_many::<String>(REPORT_NAMES)
} else { .map(|x| x.cloned().collect());
None
};
let check_fuzzer_help = args.is_present(CHECK_FUZZER_HELP); let check_fuzzer_help = args.get_flag(CHECK_FUZZER_HELP);
let config = Config { let config = Config {
target_exe, target_exe,
@ -73,75 +76,63 @@ pub fn build_regression_config(
Ok(config) Ok(config)
} }
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let config = build_regression_config(args, context.common_config.clone(), event_sender)?; let config = build_regression_config(args, context.common_config.clone(), event_sender)?;
LibFuzzerRegressionTask::new(config).run().await LibFuzzerRegressionTask::new(config).run().await
} }
pub fn build_shared_args(local_job: bool) -> Vec<Arg<'static, 'static>> { pub fn build_shared_args(local_job: bool) -> Vec<Arg> {
let mut args = vec![ let mut args = vec![
Arg::with_name(TARGET_EXE) Arg::new(TARGET_EXE).long(TARGET_EXE).required(true),
.long(TARGET_EXE) Arg::new(TARGET_ENV).long(TARGET_ENV).num_args(0..),
.takes_value(true) Arg::new(TARGET_OPTIONS)
.required(true),
Arg::with_name(TARGET_ENV)
.long(TARGET_ENV)
.takes_value(true)
.multiple(true),
Arg::with_name(TARGET_OPTIONS)
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(COVERAGE_DIR) Arg::new(COVERAGE_DIR)
.takes_value(true)
.required(!local_job) .required(!local_job)
.long(COVERAGE_DIR), .long(COVERAGE_DIR)
Arg::with_name(CHECK_FUZZER_HELP) .value_parser(value_parser!(PathBuf)),
.takes_value(false) Arg::new(CHECK_FUZZER_HELP)
.action(ArgAction::SetTrue)
.long(CHECK_FUZZER_HELP), .long(CHECK_FUZZER_HELP),
Arg::with_name(TARGET_TIMEOUT) Arg::new(TARGET_TIMEOUT)
.takes_value(true) .long(TARGET_TIMEOUT)
.long(TARGET_TIMEOUT), .value_parser(value_parser!(u64)),
Arg::with_name(CRASHES_DIR) Arg::new(CRASHES_DIR)
.long(CRASHES_DIR) .long(CRASHES_DIR)
.takes_value(true) .required(true)
.required(true), .value_parser(value_parser!(PathBuf)),
Arg::with_name(REGRESSION_REPORTS_DIR) Arg::new(REGRESSION_REPORTS_DIR)
.long(REGRESSION_REPORTS_DIR) .long(REGRESSION_REPORTS_DIR)
.takes_value(true) .required(local_job)
.required(local_job), .value_parser(value_parser!(PathBuf)),
Arg::with_name(REPORTS_DIR) Arg::new(REPORTS_DIR)
.long(REPORTS_DIR) .long(REPORTS_DIR)
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(PathBuf)),
Arg::with_name(NO_REPRO_DIR) Arg::new(NO_REPRO_DIR)
.long(NO_REPRO_DIR) .long(NO_REPRO_DIR)
.takes_value(true) .required(false)
.required(false), .value_parser(value_parser!(PathBuf)),
Arg::with_name(UNIQUE_REPORTS_DIR) Arg::new(UNIQUE_REPORTS_DIR)
.long(UNIQUE_REPORTS_DIR) .long(UNIQUE_REPORTS_DIR)
.takes_value(true) .value_parser(value_parser!(PathBuf))
.required(true), .required(true),
Arg::with_name(CHECK_RETRY_COUNT) Arg::new(CHECK_RETRY_COUNT)
.takes_value(true)
.long(CHECK_RETRY_COUNT) .long(CHECK_RETRY_COUNT)
.value_parser(value_parser!(u64))
.default_value("0"), .default_value("0"),
]; ];
if local_job { if local_job {
args.push( args.push(Arg::new(REPORT_NAMES).long(REPORT_NAMES).num_args(0..))
Arg::with_name(REPORT_NAMES)
.long(REPORT_NAMES)
.takes_value(true)
.multiple(true),
)
} }
args args
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("execute a local-only libfuzzer regression task") .about("execute a local-only libfuzzer regression task")
.args(&build_shared_args(false)) .args(&build_shared_args(true))
} }

View File

@ -9,19 +9,26 @@ use crate::{
tasks::report::libfuzzer_report::{test_input, TestInputArgs}, tasks::report::libfuzzer_report::{test_input, TestInputArgs},
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, Command};
use flume::Sender; use flume::Sender;
use std::path::PathBuf; use std::path::PathBuf;
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender).await?; let context = build_local_context(args, true, event_sender).await?;
let target_exe = value_t!(args, TARGET_EXE, PathBuf)?; let target_exe = args
.get_one::<PathBuf>(TARGET_EXE)
.expect("marked as required");
let target_env = get_cmd_env(CmdType::Target, args)?; let target_env = get_cmd_env(CmdType::Target, args)?;
let target_options = get_cmd_arg(CmdType::Target, args); let target_options = get_cmd_arg(CmdType::Target, args);
let input = value_t!(args, "input", PathBuf)?; let input = args
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok(); .get_one::<PathBuf>("input")
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?; .expect("marked as required");
let target_timeout = args.get_one::<u64>(TARGET_TIMEOUT).copied();
let check_retry_count = args
.get_one::<u64>(CHECK_RETRY_COUNT)
.copied()
.expect("has a default value");
let config = TestInputArgs { let config = TestInputArgs {
target_exe: target_exe.as_path(), target_exe: target_exe.as_path(),
@ -43,32 +50,30 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
Ok(()) Ok(())
} }
pub fn build_shared_args() -> Vec<Arg<'static, 'static>> { pub fn build_shared_args() -> Vec<Arg> {
vec![ vec![
Arg::with_name(TARGET_EXE).takes_value(true).required(true), Arg::new(TARGET_EXE).required(true),
Arg::with_name("input").takes_value(true).required(true), Arg::new("input")
Arg::with_name(TARGET_ENV) .required(true)
.long(TARGET_ENV) .value_parser(value_parser!(PathBuf)),
.takes_value(true) Arg::new(TARGET_ENV).long(TARGET_ENV).num_args(0..),
.multiple(true), Arg::new(TARGET_OPTIONS)
Arg::with_name(TARGET_OPTIONS)
.default_value("{input}") .default_value("{input}")
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(TARGET_TIMEOUT) Arg::new(TARGET_TIMEOUT)
.takes_value(true) .long(TARGET_TIMEOUT)
.long(TARGET_TIMEOUT), .value_parser(value_parser!(u64)),
Arg::with_name(CHECK_RETRY_COUNT) Arg::new(CHECK_RETRY_COUNT)
.takes_value(true)
.long(CHECK_RETRY_COUNT) .long(CHECK_RETRY_COUNT)
.value_parser(value_parser!(u64))
.default_value("0"), .default_value("0"),
] ]
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("test a libfuzzer application with a specific input") .about("test a libfuzzer application with a specific input")
.args(&build_shared_args()) .args(&build_shared_args())
} }

View File

@ -10,14 +10,14 @@ use crate::{
tasks::{config::CommonConfig, fuzz::generator::GeneratorTask, report::generic::ReportTask}, tasks::{config::CommonConfig, fuzz::generator::GeneratorTask, report::generic::ReportTask},
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::{App, SubCommand}; use clap::Command;
use flume::Sender; use flume::Sender;
use onefuzz::utils::try_wait_all_join_handles; use onefuzz::utils::try_wait_all_join_handles;
use std::collections::HashSet; use std::collections::HashSet;
use tokio::task::spawn; use tokio::task::spawn;
use uuid::Uuid; use uuid::Uuid;
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, true, event_sender.clone()).await?; let context = build_local_context(args, true, event_sender.clone()).await?;
let fuzz_config = build_fuzz_config(args, context.common_config.clone(), event_sender.clone())?; let fuzz_config = build_fuzz_config(args, context.common_config.clone(), event_sender.clone())?;
let crash_dir = fuzz_config let crash_dir = fuzz_config
@ -62,17 +62,15 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
Ok(()) Ok(())
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
let mut app = SubCommand::with_name(name).about("run a local generator & crash reporting job"); let mut app = Command::new(name).about("run a local generator & crash reporting job");
let mut used = HashSet::new(); let mut used = HashSet::new();
for args in [build_fuzz_args(), build_crash_args()] { for args in &[build_fuzz_args(), build_crash_args()] {
for arg in args { for arg in args {
if used.contains(arg.b.name) { if used.insert(arg.get_id()) {
continue; app = app.arg(arg);
} }
used.insert(arg.b.name.to_string());
app = app.arg(arg);
} }
} }

View File

@ -10,21 +10,28 @@ use crate::{
tasks::report::generic::{test_input, TestInputArgs}, tasks::report::generic::{test_input, TestInputArgs},
}; };
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, ArgAction, Command};
use flume::Sender; use flume::Sender;
use std::path::PathBuf; use std::path::PathBuf;
pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEvent>>) -> Result<()> { pub async fn run(args: &clap::ArgMatches, event_sender: Option<Sender<UiEvent>>) -> Result<()> {
let context = build_local_context(args, false, event_sender).await?; let context = build_local_context(args, false, event_sender).await?;
let target_exe = value_t!(args, TARGET_EXE, PathBuf)?; let target_exe = args
.get_one::<PathBuf>(TARGET_EXE)
.expect("is marked required");
let target_env = get_cmd_env(CmdType::Target, args)?; let target_env = get_cmd_env(CmdType::Target, args)?;
let target_options = get_cmd_arg(CmdType::Target, args); let target_options = get_cmd_arg(CmdType::Target, args);
let input = value_t!(args, "input", PathBuf)?; let input = args
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok(); .get_one::<PathBuf>("input")
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?; .expect("is marked required");
let check_asan_log = args.is_present(CHECK_ASAN_LOG); let target_timeout = args.get_one::<u64>(TARGET_TIMEOUT).copied();
let check_debugger = !args.is_present(DISABLE_CHECK_DEBUGGER); let check_retry_count = args
.get_one::<u64>(CHECK_RETRY_COUNT)
.copied()
.expect("has default value");
let check_asan_log = args.get_flag(CHECK_ASAN_LOG);
let check_debugger = !args.get_flag(DISABLE_CHECK_DEBUGGER);
let config = TestInputArgs { let config = TestInputArgs {
target_exe: target_exe.as_path(), target_exe: target_exe.as_path(),
@ -48,38 +55,36 @@ pub async fn run(args: &clap::ArgMatches<'_>, event_sender: Option<Sender<UiEven
Ok(()) Ok(())
} }
pub fn build_shared_args() -> Vec<Arg<'static, 'static>> { pub fn build_shared_args() -> Vec<Arg> {
vec![ vec![
Arg::with_name(TARGET_EXE).takes_value(true).required(true), Arg::new(TARGET_EXE).required(true),
Arg::with_name("input").takes_value(true).required(true), Arg::new("input")
Arg::with_name(TARGET_ENV) .required(true)
.long(TARGET_ENV) .value_parser(value_parser!(PathBuf)),
.takes_value(true) Arg::new(TARGET_ENV).long(TARGET_ENV).num_args(0..),
.multiple(true), Arg::new(TARGET_OPTIONS)
Arg::with_name(TARGET_OPTIONS)
.default_value("{input}") .default_value("{input}")
.long(TARGET_OPTIONS) .long(TARGET_OPTIONS)
.takes_value(true) .value_delimiter(' ')
.value_delimiter(" ")
.help("Use a quoted string with space separation to denote multiple arguments"), .help("Use a quoted string with space separation to denote multiple arguments"),
Arg::with_name(TARGET_TIMEOUT) Arg::new(TARGET_TIMEOUT)
.takes_value(true) .long(TARGET_TIMEOUT)
.long(TARGET_TIMEOUT), .value_parser(value_parser!(u64)),
Arg::with_name(CHECK_RETRY_COUNT) Arg::new(CHECK_RETRY_COUNT)
.takes_value(true)
.long(CHECK_RETRY_COUNT) .long(CHECK_RETRY_COUNT)
.value_parser(value_parser!(u64))
.default_value("0"), .default_value("0"),
Arg::with_name(CHECK_ASAN_LOG) Arg::new(CHECK_ASAN_LOG)
.takes_value(false) .action(ArgAction::SetTrue)
.long(CHECK_ASAN_LOG), .long(CHECK_ASAN_LOG),
Arg::with_name(DISABLE_CHECK_DEBUGGER) Arg::new(DISABLE_CHECK_DEBUGGER)
.takes_value(false) .action(ArgAction::SetTrue)
.long("disable_check_debugger"), .long("disable_check_debugger"),
] ]
} }
pub fn args(name: &'static str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("test an application with a specific input") .about("test an application with a specific input")
.args(&build_shared_args()) .args(&build_shared_args())
} }

View File

@ -10,7 +10,7 @@ extern crate onefuzz_telemetry;
extern crate onefuzz; extern crate onefuzz;
use anyhow::Result; use anyhow::Result;
use clap::{App, ArgMatches, SubCommand}; use clap::{ArgMatches, Command};
use std::io::{stdout, Write}; use std::io::{stdout, Write};
mod local; mod local;
@ -29,11 +29,11 @@ fn main() -> Result<()> {
env!("GIT_VERSION") env!("GIT_VERSION")
); );
let app = App::new("onefuzz-task") let app = Command::new("onefuzz-task")
.version(built_version.as_str()) .version(built_version)
.subcommand(managed::cmd::args(MANAGED_CMD)) .subcommand(managed::cmd::args(MANAGED_CMD))
.subcommand(local::cmd::args(LOCAL_CMD)) .subcommand(local::cmd::args(LOCAL_CMD))
.subcommand(SubCommand::with_name(LICENSE_CMD).about("display third-party licenses")); .subcommand(Command::new(LICENSE_CMD).about("display third-party licenses"));
let matches = app.get_matches(); let matches = app.get_matches();
@ -43,7 +43,7 @@ fn main() -> Result<()> {
result result
} }
async fn run(args: ArgMatches<'static>) -> Result<()> { async fn run(args: ArgMatches) -> Result<()> {
// It'd be best to initialize these environment vars in the same abstraction that // It'd be best to initialize these environment vars in the same abstraction that
// pulls in user-provided task vars that set the environment, e.g. `target_env`. // pulls in user-provided task vars that set the environment, e.g. `target_env`.
// For now, just ensure that sanitizer environment vars will be inherited by child // For now, just ensure that sanitizer environment vars will be inherited by child
@ -51,12 +51,10 @@ async fn run(args: ArgMatches<'static>) -> Result<()> {
set_sanitizer_env_vars()?; set_sanitizer_env_vars()?;
match args.subcommand() { match args.subcommand() {
(LICENSE_CMD, Some(_)) => licenses(), Some((LICENSE_CMD, _)) => licenses(),
(LOCAL_CMD, Some(sub)) => local::cmd::run(sub.to_owned()).await, Some((LOCAL_CMD, sub)) => local::cmd::run(sub.to_owned()).await,
(MANAGED_CMD, Some(sub)) => managed::cmd::run(sub).await, Some((MANAGED_CMD, sub)) => managed::cmd::run(sub).await,
_ => { _ => anyhow::bail!("No command provided. Run with 'help' to see available commands."),
anyhow::bail!("missing subcommand\nUSAGE: {}", args.usage());
}
} }
} }

View File

@ -3,7 +3,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use clap::{App, Arg, SubCommand}; use clap::{Arg, Command};
use std::time::Duration; use std::time::Duration;
use crate::tasks::{ use crate::tasks::{
@ -13,10 +13,17 @@ use crate::tasks::{
const OOM_CHECK_INTERVAL: Duration = Duration::from_secs(5); const OOM_CHECK_INTERVAL: Duration = Duration::from_secs(5);
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> { pub async fn run(args: &clap::ArgMatches) -> Result<()> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
let config_path = value_t!(args, "config", PathBuf)?;
let setup_dir = value_t!(args, "setup_dir", PathBuf)?; let config_path = args
.get_one::<PathBuf>("config")
.expect("marked as required");
let setup_dir = args
.get_one::<PathBuf>("setup_dir")
.expect("marked as required");
let config = Config::from_file(config_path, setup_dir)?; let config = Config::from_file(config_path, setup_dir)?;
init_telemetry(config.common()).await; init_telemetry(config.common()).await;
@ -118,9 +125,17 @@ async fn init_telemetry(config: &CommonConfig) {
.await; .await;
} }
pub fn args(name: &str) -> App<'static, 'static> { pub fn args(name: &'static str) -> Command {
SubCommand::with_name(name) Command::new(name)
.about("managed fuzzing") .about("managed fuzzing")
.arg(Arg::with_name("config").required(true)) .arg(
.arg(Arg::with_name("setup_dir").required(true)) Arg::new("config")
.required(true)
.value_parser(value_parser!(PathBuf)),
)
.arg(
Arg::new("setup_dir")
.required(true)
.value_parser(value_parser!(PathBuf)),
)
} }

View File

@ -17,7 +17,11 @@ use onefuzz_telemetry::{
}; };
use reqwest::Url; use reqwest::Url;
use serde::{self, Deserialize}; use serde::{self, Deserialize};
use std::{path::PathBuf, sync::Arc, time::Duration}; use std::{
path::{Path, PathBuf},
sync::Arc,
time::Duration,
};
use uuid::Uuid; use uuid::Uuid;
const DEFAULT_MIN_AVAILABLE_MEMORY_MB: u64 = 100; const DEFAULT_MIN_AVAILABLE_MEMORY_MB: u64 = 100;
@ -135,13 +139,13 @@ pub enum Config {
} }
impl Config { impl Config {
pub fn from_file(path: PathBuf, setup_dir: PathBuf) -> Result<Self> { pub fn from_file(path: &Path, setup_dir: &Path) -> Result<Self> {
let json = std::fs::read_to_string(path)?; let json = std::fs::read_to_string(path)?;
let json_config: serde_json::Value = serde_json::from_str(&json)?; let json_config: serde_json::Value = serde_json::from_str(&json)?;
// override the setup_dir in the config file with the parameter value if specified // override the setup_dir in the config file with the parameter value if specified
let mut config: Self = serde_json::from_value(json_config)?; let mut config: Self = serde_json::from_value(json_config)?;
config.common_mut().setup_dir = setup_dir; config.common_mut().setup_dir = setup_dir.to_owned();
Ok(config) Ok(config)
} }

View File

@ -85,7 +85,7 @@ impl CheckNotify for tokio::sync::Notify {
} }
} }
pub fn parse_key_value(value: String) -> Result<(String, String)> { pub fn parse_key_value(value: &str) -> Result<(String, String)> {
let offset = value let offset = value
.find('=') .find('=')
.ok_or_else(|| format_err!("invalid key=value, no = found {:?}", value))?; .ok_or_else(|| format_err!("invalid key=value, no = found {:?}", value))?;

View File

@ -60,8 +60,8 @@ nix = "0.25"
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]
pete = "0.9" pete = "0.9"
rstack = "0.3" rstack = "0.3"
proc-maps = "0.2" proc-maps = { version = "0.3", default-features = false }
[dev-dependencies] [dev-dependencies]
structopt = "0.3" clap = { version = "4.1.6", features = ["derive"] }
pretty_assertions = "1.3.0" pretty_assertions = "1.3.0"

View File

@ -2,18 +2,18 @@
// Licensed under the MIT License. // Licensed under the MIT License.
use anyhow::Result; use anyhow::Result;
use clap::Parser;
use onefuzz::monitor::DirectoryMonitor; use onefuzz::monitor::DirectoryMonitor;
use structopt::StructOpt;
#[derive(Debug, StructOpt)] #[derive(Debug, Parser)]
struct Opt { struct Opt {
#[structopt(short, long)] #[arg(short, long)]
path: String, path: String,
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let opt = Opt::from_args(); let opt = Opt::parse();
let mut monitor = DirectoryMonitor::new(opt.path).await?; let mut monitor = DirectoryMonitor::new(opt.path).await?;
monitor.set_report_directories(true); monitor.set_report_directories(true);

View File

@ -4,40 +4,40 @@
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use clap::Parser;
use onefuzz::{input_tester::Tester, machine_id::MachineIdentity}; use onefuzz::{input_tester::Tester, machine_id::MachineIdentity};
use structopt::StructOpt;
#[derive(Debug, PartialEq, Eq, StructOpt)] #[derive(Debug, PartialEq, Eq, Parser)]
#[structopt(name = "test-input")] #[command(name = "test-input")]
struct Opt { struct Opt {
#[structopt(short, long)] #[arg(short, long)]
pub exe: PathBuf, pub exe: PathBuf,
#[structopt(short, long, long_help = "Defaults to `{input}`")] #[arg(short, long, long_help = "Defaults to `{input}`")]
pub options: Vec<String>, pub options: Vec<String>,
#[structopt(short, long, long_help = "Defaults to dir of `exe`")] #[arg(short, long, long_help = "Defaults to dir of `exe`")]
pub setup_dir: Option<PathBuf>, pub setup_dir: Option<PathBuf>,
#[structopt(short, long)] #[arg(short, long)]
pub input: PathBuf, pub input: PathBuf,
#[structopt(long)] #[arg(long)]
pub check_asan_log: bool, pub check_asan_log: bool,
#[structopt(long)] #[arg(long)]
pub check_asan_stderr: bool, pub check_asan_stderr: bool,
#[structopt(long)] #[arg(long)]
pub no_check_debugger: bool, pub no_check_debugger: bool,
#[structopt(short, long, long_help = "Timeout (seconds)", default_value = "5")] #[arg(short, long, long_help = "Timeout (seconds)", default_value = "5")]
pub timeout: u64, pub timeout: u64,
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let opt = Opt::from_args(); let opt = Opt::parse();
// Default `setup_dir` to base dir of // Default `setup_dir` to base dir of
let setup_dir = opt.setup_dir.clone().unwrap_or_else(|| { let setup_dir = opt.setup_dir.clone().unwrap_or_else(|| {

View File

@ -17,5 +17,5 @@ regex = "1"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
quick-xml = "0.27" quick-xml = "0.27"
anyhow = "1.0" anyhow = "1.0"
structopt = "0.3" env_logger = "0.10"
env_logger = "0.9" clap = { version = "4.1.6", features = ["derive"] }

View File

@ -2,13 +2,13 @@
// Licensed under the MIT License. // Licensed under the MIT License.
use anyhow::{format_err, Context, Result}; use anyhow::{format_err, Context, Result};
use clap::Parser;
use srcview::{ModOff, Report, SrcLine, SrcView}; use srcview::{ModOff, Report, SrcLine, SrcView};
use std::fs::{self, OpenOptions}; use std::fs::{self, OpenOptions};
use std::io::{stdout, BufWriter, Write}; use std::io::{stdout, BufWriter, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use structopt::StructOpt;
#[derive(StructOpt, Debug)] #[derive(Parser, Debug)]
enum Opt { enum Opt {
Srcloc(SrcLocOpt), Srcloc(SrcLocOpt),
PdbPaths(PdbPathsOpt), PdbPaths(PdbPathsOpt),
@ -18,17 +18,17 @@ enum Opt {
} }
/// Print the file paths in the provided PDB /// Print the file paths in the provided PDB
#[derive(StructOpt, Debug)] #[derive(Parser, Debug)]
struct PdbPathsOpt { struct PdbPathsOpt {
pdb_path: PathBuf, pdb_path: PathBuf,
} }
/// Print modoffset file with file and source lines /// Print modoffset file with file and source lines
#[derive(StructOpt, Debug)] #[derive(Parser, Debug)]
struct SrcLocOpt { struct SrcLocOpt {
pdb_path: PathBuf, pdb_path: PathBuf,
modoff_path: PathBuf, modoff_path: PathBuf,
#[structopt(long)] #[arg(long)]
module_name: Option<String>, module_name: Option<String>,
} }
@ -45,30 +45,30 @@ struct SrcLocOpt {
/// ///
/// The XML report is written to either a file or stdout if the argument is /// The XML report is written to either a file or stdout if the argument is
/// a single dash. /// a single dash.
#[derive(StructOpt, Debug)] #[derive(Parser, Debug)]
struct CoberturaOpt { struct CoberturaOpt {
pdb_path: PathBuf, pdb_path: PathBuf,
modoff_path: PathBuf, modoff_path: PathBuf,
#[structopt(default_value = "-")] #[arg(default_value = "-")]
output_path: String, output_path: String,
#[structopt(long)] #[arg(long)]
module_name: Option<String>, module_name: Option<String>,
/// regular expression that will be applied against the file paths from the /// regular expression that will be applied against the file paths from the
/// srcview /// srcview
#[structopt(long)] #[arg(long)]
include_regex: Option<String>, include_regex: Option<String>,
/// search and replace regular expression that is applied to all file /// search and replace regular expression that is applied to all file
/// paths that will appear in the output report /// paths that will appear in the output report
#[structopt(long)] #[arg(long)]
filter_regex: Option<String>, filter_regex: Option<String>,
} }
fn main() -> Result<()> { fn main() -> Result<()> {
env_logger::init(); env_logger::init();
let opt = Opt::from_args(); let opt = Opt::parse();
match opt { match opt {
Opt::Srcloc(opts) => srcloc(opts)?, Opt::Srcloc(opts) => srcloc(opts)?,

View File

@ -16,8 +16,6 @@ unsound = "deny"
yanked = "deny" yanked = "deny"
ignore = [ ignore = [
"RUSTSEC-2022-0048", # xml-rs is unmaintained "RUSTSEC-2022-0048", # xml-rs is unmaintained
"RUSTSEC-2021-0139", # ansi_term is unmaintained
"RUSTSEC-2021-0145", # waiting for clap upgrade; we are unaffected by the bug (no custom allocator)
] ]
[bans] [bans]

View File

@ -51,17 +51,6 @@ dependencies = [
"syn 1.0.76", "syn 1.0.76",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -145,13 +134,13 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.0.26" version = "4.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
dependencies = [ dependencies = [
"atty",
"bitflags", "bitflags",
"clap_lex", "clap_lex",
"is-terminal",
"once_cell", "once_cell",
"strsim", "strsim",
"termcolor", "termcolor",
@ -230,17 +219,38 @@ dependencies = [
[[package]] [[package]]
name = "env_logger" name = "env_logger"
version = "0.9.0" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [ dependencies = [
"atty",
"humantime", "humantime",
"is-terminal",
"log", "log",
"regex", "regex",
"termcolor", "termcolor",
] ]
[[package]]
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]] [[package]]
name = "flume" name = "flume"
version = "0.10.9" version = "0.10.9"
@ -418,15 +428,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.2.6" version = "0.2.6"
@ -554,12 +555,34 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "io-lifetimes"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
dependencies = [
"libc",
"windows-sys 0.42.0",
]
[[package]] [[package]]
name = "ipnet" name = "ipnet"
version = "2.3.1" version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
[[package]]
name = "is-terminal"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys 0.42.0",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.8" version = "0.4.8"
@ -589,9 +612,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.126" version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "linux-raw-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
@ -700,7 +729,7 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [ dependencies = [
"hermit-abi 0.2.6", "hermit-abi",
"libc", "libc",
] ]
@ -1044,6 +1073,20 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "rustix"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys 0.42.0",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.5" version = "1.0.5"

View File

@ -9,7 +9,7 @@ license = "MIT"
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
clap = { version = "4", features = ["cargo", "string"] } clap = { version = "4", features = ["cargo", "string"] }
env_logger = "0.9" env_logger = "0.10"
futures = "0.3" futures = "0.3"
reqwest = { version = "0.11", features = [ reqwest = { version = "0.11", features = [
"json", "json",