mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-08-05 07:27:46 +00:00
Split utility files into separate library.
Everything in src/common has been moved to src/uucore. This is defined as a Cargo library, instead of directly included. This gives us flexibility to make the library an external crate in the future. Fixes #717.
This commit is contained in:
parent
67b07eaaa9
commit
6095dfee66
10 changed files with 1120 additions and 0 deletions
11
src/uucore/Cargo.toml
Normal file
11
src/uucore/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "uucore"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = "*"
|
||||||
|
time = "*"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "lib.rs"
|
240
src/uucore/c_types.rs
Normal file
240
src/uucore/c_types.rs
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
#![allow(dead_code, non_camel_case_types, raw_pointer_derive)]
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
use self::libc::{
|
||||||
|
c_char,
|
||||||
|
c_int,
|
||||||
|
uid_t,
|
||||||
|
gid_t,
|
||||||
|
};
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
||||||
|
use self::libc::time_t;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
use self::libc::int32_t;
|
||||||
|
|
||||||
|
use self::libc::getgroups;
|
||||||
|
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
use std::io::{Error, Write};
|
||||||
|
use std::iter::repeat;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
use std::ptr::{null_mut, read};
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct c_passwd {
|
||||||
|
pub pw_name: *const c_char, /* user name */
|
||||||
|
pub pw_passwd: *const c_char, /* user name */
|
||||||
|
pub pw_uid: uid_t, /* user uid */
|
||||||
|
pub pw_gid: gid_t, /* user gid */
|
||||||
|
pub pw_change: time_t,
|
||||||
|
pub pw_class: *const c_char,
|
||||||
|
pub pw_gecos: *const c_char,
|
||||||
|
pub pw_dir: *const c_char,
|
||||||
|
pub pw_shell: *const c_char,
|
||||||
|
pub pw_expire: time_t
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct c_passwd {
|
||||||
|
pub pw_name: *const c_char, /* user name */
|
||||||
|
pub pw_passwd: *const c_char, /* user name */
|
||||||
|
pub pw_uid: uid_t, /* user uid */
|
||||||
|
pub pw_gid: gid_t, /* user gid */
|
||||||
|
pub pw_gecos: *const c_char,
|
||||||
|
pub pw_dir: *const c_char,
|
||||||
|
pub pw_shell: *const c_char,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct utsname {
|
||||||
|
pub sysname: [c_char; 256],
|
||||||
|
pub nodename: [c_char; 256],
|
||||||
|
pub release: [c_char; 256],
|
||||||
|
pub version: [c_char; 256],
|
||||||
|
pub machine: [c_char; 256]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct utsname {
|
||||||
|
pub sysname: [c_char; 65],
|
||||||
|
pub nodename: [c_char; 65],
|
||||||
|
pub release: [c_char; 65],
|
||||||
|
pub version: [c_char; 65],
|
||||||
|
pub machine: [c_char; 65],
|
||||||
|
pub domainame: [c_char; 65]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct c_group {
|
||||||
|
pub gr_name: *const c_char, // group name
|
||||||
|
pub gr_passwd: *const c_char, // password
|
||||||
|
pub gr_gid: gid_t, // group id
|
||||||
|
pub gr_mem: *const *const c_char, // member list
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct c_tm {
|
||||||
|
pub tm_sec: c_int, /* seconds */
|
||||||
|
pub tm_min: c_int, /* minutes */
|
||||||
|
pub tm_hour: c_int, /* hours */
|
||||||
|
pub tm_mday: c_int, /* day of the month */
|
||||||
|
pub tm_mon: c_int, /* month */
|
||||||
|
pub tm_year: c_int, /* year */
|
||||||
|
pub tm_wday: c_int, /* day of the week */
|
||||||
|
pub tm_yday: c_int, /* day in the year */
|
||||||
|
pub tm_isdst: c_int /* daylight saving time */
|
||||||
|
}
|
||||||
|
|
||||||
|
extern {
|
||||||
|
pub fn getpwuid(uid: uid_t) -> *const c_passwd;
|
||||||
|
pub fn getpwnam(login: *const c_char) -> *const c_passwd;
|
||||||
|
pub fn getgrgid(gid: gid_t) -> *const c_group;
|
||||||
|
pub fn getgrnam(name: *const c_char) -> *const c_group;
|
||||||
|
pub fn getgrouplist(name: *const c_char,
|
||||||
|
gid: gid_t,
|
||||||
|
groups: *mut gid_t,
|
||||||
|
ngroups: *mut c_int) -> c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
extern {
|
||||||
|
pub fn getgroupcount(name: *const c_char, gid: gid_t) -> int32_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pw_from_args(free: &Vec<String>) -> Option<c_passwd> {
|
||||||
|
if free.len() == 1 {
|
||||||
|
let username = &free[0][..];
|
||||||
|
|
||||||
|
// Passed user as id
|
||||||
|
if username.chars().all(|c| c.is_digit(10)) {
|
||||||
|
let id = username.parse::<u32>().unwrap();
|
||||||
|
let pw_pointer = unsafe { getpwuid(id as uid_t) };
|
||||||
|
|
||||||
|
if !pw_pointer.is_null() {
|
||||||
|
Some(unsafe { read(pw_pointer) })
|
||||||
|
} else {
|
||||||
|
crash!(1, "{}: no such user", username);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Passed the username as a string
|
||||||
|
} else {
|
||||||
|
let pw_pointer = unsafe {
|
||||||
|
let cstr = CString::new(username).unwrap();
|
||||||
|
getpwnam(cstr.as_bytes_with_nul().as_ptr() as *const i8)
|
||||||
|
};
|
||||||
|
if !pw_pointer.is_null() {
|
||||||
|
Some(unsafe { read(pw_pointer) })
|
||||||
|
} else {
|
||||||
|
crash!(1, "{}: no such user", username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_group(groupname: &str) -> Option<c_group> {
|
||||||
|
let group = if groupname.chars().all(|c| c.is_digit(10)) {
|
||||||
|
unsafe { getgrgid(groupname.parse().unwrap()) }
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let cstr = CString::new(groupname).unwrap();
|
||||||
|
getgrnam(cstr.as_bytes_with_nul().as_ptr() as *const c_char)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !group.is_null() {
|
||||||
|
Some(unsafe { read(group) })
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_group_list(name: *const c_char, gid: gid_t) -> Vec<gid_t> {
|
||||||
|
let mut ngroups: c_int = 32;
|
||||||
|
let mut groups: Vec<gid_t> = Vec::with_capacity(ngroups as usize);
|
||||||
|
|
||||||
|
if unsafe { get_group_list_internal(name, gid, groups.as_mut_ptr(), &mut ngroups) } == -1 {
|
||||||
|
groups.reserve(ngroups as usize);
|
||||||
|
unsafe { get_group_list_internal(name, gid, groups.as_mut_ptr(), &mut ngroups); }
|
||||||
|
} else {
|
||||||
|
groups.truncate(ngroups as usize);
|
||||||
|
}
|
||||||
|
unsafe { groups.set_len(ngroups as usize); }
|
||||||
|
|
||||||
|
groups
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn get_group_list_internal(name: *const c_char, gid: gid_t, groups: *mut gid_t, grcnt: *mut c_int) -> c_int {
|
||||||
|
getgrouplist(name, gid, groups, grcnt)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
unsafe fn get_group_list_internal(name: *const c_char, gid: gid_t, groups: *mut gid_t, grcnt: *mut c_int) -> c_int {
|
||||||
|
let ngroups = getgroupcount(name, gid);
|
||||||
|
let oldsize = *grcnt;
|
||||||
|
*grcnt = ngroups;
|
||||||
|
if oldsize >= ngroups {
|
||||||
|
getgrouplist(name, gid, groups, grcnt);
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_groups() -> Result<Vec<gid_t>, i32> {
|
||||||
|
let ngroups = unsafe { getgroups(0, null_mut()) };
|
||||||
|
if ngroups == -1 {
|
||||||
|
return Err(Error::last_os_error().raw_os_error().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut groups : Vec<gid_t>= repeat(0).take(ngroups as usize).collect();
|
||||||
|
let ngroups = unsafe { getgroups(ngroups, groups.as_mut_ptr()) };
|
||||||
|
if ngroups == -1 {
|
||||||
|
Err(Error::last_os_error().raw_os_error().unwrap())
|
||||||
|
} else {
|
||||||
|
groups.truncate(ngroups as usize);
|
||||||
|
Ok(groups)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn group(possible_pw: Option<c_passwd>, nflag: bool) {
|
||||||
|
let groups = match possible_pw {
|
||||||
|
Some(pw) => Ok(get_group_list(pw.pw_name, pw.pw_gid)),
|
||||||
|
None => get_groups(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match groups {
|
||||||
|
Err(errno) =>
|
||||||
|
crash!(1, "failed to get group list (errno={})", errno),
|
||||||
|
Ok(groups) => {
|
||||||
|
for &g in groups.iter() {
|
||||||
|
if nflag {
|
||||||
|
let group = unsafe { getgrgid(g) };
|
||||||
|
if !group.is_null() {
|
||||||
|
let name = unsafe {
|
||||||
|
let gname = read(group).gr_name;
|
||||||
|
let bytes= CStr::from_ptr(gname).to_bytes();
|
||||||
|
String::from_utf8_lossy(bytes).to_string()
|
||||||
|
};
|
||||||
|
print!("{} ", name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print!("{} ", g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
src/uucore/fs.rs
Normal file
144
src/uucore/fs.rs
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the uutils coreutils package.
|
||||||
|
*
|
||||||
|
* (c) Joseph Crail <jbcrail@gmail.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Based on the pattern using by Cargo, I created a shim over the
|
||||||
|
// standard PathExt trait, so that the unstable path methods could
|
||||||
|
// be backported to stable (<= 1.1). This will likely be dropped
|
||||||
|
// when the path trait stabilizes.
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::{Error, ErrorKind, Result};
|
||||||
|
use std::path::{Component, Path, PathBuf};
|
||||||
|
|
||||||
|
pub trait UUPathExt {
|
||||||
|
fn uu_exists(&self) -> bool;
|
||||||
|
fn uu_is_file(&self) -> bool;
|
||||||
|
fn uu_is_dir(&self) -> bool;
|
||||||
|
fn uu_metadata(&self) -> Result<fs::Metadata>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UUPathExt for Path {
|
||||||
|
fn uu_exists(&self) -> bool {
|
||||||
|
fs::metadata(self).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uu_is_file(&self) -> bool {
|
||||||
|
fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uu_is_dir(&self) -> bool {
|
||||||
|
fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uu_metadata(&self) -> Result<fs::Metadata> {
|
||||||
|
fs::metadata(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum CanonicalizeMode {
|
||||||
|
None,
|
||||||
|
Normal,
|
||||||
|
Existing,
|
||||||
|
Missing,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve<P: AsRef<Path>>(original: P) -> Result<PathBuf> {
|
||||||
|
const MAX_LINKS_FOLLOWED: u32 = 255;
|
||||||
|
let mut followed = 0;
|
||||||
|
let mut result = original.as_ref().to_path_buf();
|
||||||
|
loop {
|
||||||
|
if followed == MAX_LINKS_FOLLOWED {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
match fs::metadata(&result) {
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
Ok(ref m) if !m.file_type().is_symlink() => break,
|
||||||
|
Ok(..) => {
|
||||||
|
followed += 1;
|
||||||
|
match fs::read_link(&result) {
|
||||||
|
Ok(path) => {
|
||||||
|
result.pop();
|
||||||
|
result.push(path);
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> Result<PathBuf> {
|
||||||
|
// Create an absolute path
|
||||||
|
let original = original.as_ref();
|
||||||
|
let original = if original.is_absolute() {
|
||||||
|
original.to_path_buf()
|
||||||
|
} else {
|
||||||
|
env::current_dir().unwrap().join(original)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut result = PathBuf::new();
|
||||||
|
let mut parts = vec!();
|
||||||
|
|
||||||
|
// Split path by directory separator; add prefix (Windows-only) and root
|
||||||
|
// directory to final path buffer; add remaining parts to temporary
|
||||||
|
// vector for canonicalization.
|
||||||
|
for part in original.components() {
|
||||||
|
match part {
|
||||||
|
Component::Prefix(_) | Component::RootDir => {
|
||||||
|
result.push(part.as_os_str());
|
||||||
|
},
|
||||||
|
Component::CurDir => {},
|
||||||
|
Component::ParentDir => {
|
||||||
|
parts.pop();
|
||||||
|
},
|
||||||
|
Component::Normal(_) => {
|
||||||
|
parts.push(part.as_os_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the symlinks where possible
|
||||||
|
if parts.len() > 0 {
|
||||||
|
for part in parts[..parts.len()-1].iter() {
|
||||||
|
result.push(part);
|
||||||
|
|
||||||
|
if can_mode == CanonicalizeMode::None {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match resolve(&result) {
|
||||||
|
Err(e) => match can_mode {
|
||||||
|
CanonicalizeMode::Missing => continue,
|
||||||
|
_ => return Err(e)
|
||||||
|
},
|
||||||
|
Ok(path) => {
|
||||||
|
result.pop();
|
||||||
|
result.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(parts.last().unwrap());
|
||||||
|
|
||||||
|
match resolve(&result) {
|
||||||
|
Err(e) => { if can_mode == CanonicalizeMode::Existing { return Err(e); } },
|
||||||
|
Ok(path) => {
|
||||||
|
result.pop();
|
||||||
|
result.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
14
src/uucore/lib.rs
Normal file
14
src/uucore/lib.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
extern crate libc;
|
||||||
|
extern crate time;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
|
pub mod c_types;
|
||||||
|
pub mod fs;
|
||||||
|
pub mod parse_time;
|
||||||
|
pub mod process;
|
||||||
|
#[cfg(unix)] pub mod signals;
|
||||||
|
#[cfg(unix)] pub mod utmpx;
|
||||||
|
|
||||||
|
#[cfg(windows)] pub mod wide;
|
220
src/uucore/macros.rs
Normal file
220
src/uucore/macros.rs
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the uutils coreutils package.
|
||||||
|
*
|
||||||
|
* (c) Arcterus <arcterus@mail.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! show_error(
|
||||||
|
($($args:tt)+) => ({
|
||||||
|
pipe_write!(&mut ::std::io::stderr(), "{}: error: ", module_path!());
|
||||||
|
pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! show_warning(
|
||||||
|
($($args:tt)+) => ({
|
||||||
|
pipe_write!(&mut ::std::io::stderr(), "{}: warning: ", module_path!());
|
||||||
|
pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! show_info(
|
||||||
|
($($args:tt)+) => ({
|
||||||
|
pipe_write!(&mut ::std::io::stderr(), "{}: ", module_path!());
|
||||||
|
pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! eprint(
|
||||||
|
($($args:tt)+) => (pipe_write!(&mut ::std::io::stderr(), $($args)+))
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! eprintln(
|
||||||
|
($($args:tt)+) => (pipe_writeln!(&mut ::std::io::stderr(), $($args)+))
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! crash(
|
||||||
|
($exitcode:expr, $($args:tt)+) => ({
|
||||||
|
show_error!($($args)+);
|
||||||
|
::std::process::exit($exitcode)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! exit(
|
||||||
|
($exitcode:expr) => ({
|
||||||
|
::std::process::exit($exitcode)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! crash_if_err(
|
||||||
|
($exitcode:expr, $exp:expr) => (
|
||||||
|
match $exp {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(f) => crash!($exitcode, "{}", f),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! pipe_crash_if_err(
|
||||||
|
($exitcode:expr, $exp:expr) => (
|
||||||
|
match $exp {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(f) => {
|
||||||
|
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
|
||||||
|
()
|
||||||
|
} else {
|
||||||
|
crash!($exitcode, "{}", f)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! return_if_err(
|
||||||
|
($exitcode:expr, $exp:expr) => (
|
||||||
|
match $exp {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(f) => {
|
||||||
|
show_error!("{}", f);
|
||||||
|
return $exitcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// XXX: should the pipe_* macros return an Err just to show the write failed?
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! pipe_print(
|
||||||
|
($($args:tt)+) => (
|
||||||
|
match write!(&mut ::std::io::stdout(), $($args)+) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(f) => {
|
||||||
|
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
panic!("{}", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! pipe_println(
|
||||||
|
($($args:tt)+) => (
|
||||||
|
match writeln!(&mut ::std::io::stdout(), $($args)+) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(f) => {
|
||||||
|
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
panic!("{}", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! pipe_write(
|
||||||
|
($fd:expr, $($args:tt)+) => (
|
||||||
|
match write!($fd, $($args)+) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(f) => {
|
||||||
|
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
panic!("{}", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! pipe_writeln(
|
||||||
|
($fd:expr, $($args:tt)+) => (
|
||||||
|
match writeln!($fd, $($args)+) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(f) => {
|
||||||
|
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
panic!("{}", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! pipe_flush(
|
||||||
|
() => (
|
||||||
|
match ::std::io::stdout().flush() {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(f) => {
|
||||||
|
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
panic!("{}", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
($fd:expr) => (
|
||||||
|
match $fd.flush() {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(f) => {
|
||||||
|
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
panic!("{}", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! safe_write(
|
||||||
|
($fd:expr, $($args:tt)+) => (
|
||||||
|
match write!($fd, $($args)+) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(f) => panic!(f.to_string())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! safe_writeln(
|
||||||
|
($fd:expr, $($args:tt)+) => (
|
||||||
|
match writeln!($fd, $($args)+) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(f) => panic!(f.to_string())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! safe_unwrap(
|
||||||
|
($exp:expr) => (
|
||||||
|
match $exp {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(f) => crash!(1, "{}", f.to_string())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
35
src/uucore/parse_time.rs
Normal file
35
src/uucore/parse_time.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the uutils coreutils package.
|
||||||
|
*
|
||||||
|
* (c) Arcterus <arcterus@mail.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub fn from_str(string: &str) -> Result<f64, String> {
|
||||||
|
let len = string.len();
|
||||||
|
if len == 0 {
|
||||||
|
return Err("empty string".to_string())
|
||||||
|
}
|
||||||
|
let slice = &string[..len - 1];
|
||||||
|
let (numstr, times) = match string.chars().next_back().unwrap() {
|
||||||
|
's' | 'S' => (slice, 1),
|
||||||
|
'm' | 'M' => (slice, 60),
|
||||||
|
'h' | 'H' => (slice, 60 * 60),
|
||||||
|
'd' | 'D' => (slice, 60 * 60 * 24),
|
||||||
|
val => {
|
||||||
|
if !val.is_alphabetic() {
|
||||||
|
(string, 1)
|
||||||
|
} else if string == "inf" || string == "infinity" {
|
||||||
|
("inf", 1)
|
||||||
|
} else {
|
||||||
|
return Err(format!("invalid time interval '{}'", string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match numstr.parse::<f64>() {
|
||||||
|
Ok(m) => Ok(m * times as f64),
|
||||||
|
Err(e) => Err(format!("invalid time interval '{}': {}", string, e))
|
||||||
|
}
|
||||||
|
}
|
140
src/uucore/process.rs
Normal file
140
src/uucore/process.rs
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the uutils coreutils package.
|
||||||
|
*
|
||||||
|
* (c) Maciej Dziardziel <fiedzia@gmail.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE file
|
||||||
|
* that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
use libc::{c_int, pid_t};
|
||||||
|
use std::fmt;
|
||||||
|
use std::io;
|
||||||
|
use std::process::Child;
|
||||||
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
|
use std::thread;
|
||||||
|
use time::{Duration, get_time};
|
||||||
|
use std::time::Duration as StdDuration;
|
||||||
|
|
||||||
|
// This is basically sys::unix::process::ExitStatus
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
|
pub enum ExitStatus {
|
||||||
|
Code(i32),
|
||||||
|
Signal(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExitStatus {
|
||||||
|
fn from_status(status: c_int) -> ExitStatus {
|
||||||
|
if status & 0x7F != 0 { // WIFSIGNALED(status)
|
||||||
|
ExitStatus::Signal(status & 0x7F)
|
||||||
|
} else {
|
||||||
|
ExitStatus::Code(status & 0xFF00 >> 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn success(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
ExitStatus::Code(code) => code == 0,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn code(&self) -> Option<i32> {
|
||||||
|
match *self {
|
||||||
|
ExitStatus::Code(code) => Some(code),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signal(&self) -> Option<i32> {
|
||||||
|
match *self {
|
||||||
|
ExitStatus::Signal(code) => Some(code),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ExitStatus {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
ExitStatus::Code(code) => write!(f, "exit code: {}", code),
|
||||||
|
ExitStatus::Signal(code) => write!(f, "exit code: {}", code),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Missing methods for Child objects
|
||||||
|
pub trait ChildExt {
|
||||||
|
/// Send a signal to a Child process.
|
||||||
|
fn send_signal(&mut self, signal: usize) -> io::Result<()>;
|
||||||
|
|
||||||
|
/// Wait for a process to finish or return after the specified duration.
|
||||||
|
fn wait_or_timeout(&mut self, timeout: f64) -> io::Result<Option<ExitStatus>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChildExt for Child {
|
||||||
|
fn send_signal(&mut self, signal: usize) -> io::Result<()> {
|
||||||
|
if unsafe { libc::kill(self.id() as pid_t,
|
||||||
|
signal as i32) } != 0 {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_or_timeout(&mut self, timeout: f64) -> io::Result<Option<ExitStatus>> {
|
||||||
|
// The result will be written to that Option, protected by a Mutex
|
||||||
|
// Then the Condvar will be signaled
|
||||||
|
let state = Arc::new((
|
||||||
|
Mutex::new(Option::None::<io::Result<ExitStatus>>),
|
||||||
|
Condvar::new(),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Start the waiting thread
|
||||||
|
let state_th = state.clone();
|
||||||
|
let pid_th = self.id();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let &(ref lock_th, ref cvar_th) = &*state_th;
|
||||||
|
// Child::wait() would need a &mut to self, can't use that...
|
||||||
|
// use waitpid() directly, with our own ExitStatus
|
||||||
|
let mut status: c_int = 0;
|
||||||
|
let r = unsafe { libc::waitpid(pid_th as i32, &mut status, 0) };
|
||||||
|
// Fill the Option and notify on the Condvar
|
||||||
|
let mut exitstatus_th = lock_th.lock().unwrap();
|
||||||
|
if r != pid_th as c_int {
|
||||||
|
*exitstatus_th = Some(Err(io::Error::last_os_error()));
|
||||||
|
} else {
|
||||||
|
let s = ExitStatus::from_status(status);
|
||||||
|
*exitstatus_th = Some(Ok(s));
|
||||||
|
}
|
||||||
|
cvar_th.notify_one();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Main thread waits
|
||||||
|
let &(ref lock, ref cvar) = &*state;
|
||||||
|
let mut exitstatus = lock.lock().unwrap();
|
||||||
|
// Condvar::wait_timeout_ms() can wake too soon, in this case wait again
|
||||||
|
let target = get_time() +
|
||||||
|
Duration::seconds(timeout as i64) +
|
||||||
|
Duration::nanoseconds((timeout * 1.0e-6) as i64);
|
||||||
|
while exitstatus.is_none() {
|
||||||
|
let now = get_time();
|
||||||
|
if now >= target {
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
|
let ms = (target - get_time()).num_milliseconds() as u32;
|
||||||
|
exitstatus = cvar.wait_timeout(exitstatus, StdDuration::new(0, ms*1000)).unwrap().0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn Option<Result<ExitStatus>> into Result<Option<ExitStatus>>
|
||||||
|
match exitstatus.take() {
|
||||||
|
Some(r) => match r {
|
||||||
|
Ok(s) => Ok(Some(s)),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
},
|
||||||
|
None => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
156
src/uucore/signals.rs
Normal file
156
src/uucore/signals.rs
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the uutils coreutils package.
|
||||||
|
*
|
||||||
|
* (c) Maciej Dziardziel <fiedzia@gmail.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE file
|
||||||
|
* that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub static DEFAULT_SIGNAL:usize= 15;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Signal<'a> { pub name:&'a str, pub value: usize}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Linux Programmer's Manual
|
||||||
|
|
||||||
|
1 HUP 2 INT 3 QUIT 4 ILL 5 TRAP 6 ABRT 7 BUS
|
||||||
|
8 FPE 9 KILL 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM
|
||||||
|
15 TERM 16 STKFLT 17 CHLD 18 CONT 19 STOP 20 TSTP 21 TTIN
|
||||||
|
22 TTOU 23 URG 24 XCPU 25 XFSZ 26 VTALRM 27 PROF 28 WINCH
|
||||||
|
29 POLL 30 PWR 31 SYS
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub static ALL_SIGNALS:[Signal<'static>; 31] = [
|
||||||
|
Signal{ name: "HUP", value:1 },
|
||||||
|
Signal{ name: "INT", value:2 },
|
||||||
|
Signal{ name: "QUIT", value:3 },
|
||||||
|
Signal{ name: "ILL", value:4 },
|
||||||
|
Signal{ name: "TRAP", value:5 },
|
||||||
|
Signal{ name: "ABRT", value:6 },
|
||||||
|
Signal{ name: "BUS", value:7 },
|
||||||
|
Signal{ name: "FPE", value:8 },
|
||||||
|
Signal{ name: "KILL", value:9 },
|
||||||
|
Signal{ name: "USR1", value:10 },
|
||||||
|
Signal{ name: "SEGV", value:11 },
|
||||||
|
Signal{ name: "USR2", value:12 },
|
||||||
|
Signal{ name: "PIPE", value:13 },
|
||||||
|
Signal{ name: "ALRM", value:14 },
|
||||||
|
Signal{ name: "TERM", value:15 },
|
||||||
|
Signal{ name: "STKFLT", value:16 },
|
||||||
|
Signal{ name: "CHLD", value:17 },
|
||||||
|
Signal{ name: "CONT", value:18 },
|
||||||
|
Signal{ name: "STOP", value:19 },
|
||||||
|
Signal{ name: "TSTP", value:20 },
|
||||||
|
Signal{ name: "TTIN", value:21 },
|
||||||
|
Signal{ name: "TTOU", value:22 },
|
||||||
|
Signal{ name: "URG", value:23 },
|
||||||
|
Signal{ name: "XCPU", value:24 },
|
||||||
|
Signal{ name: "XFSZ", value:25 },
|
||||||
|
Signal{ name: "VTALRM", value:26 },
|
||||||
|
Signal{ name: "PROF", value:27 },
|
||||||
|
Signal{ name: "WINCH", value:28 },
|
||||||
|
Signal{ name: "POLL", value:29 },
|
||||||
|
Signal{ name: "PWR", value:30 },
|
||||||
|
Signal{ name: "SYS", value:31 },
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html
|
||||||
|
|
||||||
|
|
||||||
|
No Name Default Action Description
|
||||||
|
1 SIGHUP terminate process terminal line hangup
|
||||||
|
2 SIGINT terminate process interrupt program
|
||||||
|
3 SIGQUIT create core image quit program
|
||||||
|
4 SIGILL create core image illegal instruction
|
||||||
|
5 SIGTRAP create core image trace trap
|
||||||
|
6 SIGABRT create core image abort program (formerly SIGIOT)
|
||||||
|
7 SIGEMT create core image emulate instruction executed
|
||||||
|
8 SIGFPE create core image floating-point exception
|
||||||
|
9 SIGKILL terminate process kill program
|
||||||
|
10 SIGBUS create core image bus error
|
||||||
|
11 SIGSEGV create core image segmentation violation
|
||||||
|
12 SIGSYS create core image non-existent system call invoked
|
||||||
|
13 SIGPIPE terminate process write on a pipe with no reader
|
||||||
|
14 SIGALRM terminate process real-time timer expired
|
||||||
|
15 SIGTERM terminate process software termination signal
|
||||||
|
16 SIGURG discard signal urgent condition present on socket
|
||||||
|
17 SIGSTOP stop process stop (cannot be caught or ignored)
|
||||||
|
18 SIGTSTP stop process stop signal generated from keyboard
|
||||||
|
19 SIGCONT discard signal continue after stop
|
||||||
|
20 SIGCHLD discard signal child status has changed
|
||||||
|
21 SIGTTIN stop process background read attempted from control terminal
|
||||||
|
22 SIGTTOU stop process background write attempted to control terminal
|
||||||
|
23 SIGIO discard signal I/O is possible on a descriptor (see fcntl(2))
|
||||||
|
24 SIGXCPU terminate process cpu time limit exceeded (see setrlimit(2))
|
||||||
|
25 SIGXFSZ terminate process file size limit exceeded (see setrlimit(2))
|
||||||
|
26 SIGVTALRM terminate process virtual time alarm (see setitimer(2))
|
||||||
|
27 SIGPROF terminate process profiling timer alarm (see setitimer(2))
|
||||||
|
28 SIGWINCH discard signal Window size change
|
||||||
|
29 SIGINFO discard signal status request from keyboard
|
||||||
|
30 SIGUSR1 terminate process User defined signal 1
|
||||||
|
31 SIGUSR2 terminate process User defined signal 2
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
|
||||||
|
pub static ALL_SIGNALS:[Signal<'static>; 31] = [
|
||||||
|
Signal{ name: "HUP", value:1 },
|
||||||
|
Signal{ name: "INT", value:2 },
|
||||||
|
Signal{ name: "QUIT", value:3 },
|
||||||
|
Signal{ name: "ILL", value:4 },
|
||||||
|
Signal{ name: "TRAP", value:5 },
|
||||||
|
Signal{ name: "ABRT", value:6 },
|
||||||
|
Signal{ name: "EMT", value:7 },
|
||||||
|
Signal{ name: "FPE", value:8 },
|
||||||
|
Signal{ name: "KILL", value:9 },
|
||||||
|
Signal{ name: "BUS", value:10 },
|
||||||
|
Signal{ name: "SEGV", value:11 },
|
||||||
|
Signal{ name: "SYS", value:12 },
|
||||||
|
Signal{ name: "PIPE", value:13 },
|
||||||
|
Signal{ name: "ALRM", value:14 },
|
||||||
|
Signal{ name: "TERM", value:15 },
|
||||||
|
Signal{ name: "URG", value:16 },
|
||||||
|
Signal{ name: "STOP", value:17 },
|
||||||
|
Signal{ name: "TSTP", value:18 },
|
||||||
|
Signal{ name: "CONT", value:19 },
|
||||||
|
Signal{ name: "CHLD", value:20 },
|
||||||
|
Signal{ name: "TTIN", value:21 },
|
||||||
|
Signal{ name: "TTOU", value:22 },
|
||||||
|
Signal{ name: "IO", value:23 },
|
||||||
|
Signal{ name: "XCPU", value:24 },
|
||||||
|
Signal{ name: "XFSZ", value:25 },
|
||||||
|
Signal{ name: "VTALRM", value:26 },
|
||||||
|
Signal{ name: "PROF", value:27 },
|
||||||
|
Signal{ name: "WINCH", value:28 },
|
||||||
|
Signal{ name: "INFO", value:29 },
|
||||||
|
Signal{ name: "USR1", value:30 },
|
||||||
|
Signal{ name: "USR2", value:31 },
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
|
||||||
|
if signal_name_or_value == "0" {
|
||||||
|
return Some(0);
|
||||||
|
}
|
||||||
|
for signal in ALL_SIGNALS.iter() {
|
||||||
|
let long_name = format!("SIG{}", signal.name);
|
||||||
|
if signal.name == signal_name_or_value || (signal_name_or_value == signal.value.to_string()) || (long_name == signal_name_or_value) {
|
||||||
|
return Some(signal.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_signal(num: usize) -> bool {
|
||||||
|
num < ALL_SIGNALS.len()
|
||||||
|
}
|
125
src/uucore/utmpx.rs
Normal file
125
src/uucore/utmpx.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
#![allow(dead_code, non_camel_case_types)]
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
pub use self::utmpx::{DEFAULT_FILE,USER_PROCESS,BOOT_TIME,c_utmp};
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
mod utmpx {
|
||||||
|
use super::libc;
|
||||||
|
|
||||||
|
pub static DEFAULT_FILE: &'static str = "/var/run/utmp";
|
||||||
|
|
||||||
|
pub const UT_LINESIZE: usize = 32;
|
||||||
|
pub const UT_NAMESIZE: usize = 32;
|
||||||
|
pub const UT_IDSIZE: usize = 4;
|
||||||
|
pub const UT_HOSTSIZE: usize = 256;
|
||||||
|
|
||||||
|
pub const EMPTY: libc::c_short = 0;
|
||||||
|
pub const RUN_LVL: libc::c_short = 1;
|
||||||
|
pub const BOOT_TIME: libc::c_short = 2;
|
||||||
|
pub const NEW_TIME: libc::c_short = 3;
|
||||||
|
pub const OLD_TIME: libc::c_short = 4;
|
||||||
|
pub const INIT_PROCESS: libc::c_short = 5;
|
||||||
|
pub const LOGIN_PROCESS: libc::c_short = 6;
|
||||||
|
pub const USER_PROCESS: libc::c_short = 7;
|
||||||
|
pub const DEAD_PROCESS: libc::c_short = 8;
|
||||||
|
pub const ACCOUNTING: libc::c_short = 9;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct c_exit_status {
|
||||||
|
pub e_termination: libc::c_short,
|
||||||
|
pub e_exit: libc::c_short,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct c_utmp {
|
||||||
|
pub ut_type: libc::c_short,
|
||||||
|
pub ut_pid: libc::pid_t,
|
||||||
|
pub ut_line: [libc::c_char; UT_LINESIZE],
|
||||||
|
pub ut_id: [libc::c_char; UT_IDSIZE],
|
||||||
|
|
||||||
|
pub ut_user: [libc::c_char; UT_NAMESIZE],
|
||||||
|
pub ut_host: [libc::c_char; UT_HOSTSIZE],
|
||||||
|
pub ut_exit: c_exit_status,
|
||||||
|
pub ut_session: libc::c_long,
|
||||||
|
pub ut_tv: libc::timeval,
|
||||||
|
|
||||||
|
pub ut_addr_v6: [libc::int32_t; 4],
|
||||||
|
pub __unused: [libc::c_char; 20],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
mod utmpx {
|
||||||
|
use super::libc;
|
||||||
|
|
||||||
|
pub static DEFAULT_FILE: &'static str = "/var/run/utmpx";
|
||||||
|
|
||||||
|
pub const UT_LINESIZE: usize = 32;
|
||||||
|
pub const UT_NAMESIZE: usize = 256;
|
||||||
|
pub const UT_IDSIZE: usize = 4;
|
||||||
|
pub const UT_HOSTSIZE: usize = 256;
|
||||||
|
|
||||||
|
pub const EMPTY: libc::c_short = 0;
|
||||||
|
pub const RUN_LVL: libc::c_short = 1;
|
||||||
|
pub const BOOT_TIME: libc::c_short = 2;
|
||||||
|
pub const OLD_TIME: libc::c_short = 3;
|
||||||
|
pub const NEW_TIME: libc::c_short = 4;
|
||||||
|
pub const INIT_PROCESS: libc::c_short = 5;
|
||||||
|
pub const LOGIN_PROCESS: libc::c_short = 6;
|
||||||
|
pub const USER_PROCESS: libc::c_short = 7;
|
||||||
|
pub const DEAD_PROCESS: libc::c_short = 8;
|
||||||
|
pub const ACCOUNTING: libc::c_short = 9;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct c_exit_status {
|
||||||
|
pub e_termination: libc::c_short,
|
||||||
|
pub e_exit: libc::c_short,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct c_utmp {
|
||||||
|
pub ut_user: [libc::c_char; UT_NAMESIZE],
|
||||||
|
pub ut_id: [libc::c_char; UT_IDSIZE],
|
||||||
|
pub ut_line: [libc::c_char; UT_LINESIZE],
|
||||||
|
pub ut_pid: libc::pid_t,
|
||||||
|
pub ut_type: libc::c_short,
|
||||||
|
pub ut_tv: libc::timeval,
|
||||||
|
pub ut_host: [libc::c_char; UT_HOSTSIZE],
|
||||||
|
pub __unused: [libc::c_char; 16]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "freebsd")]
|
||||||
|
mod utmpx {
|
||||||
|
use super::libc;
|
||||||
|
|
||||||
|
pub static DEFAULT_FILE : &'static str = "";
|
||||||
|
|
||||||
|
pub const UT_LINESIZE : usize = 16;
|
||||||
|
pub const UT_NAMESIZE : usize = 32;
|
||||||
|
pub const UT_IDSIZE : usize = 8;
|
||||||
|
pub const UT_HOSTSIZE : usize = 128;
|
||||||
|
|
||||||
|
pub const EMPTY : libc::c_short = 0;
|
||||||
|
pub const BOOT_TIME : libc::c_short = 1;
|
||||||
|
pub const OLD_TIME : libc::c_short = 2;
|
||||||
|
pub const NEW_TIME : libc::c_short = 3;
|
||||||
|
pub const USER_PROCESS : libc::c_short = 4;
|
||||||
|
pub const INIT_PROCESS : libc::c_short = 5;
|
||||||
|
pub const LOGIN_PROCESS : libc::c_short = 6;
|
||||||
|
pub const DEAD_PROCESS : libc::c_short = 7;
|
||||||
|
pub const SHUTDOWN_TIME : libc::c_short = 8;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct c_utmp {
|
||||||
|
pub ut_type : libc::c_short,
|
||||||
|
pub ut_tv : libc::timeval,
|
||||||
|
pub ut_id : [libc::c_char; UT_IDSIZE],
|
||||||
|
pub ut_pid : libc::pid_t,
|
||||||
|
pub ut_user : [libc::c_char; UT_NAMESIZE],
|
||||||
|
pub ut_line : [libc::c_char; UT_LINESIZE],
|
||||||
|
pub ut_host : [libc::c_char; UT_HOSTSIZE],
|
||||||
|
pub ut_spare : [libc::c_char; 64],
|
||||||
|
}
|
||||||
|
}
|
35
src/uucore/wide.rs
Normal file
35
src/uucore/wide.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the uutils coreutils package.
|
||||||
|
*
|
||||||
|
* (c) Peter Atashian <retep998@gmail.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
use std::ffi::{OsStr, OsString};
|
||||||
|
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||||
|
pub trait ToWide {
|
||||||
|
fn to_wide(&self) -> Vec<u16>;
|
||||||
|
fn to_wide_null(&self) -> Vec<u16>;
|
||||||
|
}
|
||||||
|
impl<T> ToWide for T where T: AsRef<OsStr> {
|
||||||
|
fn to_wide(&self) -> Vec<u16> {
|
||||||
|
self.as_ref().encode_wide().collect()
|
||||||
|
}
|
||||||
|
fn to_wide_null(&self) -> Vec<u16> {
|
||||||
|
self.as_ref().encode_wide().chain(Some(0)).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub trait FromWide {
|
||||||
|
fn from_wide(wide: &[u16]) -> Self;
|
||||||
|
fn from_wide_null(wide: &[u16]) -> Self;
|
||||||
|
}
|
||||||
|
impl FromWide for String {
|
||||||
|
fn from_wide(wide: &[u16]) -> String {
|
||||||
|
OsString::from_wide(wide).to_string_lossy().into_owned()
|
||||||
|
}
|
||||||
|
fn from_wide_null(wide: &[u16]) -> String {
|
||||||
|
let len = wide.iter().take_while(|&&c| c != 0).count();
|
||||||
|
OsString::from_wide(&wide[..len]).to_string_lossy().into_owned()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue