From 4dcef4b78abc3a7fc3f7d6bfae1d34868421dc49 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 22 Sep 2023 17:47:30 -0700 Subject: [PATCH] WIP port from nix to rustix --- wayland-backend/Cargo.toml | 13 ++--- wayland-backend/src/rs/server_impl/client.rs | 23 +++++---- .../src/rs/server_impl/common_poll.rs | 20 ++++---- wayland-backend/src/rs/server_impl/handle.rs | 17 ++++--- wayland-backend/src/rs/socket.rs | 50 ++++++++++--------- wayland-backend/src/types/server.rs | 6 +-- wayland-client/Cargo.toml | 2 +- wayland-client/src/conn.rs | 27 +++++----- wayland-client/src/event_queue.rs | 3 +- wayland-cursor/Cargo.toml | 2 +- wayland-cursor/src/lib.rs | 44 +++++++--------- wayland-server/Cargo.toml | 2 +- wayland-server/src/socket.rs | 4 +- 13 files changed, 106 insertions(+), 107 deletions(-) diff --git a/wayland-backend/Cargo.toml b/wayland-backend/Cargo.toml index 766a7a25963..e54aff17723 100644 --- a/wayland-backend/Cargo.toml +++ b/wayland-backend/Cargo.toml @@ -19,6 +19,7 @@ log = { version = "0.4", optional = true } scoped-tls = "1.0" downcast-rs = "1.2" raw-window-handle = { version = "0.5.0", optional = true } +libc = "0.2.148" [dependencies.smallvec] version = "1.9" @@ -29,15 +30,15 @@ features = [ "const_new", # 1.51 ] -[dependencies.nix] -version = "0.26.0" -default-features = false +[dependencies.rustix] +# version = "0.38.0" +git = "https://github.com/ids1024/rustix" +branch = "peercred" features = [ "event", "fs", - "poll", - "socket", - "uio", + "net", + "process", ] [build-dependencies] diff --git a/wayland-backend/src/rs/server_impl/client.rs b/wayland-backend/src/rs/server_impl/client.rs index eb845e6fa47..b324d5fb09c 100644 --- a/wayland-backend/src/rs/server_impl/client.rs +++ b/wayland-backend/src/rs/server_impl/client.rs @@ -1,6 +1,6 @@ use std::{ ffi::CString, - os::unix::io::OwnedFd, + os::unix::io::{AsFd, BorrowedFd, OwnedFd}, os::unix::{io::RawFd, net::UnixStream}, sync::Arc, }; @@ -295,13 +295,10 @@ impl Client { #[cfg(any(target_os = "linux", target_os = "android"))] pub(crate) fn get_credentials(&self) -> Credentials { - use std::os::unix::io::AsRawFd; - let creds = nix::sys::socket::getsockopt( - self.socket.as_raw_fd(), - nix::sys::socket::sockopt::PeerCredentials, - ) - .expect("getsockopt failed!?"); - Credentials { pid: creds.pid(), uid: creds.uid(), gid: creds.gid() } + let creds = + rustix::net::sockopt::get_socket_peercred(&self.socket).expect("getsockopt failed!?"); + let pid = rustix::process::Pid::as_raw(Some(creds.pid)); + Credentials { pid, uid: creds.uid.as_raw(), gid: creds.gid.as_raw() } } #[cfg(not(any(target_os = "linux", target_os = "android")))] @@ -336,7 +333,7 @@ impl Client { &mut self, ) -> std::io::Result<(Message, Object>)> { if self.killed { - return Err(nix::errno::Errno::EPIPE.into()); + return Err(rustix::io::Errno::PIPE.into()); } loop { let map = &self.map; @@ -358,7 +355,7 @@ impl Client { } Err(MessageParseError::Malformed) => { self.kill(DisconnectReason::ConnectionClosed); - return Err(nix::errno::Errno::EPROTO.into()); + return Err(rustix::io::Errno::PROTO.into()); } }; @@ -659,6 +656,12 @@ impl Client { } } +impl AsFd for Client { + fn as_fd(&self) -> BorrowedFd<'_> { + self.socket.as_fd() + } +} + #[derive(Debug)] pub(crate) struct ClientStore { clients: Vec>>, diff --git a/wayland-backend/src/rs/server_impl/common_poll.rs b/wayland-backend/src/rs/server_impl/common_poll.rs index c0b8fd4ac3b..dc281789267 100644 --- a/wayland-backend/src/rs/server_impl/common_poll.rs +++ b/wayland-backend/src/rs/server_impl/common_poll.rs @@ -1,5 +1,5 @@ use std::{ - os::unix::io::{AsRawFd, FromRawFd}, + os::unix::io::{AsFd, AsRawFd}, os::unix::io::{BorrowedFd, OwnedFd}, sync::{Arc, Mutex}, }; @@ -16,7 +16,7 @@ use crate::{ }; #[cfg(any(target_os = "linux", target_os = "android"))] -use nix::sys::epoll::*; +use rustix::event::epoll; #[cfg(any( target_os = "dragonfly", @@ -35,7 +35,7 @@ pub struct InnerBackend { impl InnerBackend { pub fn new() -> Result { #[cfg(any(target_os = "linux", target_os = "android"))] - let poll_fd = epoll_create1(EpollCreateFlags::EPOLL_CLOEXEC) + let poll_fd = epoll::create(epoll::CreateFlags::CLOEXEC) .map_err(Into::into) .map_err(InitError::Io)?; @@ -47,9 +47,7 @@ impl InnerBackend { ))] let poll_fd = kqueue().map_err(Into::into).map_err(InitError::Io)?; - Ok(Self { - state: Arc::new(Mutex::new(State::new(unsafe { OwnedFd::from_raw_fd(poll_fd) }))), - }) + Ok(Self { state: Arc::new(Mutex::new(State::new(poll_fd))) }) } pub fn flush(&self, client: Option) -> std::io::Result<()> { @@ -83,15 +81,15 @@ impl InnerBackend { let poll_fd = self.poll_fd(); let mut dispatched = 0; loop { - let mut events = [EpollEvent::empty(); 32]; - let nevents = epoll_wait(poll_fd.as_raw_fd(), &mut events, 0)?; + let mut events = epoll::EventVec::with_capacity(32); + epoll::wait(poll_fd.as_fd(), &mut events, 0)?; - if nevents == 0 { + if events.is_empty() { break; } - for event in events.iter().take(nevents) { - let id = InnerClientId::from_u64(event.data()); + for event in events.iter() { + let id = InnerClientId::from_u64(event.data.u64()); // remove the cb while we call it, to gracefully handle reentrancy if let Ok(count) = self.dispatch_events_for(data, id) { dispatched += count; diff --git a/wayland-backend/src/rs/server_impl/handle.rs b/wayland-backend/src/rs/server_impl/handle.rs index 0ec5de8e4cf..91149289f36 100644 --- a/wayland-backend/src/rs/server_impl/handle.rs +++ b/wayland-backend/src/rs/server_impl/handle.rs @@ -1,10 +1,7 @@ use std::{ ffi::CString, os::unix::io::OwnedFd, - os::unix::{ - io::{AsRawFd, RawFd}, - net::UnixStream, - }, + os::unix::{io::RawFd, net::UnixStream}, sync::{Arc, Mutex, Weak}, }; @@ -314,15 +311,19 @@ impl ErasedState for State { stream: UnixStream, data: Arc, ) -> std::io::Result { - let client_fd = stream.as_raw_fd(); let id = self.clients.create_client(stream, data); + let client = self.clients.get_client(id.clone()).unwrap(); // register the client to the internal epoll #[cfg(any(target_os = "linux", target_os = "android"))] let ret = { - use nix::sys::epoll::*; - let mut evt = EpollEvent::new(EpollFlags::EPOLLIN, id.as_u64()); - epoll_ctl(self.poll_fd.as_raw_fd(), EpollOp::EpollCtlAdd, client_fd, &mut evt) + use rustix::event::epoll; + epoll::add( + &self.poll_fd, + &client, + epoll::EventData::new_u64(id.as_u64()), + epoll::EventFlags::IN, + ) }; #[cfg(any( diff --git a/wayland-backend/src/rs/socket.rs b/wayland-backend/src/rs/socket.rs index 27c7749f761..b3755531a84 100644 --- a/wayland-backend/src/rs/socket.rs +++ b/wayland-backend/src/rs/socket.rs @@ -1,11 +1,13 @@ //! Wayland socket manipulation use std::io::{ErrorKind, IoSlice, IoSliceMut, Result as IoResult}; -use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd}; +use std::os::unix::io::{AsFd, BorrowedFd, IntoRawFd, OwnedFd}; use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::net::UnixStream; -use nix::sys::socket; +use rustix::net::{ + recvmsg, sendmsg, RecvAncillaryBuffer, RecvFlags, SendAncillaryBuffer, SendFlags, +}; use crate::protocol::{ArgumentType, Message}; @@ -35,15 +37,12 @@ impl Socket { /// slice should not be longer than `MAX_BYTES_OUT` otherwise the receiving /// end may lose some data. pub fn send_msg(&self, bytes: &[u8], fds: &[RawFd]) -> IoResult { - let flags = socket::MsgFlags::MSG_DONTWAIT | socket::MsgFlags::MSG_NOSIGNAL; + let flags = SendFlags::DONTWAIT | SendFlags::NOSIGNAL; let iov = [IoSlice::new(bytes)]; - if !fds.is_empty() { - let cmsgs = [socket::ControlMessage::ScmRights(fds)]; - Ok(socket::sendmsg::<()>(self.stream.as_raw_fd(), &iov, &cmsgs, flags, None)?) - } else { - Ok(socket::sendmsg::<()>(self.stream.as_raw_fd(), &iov, &[], flags, None)?) - } + let mut cmsg_space = vec![0; rustix::cmsg_space!(ScmRights(fds.len()))]; + let mut cmsg_buffer = SendAncillaryBuffer::new(&mut cmsg_space); + Ok(sendmsg(&self, &iov, &mut cmsg_buffer, flags)?) } /// Receive a single message from the socket @@ -58,25 +57,28 @@ impl Socket { /// slice `MAX_FDS_OUT` long, otherwise some data of the received message may /// be lost. pub fn rcv_msg(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> IoResult<(usize, usize)> { - let mut cmsg = nix::cmsg_space!([RawFd; MAX_FDS_OUT]); + let mut cmsg_space = vec![0; rustix::cmsg_space!(ScmRights(MAX_FDS_OUT))]; + let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut cmsg_space); let mut iov = [IoSliceMut::new(buffer)]; - let msg = socket::recvmsg::<()>( - self.stream.as_raw_fd(), + let msg = recvmsg( + &self.stream, &mut iov[..], - Some(&mut cmsg), - socket::MsgFlags::MSG_DONTWAIT - | socket::MsgFlags::MSG_CMSG_CLOEXEC - | socket::MsgFlags::MSG_NOSIGNAL, + &mut cmsg_buffer, + RecvFlags::DONTWAIT | RecvFlags::CMSG_CLOEXEC, )?; let mut fd_count = 0; - let received_fds = msg.cmsgs().flat_map(|cmsg| match cmsg { - socket::ControlMessageOwned::ScmRights(s) => s, - _ => Vec::new(), - }); + let received_fds = cmsg_buffer + .drain() + .filter_map(|cmsg| match cmsg { + rustix::net::RecvAncillaryMessage::ScmRights(fds) => Some(fds), + _ => None, + }) + .flatten(); for (fd, place) in received_fds.zip(fds.iter_mut()) { fd_count += 1; - *place = fd; + // TODO use OwnedFd? + *place = fd.into_raw_fd(); } Ok((msg.bytes, fd_count)) } @@ -141,7 +143,7 @@ impl BufferedSocket { let written = self.socket.send_msg(bytes, fds)?; for &fd in fds { // once the fds are sent, we can close them - let _ = ::nix::unistd::close(fd); + let _ = unsafe { libc::close(fd) }; } written }; @@ -192,7 +194,7 @@ impl BufferedSocket { if !self.attempt_write_message(msg)? { // If this fails again, this means the message is too big // to be transmitted at all - return Err(::nix::errno::Errno::E2BIG.into()); + return Err(rustix::io::Errno::TOOBIG.into()); } } Ok(()) @@ -215,7 +217,7 @@ impl BufferedSocket { }; if in_bytes == 0 { // the other end of the socket was closed - return Err(::nix::errno::Errno::EPIPE.into()); + return Err(rustix::io::Errno::PIPE.into()); } // advance the storage self.in_data.advance(in_bytes / 4 + usize::from(in_bytes % 4 > 0)); diff --git a/wayland-backend/src/types/server.rs b/wayland-backend/src/types/server.rs index 27b286a8bba..3377479078a 100644 --- a/wayland-backend/src/types/server.rs +++ b/wayland-backend/src/types/server.rs @@ -66,9 +66,9 @@ pub enum DisconnectReason { #[derive(Debug, Clone, Copy)] pub struct Credentials { /// pid of the client - pub pid: nix::libc::pid_t, + pub pid: libc::pid_t, /// uid of the client - pub uid: nix::libc::uid_t, + pub uid: libc::uid_t, /// gid of the client - pub gid: nix::libc::gid_t, + pub gid: libc::gid_t, } diff --git a/wayland-client/Cargo.toml b/wayland-client/Cargo.toml index 2aa03c1ba43..d51bb3cfa50 100644 --- a/wayland-client/Cargo.toml +++ b/wayland-client/Cargo.toml @@ -16,7 +16,7 @@ readme = "README.md" wayland-backend = { version = "0.3.1", path = "../wayland-backend" } wayland-scanner = { version = "0.31.0", path = "../wayland-scanner" } bitflags = "2" -nix = { version = "0.26.0", default-features = false } +rustix = { version = "0.38.0", features = ["event"] } log = { version = "0.4", optional = true } [dev-dependencies] diff --git a/wayland-client/src/conn.rs b/wayland-client/src/conn.rs index 3dc89af8796..489315d6c22 100644 --- a/wayland-client/src/conn.rs +++ b/wayland-client/src/conn.rs @@ -16,8 +16,6 @@ use wayland_backend::{ protocol::{ObjectInfo, ProtocolError}, }; -use nix::{fcntl, Error}; - use crate::{protocol::wl_display::WlDisplay, EventQueue, Proxy}; /// The Wayland connection @@ -50,21 +48,23 @@ impl Connection { let stream = if let Ok(txt) = env::var("WAYLAND_SOCKET") { // We should connect to the provided WAYLAND_SOCKET let fd = txt.parse::().map_err(|_| ConnectError::InvalidFd)?; + let fd = unsafe { OwnedFd::from_raw_fd(fd) }; // remove the variable so any child processes don't see it env::remove_var("WAYLAND_SOCKET"); // set the CLOEXEC flag on this FD - let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD); + let flags = rustix::io::fcntl_getfd(&fd); let result = flags - .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC) - .and_then(|f| fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(f))); + .map(|f| f | rustix::io::FdFlags::CLOEXEC) + .and_then(|f| rustix::io::fcntl_setfd(&fd, f)); match result { Ok(_) => { // setting the O_CLOEXEC worked - unsafe { FromRawFd::from_raw_fd(fd) } + // XXX + use rustix::fd::IntoRawFd; + unsafe { FromRawFd::from_raw_fd(fd.into_raw_fd()) } } Err(_) => { // something went wrong in F_GETFD or F_SETFD - let _ = ::nix::unistd::close(fd); return Err(ConnectError::InvalidFd); } } @@ -156,7 +156,7 @@ impl Connection { crate::protocol::wl_display::Request::Sync {}, Some(done.clone()), ) - .map_err(|_| WaylandError::Io(Error::EPIPE.into()))?; + .map_err(|_| WaylandError::Io(rustix::io::Errno::PIPE.into()))?; let mut dispatched = 0; @@ -220,15 +220,16 @@ impl Connection { } pub(crate) fn blocking_read(guard: ReadEventsGuard) -> Result { - let mut fds = [nix::poll::PollFd::new( - guard.connection_fd().as_raw_fd(), - nix::poll::PollFlags::POLLIN | nix::poll::PollFlags::POLLERR, + let fd = guard.connection_fd(); + let mut fds = [rustix::event::PollFd::new( + &fd, + rustix::event::PollFlags::IN | rustix::event::PollFlags::ERR, )]; loop { - match nix::poll::poll(&mut fds, -1) { + match rustix::event::poll(&mut fds, -1) { Ok(_) => break, - Err(nix::errno::Errno::EINTR) => continue, + Err(rustix::io::Errno::INTR) => continue, Err(e) => return Err(WaylandError::Io(e.into())), } } diff --git a/wayland-client/src/event_queue.rs b/wayland-client/src/event_queue.rs index 5507ab9e98d..94674bd3747 100644 --- a/wayland-client/src/event_queue.rs +++ b/wayland-client/src/event_queue.rs @@ -6,7 +6,6 @@ use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd}; use std::sync::{atomic::Ordering, Arc, Condvar, Mutex}; use std::task; -use nix::Error; use wayland_backend::{ client::{Backend, ObjectData, ObjectId, ReadEventsGuard, WaylandError}, protocol::{Argument, Message}, @@ -424,7 +423,7 @@ impl EventQueue { crate::protocol::wl_display::Request::Sync {}, Some(done.clone()), ) - .map_err(|_| WaylandError::Io(Error::EPIPE.into()))?; + .map_err(|_| WaylandError::Io(rustix::io::Errno::PIPE.into()))?; let mut dispatched = 0; diff --git a/wayland-cursor/Cargo.toml b/wayland-cursor/Cargo.toml index fec81b01b1c..5d57a9e1d16 100644 --- a/wayland-cursor/Cargo.toml +++ b/wayland-cursor/Cargo.toml @@ -15,7 +15,7 @@ readme = "README.md" [dependencies] wayland-client = { version = "0.31.0", path = "../wayland-client" } xcursor = "0.3.1" -nix = { version = "0.26.0", default-features = false, features = ["mman"] } +rustix = { version = "0.38.15", features = ["shm"] } [package.metadata.docs.rs] all-features = true diff --git a/wayland-cursor/src/lib.rs b/wayland-cursor/src/lib.rs index a7e3061dc6f..b527ffe4334 100644 --- a/wayland-cursor/src/lib.rs +++ b/wayland-cursor/src/lib.rs @@ -49,16 +49,16 @@ use std::env; use std::fs::File; use std::io::{Error as IoError, Read, Result as IoResult, Seek, SeekFrom, Write}; use std::ops::{Deref, Index}; -use std::os::unix::io::{AsFd, FromRawFd, OwnedFd, RawFd}; +use std::os::unix::io::{AsFd, OwnedFd}; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; -use nix::errno::Errno; -use nix::fcntl; -use nix::sys::{mman, stat}; -use nix::unistd; #[cfg(any(target_os = "linux", target_os = "android"))] -use {nix::sys::memfd, std::ffi::CStr}; +use rustix::fs::{memfd_create, MemfdFlags, Mode}; +use rustix::io::Errno; +use rustix::shm::{shm_open, shm_unlink, ShmOFlags}; +#[cfg(any(target_os = "linux", target_os = "android"))] +use std::ffi::CStr; use wayland_client::backend::{InvalidId, ObjectData, WeakBackend}; use wayland_client::protocol::wl_buffer::WlBuffer; @@ -134,7 +134,7 @@ impl CursorTheme { // Create shm. let mem_fd = create_shm_fd().expect("Shm fd allocation failed"); - let mut file = unsafe { File::from_raw_fd(mem_fd) }; + let mut file = File::from(mem_fd); file.set_len(INITIAL_POOL_SIZE as u64).expect("Failed to set buffer length"); // Ensure that we have the same we requested. @@ -374,17 +374,17 @@ pub struct FrameAndDuration { } /// Create a shared file descriptor in memory. -fn create_shm_fd() -> IoResult { +fn create_shm_fd() -> IoResult { // Only try memfd on systems that provide it, (like Linux, Android) #[cfg(any(target_os = "linux", target_os = "android"))] loop { - match memfd::memfd_create( + match memfd_create( CStr::from_bytes_with_nul(b"wayland-cursor-rs\0").unwrap(), - memfd::MemFdCreateFlag::MFD_CLOEXEC, + MemfdFlags::CLOEXEC, ) { Ok(fd) => return Ok(fd), - Err(Errno::EINTR) => continue, - Err(Errno::ENOSYS) => break, + Err(Errno::INTR) => continue, + Err(Errno::NOSYS) => break, Err(errno) => return Err(errno.into()), } } @@ -396,22 +396,16 @@ fn create_shm_fd() -> IoResult { sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos() ); loop { - match mman::shm_open( + match shm_open( mem_file_handle.as_str(), - fcntl::OFlag::O_CREAT - | fcntl::OFlag::O_EXCL - | fcntl::OFlag::O_RDWR - | fcntl::OFlag::O_CLOEXEC, - stat::Mode::S_IRUSR | stat::Mode::S_IWUSR, + ShmOFlags::CREATE | ShmOFlags::EXCL | ShmOFlags::RDWR, + Mode::RUSR | Mode::WUSR, ) { - Ok(fd) => match mman::shm_unlink(mem_file_handle.as_str()) { + Ok(fd) => match shm_unlink(mem_file_handle.as_str()) { Ok(_) => return Ok(fd), - Err(errno) => match unistd::close(fd) { - Ok(_) => return Err(IoError::from(errno)), - Err(errno) => return Err(IoError::from(errno)), - }, + Err(errno) => return Err(IoError::from(errno)), }, - Err(Errno::EEXIST) => { + Err(Errno::EXIST) => { // If a file with that handle exists then change the handle mem_file_handle = format!( "/wayland-cursor-rs-{}", @@ -419,7 +413,7 @@ fn create_shm_fd() -> IoResult { ); continue; } - Err(Errno::EINTR) => continue, + Err(Errno::INTR) => continue, Err(errno) => return Err(IoError::from(errno)), } } diff --git a/wayland-server/Cargo.toml b/wayland-server/Cargo.toml index 020d6f37ad8..e6d80c0e85e 100644 --- a/wayland-server/Cargo.toml +++ b/wayland-server/Cargo.toml @@ -17,9 +17,9 @@ wayland-backend = { version = "0.3.0", path = "../wayland-backend" } wayland-scanner = { version = "0.31.0", path = "../wayland-scanner" } bitflags = "2" log = { version = "0.4", optional = true } -nix = { version = "0.26.0", default-features = false } downcast-rs = "1.2" io-lifetimes = "2" +rustix = { version = "0.38.14", features = ["fs"] } [package.metadata.docs.rs] all-features = true diff --git a/wayland-server/src/socket.rs b/wayland-server/src/socket.rs index ce40c838998..1b594ab1b5e 100644 --- a/wayland-server/src/socket.rs +++ b/wayland-server/src/socket.rs @@ -15,7 +15,7 @@ use std::{ path::PathBuf, }; -use nix::fcntl::{flock, FlockArg}; +use rustix::fs::{flock, FlockOperation}; /// An utility representing a unix socket on which your compositor is listening for new clients #[derive(Debug)] @@ -91,7 +91,7 @@ impl ListeningSocket { .map_err(|_| BindError::PermissionDenied)?; // lock the lockfile - if flock(_lock.as_raw_fd(), FlockArg::LockExclusiveNonblock).is_err() { + if flock(&_lock, FlockOperation::NonBlockingLockExclusive).is_err() { return Err(BindError::AlreadyInUse); }