Convert several commands to use raw system calls instead of libc
functions
This commit is contained in:
parent
fcc8abb67b
commit
6963ba4a4b
36
Cargo.lock
generated
36
Cargo.lock
generated
@ -121,17 +121,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"match_cfg",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.4"
|
||||
@ -166,22 +155,6 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "match_cfg"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||
dependencies = [
|
||||
"hermit-abi 0.2.6",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.4.1"
|
||||
@ -217,6 +190,12 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sc"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "010e18bd3bfd1d45a7e666b236c78720df0d9a7698ebaa9c1c559961eb60a38b"
|
||||
|
||||
[[package]]
|
||||
name = "shitbox"
|
||||
version = "0.1.0"
|
||||
@ -227,9 +206,8 @@ dependencies = [
|
||||
"clap_complete_nushell",
|
||||
"clap_mangen",
|
||||
"data-encoding",
|
||||
"hostname",
|
||||
"libc",
|
||||
"num_cpus",
|
||||
"sc",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
"walkdir",
|
||||
|
@ -12,9 +12,8 @@ clap_complete = "4.0"
|
||||
clap_complete_nushell = "0.1"
|
||||
clap_mangen = "0.2"
|
||||
data-encoding = "2.3"
|
||||
hostname = { version = "0.3", features = ["set"] }
|
||||
libc = "0.2"
|
||||
num_cpus = "1.15"
|
||||
sc = "0.2"
|
||||
termcolor = "1.1"
|
||||
textwrap = { version = "0.16", default-features = false, features = ["smawk"] }
|
||||
walkdir = "2.3.2"
|
||||
|
53
src/cmd/expand/mod.rs
Normal file
53
src/cmd/expand/mod.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use std::io;
|
||||
|
||||
use super::Cmd;
|
||||
use clap::{Arg, ArgAction, Command, ValueHint};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Expand;
|
||||
|
||||
impl Cmd for Expand {
|
||||
fn cli(&self) -> clap::Command {
|
||||
Command::new("expand")
|
||||
.about("convert tabs to spaces")
|
||||
.author("Nathan Fisher")
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.args([
|
||||
Arg::new("file")
|
||||
.num_args(1..)
|
||||
.default_value("-")
|
||||
.value_name("FILE")
|
||||
.value_hint(ValueHint::FilePath),
|
||||
Arg::new("initial")
|
||||
.short('i')
|
||||
.long("initial")
|
||||
.help("do not convert tabs after non blanks")
|
||||
.action(ArgAction::SetTrue),
|
||||
Arg::new("tabs")
|
||||
.short('t')
|
||||
.long("tabs")
|
||||
.default_value("8")
|
||||
.help(
|
||||
"Specify the tab stops. The application shall ensure that \
|
||||
the argument tablist consists of either a single positive \
|
||||
decimal integer or a list of tabstops. If a single number \
|
||||
is given, tabs shall be set that number of column positions \
|
||||
apart instead of the default 8.",
|
||||
)
|
||||
.value_name("tablist")
|
||||
.value_delimiter(',')
|
||||
.num_args(1..),
|
||||
])
|
||||
}
|
||||
|
||||
fn run(&self, matches: Option<&clap::ArgMatches>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let Some(matches) = matches else {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "no input").into());
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn path(&self) -> Option<crate::Path> {
|
||||
Some(crate::Path::UsrBin)
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
use super::Cmd;
|
||||
use crate::unistd;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use std::{error::Error, io};
|
||||
|
||||
@ -24,14 +25,14 @@ impl Cmd for Hostname {
|
||||
fn run(&self, matches: Option<&ArgMatches>) -> Result<(), Box<dyn Error>> {
|
||||
let matches = matches.unwrap();
|
||||
if let Some(name) = matches.get_one::<String>("NAME") {
|
||||
hostname::set(name)?;
|
||||
unistd::sethostname(name)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let hostname = hostname::get()?;
|
||||
let hostname = unistd::gethostname()?;
|
||||
if matches.get_flag("STRIP") {
|
||||
println!(
|
||||
"{}",
|
||||
if let Some(s) = hostname.to_string_lossy().split('.').next() {
|
||||
if let Some(s) = hostname.split('.').next() {
|
||||
s
|
||||
} else {
|
||||
return Err(io::Error::new(
|
||||
@ -42,7 +43,7 @@ impl Cmd for Hostname {
|
||||
}
|
||||
);
|
||||
} else {
|
||||
println!("{}", hostname.to_string_lossy());
|
||||
println!("{hostname}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::Cmd;
|
||||
use crate::{args, mode::Parser};
|
||||
use crate::{args, mode::Parser, stat};
|
||||
use clap::{Arg, ArgMatches, Command};
|
||||
use std::{error::Error, ffi::CString, io};
|
||||
use std::{error::Error, io};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct MkFifo;
|
||||
@ -46,11 +46,7 @@ impl Cmd for MkFifo {
|
||||
};
|
||||
if let Some(files) = matches.get_many::<String>("file") {
|
||||
for f in files {
|
||||
let fname = CString::new(f.as_str())?;
|
||||
let res = unsafe { libc::mkfifo(fname.as_ptr(), mode) };
|
||||
if res != 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
stat::mkfifo(f.as_str(), mode)?;
|
||||
if matches.get_flag("verbose") {
|
||||
println!(
|
||||
"{}: created pipe '{f}' with mode {mode:o}",
|
||||
|
@ -1,10 +1,10 @@
|
||||
use super::Cmd;
|
||||
use crate::{
|
||||
args,
|
||||
mode::{get_umask, Parser},
|
||||
mode::{get_umask, Parser}, stat,
|
||||
};
|
||||
use clap::{value_parser, Arg, ArgMatches, Command};
|
||||
use std::{convert::Infallible, error::Error, ffi::CString, io, str::FromStr};
|
||||
use std::{convert::Infallible, error::Error, io, str::FromStr};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct MkNod;
|
||||
@ -69,11 +69,7 @@ impl Cmd for MkNod {
|
||||
}
|
||||
Special::Pipe => 0,
|
||||
};
|
||||
let fname = CString::new(file.as_str())?;
|
||||
let ret = unsafe { libc::mknod(fname.as_ptr(), mode, dev_t) };
|
||||
if ret != 0 {
|
||||
return Err(io::Error::last_os_error().into());
|
||||
}
|
||||
stat::mknod(file.as_str(), mode, dev_t)?;
|
||||
if matches.get_flag("verbose") {
|
||||
match special {
|
||||
Special::Block => {
|
||||
|
@ -24,9 +24,9 @@ impl Cmd for Nproc {
|
||||
return Err(Box::new(io::Error::new(io::ErrorKind::Other, "no input")));
|
||||
};
|
||||
if matches.get_flag("ALL") {
|
||||
println!("{}", num_cpus::get());
|
||||
println!("{}", unsafe { get_nprocs_conf() });
|
||||
} else {
|
||||
println!("{}", num_cpus::get_physical());
|
||||
println!("{}", unsafe { get_nprocs() });
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -35,3 +35,8 @@ impl Cmd for Nproc {
|
||||
Some(crate::Path::UsrBin)
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn get_nprocs() -> libc::c_int;
|
||||
fn get_nprocs_conf() -> libc::c_int;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::unistd;
|
||||
|
||||
use super::Cmd;
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use std::{error::Error, ffi::CString, io};
|
||||
use std::{error::Error, io, fs::OpenOptions};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Sync;
|
||||
@ -38,37 +40,19 @@ impl Cmd for Sync {
|
||||
};
|
||||
if let Some(files) = matches.get_many::<String>("FILE") {
|
||||
for f in files {
|
||||
let file = CString::new(f.as_bytes())?;
|
||||
let mut opts = OpenOptions::new();
|
||||
let opts = opts.read(true).write(true);
|
||||
let fd = opts.open(f)?;
|
||||
if matches.get_flag("data") {
|
||||
let rc = unsafe {
|
||||
let fd = libc::open(file.as_ptr(), libc::O_RDWR | libc::O_NOATIME);
|
||||
libc::fdatasync(fd)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(Box::new(io::Error::last_os_error()));
|
||||
}
|
||||
unistd::fdatasync(&fd)?;
|
||||
} else if matches.get_flag("fs") {
|
||||
let rc = unsafe {
|
||||
let fd = libc::open(file.as_ptr(), libc::O_RDWR | libc::O_NOATIME);
|
||||
libc::syncfs(fd)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(Box::new(io::Error::last_os_error()));
|
||||
}
|
||||
unistd::syncfs(&fd)?;
|
||||
} else {
|
||||
let rc = unsafe {
|
||||
let fd = libc::open(file.as_ptr(), libc::O_RDWR | libc::O_NOATIME);
|
||||
libc::fsync(fd)
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(Box::new(io::Error::last_os_error()));
|
||||
}
|
||||
unistd::fsync(&fd)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
libc::sync();
|
||||
}
|
||||
unistd::sync();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::Cmd;
|
||||
use crate::args;
|
||||
use crate::{args, unistd};
|
||||
use clap::{Arg, Command};
|
||||
use std::{ffi::CString, io, process};
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Unlink;
|
||||
@ -27,14 +27,9 @@ impl Cmd for Unlink {
|
||||
};
|
||||
if let Some(files) = matches.get_many::<String>("file") {
|
||||
for f in files {
|
||||
let fname = CString::new(f.as_str())?;
|
||||
let ret = unsafe { libc::unlink(fname.as_ptr()) };
|
||||
if matches.get_flag("verbose") && ret == 0 {
|
||||
unistd::unlink(f)?;
|
||||
if matches.get_flag("verbose") {
|
||||
println!("unlink: {f}");
|
||||
} else if ret != 0 {
|
||||
let err = io::Error::last_os_error();
|
||||
eprintln!("unlink: cannot unlink {f}: {err}");
|
||||
process::exit(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ pub mod fs;
|
||||
pub mod math;
|
||||
pub mod mode;
|
||||
pub mod pw;
|
||||
pub mod stat;
|
||||
pub mod unistd;
|
||||
|
||||
pub use cmd::Cmd;
|
||||
|
||||
|
22
src/stat/mod.rs
Normal file
22
src/stat/mod.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use sc::*;
|
||||
use std::{ffi::CString, io};
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mknod(path: &str, mode: u32, dev: u64) -> io::Result<()> {
|
||||
let ret = unsafe { syscall!(MKNOD, CString::new(path)?.as_ptr(), mode, dev) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mkfifo(path: &str, mode: u32) -> io::Result<()> {
|
||||
let ret = unsafe { syscall!(MKNOD, CString::new(path)?.as_ptr(), mode | libc::S_IFIFO, 0) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
115
src/unistd/mod.rs
Normal file
115
src/unistd/mod.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use libc::utsname;
|
||||
use sc::syscall;
|
||||
use std::{ffi::CString, io, u8, fs::File, os::fd::AsRawFd};
|
||||
|
||||
#[inline(always)]
|
||||
fn new_utsname() -> utsname {
|
||||
utsname {
|
||||
sysname: [0; 65],
|
||||
nodename: [0; 65],
|
||||
release: [0; 65],
|
||||
version: [0; 65],
|
||||
machine: [0; 65],
|
||||
domainname: [0; 65],
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn gethostname() -> io::Result<String> {
|
||||
let mut uts = new_utsname();
|
||||
unsafe {
|
||||
if syscall!(UNAME, &mut uts as *mut utsname) != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
}
|
||||
let name = uts
|
||||
.nodename
|
||||
.iter()
|
||||
.map(|x| *x as u8)
|
||||
.take_while(|x| *x != 0)
|
||||
.collect();
|
||||
String::from_utf8(name).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sethostname(name: &str) -> io::Result<()> {
|
||||
let ret = unsafe { syscall!(SETHOSTNAME, name.as_ptr(), name.len()) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error().into())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn link(source: &str, dest: &str) -> io::Result<()> {
|
||||
let ret = unsafe {
|
||||
syscall!(
|
||||
LINK,
|
||||
CString::new(source)?.as_ptr(),
|
||||
CString::new(dest)?.as_ptr()
|
||||
)
|
||||
};
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn unlink(name: &str) -> io::Result<()> {
|
||||
let ret = unsafe { syscall!(UNLINK, CString::new(name)?.as_ptr()) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error().into())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn readlink(name: &str) -> io::Result<String> {
|
||||
let mut buf = Vec::<i8>::with_capacity(1024);
|
||||
let ret = unsafe { syscall!(READLINK, CString::new(name)?.as_ptr(), buf.as_mut_ptr(), 1024) };
|
||||
if ret == 0 {
|
||||
let path = buf.iter().map(|x| *x as u8).take_while(|x| *x != 0).collect();
|
||||
String::from_utf8(path).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn fdatasync(fd: &File) -> io::Result<()> {
|
||||
let ret = unsafe { syscall!(FDATASYNC, fd.as_raw_fd()) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn syncfs(fd: &File) -> io::Result<()> {
|
||||
let ret = unsafe { syscall!(SYNCFS, fd.as_raw_fd()) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn fsync(fd: &File) -> io::Result<()> {
|
||||
let ret = unsafe { syscall!(FSYNC, fd.as_raw_fd()) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sync() {
|
||||
unsafe { syscall!(SYNC) };
|
||||
}
|
Loading…
Reference in New Issue
Block a user