Implement uuidgen
Implement uuidgen as a wrapper over the `uuid` crate.
This commit is contained in:
		
							
								
								
									
										128
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										128
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -76,6 +76,15 @@ dependencies = [
 | 
			
		||||
 "windows-sys 0.59.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "atomic"
 | 
			
		||||
version = "0.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bytemuck",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "autocfg"
 | 
			
		||||
version = "1.4.0"
 | 
			
		||||
@@ -123,6 +132,12 @@ version = "3.17.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bytemuck"
 | 
			
		||||
version = "1.23.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "cc"
 | 
			
		||||
version = "1.2.19"
 | 
			
		||||
@@ -391,7 +406,7 @@ dependencies = [
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "log",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "windows-core 0.57.0",
 | 
			
		||||
 "windows-core",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -505,6 +520,15 @@ version = "2.7.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "memoffset"
 | 
			
		||||
version = "0.9.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "autocfg",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "minimal-lexical"
 | 
			
		||||
version = "0.2.1"
 | 
			
		||||
@@ -521,6 +545,7 @@ dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "cfg_aliases",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "memoffset",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -934,6 +959,12 @@ dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sha1_smol"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "shlex"
 | 
			
		||||
version = "1.3.0"
 | 
			
		||||
@@ -1166,7 +1197,9 @@ dependencies = [
 | 
			
		||||
 "uu_renice",
 | 
			
		||||
 "uu_rev",
 | 
			
		||||
 "uu_setsid",
 | 
			
		||||
 "uu_uuidgen",
 | 
			
		||||
 "uucore",
 | 
			
		||||
 "uuid",
 | 
			
		||||
 "xattr",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@@ -1331,6 +1364,19 @@ dependencies = [
 | 
			
		||||
 "uucore",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "uu_uuidgen"
 | 
			
		||||
version = "0.0.1"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "clap",
 | 
			
		||||
 "nix",
 | 
			
		||||
 "rand 0.9.1",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
 "uucore",
 | 
			
		||||
 "uuid",
 | 
			
		||||
 "windows",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "uucore"
 | 
			
		||||
version = "0.0.30"
 | 
			
		||||
@@ -1369,6 +1415,29 @@ version = "0.0.30"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0bb6d972f580f8223cb7052d8580aea2b7061e368cf476de32ea9457b19459ed"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "uuid"
 | 
			
		||||
version = "1.16.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "atomic",
 | 
			
		||||
 "getrandom",
 | 
			
		||||
 "md-5",
 | 
			
		||||
 "rand 0.9.1",
 | 
			
		||||
 "sha1_smol",
 | 
			
		||||
 "uuid-rng-internal",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "uuid-rng-internal"
 | 
			
		||||
version = "1.16.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9376f53b15ed85851c10175b5e45f0af556b4853ff3fe335080b337e3828981e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "rand 0.9.1",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "version_check"
 | 
			
		||||
version = "0.9.5"
 | 
			
		||||
@@ -1499,7 +1568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-collections",
 | 
			
		||||
 "windows-core 0.61.0",
 | 
			
		||||
 "windows-core",
 | 
			
		||||
 "windows-future",
 | 
			
		||||
 "windows-link",
 | 
			
		||||
 "windows-numerics",
 | 
			
		||||
@@ -1511,19 +1580,7 @@ version = "0.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-core 0.61.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-core"
 | 
			
		||||
version = "0.57.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-implement 0.57.0",
 | 
			
		||||
 "windows-interface 0.57.0",
 | 
			
		||||
 "windows-result 0.1.2",
 | 
			
		||||
 "windows-targets 0.52.6",
 | 
			
		||||
 "windows-core",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -1532,10 +1589,10 @@ version = "0.61.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-implement 0.60.0",
 | 
			
		||||
 "windows-interface 0.59.1",
 | 
			
		||||
 "windows-implement",
 | 
			
		||||
 "windows-interface",
 | 
			
		||||
 "windows-link",
 | 
			
		||||
 "windows-result 0.3.2",
 | 
			
		||||
 "windows-result",
 | 
			
		||||
 "windows-strings",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@@ -1545,21 +1602,10 @@ version = "0.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-core 0.61.0",
 | 
			
		||||
 "windows-core",
 | 
			
		||||
 "windows-link",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-implement"
 | 
			
		||||
version = "0.57.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-implement"
 | 
			
		||||
version = "0.60.0"
 | 
			
		||||
@@ -1571,17 +1617,6 @@ dependencies = [
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-interface"
 | 
			
		||||
version = "0.57.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-interface"
 | 
			
		||||
version = "0.59.1"
 | 
			
		||||
@@ -1605,19 +1640,10 @@ version = "0.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-core 0.61.0",
 | 
			
		||||
 "windows-core",
 | 
			
		||||
 "windows-link",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-result"
 | 
			
		||||
version = "0.1.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-targets 0.52.6",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-result"
 | 
			
		||||
version = "0.3.2"
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,7 @@ feat_common_core = [
 | 
			
		||||
  "renice",
 | 
			
		||||
  "rev",
 | 
			
		||||
  "setsid",
 | 
			
		||||
  "uuidgen",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[workspace.dependencies]
 | 
			
		||||
@@ -69,6 +70,8 @@ tempfile = "3.9.0"
 | 
			
		||||
textwrap = { version = "0.16.0", features = ["terminal_size"] }
 | 
			
		||||
thiserror = "2.0"
 | 
			
		||||
uucore = "0.0.30"
 | 
			
		||||
uuid = { version = "1.16.0", features = ["rng-rand"] }
 | 
			
		||||
windows = { version = "0.61.1" }
 | 
			
		||||
xattr = "1.3.1"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
@@ -99,6 +102,7 @@ mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", pa
 | 
			
		||||
renice = { optional = true, version = "0.0.1", package = "uu_renice", path = "src/uu/renice" }
 | 
			
		||||
rev = { optional = true, version = "0.0.1", package = "uu_rev", path = "src/uu/rev" }
 | 
			
		||||
setsid = { optional = true, version = "0.0.1", package = "uu_setsid", path ="src/uu/setsid" }
 | 
			
		||||
uuidgen = { optional = true, version = "0.0.1", package = "uu_uuidgen", path ="src/uu/uuidgen" }
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
# dmesg test require fixed-boot-time feature turned on.
 | 
			
		||||
@@ -109,6 +113,7 @@ rand = { workspace = true }
 | 
			
		||||
regex = { workspace = true }
 | 
			
		||||
tempfile = { workspace = true }
 | 
			
		||||
uucore = { workspace = true, features = ["entries", "process", "signals"] }
 | 
			
		||||
uuid = { workspace = true }
 | 
			
		||||
 | 
			
		||||
[target.'cfg(unix)'.dev-dependencies]
 | 
			
		||||
nix = { workspace = true, features = ["term"] }
 | 
			
		||||
 
 | 
			
		||||
@@ -99,6 +99,7 @@ First, reimplement the most important tools from util-linux:
 | 
			
		||||
- `ldattach`: Attaches line discipline to a serial line.
 | 
			
		||||
- `readprofile`: Reads kernel profiling info.
 | 
			
		||||
- `i386, linux32, linux64, x86_64`: Set personality flags for execution environment.
 | 
			
		||||
- `uuidgen`: Generate different types of UUID.
 | 
			
		||||
 | 
			
		||||
Note:
 | 
			
		||||
* /bin/more is already implemented in https://github.com/uutils/coreutils
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								src/uu/uuidgen/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/uu/uuidgen/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "uu_uuidgen"
 | 
			
		||||
version = "0.0.1"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
path = "src/uuidgen.rs"
 | 
			
		||||
 | 
			
		||||
[[bin]]
 | 
			
		||||
name = "uuidgen"
 | 
			
		||||
path = "src/main.rs"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
clap = { workspace = true }
 | 
			
		||||
rand = { workspace = true }
 | 
			
		||||
thiserror = { workspace = true }
 | 
			
		||||
uucore = { workspace = true }
 | 
			
		||||
uuid = { workspace = true, features = ["v1", "v3", "v4", "v5"] }
 | 
			
		||||
 | 
			
		||||
[target.'cfg(target_os = "windows")'.dependencies]
 | 
			
		||||
windows = { workspace = true, features = ["Win32_NetworkManagement_IpHelper", "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock"] }
 | 
			
		||||
 | 
			
		||||
[target.'cfg(all(target_family = "unix", not(target_os = "redox")))'.dependencies]
 | 
			
		||||
nix = { workspace = true, features = ["net"] }
 | 
			
		||||
							
								
								
									
										1
									
								
								src/uu/uuidgen/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/uu/uuidgen/src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
uucore::bin!(uu_uuidgen);
 | 
			
		||||
							
								
								
									
										209
									
								
								src/uu/uuidgen/src/uuidgen.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								src/uu/uuidgen/src/uuidgen.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,209 @@
 | 
			
		||||
// This file is part of the uutils util-linux package.
 | 
			
		||||
//
 | 
			
		||||
// For the full copyright and license information, please view the LICENSE
 | 
			
		||||
// file that was distributed with this source code.
 | 
			
		||||
 | 
			
		||||
#[cfg(target_os = "windows")]
 | 
			
		||||
use windows::Win32::{
 | 
			
		||||
    Foundation::{ERROR_BUFFER_OVERFLOW, ERROR_SUCCESS},
 | 
			
		||||
    NetworkManagement::IpHelper::{
 | 
			
		||||
        GetAdaptersAddresses, GAA_FLAG_SKIP_ANYCAST, GAA_FLAG_SKIP_DNS_SERVER,
 | 
			
		||||
        GAA_FLAG_SKIP_FRIENDLY_NAME, GAA_FLAG_SKIP_MULTICAST, GAA_FLAG_SKIP_UNICAST,
 | 
			
		||||
        IP_ADAPTER_ADDRESSES_LH,
 | 
			
		||||
    },
 | 
			
		||||
    Networking::WinSock::AF_UNSPEC,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use clap::{crate_version, Arg, ArgAction, ArgGroup, Command};
 | 
			
		||||
 | 
			
		||||
#[cfg(all(target_family = "unix", not(target_os = "redox")))]
 | 
			
		||||
use nix::ifaddrs::getifaddrs;
 | 
			
		||||
use uucore::{
 | 
			
		||||
    error::{UResult, USimpleError},
 | 
			
		||||
    format_usage, help_about, help_usage,
 | 
			
		||||
};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
const ABOUT: &str = help_about!("uuidgen.md");
 | 
			
		||||
const USAGE: &str = help_usage!("uuidgen.md");
 | 
			
		||||
 | 
			
		||||
#[uucore::main]
 | 
			
		||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
 | 
			
		||||
    let args = uu_app().try_get_matches_from_mut(args)?;
 | 
			
		||||
 | 
			
		||||
    let md5 = args.get_flag(options::MD5);
 | 
			
		||||
    let sha1 = args.get_flag(options::SHA1);
 | 
			
		||||
 | 
			
		||||
    let namespace = args.get_one(options::NAMESPACE);
 | 
			
		||||
    let name: Option<&String> = args.get_one(options::NAME);
 | 
			
		||||
 | 
			
		||||
    // https://github.com/clap-rs/clap/issues/1537
 | 
			
		||||
    if !(md5 || sha1) && (namespace.is_some() || name.is_some()) {
 | 
			
		||||
        return Err(USimpleError::new(
 | 
			
		||||
            1,
 | 
			
		||||
            "--namespace and --name arguments require either --md5 or --sha1",
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if args.get_flag(options::TIME) {
 | 
			
		||||
        let node_id = get_node_id().unwrap_or_else(|| {
 | 
			
		||||
            let mut default: [u8; 6] = rand::random();
 | 
			
		||||
            default[0] |= 0x01;
 | 
			
		||||
            default
 | 
			
		||||
        });
 | 
			
		||||
        println!("{:?}", Uuid::now_v1(&node_id));
 | 
			
		||||
    } else if md5 || sha1 {
 | 
			
		||||
        let f = if md5 { Uuid::new_v3 } else { Uuid::new_v5 };
 | 
			
		||||
 | 
			
		||||
        println!(
 | 
			
		||||
            "{:?}",
 | 
			
		||||
            f(
 | 
			
		||||
                namespace.expect("namespace arg to be set"),
 | 
			
		||||
                name.expect("name to be set").as_bytes()
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    } else {
 | 
			
		||||
        // Random is the default
 | 
			
		||||
        println!("{}", Uuid::new_v4());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn uu_app() -> Command {
 | 
			
		||||
    let all_uuid_types = [options::RANDOM, options::TIME, options::MD5, options::SHA1];
 | 
			
		||||
 | 
			
		||||
    Command::new(uucore::util_name())
 | 
			
		||||
        .version(crate_version!())
 | 
			
		||||
        .about(ABOUT)
 | 
			
		||||
        .override_usage(format_usage(USAGE))
 | 
			
		||||
        .infer_long_args(true)
 | 
			
		||||
        .arg(
 | 
			
		||||
            Arg::new(options::RANDOM)
 | 
			
		||||
                .short('r')
 | 
			
		||||
                .long(options::RANDOM)
 | 
			
		||||
                .action(ArgAction::SetTrue)
 | 
			
		||||
                .help("generate random UUID (v4)"),
 | 
			
		||||
        )
 | 
			
		||||
        .arg(
 | 
			
		||||
            Arg::new(options::TIME)
 | 
			
		||||
                .short('t')
 | 
			
		||||
                .long(options::TIME)
 | 
			
		||||
                .action(ArgAction::SetTrue)
 | 
			
		||||
                .help("generate time UUID (v1)"),
 | 
			
		||||
        )
 | 
			
		||||
        .arg(
 | 
			
		||||
            Arg::new(options::NAMESPACE)
 | 
			
		||||
                .short('n')
 | 
			
		||||
                .long(options::NAMESPACE)
 | 
			
		||||
                .action(ArgAction::Set)
 | 
			
		||||
                .value_parser(namespace_from_str)
 | 
			
		||||
                .help("namespace for md5/sha1 - one of: @dns @url @oid @x500"),
 | 
			
		||||
        )
 | 
			
		||||
        .arg(
 | 
			
		||||
            Arg::new(options::NAME)
 | 
			
		||||
                .short('N')
 | 
			
		||||
                .long(options::NAME)
 | 
			
		||||
                .action(ArgAction::Set)
 | 
			
		||||
                .help("name for md5/sha1"),
 | 
			
		||||
        )
 | 
			
		||||
        .arg(
 | 
			
		||||
            Arg::new(options::MD5)
 | 
			
		||||
                .short('m')
 | 
			
		||||
                .long(options::MD5)
 | 
			
		||||
                .action(ArgAction::SetTrue)
 | 
			
		||||
                .requires_all([options::NAMESPACE, options::NAME])
 | 
			
		||||
                .help("generate md5 UUID (v3)"),
 | 
			
		||||
        )
 | 
			
		||||
        .arg(
 | 
			
		||||
            Arg::new(options::SHA1)
 | 
			
		||||
                .short('s')
 | 
			
		||||
                .long(options::SHA1)
 | 
			
		||||
                .action(ArgAction::SetTrue)
 | 
			
		||||
                .requires_all([options::NAMESPACE, options::NAME])
 | 
			
		||||
                .help("generate sha1 UUID (v5)"),
 | 
			
		||||
        )
 | 
			
		||||
        .group(ArgGroup::new("mode").args(all_uuid_types).multiple(false))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn namespace_from_str(s: &str) -> Result<Uuid, USimpleError> {
 | 
			
		||||
    match s {
 | 
			
		||||
        "@dns" => Ok(Uuid::NAMESPACE_DNS),
 | 
			
		||||
        "@url" => Ok(Uuid::NAMESPACE_URL),
 | 
			
		||||
        "@oid" => Ok(Uuid::NAMESPACE_OID),
 | 
			
		||||
        "@x500" => Ok(Uuid::NAMESPACE_X500),
 | 
			
		||||
        _ => Err(USimpleError {
 | 
			
		||||
            code: 1,
 | 
			
		||||
            message: format!("Invalid namespace {}.", s),
 | 
			
		||||
        }),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod options {
 | 
			
		||||
    pub const RANDOM: &str = "random";
 | 
			
		||||
    pub const TIME: &str = "time";
 | 
			
		||||
    pub const MD5: &str = "md5";
 | 
			
		||||
    pub const SHA1: &str = "sha1";
 | 
			
		||||
    pub const NAMESPACE: &str = "namespace";
 | 
			
		||||
    pub const NAME: &str = "name";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(target_os = "windows")]
 | 
			
		||||
fn get_node_id() -> Option<[u8; 6]> {
 | 
			
		||||
    unsafe {
 | 
			
		||||
        // Skip everything we can - we are only interested in PhysicalAddress
 | 
			
		||||
        let flags = GAA_FLAG_SKIP_UNICAST
 | 
			
		||||
            | GAA_FLAG_SKIP_ANYCAST
 | 
			
		||||
            | GAA_FLAG_SKIP_MULTICAST
 | 
			
		||||
            | GAA_FLAG_SKIP_DNS_SERVER
 | 
			
		||||
            | GAA_FLAG_SKIP_FRIENDLY_NAME;
 | 
			
		||||
 | 
			
		||||
        let mut size = 0;
 | 
			
		||||
        let ret = GetAdaptersAddresses(AF_UNSPEC.0 as u32, flags, None, None, &mut size);
 | 
			
		||||
        if ret != ERROR_BUFFER_OVERFLOW.0 {
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut buf = vec![0u8; size as usize];
 | 
			
		||||
        let ret = GetAdaptersAddresses(
 | 
			
		||||
            AF_UNSPEC.0 as u32,
 | 
			
		||||
            flags,
 | 
			
		||||
            None,
 | 
			
		||||
            Some(buf.as_mut_ptr() as *mut IP_ADAPTER_ADDRESSES_LH),
 | 
			
		||||
            &mut size,
 | 
			
		||||
        );
 | 
			
		||||
        if ret != ERROR_SUCCESS.0 {
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // SAFETY: GetAdaptersAddresses returns ERROR_NO_DATA error if it's zero len
 | 
			
		||||
        let mut adapter_ptr = buf.as_ptr() as *const IP_ADAPTER_ADDRESSES_LH;
 | 
			
		||||
        while !adapter_ptr.is_null() {
 | 
			
		||||
            let adapter = adapter_ptr.read();
 | 
			
		||||
 | 
			
		||||
            if adapter.PhysicalAddressLength == 6 {
 | 
			
		||||
                return Some(adapter.PhysicalAddress[0..6].try_into().unwrap());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            adapter_ptr = adapter.Next;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    None
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(all(target_family = "unix", not(target_os = "redox")))]
 | 
			
		||||
fn get_node_id() -> Option<[u8; 6]> {
 | 
			
		||||
    getifaddrs().ok().and_then(|iflist| {
 | 
			
		||||
        iflist
 | 
			
		||||
            .filter_map(|intf| intf.address?.as_link_addr()?.addr())
 | 
			
		||||
            .find(|mac| mac.iter().any(|x| *x != 0))
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(not(any(
 | 
			
		||||
    target_os = "windows",
 | 
			
		||||
    all(target_family = "unix", not(target_os = "redox"))
 | 
			
		||||
)))]
 | 
			
		||||
fn get_node_id() -> Option<[u8; 6]> {
 | 
			
		||||
    None
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								src/uu/uuidgen/uuidgen.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/uu/uuidgen/uuidgen.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
# uuidgen
 | 
			
		||||
```
 | 
			
		||||
uuidgen [options]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Create UUIDs:
 | 
			
		||||
 - v1: time + MAC address (-t/--time)
 | 
			
		||||
 - v3: namespace + name, MD5 based (-m/--md5)
 | 
			
		||||
 - v4: random (-r/--random)
 | 
			
		||||
 - v5: namespace + name, SHA1 based (-s/--sha1)
 | 
			
		||||
							
								
								
									
										98
									
								
								tests/by-util/test_uuidgen.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								tests/by-util/test_uuidgen.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
// This file is part of the uutils util-linux package.
 | 
			
		||||
//
 | 
			
		||||
// For the full copyright and license information, please view the LICENSE
 | 
			
		||||
// file that was distributed with this source code.
 | 
			
		||||
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use crate::common::util::{TestScenario, UCommand};
 | 
			
		||||
 | 
			
		||||
fn assert_ver_eq(cmd: &mut UCommand, ver: uuid::Version) {
 | 
			
		||||
    let uuid = Uuid::parse_str(
 | 
			
		||||
        cmd.succeeds()
 | 
			
		||||
            .stdout_str()
 | 
			
		||||
            .strip_suffix('\n')
 | 
			
		||||
            .expect("newline"),
 | 
			
		||||
    )
 | 
			
		||||
    .expect("valid UUID");
 | 
			
		||||
    assert_eq!(uuid.get_variant(), uuid::Variant::RFC4122);
 | 
			
		||||
    assert_eq!(uuid.get_version(), Some(ver));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_random() {
 | 
			
		||||
    assert_ver_eq(&mut new_ucmd!(), uuid::Version::Random);
 | 
			
		||||
    assert_ver_eq(new_ucmd!().arg("-r"), uuid::Version::Random);
 | 
			
		||||
    assert_ver_eq(new_ucmd!().arg("--random"), uuid::Version::Random);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_time() {
 | 
			
		||||
    assert_ver_eq(new_ucmd!().arg("-t"), uuid::Version::Mac);
 | 
			
		||||
    assert_ver_eq(new_ucmd!().arg("--time"), uuid::Version::Mac);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_arg_conflict() {
 | 
			
		||||
    new_ucmd!().args(&["-r", "-t"]).fails().code_is(1);
 | 
			
		||||
    new_ucmd!().args(&["--time", "--random"]).fails().code_is(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_md5_sha1() {
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["--namespace", "@dns", "--name", "example.com", "-m"])
 | 
			
		||||
        .succeeds()
 | 
			
		||||
        .stdout_only("9073926b-929f-31c2-abc9-fad77ae3e8eb\n");
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["-s", "--namespace", "@dns", "--name", "foobar"])
 | 
			
		||||
        .succeeds()
 | 
			
		||||
        .stdout_only("a050b517-6677-5119-9a77-2d26bbf30507\n");
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["-s", "--namespace", "@url", "--name", "foobar"])
 | 
			
		||||
        .succeeds()
 | 
			
		||||
        .stdout_only("8304efdd-bd6e-5b7c-a27f-83f3f05c64e0\n");
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["--sha1", "--namespace", "@oid", "--name", "foobar"])
 | 
			
		||||
        .succeeds()
 | 
			
		||||
        .stdout_only("364c03e1-bcdc-58bb-94ed-43e9a92f5f08\n");
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["--sha1", "--namespace", "@x500", "--name", "foobar"])
 | 
			
		||||
        .succeeds()
 | 
			
		||||
        .stdout_only("34da942e-f4a3-5169-9c65-267d2b22cf11\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_invalid_arg() {
 | 
			
		||||
    new_ucmd!().arg("-Z").fails().code_is(1);
 | 
			
		||||
    new_ucmd!().args(&["-r", "-Z"]).fails().code_is(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_name_namespace_on_non_hash() {
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["--namespace", "@dns", "-r"])
 | 
			
		||||
        .fails()
 | 
			
		||||
        .code_is(1);
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["--name", "example.com", "-r"])
 | 
			
		||||
        .fails()
 | 
			
		||||
        .code_is(1);
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["--namespace", "@dns", "--name", "example.com", "-r"])
 | 
			
		||||
        .fails()
 | 
			
		||||
        .code_is(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_missing_name_namespace() {
 | 
			
		||||
    new_ucmd!().arg("--sha1").fails().code_is(1);
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["--sha1", "--namespace", "@dns"])
 | 
			
		||||
        .fails()
 | 
			
		||||
        .code_is(1);
 | 
			
		||||
    new_ucmd!()
 | 
			
		||||
        .args(&["--sha1", "--name", "example.com"])
 | 
			
		||||
        .fails()
 | 
			
		||||
        .code_is(1);
 | 
			
		||||
}
 | 
			
		||||
@@ -60,3 +60,7 @@ mod test_fsfreeze;
 | 
			
		||||
#[cfg(feature = "mcookie")]
 | 
			
		||||
#[path = "by-util/test_mcookie.rs"]
 | 
			
		||||
mod test_mcookie;
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "uuidgen")]
 | 
			
		||||
#[path = "by-util/test_uuidgen.rs"]
 | 
			
		||||
mod test_uuidgen;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user