proxmox-sys: imported proxmox tools/sys

And split some files into smaller parts.

Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
Dietmar Maurer 2021-11-22 12:51:33 +01:00
parent 4b1cb9f9b3
commit 32b69176dd
28 changed files with 427 additions and 385 deletions

View File

@ -11,9 +11,13 @@ exclude = [ "debian" ]
[dependencies]
anyhow = "1.0"
base64 = "0.13"
lazy_static = "1.4"
libc = "0.2.107"
log = "0.4"
nix = "0.19.1"
serde_json = "1.0"
zstd = { version = "0.6", features = [ "bindgen" ] }
proxmox = { path = "../proxmox", version = "0.15", default-features = false }
proxmox-io = { path = "../proxmox-io", version = "1.0.0" }
proxmox-lang = { path = "../proxmox-lang", version = "1.0.0" }

View File

@ -41,8 +41,8 @@ Provides:
librust-proxmox-sys-0+default-dev (= ${binary:Version}),
librust-proxmox-sys-0.1-dev (= ${binary:Version}),
librust-proxmox-sys-0.1+default-dev (= ${binary:Version}),
librust-proxmox-sys-0.1.1-dev (= ${binary:Version}),
librust-proxmox-sys-0.1.1+default-dev (= ${binary:Version})
librust-proxmox-sys-0.1.2-dev (= ${binary:Version}),
librust-proxmox-sys-0.1.2+default-dev (= ${binary:Version})
Description: System tools (using nix) - Rust source code
This package contains the source for the Rust proxmox-sys crate, packaged by
debcargo for use with cargo and dh-cargo.

View File

@ -53,7 +53,7 @@ pub fn crypt(password: &[u8], salt: &[u8]) -> Result<String, Error> {
pub fn encrypt_pw(password: &str) -> Result<String, Error> {
let salt = proxmox::sys::linux::random_data(8)?;
let salt = crate::linux::random_data(8)?;
let salt = format!("$5${}$", base64::encode_config(&salt, base64::CRYPT));
crypt(password.as_bytes(), salt.as_bytes())

View File

@ -150,7 +150,7 @@ macro_rules! other_error {
#[inline]
fn into_io_result(self) -> io::Result<T> {
self.map_err($crate::sys::error::io_err_other)
self.map_err($crate::error::io_err_other)
}
}
};

View File

@ -0,0 +1,37 @@
use std::marker::PhantomData;
use std::os::unix::io::{AsRawFd, RawFd};
/// A borrowed file raw descriptor. (A `RawFd` with an attached lifetime).
///
/// For when using `&FdRef` is not an option.
///
/// This specifically does not implement `IntoRawFd` or `FromRawFd`, since those would drop life
/// times.
#[derive(Debug, Eq, PartialEq)]
pub struct BorrowedFd<'a> {
fd: RawFd,
_borrow: PhantomData<&'a RawFd>,
}
impl<'a> BorrowedFd<'a> {
#[inline]
pub fn new<T: ?Sized + AsRawFd>(fd: &T) -> Self {
Self {
fd: fd.as_raw_fd(),
_borrow: PhantomData,
}
}
}
impl AsRawFd for BorrowedFd<'_> {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl<'a, T: ?Sized + AsRawFd> From<&'a T> for BorrowedFd<'a> {
#[inline]
fn from(fd: &'a T) -> Self {
Self::new(fd)
}
}

View File

@ -1,13 +1,10 @@
//! Raw file descriptor related structures.
use std::borrow::Borrow;
use std::marker::PhantomData;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use nix::fcntl::OFlag;
use nix::sys::stat::Mode;
use nix::NixPath;
use nix::fcntl::{fcntl, FdFlag, F_GETFD, F_SETFD};
/// Guard a raw file descriptor with a drop handler. This is mostly useful when access to an owned
/// `RawFd` is required without the corresponding handler object (such as when only the file
@ -92,56 +89,6 @@ impl std::ops::Deref for Fd {
}
}
/// Raw file descriptor by number. Thin wrapper to provide `AsRawFd` which a simple `RawFd` does
/// not since it's just an `i32`.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct RawFdNum(RawFd);
impl RawFdNum {
/// Borrow this file descriptor as an `&FdRef`.
pub fn as_fd_ref(&self) -> &FdRef {
unsafe { &*(&self.0 as *const RawFd as *const FdRef) }
}
}
impl AsRawFd for RawFdNum {
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
impl FromRawFd for RawFdNum {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self(fd)
}
}
impl IntoRawFd for RawFdNum {
fn into_raw_fd(self) -> RawFd {
self.0
}
}
impl AsRef<FdRef> for RawFdNum {
fn as_ref(&self) -> &FdRef {
self.as_fd_ref()
}
}
impl Borrow<FdRef> for RawFdNum {
fn borrow(&self) -> &FdRef {
self.as_fd_ref()
}
}
impl std::ops::Deref for RawFdNum {
type Target = FdRef;
fn deref(&self) -> &FdRef {
self.as_fd_ref()
}
}
/// A reference to a raw file descriptor. (Strongly typed `&RawFd` which is not equivalent to an
/// `&i32`.
///
@ -161,45 +108,3 @@ impl AsRawFd for FdRef {
}
}
/// A borrowed file raw descriptor. (A `RawFd` with an attached lifetime).
///
/// For when using `&FdRef` is not an option.
///
/// This specifically does not implement `IntoRawFd` or `FromRawFd`, since those would drop life
/// times.
#[derive(Debug, Eq, PartialEq)]
pub struct BorrowedFd<'a> {
fd: RawFd,
_borrow: PhantomData<&'a RawFd>,
}
impl<'a> BorrowedFd<'a> {
#[inline]
pub fn new<T: ?Sized + AsRawFd>(fd: &T) -> Self {
Self {
fd: fd.as_raw_fd(),
_borrow: PhantomData,
}
}
}
impl AsRawFd for BorrowedFd<'_> {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl<'a, T: ?Sized + AsRawFd> From<&'a T> for BorrowedFd<'a> {
#[inline]
fn from(fd: &'a T) -> Self {
Self::new(fd)
}
}
/// Change the `O_CLOEXEC` flag of an existing file descriptor.
pub fn fd_change_cloexec(fd: RawFd, on: bool) -> Result<(), anyhow::Error> {
let mut flags = unsafe { FdFlag::from_bits_unchecked(fcntl(fd, F_GETFD)?) };
flags.set(FdFlag::FD_CLOEXEC, on);
fcntl(fd, F_SETFD(flags))?;
Ok(())
}

22
proxmox-sys/src/fd/mod.rs Normal file
View File

@ -0,0 +1,22 @@
//! Raw file descriptor related structures.
mod fd;
pub use fd::*;
mod raw_fd_num;
pub use raw_fd_num::*;
mod borrowed_fd;
pub use borrowed_fd::*;
use std::os::unix::io::RawFd;
use nix::fcntl::{fcntl, FdFlag, F_GETFD, F_SETFD};
/// Change the `O_CLOEXEC` flag of an existing file descriptor.
pub fn fd_change_cloexec(fd: RawFd, on: bool) -> Result<(), anyhow::Error> {
let mut flags = unsafe { FdFlag::from_bits_unchecked(fcntl(fd, F_GETFD)?) };
flags.set(FdFlag::FD_CLOEXEC, on);
fcntl(fd, F_SETFD(flags))?;
Ok(())
}

View File

@ -0,0 +1,55 @@
use std::borrow::Borrow;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use super::FdRef;
/// Raw file descriptor by number. Thin wrapper to provide `AsRawFd` which a simple `RawFd` does
/// not since it's just an `i32`.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct RawFdNum(RawFd);
impl RawFdNum {
/// Borrow this file descriptor as an `&FdRef`.
pub fn as_fd_ref(&self) -> &FdRef {
unsafe { &*(&self.0 as *const RawFd as *const FdRef) }
}
}
impl AsRawFd for RawFdNum {
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
impl FromRawFd for RawFdNum {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self(fd)
}
}
impl IntoRawFd for RawFdNum {
fn into_raw_fd(self) -> RawFd {
self.0
}
}
impl AsRef<FdRef> for RawFdNum {
fn as_ref(&self) -> &FdRef {
self.as_fd_ref()
}
}
impl Borrow<FdRef> for RawFdNum {
fn borrow(&self) -> &FdRef {
self.as_fd_ref()
}
}
impl std::ops::Deref for RawFdNum {
type Target = FdRef;
fn deref(&self) -> &FdRef {
self.as_fd_ref()
}
}

168
proxmox-sys/src/fs/dir.rs Normal file
View File

@ -0,0 +1,168 @@
use std::ffi::CStr;
use std::os::unix::io::AsRawFd;
use std::path::Path;
use anyhow::{bail, Error};
use nix::errno::Errno;
use nix::fcntl::OFlag;
use nix::sys::stat;
use nix::unistd;
use crate::fd::Fd;
use crate::fs::{fchown, CreateOptions};
/// Creates directory at the provided path with specified ownership.
///
/// Errors if the directory already exists.
pub fn create_dir<P: AsRef<Path>>(path: P, options: CreateOptions) -> Result<(), nix::Error> {
// clippy bug?: from_bits_truncate is actually a const fn...
#[allow(clippy::or_fun_call)]
let mode: stat::Mode = options
.perm
.unwrap_or(stat::Mode::from_bits_truncate(0o770));
let path = path.as_ref();
nix::unistd::mkdir(path, mode)?;
unistd::chown(path, options.owner, options.group)?;
Ok(())
}
/// Recursively create a path with separately defined metadata for intermediate directories and the
/// final component in the path.
///
/// Returns `true` if the final directory was created. Otherwise `false` is returned and no changes
/// to the directory's metadata have been performed.
///
/// ```no_run
/// # use nix::sys::stat::Mode;
/// # use nix::unistd::{Gid, Uid};
/// # use proxmox::tools::fs::{create_path, CreateOptions};
/// # fn code() -> Result<(), anyhow::Error> {
/// create_path(
/// "/var/lib/mytool/wwwdata",
/// None,
/// Some(CreateOptions::new()
/// .perm(Mode::from_bits(0o777).unwrap())
/// .owner(Uid::from_raw(33))
/// ),
/// )?;
/// # Ok(())
/// # }
/// ```
pub fn create_path<P: AsRef<Path>>(
path: P,
intermediate_opts: Option<CreateOptions>,
final_opts: Option<CreateOptions>,
) -> Result<bool, Error> {
create_path_do(path.as_ref(), intermediate_opts, final_opts)
}
fn create_path_do(
path: &Path,
intermediate_opts: Option<CreateOptions>,
final_opts: Option<CreateOptions>,
) -> Result<bool, Error> {
use std::path::Component;
let mut iter = path.components().peekable();
let at: Fd = match iter.peek() {
Some(Component::Prefix(_)) => bail!("illegal prefix path component encountered"),
Some(Component::RootDir) => {
let _ = iter.next();
Fd::open(
unsafe { CStr::from_bytes_with_nul_unchecked(b"/\0") },
OFlag::O_DIRECTORY,
stat::Mode::empty(),
)?
}
Some(Component::CurDir) => {
let _ = iter.next();
Fd::cwd()
}
Some(Component::ParentDir) => {
let _ = iter.next();
Fd::open(
unsafe { CStr::from_bytes_with_nul_unchecked(b"..\0") },
OFlag::O_DIRECTORY,
stat::Mode::empty(),
)?
}
Some(Component::Normal(_)) => {
// simply do not advance the iterator, heavy lifting happens in create_path_at_do()
Fd::cwd()
}
None => bail!("create_path on empty path?"),
};
create_path_at_do(at, iter, intermediate_opts, final_opts)
}
fn create_path_at_do(
mut at: Fd,
mut iter: std::iter::Peekable<std::path::Components>,
intermediate_opts: Option<CreateOptions>,
final_opts: Option<CreateOptions>,
) -> Result<bool, Error> {
let mut created = false;
loop {
use std::path::Component;
match iter.next() {
None => return Ok(created),
Some(Component::ParentDir) => {
at = Fd::openat(
&at,
unsafe { CStr::from_bytes_with_nul_unchecked(b"..\0") },
OFlag::O_DIRECTORY,
stat::Mode::empty(),
)?;
}
Some(Component::Normal(path)) => {
let opts = if iter.peek().is_some() {
intermediate_opts.as_ref()
} else {
final_opts.as_ref()
};
// clippy bug?: from_bits_truncate is actually a const fn...
#[allow(clippy::or_fun_call)]
let mode = opts
.and_then(|o| o.perm)
.unwrap_or(stat::Mode::from_bits_truncate(0o755));
created = match stat::mkdirat(at.as_raw_fd(), path, mode) {
Err(nix::Error::Sys(Errno::EEXIST)) => false,
Err(e) => return Err(e.into()),
Ok(_) => true,
};
at = Fd::openat(&at, path, OFlag::O_DIRECTORY, stat::Mode::empty())?;
if let (true, Some(opts)) = (created, opts) {
if opts.owner.is_some() || opts.group.is_some() {
fchown(at.as_raw_fd(), opts.owner, opts.group)?;
}
}
}
// impossible according to the docs:
Some(_) => bail!("encountered unexpected special path component"),
}
}
}
#[test]
fn test_create_path() {
create_path(
"testdir/testsub/testsub2/testfinal",
Some(CreateOptions::new().perm(stat::Mode::from_bits_truncate(0o755))),
Some(
CreateOptions::new()
.owner(Uid::effective())
.group(Gid::effective()),
),
)
.expect("expected create_path to work");
}

View File

@ -1,9 +1,6 @@
//! File related utilities such as `replace_file`.
use std::ffi::CStr;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::path::{Path, PathBuf};
use std::time::Duration;
@ -11,15 +8,16 @@ use anyhow::{bail, format_err, Error};
use nix::errno::Errno;
use nix::fcntl::OFlag;
use nix::sys::stat;
use nix::unistd::{self, Gid, Uid};
use nix::unistd;
use nix::NixPath;
use serde_json::Value;
use proxmox_lang::try_block;
use crate::sys::error::{SysError, SysResult};
use crate::sys::timer;
use crate::tools::fd::Fd;
use crate::error::{SysError, SysResult};
use crate::linux::timer;
use crate::fs::CreateOptions;
/// Read the entire contents of a file into a bytes vector
///
@ -318,248 +316,6 @@ pub fn atomic_open_or_create_file<P: AsRef<Path>>(
}
}
/// Change ownership of an open file handle
pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<(), Error> {
// According to the POSIX specification, -1 is used to indicate that owner and group
// are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap
// around to get -1 (copied fron nix crate).
let uid = owner.map(Into::into).unwrap_or(!(0 as libc::uid_t));
let gid = group.map(Into::into).unwrap_or(!(0 as libc::gid_t));
let res = unsafe { libc::fchown(fd, uid, gid) };
Errno::result(res)?;
Ok(())
}
// FIXME: Consider using derive-builder!
#[derive(Clone, Default)]
pub struct CreateOptions {
perm: Option<stat::Mode>,
owner: Option<Uid>,
group: Option<Gid>,
}
impl CreateOptions {
// contrary to Default::default() this is const
pub const fn new() -> Self {
Self {
perm: None,
owner: None,
group: None,
}
}
pub const fn perm(mut self, perm: stat::Mode) -> Self {
self.perm = Some(perm);
self
}
pub const fn owner(mut self, owner: Uid) -> Self {
self.owner = Some(owner);
self
}
pub const fn group(mut self, group: Gid) -> Self {
self.group = Some(group);
self
}
/// Convenience shortcut around having to import `Uid` from nix.
pub const fn owner_root(self) -> Self {
self.owner(nix::unistd::ROOT)
}
pub fn apply_to(&self, file: &mut File, path: &Path) -> Result<(), Error> {
// clippy bug?: from_bits_truncate is actually a const fn...
#[allow(clippy::or_fun_call)]
let mode: stat::Mode = self.perm
.unwrap_or(stat::Mode::from_bits_truncate(0o644));
if let Err(err) = stat::fchmod(file.as_raw_fd(), mode) {
bail!("fchmod {:?} failed: {}", path, err);
}
if self.owner.is_some() || self.group.is_some() {
if let Err(err) = fchown(file.as_raw_fd(), self.owner, self.group) {
bail!("fchown {:?} failed: {}", path, err);
}
}
Ok(())
}
// TODO: once 'nix' has `const fn` constructors for Uid and Gid we can enable these:
/*
/// Convenience shortcut around having to import `Gid` from nix.
pub const fn group_root(self) -> Self {
// nix hasn't constified these yet, but it's just an alias to gid_t:
self.group(Gid::from_raw(0))
}
/// Convenience shortcut to set both owner and group to 0.
pub const fn root_only(self) -> Self {
self.owner_root().group_root()
}
*/
}
/// Creates directory at the provided path with specified ownership.
///
/// Errors if the directory already exists.
pub fn create_dir<P: AsRef<Path>>(path: P, options: CreateOptions) -> Result<(), nix::Error> {
// clippy bug?: from_bits_truncate is actually a const fn...
#[allow(clippy::or_fun_call)]
let mode: stat::Mode = options
.perm
.unwrap_or(stat::Mode::from_bits_truncate(0o770));
let path = path.as_ref();
nix::unistd::mkdir(path, mode)?;
unistd::chown(path, options.owner, options.group)?;
Ok(())
}
/// Recursively create a path with separately defined metadata for intermediate directories and the
/// final component in the path.
///
/// Returns `true` if the final directory was created. Otherwise `false` is returned and no changes
/// to the directory's metadata have been performed.
///
/// ```no_run
/// # use nix::sys::stat::Mode;
/// # use nix::unistd::{Gid, Uid};
/// # use proxmox::tools::fs::{create_path, CreateOptions};
/// # fn code() -> Result<(), anyhow::Error> {
/// create_path(
/// "/var/lib/mytool/wwwdata",
/// None,
/// Some(CreateOptions::new()
/// .perm(Mode::from_bits(0o777).unwrap())
/// .owner(Uid::from_raw(33))
/// ),
/// )?;
/// # Ok(())
/// # }
/// ```
pub fn create_path<P: AsRef<Path>>(
path: P,
intermediate_opts: Option<CreateOptions>,
final_opts: Option<CreateOptions>,
) -> Result<bool, Error> {
create_path_do(path.as_ref(), intermediate_opts, final_opts)
}
fn create_path_do(
path: &Path,
intermediate_opts: Option<CreateOptions>,
final_opts: Option<CreateOptions>,
) -> Result<bool, Error> {
use std::path::Component;
let mut iter = path.components().peekable();
let at: Fd = match iter.peek() {
Some(Component::Prefix(_)) => bail!("illegal prefix path component encountered"),
Some(Component::RootDir) => {
let _ = iter.next();
Fd::open(
unsafe { CStr::from_bytes_with_nul_unchecked(b"/\0") },
OFlag::O_DIRECTORY,
stat::Mode::empty(),
)?
}
Some(Component::CurDir) => {
let _ = iter.next();
Fd::cwd()
}
Some(Component::ParentDir) => {
let _ = iter.next();
Fd::open(
unsafe { CStr::from_bytes_with_nul_unchecked(b"..\0") },
OFlag::O_DIRECTORY,
stat::Mode::empty(),
)?
}
Some(Component::Normal(_)) => {
// simply do not advance the iterator, heavy lifting happens in create_path_at_do()
Fd::cwd()
}
None => bail!("create_path on empty path?"),
};
create_path_at_do(at, iter, intermediate_opts, final_opts)
}
fn create_path_at_do(
mut at: Fd,
mut iter: std::iter::Peekable<std::path::Components>,
intermediate_opts: Option<CreateOptions>,
final_opts: Option<CreateOptions>,
) -> Result<bool, Error> {
let mut created = false;
loop {
use std::path::Component;
match iter.next() {
None => return Ok(created),
Some(Component::ParentDir) => {
at = Fd::openat(
&at,
unsafe { CStr::from_bytes_with_nul_unchecked(b"..\0") },
OFlag::O_DIRECTORY,
stat::Mode::empty(),
)?;
}
Some(Component::Normal(path)) => {
let opts = if iter.peek().is_some() {
intermediate_opts.as_ref()
} else {
final_opts.as_ref()
};
// clippy bug?: from_bits_truncate is actually a const fn...
#[allow(clippy::or_fun_call)]
let mode = opts
.and_then(|o| o.perm)
.unwrap_or(stat::Mode::from_bits_truncate(0o755));
created = match stat::mkdirat(at.as_raw_fd(), path, mode) {
Err(nix::Error::Sys(Errno::EEXIST)) => false,
Err(e) => return Err(e.into()),
Ok(_) => true,
};
at = Fd::openat(&at, path, OFlag::O_DIRECTORY, stat::Mode::empty())?;
if let (true, Some(opts)) = (created, opts) {
if opts.owner.is_some() || opts.group.is_some() {
fchown(at.as_raw_fd(), opts.owner, opts.group)?;
}
}
}
// impossible according to the docs:
Some(_) => bail!("encountered unexpected special path component"),
}
}
}
#[test]
fn test_create_path() {
create_path(
"testdir/testsub/testsub2/testfinal",
Some(CreateOptions::new().perm(stat::Mode::from_bits_truncate(0o755))),
Some(
CreateOptions::new()
.owner(Uid::effective())
.group(Gid::effective()),
),
)
.expect("expected create_path to work");
}
// /usr/include/linux/fs.h: #define BLKGETSIZE64 _IOR(0x12,114,size_t)
// return device size in bytes (u64 *arg)

104
proxmox-sys/src/fs/mod.rs Normal file
View File

@ -0,0 +1,104 @@
//! File system related utilities
use std::fs::File;
use std::path::Path;
use anyhow::{bail, Error};
use std::os::unix::io::{AsRawFd, RawFd};
use nix::unistd::{Gid, Uid};
use nix::sys::stat;
use nix::errno::Errno;
mod file;
pub use file::*;
mod dir;
pub use dir::*;
/// Change ownership of an open file handle
pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<(), Error> {
// According to the POSIX specification, -1 is used to indicate that owner and group
// are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap
// around to get -1 (copied fron nix crate).
let uid = owner.map(Into::into).unwrap_or(!(0 as libc::uid_t));
let gid = group.map(Into::into).unwrap_or(!(0 as libc::gid_t));
let res = unsafe { libc::fchown(fd, uid, gid) };
Errno::result(res)?;
Ok(())
}
// FIXME: Consider using derive-builder!
#[derive(Clone, Default)]
pub struct CreateOptions {
perm: Option<stat::Mode>,
owner: Option<Uid>,
group: Option<Gid>,
}
impl CreateOptions {
// contrary to Default::default() this is const
pub const fn new() -> Self {
Self {
perm: None,
owner: None,
group: None,
}
}
pub const fn perm(mut self, perm: stat::Mode) -> Self {
self.perm = Some(perm);
self
}
pub const fn owner(mut self, owner: Uid) -> Self {
self.owner = Some(owner);
self
}
pub const fn group(mut self, group: Gid) -> Self {
self.group = Some(group);
self
}
/// Convenience shortcut around having to import `Uid` from nix.
pub const fn owner_root(self) -> Self {
self.owner(nix::unistd::ROOT)
}
pub fn apply_to(&self, file: &mut File, path: &Path) -> Result<(), Error> {
// clippy bug?: from_bits_truncate is actually a const fn...
#[allow(clippy::or_fun_call)]
let mode: stat::Mode = self.perm
.unwrap_or(stat::Mode::from_bits_truncate(0o644));
if let Err(err) = stat::fchmod(file.as_raw_fd(), mode) {
bail!("fchmod {:?} failed: {}", path, err);
}
if self.owner.is_some() || self.group.is_some() {
if let Err(err) = fchown(file.as_raw_fd(), self.owner, self.group) {
bail!("fchown {:?} failed: {}", path, err);
}
}
Ok(())
}
// TODO: once 'nix' has `const fn` constructors for Uid and Gid we can enable these:
/*
/// Convenience shortcut around having to import `Gid` from nix.
pub const fn group_root(self) -> Self {
// nix hasn't constified these yet, but it's just an alias to gid_t:
self.group(Gid::from_raw(0))
}
/// Convenience shortcut to set both owner and group to 0.
pub const fn root_only(self) -> Self {
self.owner_root().group_root()
}
*/
}

View File

@ -1,4 +1,10 @@
pub mod crypt;
pub mod error;
pub mod fd;
pub mod fs;
pub mod linux;
pub mod logrotate;
pub mod macros;
pub mod mmap;
pub mod process_locker;
pub mod worker_task_context;

View File

@ -9,6 +9,7 @@ pub mod pid;
pub mod procfs;
pub mod pty;
pub mod socket;
pub mod timer;
pub mod tty;
/// Get pseudo random data (/dev/urandom)

View File

@ -13,9 +13,9 @@ use nix::NixPath;
use proxmox_lang::c_str;
use crate::sys::error::{io_err_other, SysResult};
use crate::sys::linux::procfs::{MountInfo, PidStat};
use crate::tools::fd::Fd;
use crate::error::{io_err_other, SysResult};
use crate::linux::procfs::{MountInfo, PidStat};
use crate::fd::Fd;
use crate::{c_result, c_try};
/// asm-generic pidfd_open syscall number

View File

@ -12,8 +12,7 @@ use anyhow::*;
use lazy_static::lazy_static;
use nix::unistd::Pid;
use crate::tools::fs::file_read_firstline;
use crate::tools::parse::hex_nibble;
use crate::fs::file_read_firstline;
pub mod mountinfo;
#[doc(inline)]
@ -570,6 +569,17 @@ pub fn read_proc_net_dev() -> Result<Vec<ProcFsNetDev>, Error> {
Ok(result)
}
// Parse a hexadecimal digit into a byte.
#[inline]
fn hex_nibble(c: u8) -> Result<u8, Error> {
Ok(match c {
b'0'..=b'9' => c - b'0',
b'a'..=b'f' => c - b'a' + 0xa,
b'A'..=b'F' => c - b'A' + 0xa,
_ => bail!("not a hex digit: {}", c as char),
})
}
fn hexstr_to_ipv4addr<T: AsRef<[u8]>>(hex: T) -> Result<Ipv4Addr, Error> {
let hex = hex.as_ref();
if hex.len() != 8 {

View File

@ -11,7 +11,7 @@ use nix::sys::stat::Mode;
use nix::unistd::{dup2, setsid};
use nix::{ioctl_write_int_bad, ioctl_write_ptr_bad, Result};
use crate::tools::fd::Fd;
use crate::fd::Fd;
ioctl_write_int_bad!(set_controlling_tty, libc::TIOCSCTTY);
ioctl_write_ptr_bad!(set_size, libc::TIOCSWINSZ, nix::pty::Winsize);

View File

@ -9,8 +9,8 @@ use nix::sys::stat::Mode;
use proxmox_lang::try_block;
use crate::c_try;
use crate::sys::error::SysError;
use crate::tools::fd::Fd;
use crate::error::SysError;
use crate::fd::Fd;
/// Get the current size of the terminal (for stdout).
/// # Safety

View File

@ -6,7 +6,7 @@ use std::io::Read;
use anyhow::{bail, Error};
use nix::unistd;
use proxmox::tools::fs::{CreateOptions, make_tmp_file};
use crate::fs::{CreateOptions, make_tmp_file};
/// Used for rotating log files and iterating over them
pub struct LogRotate {

View File

@ -7,7 +7,7 @@ use std::{io, mem, ptr};
use nix::sys::mman;
use crate::sys::error::{io_err_other, SysError};
use crate::error::{io_err_other, SysError};
pub struct Mmap<T> {
data: *mut T,

View File

@ -4,7 +4,6 @@
#[macro_use]
pub mod serde_macros;
pub mod sys;
pub mod tools;
/// An identity (nop) macro. Used by the `#[sortable]` proc macro.

View File

@ -1,7 +0,0 @@
//! This is a system utility crate used by all our rust projects.
pub mod macros;
pub mod error;
pub mod linux;
pub mod timer;

View File

@ -9,10 +9,6 @@ use proxmox_io::vec;
pub mod common_regex;
pub mod email;
pub mod fd;
pub mod fs;
pub mod mmap;
pub mod parse;
pub mod serde;
pub mod systemd;

View File

@ -1,14 +0,0 @@
//! Some parsing utilities.
use anyhow::{bail, Error};
/// Parse a hexadecimal digit into a byte.
#[inline]
pub fn hex_nibble(c: u8) -> Result<u8, Error> {
Ok(match c {
b'0'..=b'9' => c - b'0',
b'a'..=b'f' => c - b'a' + 0xa,
b'A'..=b'F' => c - b'A' + 0xa,
_ => bail!("not a hex digit: {}", c as char),
})
}