1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-02 05:57:46 +00:00

Merge pull request #552 from kwantam/master

fix `whoami`, `users`, `wc`, `uptime`, `uname`
This commit is contained in:
Alex Lyon 2015-04-27 19:36:37 -07:00
commit b827ccb901
8 changed files with 161 additions and 132 deletions

View file

@ -1,5 +1,5 @@
#![crate_name = "uname"]
#![feature(collections, core, old_io, rustc_private, std_misc)]
#![feature(rustc_private)]
/*
* This file is part of the uutils coreutils package.
@ -12,20 +12,18 @@
/* last synced with: uname (GNU coreutils) 8.21 */
#![allow(non_camel_case_types)]
extern crate getopts;
extern crate libc;
use std::ffi::CStr;
use std::io::Write;
use std::mem::uninitialized;
use std::old_io::print;
use c_types::utsname;
#[path = "../common/util.rs"] #[macro_use] mod util;
#[path = "../common/c_types.rs"] mod c_types;
struct utsrust {
struct Uts {
sysname: String,
nodename: String,
release: String,
@ -41,10 +39,10 @@ unsafe fn string_from_c_str(ptr: *const i8) -> String {
String::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).to_string()
}
unsafe fn getuname() -> utsrust {
unsafe fn getuname() -> Uts {
let mut uts: utsname = uninitialized();
uname(&mut uts);
utsrust {
Uts {
sysname: string_from_c_str(uts.sysname.as_ptr() as *const i8),
nodename: string_from_c_str(uts.nodename.as_ptr() as *const i8),
release: string_from_c_str(uts.release.as_ptr() as *const i8),
@ -57,7 +55,6 @@ unsafe fn getuname() -> utsrust {
static NAME: &'static str = "uname";
pub fn uumain(args: Vec<String>) -> i32 {
let program = args[0].as_slice();
let opts = [
getopts::optflag("h", "help", "display this help and exit"),
getopts::optflag("a", "all", "Behave as though all of the options -mnrsv were specified."),
@ -68,7 +65,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
getopts::optflag("s", "sysname", "print the operating system name."),
getopts::optflag("v", "version", "print the operating system version."),
];
let matches = match getopts::getopts(args.tail(), &opts) {
let matches = match getopts::getopts(&args[1..], &opts) {
Ok(m) => m,
Err(f) => crash!(1, "{}", f),
};
@ -76,36 +73,36 @@ pub fn uumain(args: Vec<String>) -> i32 {
println!("uname 1.0.0");
println!("");
println!("Usage:");
println!(" {}", program);
println!(" {}", args[0]);
println!("");
print(getopts::usage("The uname utility writes symbols representing one or more system characteristics to the standard output.", &opts).as_slice());
println!("{}", getopts::usage("The uname utility writes symbols representing one or more system characteristics to the standard output.", &opts));
return 0;
}
let uname = unsafe { getuname() };
let mut output = String::new();
if matches.opt_present("sysname") || matches.opt_present("all")
|| !matches.opts_present(&["nodename".to_string(), "release".to_string(), "version".to_string(), "machine".to_string()]) {
output.push_str(uname.sysname.as_slice());
output.push_str(uname.sysname.as_ref());
output.push_str(" ");
}
if matches.opt_present("nodename") || matches.opt_present("all") {
output.push_str(uname.nodename.as_slice());
output.push_str(uname.nodename.as_ref());
output.push_str(" ");
}
if matches.opt_present("release") || matches.opt_present("all") {
output.push_str(uname.release.as_slice());
output.push_str(uname.release.as_ref());
output.push_str(" ");
}
if matches.opt_present("version") || matches.opt_present("all") {
output.push_str(uname.version.as_slice());
output.push_str(uname.version.as_ref());
output.push_str(" ");
}
if matches.opt_present("machine") || matches.opt_present("all") {
output.push_str(uname.machine.as_slice());
output.push_str(uname.machine.as_ref());
output.push_str(" ");
}
println!("{}", output.as_slice().trim());
println!("{}", output.trim());
0
}

View file

@ -1,5 +1,5 @@
#![crate_name = "uptime"]
#![feature(collections, core, old_io, old_path, rustc_private, std_misc, str_words)]
#![feature(rustc_private)]
/*
* This file is part of the uutils coreutils package.
@ -12,15 +12,14 @@
/* last synced with: cat (GNU coreutils) 8.13 */
#![allow(non_camel_case_types)]
extern crate getopts;
extern crate libc;
extern crate time as rtime;
use std::ffi::CString;
use std::fs::File;
use std::io::{Read, Write};
use std::mem::transmute;
use std::old_io::{print, File};
use std::ptr::null;
use libc::{time_t, c_double, c_int, c_char};
use utmpx::*;
@ -61,7 +60,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
getopts::optflag("v", "version", "output version information and exit"),
getopts::optflag("h", "help", "display this help and exit"),
];
let matches = match getopts::getopts(args.tail(), &opts) {
let matches = match getopts::getopts(&args[1..], &opts) {
Ok(m) => m,
Err(f) => crash!(1, "Invalid options\n{}", f)
};
@ -73,9 +72,9 @@ pub fn uumain(args: Vec<String>) -> i32 {
println!("Usage:");
println!(" {0} [OPTION]", program);
println!("");
print(getopts::usage("Print the current time, the length of time the system has been up,\n\
println!("{}", getopts::usage("Print the current time, the length of time the system has been up,\n\
the number of users on the system, and the average number of jobs\n\
in the run queue over the last 1, 5 and 15 minutes.", &opts).as_slice());
in the run queue over the last 1, 5 and 15 minutes.", &opts));
return 0;
}
@ -98,7 +97,7 @@ fn print_loadavg() {
}
else {
print!("load average: ");
for n in range(0, loads) {
for n in 0..loads {
print!("{:.2}{}", avg[n as usize], if n == loads - 1 { "\n" }
else { ", " } );
}
@ -164,27 +163,23 @@ fn print_time() {
#[cfg(unix)]
fn get_uptime(boot_time: Option<time_t>) -> i64 {
let proc_uptime = File::open(&Path::new("/proc/uptime"))
.read_to_string();
let mut proc_uptime = String::new();
let uptime_text = match proc_uptime {
Ok(s) => s,
_ => return match boot_time {
Some(t) => {
let now = rtime::get_time().sec;
let time = t as i64;
((now - time) * 100) as i64 // Return in ms
},
_ => -1
}
};
match uptime_text.as_slice().words().next() {
Some(s) => match s.replace(".", "").as_slice().parse() {
Ok(n) => n,
Err(_) => -1
},
None => -1
if let Some(n) =
File::open("/proc/uptime").ok()
.and_then(|mut f| f.read_to_string(&mut proc_uptime).ok())
.and_then(|_| proc_uptime.split_whitespace().next())
.and_then(|s| s.replace(".", "").parse().ok()) {
n
} else {
match boot_time {
Some(t) => {
let now = rtime::get_time().sec;
let time = t as i64;
((now - time) * 100)
},
_ => -1,
}
}
}
@ -198,12 +193,12 @@ fn print_uptime(upsecs: i64) {
let uphours = (upsecs - (updays * 86400)) / 3600;
let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
if updays == 1 {
print!("up {:1} day, {:2}:{:02}, ", updays, uphours, upmins);
print!("up {:1} day, {:2}:{:02}, ", updays, uphours, upmins);
}
else if updays > 1 {
print!("up {:1} days, {:2}:{:02}, ", updays, uphours, upmins);
print!("up {:1} days, {:2}:{:02}, ", updays, uphours, upmins);
}
else {
print!("up {:2}:{:02}, ", uphours, upmins);
print!("up {:2}:{:02}, ", uphours, upmins);
}
}

View file

@ -1,5 +1,5 @@
#![crate_name = "users"]
#![feature(collections, core, old_io, rustc_private, std_misc)]
#![feature(rustc_private)]
/*
* This file is part of the uutils coreutils package.
@ -13,13 +13,12 @@
/* last synced with: whoami (GNU coreutils) 8.22 */
// Allow dead code here in order to keep all fields, constants here, for consistency.
#![allow(dead_code, non_camel_case_types)]
#![allow(dead_code)]
extern crate getopts;
extern crate libc;
use std::ffi::{CStr, CString};
use std::old_io::print;
use std::mem;
use std::ptr;
use utmpx::*;
@ -53,13 +52,12 @@ unsafe extern fn utmpxname(_file: *const libc::c_char) -> libc::c_int {
static NAME: &'static str = "users";
pub fn uumain(args: Vec<String>) -> i32 {
let program = args[0].as_slice();
let opts = [
getopts::optflag("h", "help", "display this help and exit"),
getopts::optflag("V", "version", "output version information and exit"),
];
let matches = match getopts::getopts(args.tail(), &opts) {
let matches = match getopts::getopts(&args[1..], &opts) {
Ok(m) => m,
Err(f) => panic!("{}", f),
};
@ -68,9 +66,9 @@ pub fn uumain(args: Vec<String>) -> i32 {
println!("users 1.0.0");
println!("");
println!("Usage:");
println!(" {} [OPTION]... [FILE]", program);
println!(" {} [OPTION]... [FILE]", args[0]);
println!("");
print(getopts::usage("Output who is currently logged in according to FILE.", &opts).as_slice());
println!("{}", getopts::usage("Output who is currently logged in according to FILE.", &opts));
return 0;
}
@ -79,10 +77,11 @@ pub fn uumain(args: Vec<String>) -> i32 {
return 0;
}
let mut filename = DEFAULT_FILE;
if matches.free.len() > 0 {
filename = matches.free[0].as_slice();
}
let filename = if matches.free.len() > 0 {
matches.free[0].as_ref()
} else {
DEFAULT_FILE
};
exec(filename);

View file

@ -1,5 +1,5 @@
#![crate_name = "wc"]
#![feature(collections, old_io, old_path, rustc_private, str_words)]
#![feature(rustc_private, path_ext)]
/*
* This file is part of the uutils coreutils package.
@ -13,15 +13,15 @@
extern crate getopts;
extern crate libc;
use std::ascii::AsciiExt;
use std::str::from_utf8;
use std::old_io::{print, File, BufferedReader};
use std::old_io::fs::PathExtensions;
use std::old_io::stdio::stdin_raw;
use std::result::Result as StdResult;
use std::borrow::IntoCow;
use getopts::Matches;
use std::ascii::AsciiExt;
use std::fs::{File, PathExt};
use std::io::{stdin, BufRead, BufReader, Read, Write};
use std::path::Path;
use std::result::Result as StdResult;
use std::str::from_utf8;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
@ -49,7 +49,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
getopts::optflag("V", "version", "output version information and exit"),
];
let matches = match getopts::getopts(args.tail(), &opts) {
let mut matches = match getopts::getopts(&args[1..], &opts) {
Ok(m) => m,
Err(f) => {
crash!(1, "Invalid options\n{}", f)
@ -60,8 +60,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
println!("Usage:");
println!(" {0} [OPTION]... [FILE]...", program);
println!("");
print(&getopts::usage("Print newline, word and byte counts for each FILE", &opts)[..]);
println!("");
println!("{}", getopts::usage("Print newline, word and byte counts for each FILE", &opts));
println!("With no FILE, or when FILE is -, read standard input.");
return 0;
}
@ -71,13 +70,11 @@ pub fn uumain(args: Vec<String>) -> i32 {
return 0;
}
let files = if matches.free.is_empty() {
vec!["-".to_string()].into_cow()
} else {
matches.free[..].into_cow()
};
if matches.free.is_empty() {
matches.free.push("-".to_string());
}
match wc(&files[..], &matches) {
match wc(&matches) {
Ok(()) => ( /* pass */ ),
Err(e) => return e
}
@ -97,7 +94,7 @@ fn is_word_seperator(byte: u8) -> bool {
byte == SPACE || byte == TAB || byte == CR || byte == SYN || byte == FF
}
pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
pub fn wc(matches: &Matches) -> StdResult<(), i32> {
let mut total_line_count: usize = 0;
let mut total_word_count: usize = 0;
let mut total_char_count: usize = 0;
@ -107,7 +104,7 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
let mut results = vec!();
let mut max_str_len: usize = 0;
for path in files.iter() {
for path in matches.free.iter() {
let mut reader = try!(open(&path[..]));
let mut line_count: usize = 0;
@ -115,10 +112,18 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
let mut byte_count: usize = 0;
let mut char_count: usize = 0;
let mut longest_line_length: usize = 0;
let mut raw_line = Vec::new();
// reading from a TTY seems to raise a condition on, rather than return Some(0) like a file.
// hence the option wrapped in a result here
while let Ok(raw_line) = reader.read_until(LF) {
while match reader.read_until(LF, &mut raw_line) {
Ok(n) if n > 0 => true,
Err(ref e) if raw_line.len() > 0 => {
show_warning!("Error while reading {}: {}", path, e);
raw_line.len() > 0
},
_ => false,
} {
// GNU 'wc' only counts lines that end in LF as lines
if *raw_line.last().unwrap() == LF {
line_count += 1;
@ -130,7 +135,7 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
let current_char_count;
match from_utf8(&raw_line[..]) {
Ok(line) => {
word_count += line.words().count();
word_count += line.split_whitespace().count();
current_char_count = line.chars().count();
},
Err(..) => {
@ -145,6 +150,8 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
// matches GNU 'wc' behaviour
longest_line_length = current_char_count - 1;
}
raw_line.truncate(0);
}
results.push(Result {
@ -173,7 +180,7 @@ pub fn wc(files: &[String], matches: &Matches) -> StdResult<(), i32> {
print_stats(&result.filename[..], result.lines, result.words, result.chars, result.bytes, result.max_line_length, matches, max_str_len);
}
if files.len() > 1 {
if matches.free.len() > 1 {
print_stats("total", total_line_count, total_word_count, total_char_count, total_byte_count, total_longest_line_length, matches, max_str_len);
}
@ -217,10 +224,10 @@ fn print_stats(filename: &str, line_count: usize, word_count: usize, char_count:
}
}
fn open(path: &str) -> StdResult<BufferedReader<Box<Reader+'static>>, i32> {
fn open(path: &str) -> StdResult<BufReader<Box<Read+'static>>, i32> {
if "-" == path {
let reader = Box::new(stdin_raw()) as Box<Reader>;
return Ok(BufferedReader::new(reader));
let reader = Box::new(stdin()) as Box<Read>;
return Ok(BufReader::new(reader));
}
let fpath = Path::new(path);
@ -229,8 +236,8 @@ fn open(path: &str) -> StdResult<BufferedReader<Box<Reader+'static>>, i32> {
}
match File::open(&fpath) {
Ok(fd) => {
let reader = Box::new(fd) as Box<Reader>;
Ok(BufferedReader::new(reader))
let reader = Box::new(fd) as Box<Read>;
Ok(BufReader::new(reader))
}
Err(e) => {
show_error!("wc: {}: {}", path, e);

View file

@ -0,0 +1,20 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#[cfg(unix)]
pub use self::unix::getusername;
#[cfg(windows)]
pub use self::windows::getusername;
#[cfg(unix)]
mod unix;
#[cfg(windows)]
mod windows;

View file

@ -0,0 +1,24 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use ::libc;
use self::c_types::{c_passwd, getpwuid};
#[path = "../../common/c_types.rs"] mod c_types;
extern {
pub fn geteuid() -> libc::uid_t;
}
pub unsafe fn getusername() -> String {
let passwd: *const c_passwd = getpwuid(geteuid());
let pw_name: *const libc::c_char = (*passwd).pw_name;
String::from_utf8_lossy(::std::ffi::CStr::from_ptr(pw_name).to_bytes()).to_string()
}

View file

@ -0,0 +1,27 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use ::libc;
use std::mem;
use std::io::Write;
extern "system" {
pub fn GetUserNameA(out: *mut libc::c_char, len: *mut libc::uint32_t) -> libc::uint8_t;
}
#[allow(unused_unsafe)]
pub unsafe fn getusername() -> String {
// XXX: it may be possible that this isn't long enough. I don't know
let mut buffer: [libc::c_char; 2048] = mem::uninitialized();
if !GetUserNameA(buffer.as_mut_ptr(), &mut (buffer.len() as libc::uint32_t)) == 0 {
crash!(1, "username is too long");
}
String::from_utf8_lossy(::std::ffi::CStr::from_ptr(buffer.as_ptr()).to_bytes()).to_string()
}

View file

@ -1,5 +1,5 @@
#![crate_name = "whoami"]
#![feature(collections, core, old_io, rustc_private, std_misc)]
#![feature(rustc_private)]
/*
* This file is part of the uutils coreutils package.
@ -12,62 +12,22 @@
/* last synced with: whoami (GNU coreutils) 8.21 */
#![allow(non_camel_case_types)]
extern crate getopts;
extern crate libc;
use std::old_io::print;
use std::io::Write;
#[path = "../common/util.rs"] #[macro_use] mod util;
#[cfg(unix)]
mod platform {
use super::libc;
use self::c_types::{c_passwd, getpwuid};
#[path = "../../common/c_types.rs"] mod c_types;
extern {
pub fn geteuid() -> libc::uid_t;
}
pub unsafe fn getusername() -> String {
let passwd: *const c_passwd = getpwuid(geteuid());
let pw_name: *const libc::c_char = (*passwd).pw_name;
String::from_utf8_lossy(::std::ffi::CStr::from_ptr(pw_name).to_bytes()).to_string()
}
}
#[cfg(windows)]
mod platform {
pub use super::libc;
use std::mem;
extern "system" {
pub fn GetUserNameA(out: *mut libc::c_char, len: *mut libc::uint32_t) -> libc::uint8_t;
}
#[allow(unused_unsafe)]
pub unsafe fn getusername() -> String {
let mut buffer: [libc::c_char; 2048] = mem::uninitialized(); // XXX: it may be possible that this isn't long enough. I don't know
if !GetUserNameA(buffer.as_mut_ptr(), &mut (buffer.len() as libc::uint32_t)) == 0 {
crash!(1, "username is too long");
}
String::from_utf8_lossy(::std::ffi::CStr::from_ptr(buffer.as_ptr()).to_bytes()).to_string()
}
}
mod platform;
static NAME: &'static str = "whoami";
pub fn uumain(args: Vec<String>) -> i32 {
let program = args[0].as_slice();
let opts = [
getopts::optflag("h", "help", "display this help and exit"),
getopts::optflag("V", "version", "output version information and exit"),
];
let matches = match getopts::getopts(args.tail(), &opts) {
let matches = match getopts::getopts(&args[1..], &opts) {
Ok(m) => m,
Err(f) => crash!(1, "{}", f),
};
@ -75,9 +35,9 @@ pub fn uumain(args: Vec<String>) -> i32 {
println!("whoami 1.0.0");
println!("");
println!("Usage:");
println!(" {}", program);
println!(" {}", args[0]);
println!("");
print(getopts::usage("print effective userid", &opts).as_slice());
println!("{}", getopts::usage("print effective userid", &opts));
return 0;
}
if matches.opt_present("version") {