mirror of
https://github.com/uutils/coreutils
synced 2024-12-13 14:52:41 +00:00
users: support OpenBS using utmp
OpenBSD uses the original utmp file format so the general `users` does not work there. By using the `utmp-classic` lib, we cna process the current users on the system from the /var/run/utmp and show the list. fixes #5665
This commit is contained in:
parent
92665144c9
commit
576341bb93
9 changed files with 123 additions and 90 deletions
34
Cargo.lock
generated
34
Cargo.lock
generated
|
@ -2449,6 +2449,30 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utmp-classic"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e24c654e19afaa6b8f3877ece5d3bed849c2719c56f6752b18ca7da4fcc6e85a"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"thiserror",
|
||||||
|
"time",
|
||||||
|
"utmp-classic-raw",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utmp-classic-raw"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22c226537a3d6e01c440c1926ca0256dbee2d19b2229ede6fc4863a6493dd831"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uu_arch"
|
name = "uu_arch"
|
||||||
version = "0.0.27"
|
version = "0.0.27"
|
||||||
|
@ -3390,6 +3414,7 @@ name = "uu_users"
|
||||||
version = "0.0.27"
|
version = "0.0.27"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
|
"utmp-classic",
|
||||||
"uucore",
|
"uucore",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3897,18 +3922,19 @@ checksum = "2a599daf1b507819c1121f0bf87fa37eb19daac6aff3aefefd4e6e2e0f2020fc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.33"
|
version = "0.7.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "087eca3c1eaf8c47b94d02790dd086cd594b912d2043d4de4bfdd466b3befb7c"
|
checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.7.33"
|
version = "0.7.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f4b6c273f496d8fd4eaf18853e6b448760225dc030ff2c485a786859aea6393"
|
checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -330,6 +330,7 @@ time = { version = "0.3.36" }
|
||||||
unicode-segmentation = "1.11.0"
|
unicode-segmentation = "1.11.0"
|
||||||
unicode-width = "0.1.12"
|
unicode-width = "0.1.12"
|
||||||
utf-8 = "0.7.6"
|
utf-8 = "0.7.6"
|
||||||
|
utmp-classic = "0.1.6"
|
||||||
walkdir = "2.5"
|
walkdir = "2.5"
|
||||||
winapi-util = "0.1.8"
|
winapi-util = "0.1.8"
|
||||||
windows-sys = { version = "0.48.0", default-features = false }
|
windows-sys = { version = "0.48.0", default-features = false }
|
||||||
|
|
|
@ -18,6 +18,9 @@ path = "src/users.rs"
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
uucore = { workspace = true, features = ["utmpx"] }
|
uucore = { workspace = true, features = ["utmpx"] }
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "openbsd")'.dependencies]
|
||||||
|
utmp-classic = { workspace = true }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "users"
|
name = "users"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
// This file is part of the uutils coreutils package.
|
|
||||||
//
|
|
||||||
// For the full copyright and license information, please view the LICENSE
|
|
||||||
// file that was distributed with this source code.
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "openbsd"))]
|
|
||||||
mod unix;
|
|
||||||
#[cfg(not(target_os = "openbsd"))]
|
|
||||||
pub use self::unix::*;
|
|
||||||
|
|
||||||
#[cfg(target_os = "openbsd")]
|
|
||||||
mod openbsd;
|
|
||||||
#[cfg(target_os = "openbsd")]
|
|
||||||
pub use self::openbsd::*;
|
|
|
@ -1,17 +0,0 @@
|
||||||
// This file is part of the uutils coreutils package.
|
|
||||||
//
|
|
||||||
// For the full copyright and license information, please view the LICENSE
|
|
||||||
// file that was distributed with this source code.
|
|
||||||
|
|
||||||
// Specific implementation for OpenBSD: tool unsupported (utmpx not supported)
|
|
||||||
|
|
||||||
use crate::uu_app;
|
|
||||||
|
|
||||||
use uucore::error::UResult;
|
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|
||||||
let _matches = uu_app().try_get_matches_from(args)?;
|
|
||||||
|
|
||||||
println!("unsupported command on OpenBSD");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
// This file is part of the uutils coreutils package.
|
|
||||||
//
|
|
||||||
// For the full copyright and license information, please view the LICENSE
|
|
||||||
// file that was distributed with this source code.
|
|
||||||
|
|
||||||
// spell-checker:ignore (paths) wtmp
|
|
||||||
|
|
||||||
use crate::uu_app;
|
|
||||||
|
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use uucore::error::UResult;
|
|
||||||
use uucore::utmpx::{self, Utmpx};
|
|
||||||
|
|
||||||
static ARG_FILES: &str = "files";
|
|
||||||
|
|
||||||
fn get_long_usage() -> String {
|
|
||||||
format!(
|
|
||||||
"Output who is currently logged in according to FILE.
|
|
||||||
If FILE is not specified, use {}. /var/log/wtmp as FILE is common.",
|
|
||||||
utmpx::DEFAULT_FILE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|
||||||
let matches = uu_app()
|
|
||||||
.after_help(get_long_usage())
|
|
||||||
.try_get_matches_from(args)?;
|
|
||||||
|
|
||||||
let files: Vec<&Path> = matches
|
|
||||||
.get_many::<OsString>(ARG_FILES)
|
|
||||||
.map(|v| v.map(AsRef::as_ref).collect())
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let filename = if files.is_empty() {
|
|
||||||
utmpx::DEFAULT_FILE.as_ref()
|
|
||||||
} else {
|
|
||||||
files[0]
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut users = Utmpx::iter_all_records_from(filename)
|
|
||||||
.filter(Utmpx::is_user_process)
|
|
||||||
.map(|ut| ut.user())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if !users.is_empty() {
|
|
||||||
users.sort();
|
|
||||||
println!("{}", users.join(" "));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -5,19 +5,97 @@
|
||||||
|
|
||||||
// spell-checker:ignore (paths) wtmp
|
// spell-checker:ignore (paths) wtmp
|
||||||
|
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use clap::builder::ValueParser;
|
use clap::builder::ValueParser;
|
||||||
use clap::{crate_version, Arg, Command};
|
use clap::{crate_version, Arg, Command};
|
||||||
|
use uucore::error::UResult;
|
||||||
use uucore::{format_usage, help_about, help_usage};
|
use uucore::{format_usage, help_about, help_usage};
|
||||||
|
|
||||||
mod platform;
|
#[cfg(target_os = "openbsd")]
|
||||||
|
use utmp_classic::{parse_from_path, UtmpEntry};
|
||||||
|
#[cfg(not(target_os = "openbsd"))]
|
||||||
|
use uucore::utmpx::{self, Utmpx};
|
||||||
|
|
||||||
const ABOUT: &str = help_about!("users.md");
|
const ABOUT: &str = help_about!("users.md");
|
||||||
const USAGE: &str = help_usage!("users.md");
|
const USAGE: &str = help_usage!("users.md");
|
||||||
|
|
||||||
|
#[cfg(target_os = "openbsd")]
|
||||||
|
const OPENBSD_UTMP_FILE: &str = "/var/run/utmp";
|
||||||
|
|
||||||
static ARG_FILES: &str = "files";
|
static ARG_FILES: &str = "files";
|
||||||
|
|
||||||
|
fn get_long_usage() -> String {
|
||||||
|
#[cfg(not(target_os = "openbsd"))]
|
||||||
|
let default_path: &str = utmpx::DEFAULT_FILE;
|
||||||
|
#[cfg(target_os = "openbsd")]
|
||||||
|
let default_path: &str = OPENBSD_UTMP_FILE;
|
||||||
|
format!(
|
||||||
|
"Output who is currently logged in according to FILE.
|
||||||
|
If FILE is not specified, use {}. /var/log/wtmp as FILE is common.",
|
||||||
|
default_path
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
use platform::uumain;
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
let matches = uu_app()
|
||||||
|
.after_help(get_long_usage())
|
||||||
|
.try_get_matches_from(args)?;
|
||||||
|
|
||||||
|
let files: Vec<&Path> = matches
|
||||||
|
.get_many::<OsString>(ARG_FILES)
|
||||||
|
.map(|v| v.map(AsRef::as_ref).collect())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut users: Vec<String>;
|
||||||
|
|
||||||
|
// OpenBSD uses the Unix version 1 UTMP, all other Unixes use the newer UTMPX
|
||||||
|
#[cfg(target_os = "openbsd")]
|
||||||
|
{
|
||||||
|
let filename = if files.is_empty() {
|
||||||
|
Path::new(OPENBSD_UTMP_FILE)
|
||||||
|
} else {
|
||||||
|
files[0]
|
||||||
|
};
|
||||||
|
let entries = parse_from_path(&filename).unwrap_or(Vec::new());
|
||||||
|
users = Vec::new();
|
||||||
|
for entry in entries {
|
||||||
|
if let UtmpEntry::UTMP {
|
||||||
|
line: _,
|
||||||
|
user,
|
||||||
|
host: _,
|
||||||
|
time: _,
|
||||||
|
} = entry
|
||||||
|
{
|
||||||
|
if !user.is_empty() {
|
||||||
|
users.push(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#[cfg(not(target_os = "openbsd"))]
|
||||||
|
{
|
||||||
|
let filename = if files.is_empty() {
|
||||||
|
utmpx::DEFAULT_FILE.as_ref()
|
||||||
|
} else {
|
||||||
|
files[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
users = Utmpx::iter_all_records_from(filename)
|
||||||
|
.filter(Utmpx::is_user_process)
|
||||||
|
.map(|ut| ut.user())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
};
|
||||||
|
|
||||||
|
if !users.is_empty() {
|
||||||
|
users.sort();
|
||||||
|
println!("{}", users.join(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn uu_app() -> Command {
|
pub fn uu_app() -> Command {
|
||||||
Command::new(uucore::util_name())
|
Command::new(uucore::util_name())
|
||||||
|
|
|
@ -31,3 +31,12 @@ fn test_users_check_name() {
|
||||||
|
|
||||||
new_ucmd!().succeeds().stdout_is(&expected);
|
new_ucmd!().succeeds().stdout_is(&expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(target_os = "openbsd")]
|
||||||
|
fn test_users_check_name_openbsd() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["openbsd_utmp"])
|
||||||
|
.run()
|
||||||
|
.stdout_contains("test");
|
||||||
|
}
|
||||||
|
|
BIN
tests/fixtures/users/openbsd_utmp
vendored
Normal file
BIN
tests/fixtures/users/openbsd_utmp
vendored
Normal file
Binary file not shown.
Loading…
Reference in a new issue