From b62ab099c8aa3ae59a9298fee342cd316f14a8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Sat, 24 Jun 2017 10:05:03 +0200 Subject: Newtypes for uid_t, gid_t and pid_t. --- src/sched.rs | 11 +-- src/sys/ptrace.rs | 25 +++---- src/sys/signal.rs | 4 +- src/sys/wait.rs | 27 ++++---- src/unistd.rs | 201 +++++++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 195 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/sched.rs b/src/sched.rs index eefd29b2..0b98c580 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -1,8 +1,9 @@ use std::mem; use std::os::unix::io::RawFd; use std::option::Option; -use libc::{self, c_int, c_void, pid_t}; +use libc::{self, c_int, c_void}; use {Errno, Error, Result}; +use ::unistd::Pid; // For some functions taking with a parameter of type CloneFlags, // only a subset of these flags have an effect. @@ -91,9 +92,9 @@ mod ffi { } } -pub fn sched_setaffinity(pid: pid_t, cpuset: &CpuSet) -> Result<()> { +pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> { let res = unsafe { - libc::sched_setaffinity(pid, + libc::sched_setaffinity(pid.into(), mem::size_of::() as libc::size_t, mem::transmute(cpuset)) }; @@ -105,7 +106,7 @@ pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags, signal: Option) - -> Result { + -> Result { extern "C" fn callback(data: *mut CloneCb) -> c_int { let cb: &mut CloneCb = unsafe { &mut *data }; (*cb)() as c_int @@ -121,7 +122,7 @@ pub fn clone(mut cb: CloneCb, &mut cb) }; - Errno::result(res) + Errno::result(res).map(Pid::from_raw) } pub fn unshare(flags: CloneFlags) -> Result<()> { diff --git a/src/sys/ptrace.rs b/src/sys/ptrace.rs index bf6ee8bb..17dfee34 100644 --- a/src/sys/ptrace.rs +++ b/src/sys/ptrace.rs @@ -1,6 +1,7 @@ use std::{mem, ptr}; use {Errno, Error, Result}; -use libc::{pid_t, c_void, c_long, siginfo_t}; +use libc::{c_void, c_long, siginfo_t}; +use ::unistd::Pid; #[cfg(all(target_os = "linux", any(target_arch = "x86", @@ -74,7 +75,7 @@ mod ffi { /// Performs a ptrace request. If the request in question is provided by a specialised function /// this function will return an unsupported operation error. -pub fn ptrace(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result { +pub fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result { use self::ptrace::*; match request { @@ -84,10 +85,10 @@ pub fn ptrace(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, dat } } -fn ptrace_peek(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result { +fn ptrace_peek(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result { let ret = unsafe { Errno::clear(); - ffi::ptrace(request, pid, addr, data) + ffi::ptrace(request, pid.into(), addr, data) }; match Errno::result(ret) { Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret), @@ -99,7 +100,7 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, da /// Some ptrace get requests populate structs or larger elements than c_long /// and therefore use the data field to return values. This function handles these /// requests. -fn ptrace_get_data(request: ptrace::PtraceRequest, pid: pid_t) -> Result { +fn ptrace_get_data(request: ptrace::PtraceRequest, pid: Pid) -> Result { // Creates an uninitialized pointer to store result in let data: Box = Box::new(unsafe { mem::uninitialized() }); let data: *mut c_void = unsafe { mem::transmute(data) }; @@ -109,12 +110,12 @@ fn ptrace_get_data(request: ptrace::PtraceRequest, pid: pid_t) -> Result { Ok(*data) } -fn ptrace_other(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result { - Errno::result(unsafe { ffi::ptrace(request, pid, addr, data) }).map(|_| 0) +fn ptrace_other(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result { + Errno::result(unsafe { ffi::ptrace(request, pid.into(), addr, data) }).map(|_| 0) } /// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. -pub fn ptrace_setoptions(pid: pid_t, options: ptrace::PtraceOptions) -> Result<()> { +pub fn ptrace_setoptions(pid: Pid, options: ptrace::PtraceOptions) -> Result<()> { use self::ptrace::*; use std::ptr; @@ -122,23 +123,23 @@ pub fn ptrace_setoptions(pid: pid_t, options: ptrace::PtraceOptions) -> Result<( } /// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)` -pub fn ptrace_getevent(pid: pid_t) -> Result { +pub fn ptrace_getevent(pid: Pid) -> Result { use self::ptrace::*; ptrace_get_data::(PTRACE_GETEVENTMSG, pid) } /// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)` -pub fn ptrace_getsiginfo(pid: pid_t) -> Result { +pub fn ptrace_getsiginfo(pid: Pid) -> Result { use self::ptrace::*; ptrace_get_data::(PTRACE_GETSIGINFO, pid) } /// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` -pub fn ptrace_setsiginfo(pid: pid_t, sig: &siginfo_t) -> Result<()> { +pub fn ptrace_setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { use self::ptrace::*; let ret = unsafe{ Errno::clear(); - ffi::ptrace(PTRACE_SETSIGINFO, pid, ptr::null_mut(), sig as *const _ as *const c_void) + ffi::ptrace(PTRACE_SETSIGINFO, pid.into(), ptr::null_mut(), sig as *const _ as *const c_void) }; match Errno::result(ret) { Ok(_) => Ok(()), diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 887c24f3..e7978052 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -409,8 +409,8 @@ pub fn pthread_sigmask(how: SigmaskHow, Errno::result(res).map(drop) } -pub fn kill>>(pid: libc::pid_t, signal: T) -> Result<()> { - let res = unsafe { libc::kill(pid, +pub fn kill>>(pid: ::unistd::Pid, signal: T) -> Result<()> { + let res = unsafe { libc::kill(pid.into(), match signal.into() { Some(s) => s as libc::c_int, None => 0, diff --git a/src/sys/wait.rs b/src/sys/wait.rs index 35b94790..ee0beade 100644 --- a/src/sys/wait.rs +++ b/src/sys/wait.rs @@ -1,5 +1,6 @@ -use libc::{self, pid_t, c_int}; +use libc::{self, c_int}; use {Errno, Result}; +use unistd::Pid; use sys::signal::Signal; @@ -41,12 +42,12 @@ const WSTOPPED: WaitPidFlag = WUNTRACED; #[derive(Eq, PartialEq, Clone, Copy, Debug)] pub enum WaitStatus { - Exited(pid_t, i8), - Signaled(pid_t, Signal, bool), - Stopped(pid_t, Signal), + Exited(Pid, i8), + Signaled(Pid, Signal, bool), + Stopped(Pid, Signal), #[cfg(any(target_os = "linux", target_os = "android"))] - PtraceEvent(pid_t, Signal, c_int), - Continued(pid_t), + PtraceEvent(Pid, Signal, c_int), + Continued(Pid), StillAlive } @@ -185,7 +186,7 @@ mod status { } } -fn decode(pid : pid_t, status: i32) -> WaitStatus { +fn decode(pid : Pid, status: i32) -> WaitStatus { if status::exited(status) { WaitStatus::Exited(pid, status::exit_status(status)) } else if status::signaled(status) { @@ -193,7 +194,7 @@ fn decode(pid : pid_t, status: i32) -> WaitStatus { } else if status::stopped(status) { cfg_if! { if #[cfg(any(target_os = "linux", target_os = "android"))] { - fn decode_stopped(pid: pid_t, status: i32) -> WaitStatus { + fn decode_stopped(pid: Pid, status: i32) -> WaitStatus { let status_additional = status::stop_additional(status); if status_additional == 0 { WaitStatus::Stopped(pid, status::stop_signal(status)) @@ -202,7 +203,7 @@ fn decode(pid : pid_t, status: i32) -> WaitStatus { } } } else { - fn decode_stopped(pid: pid_t, status: i32) -> WaitStatus { + fn decode_stopped(pid: Pid, status: i32) -> WaitStatus { WaitStatus::Stopped(pid, status::stop_signal(status)) } } @@ -214,7 +215,7 @@ fn decode(pid : pid_t, status: i32) -> WaitStatus { } } -pub fn waitpid(pid: pid_t, options: Option) -> Result { +pub fn waitpid>>(pid: P, options: Option) -> Result { use self::WaitStatus::*; let mut status: i32 = 0; @@ -224,14 +225,14 @@ pub fn waitpid(pid: pid_t, options: Option) -> Result { None => 0 }; - let res = unsafe { ffi::waitpid(pid as pid_t, &mut status as *mut c_int, option_bits) }; + let res = unsafe { ffi::waitpid(pid.into().unwrap_or(Pid::from_raw(-1)).into(), &mut status as *mut c_int, option_bits) }; Ok(match try!(Errno::result(res)) { 0 => StillAlive, - res => decode(res, status), + res => decode(Pid::from_raw(res), status), }) } pub fn wait() -> Result { - waitpid(-1, None) + waitpid(None, None) } diff --git a/src/unistd.rs b/src/unistd.rs index 566212d0..2925f41c 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -11,10 +11,128 @@ use std::os::unix::io::RawFd; use std::path::{PathBuf}; use void::Void; use sys::stat::Mode; +use std::fmt; #[cfg(any(target_os = "linux", target_os = "android"))] pub use self::linux::*; +/// User identifier +/// +/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally +/// passing wrong value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Uid(uid_t); + +impl Uid { + /// Creates `Uid` from raw `uid_t`. + pub fn from_raw(uid: uid_t) -> Self { + Uid(uid) + } + + /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`. + pub fn current() -> Self { + getuid() + } + + /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`. + pub fn effective() -> Self { + geteuid() + } + + /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.) + pub fn is_root(&self) -> bool { + *self == ROOT + } +} + +impl From for uid_t { + fn from(uid: Uid) -> Self { + uid.0 + } +} + +impl fmt::Display for Uid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +/// Constant for UID = 0 +pub const ROOT: Uid = Uid(0); + +/// Group identifier +/// +/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally +/// passing wrong value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Gid(gid_t); + +impl Gid { + /// Creates `Gid` from raw `gid_t`. + pub fn from_raw(gid: gid_t) -> Self { + Gid(gid) + } + + /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`. + pub fn current() -> Self { + getgid() + } + + /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getgid`. + pub fn effective() -> Self { + getegid() + } +} + +impl From for gid_t { + fn from(gid: Gid) -> Self { + gid.0 + } +} + +impl fmt::Display for Gid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +/// Process identifier +/// +/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally +/// passing wrong value. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Pid(pid_t); + +impl Pid { + /// Creates `Pid` from raw `pid_t`. + pub fn from_raw(pid: pid_t) -> Self { + Pid(pid) + } + + /// Returns PID of calling process + pub fn this() -> Self { + getpid() + } + + /// Returns PID of parent of calling process + pub fn parent() -> Self { + getppid() + } +} + +impl From for pid_t { + fn from(pid: Pid) -> Self { + pid.0 + } +} + +impl fmt::Display for Pid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + + /// Represents the successful result of calling `fork` /// /// When `fork` is called, the process continues execution in the parent process @@ -22,7 +140,7 @@ pub use self::linux::*; /// you are now executing in the parent process or in the child. #[derive(Clone, Copy)] pub enum ForkResult { - Parent { child: pid_t }, + Parent { child: Pid }, Child, } @@ -78,7 +196,7 @@ pub fn fork() -> Result { Errno::result(res).map(|res| match res { 0 => Child, - res => Parent { child: res }, + res => Parent { child: Pid(res) }, }) } @@ -88,8 +206,8 @@ pub fn fork() -> Result { /// Since you are running code, there is always a pid to return, so there /// is no error case that needs to be handled. #[inline] -pub fn getpid() -> pid_t { - unsafe { libc::getpid() } +pub fn getpid() -> Pid { + Pid(unsafe { libc::getpid() }) } /// Get the pid of this processes' parent (see @@ -98,8 +216,8 @@ pub fn getpid() -> pid_t { /// There is always a parent pid to return, so there is no error case that needs /// to be handled. #[inline] -pub fn getppid() -> pid_t { - unsafe { libc::getppid() } // no error handling, according to man page: "These functions are always successful." +pub fn getppid() -> Pid { + Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful." } /// Set a process group ID (see @@ -112,21 +230,21 @@ pub fn getppid() -> pid_t { /// /// `setsid()` may be used to create a new process group. #[inline] -pub fn setpgid(pid: pid_t, pgid: pid_t) -> Result<()> { - let res = unsafe { libc::setpgid(pid, pgid) }; +pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> { + let res = unsafe { libc::setpgid(pid.into(), pgid.into()) }; Errno::result(res).map(drop) } #[inline] -pub fn getpgid(pid: Option) -> Result { - let res = unsafe { libc::getpgid(pid.unwrap_or(0 as pid_t)) }; - Errno::result(res) +pub fn getpgid(pid: Option) -> Result { + let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) }; + Errno::result(res).map(Pid) } /// Create new session and set process group id (see /// [setsid(2)](http://man7.org/linux/man-pages/man2/setsid.2.html)). #[inline] -pub fn setsid() -> Result { - Errno::result(unsafe { libc::setsid() }) +pub fn setsid() -> Result { + Errno::result(unsafe { libc::setsid() }).map(Pid) } @@ -136,9 +254,9 @@ pub fn setsid() -> Result { /// Get the group process id (GPID) of the foreground process group on the /// terminal associated to file descriptor (FD). #[inline] -pub fn tcgetpgrp(fd: c_int) -> Result { +pub fn tcgetpgrp(fd: c_int) -> Result { let res = unsafe { libc::tcgetpgrp(fd) }; - Errno::result(res) + Errno::result(res).map(Pid) } /// Set the terminal foreground process group (see /// [tcgetpgrp(3)](http://man7.org/linux/man-pages/man3/tcgetpgrp.3.html)). @@ -146,8 +264,8 @@ pub fn tcgetpgrp(fd: c_int) -> Result { /// Get the group process id (PGID) to the foreground process group on the /// terminal associated to file descriptor (FD). #[inline] -pub fn tcsetpgrp(fd: c_int, pgrp: pid_t) -> Result<()> { - let res = unsafe { libc::tcsetpgrp(fd, pgrp) }; +pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> { + let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) }; Errno::result(res).map(drop) } @@ -158,8 +276,8 @@ pub fn tcsetpgrp(fd: c_int, pgrp: pid_t) -> Result<()> { /// Get the process group id (PGID) of the calling process. /// According to the man page it is always successful. #[inline] -pub fn getpgrp() -> pid_t { - unsafe { libc::getpgrp() } +pub fn getpgrp() -> Pid { + Pid(unsafe { libc::getpgrp() }) } /// Get the caller's thread ID (see @@ -174,8 +292,8 @@ pub fn getpgrp() -> pid_t { /// process, even if threads are not being used. #[cfg(any(target_os = "linux", target_os = "android"))] #[inline] -pub fn gettid() -> pid_t { - unsafe { libc::syscall(libc::SYS_gettid) as pid_t } +pub fn gettid() -> Pid { + Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t }) } /// Create a copy of the specified file descriptor (see @@ -368,14 +486,14 @@ pub fn getcwd() -> Result { /// pages](http://man7.org/linux/man-pages/man2/lchown.2.html#ERRORS) for /// additional details. #[inline] -pub fn chown(path: &P, owner: Option, group: Option) -> Result<()> { +pub fn chown(path: &P, owner: Option, group: Option) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { // According to the POSIX specification, -1 is used to indicate that // owner and group, respectively, are not to be changed. Since uid_t and // gid_t are unsigned types, we use wrapping_sub to get '-1'. unsafe { libc::chown(cstr.as_ptr(), - owner.unwrap_or((0 as uid_t).wrapping_sub(1)), - group.unwrap_or((0 as gid_t).wrapping_sub(1))) } + owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1)), + group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1))) } })); Errno::result(res).map(drop) @@ -738,35 +856,35 @@ pub fn fdatasync(fd: RawFd) -> Result<()> { // - http://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html // - http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html #[inline] -pub fn getuid() -> uid_t { - unsafe { libc::getuid() } +pub fn getuid() -> Uid { + Uid(unsafe { libc::getuid() }) } #[inline] -pub fn geteuid() -> uid_t { - unsafe { libc::geteuid() } +pub fn geteuid() -> Uid { + Uid(unsafe { libc::geteuid() }) } #[inline] -pub fn getgid() -> gid_t { - unsafe { libc::getgid() } +pub fn getgid() -> Gid { + Gid(unsafe { libc::getgid() }) } #[inline] -pub fn getegid() -> gid_t { - unsafe { libc::getegid() } +pub fn getegid() -> Gid { + Gid(unsafe { libc::getegid() }) } #[inline] -pub fn setuid(uid: uid_t) -> Result<()> { - let res = unsafe { libc::setuid(uid) }; +pub fn setuid(uid: Uid) -> Result<()> { + let res = unsafe { libc::setuid(uid.into()) }; Errno::result(res).map(drop) } #[inline] -pub fn setgid(gid: gid_t) -> Result<()> { - let res = unsafe { libc::setgid(gid) }; +pub fn setgid(gid: Gid) -> Result<()> { + let res = unsafe { libc::setgid(gid.into()) }; Errno::result(res).map(drop) } @@ -821,9 +939,10 @@ pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { #[cfg(any(target_os = "linux", target_os = "android"))] mod linux { - use libc::{self, uid_t, gid_t}; + use libc; use sys::syscall::{syscall, SYSPIVOTROOT}; use {Errno, Result, NixPath}; + use super::{Uid, Gid}; #[cfg(feature = "execvpe")] use std::ffi::CString; @@ -851,8 +970,8 @@ mod linux { /// /// Err is returned if the user doesn't have permission to set this UID. #[inline] - pub fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) -> Result<()> { - let res = unsafe { libc::setresuid(ruid, euid, suid) }; + pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> { + let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) }; Errno::result(res).map(drop) } @@ -867,8 +986,8 @@ mod linux { /// /// Err is returned if the user doesn't have permission to set this GID. #[inline] - pub fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) -> Result<()> { - let res = unsafe { libc::setresgid(rgid, egid, sgid) }; + pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> { + let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) }; Errno::result(res).map(drop) } -- cgit v1.2.3