From 082953c364f80a54a5b9548dddfffa65e6749a94 Mon Sep 17 00:00:00 2001 From: Hannes de Jager Date: Sun, 19 May 2024 12:37:30 +0200 Subject: [PATCH] Fix windows build The windows build got broken since it seems we introduced non-backwards compatible code during the Capsicum additions. In this commit I hide some of that code behind a '#[cfg(unix))' conditional. I also added CI builds for all supported platforms that will run in the context of pull requests. --- .github/workflows/rust.yml | 112 +++++++++++++++++++++++++++++++++ src/server/ftpserver.rs | 1 + src/server/ftpserver/listen.rs | 53 ++++++++++------ 3 files changed, 147 insertions(+), 19 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index caee4b95..7d282956 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -80,3 +80,115 @@ jobs: run: cargo build --workspace - name: Build Docs run: cargo doc --workspace --no-deps + + build-linux-gnu: + runs-on: ubuntu-latest + if: ${{ github.ref != 'refs/heads/master' }} + name: Build on Linux (GNU) + env: + target: x86_64-unknown-linux-gnu + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 # Otherwise the code that retrieves the git version doesn't work + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.RUST_VERSION }} + override: true + default: true + target: ${{ env.target }} + - name: Install build dependencies + run: sudo apt-get update && sudo apt-get install -y libpam-dev + - name: Build for Linux (GNU) + run: cargo build --target=${{ env.target }} + + build-linux-musl: + runs-on: ubuntu-latest + if: ${{ github.ref != 'refs/heads/master' }} + name: Build on Linux (MUSL) + env: + target: x86_64-unknown-linux-musl + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 # Otherwise the code that retrieves the git version doesn't work + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.RUST_VERSION }} + override: true + default: true + target: ${{ env.target }} + - name: Install build dependencies + run: sudo apt-get update && sudo apt-get install -y musl-tools + - name: Build for Linux (MUSL) + run: RUSTFLAGS="-C target-feature=+crt-static" cargo build --target=${{ env.target }} + + build-windows: + runs-on: windows-latest + if: ${{ github.ref != 'refs/heads/master' }} + name: Build on Windows + env: + trget: x86_64-pc-windows-msvc + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 # Otherwise the code that retrieves the git version doesn't work + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.RUST_VERSION }} + override: true + default: true + target: ${{ env.trget }} + - name: Build for Windows + run: cargo build --target=${{ env.trget }} + + build-macos-intel: + runs-on: macos-latest + if: ${{ github.ref != 'refs/heads/master' }} + name: Build on macOS (Intel) + env: + target: x86_64-apple-darwin + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 # Otherwise the code that retrieves the git version doesn't work + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.RUST_VERSION }} + override: true + default: true + target: ${{ env.target }} + - name: Build for macOS (Intel) + run: cargo build --target=${{ env.target }} + + build-macos-arm: + runs-on: macos-latest + if: ${{ github.ref != 'refs/heads/master' }} + name: Build on macOS (ARM) + env: + target: aarch64-apple-darwin + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 # Otherwise the code that retrieves the git version doesn't work + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ env.RUST_VERSION }} + override: true + default: true + target: ${{ env.target }} + - name: Install Rosetta + if: runner.os == 'macOS' && runner.arch == 'arm64' + run: softwareupdate --install-rosetta --agree-to-license + - name: Build + run: cargo build --target=${{ env.target }} diff --git a/src/server/ftpserver.rs b/src/server/ftpserver.rs index f2393a07..875e061f 100644 --- a/src/server/ftpserver.rs +++ b/src/server/ftpserver.rs @@ -599,6 +599,7 @@ where /// /// - `path` - Path to the helper executable /// - `args` - Optional arguments to pass to the helper executable. + #[cfg(unix)] pub fn connection_helper(mut self, path: OsString, args: Vec) -> Self { self.connection_helper = Some(path); self.connection_helper_args = args; diff --git a/src/server/ftpserver/listen.rs b/src/server/ftpserver/listen.rs index 7b7f8bc8..c53d834c 100644 --- a/src/server/ftpserver/listen.rs +++ b/src/server/ftpserver/listen.rs @@ -6,6 +6,7 @@ use crate::server::shutdown; use crate::{auth::UserDetail, server::controlchan, storage::StorageBackend}; use std::ffi::OsString; use std::net::SocketAddr; +#[cfg(unix)] use std::os::fd::AsRawFd; use std::sync::Arc; use tokio::net::TcpListener; @@ -49,25 +50,11 @@ where Ok((tcp_stream, socket_addr)) => { slog::info!(logger, "Incoming control connection from {:?}", socket_addr); if let Some(helper) = connection_helper.as_ref() { - slog::info!(logger, "Spawning {:?}", helper); - let fd = tcp_stream.as_raw_fd(); - nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_SETFD(nix::fcntl::FdFlag::empty())).unwrap(); - let result = tokio::process::Command::new(helper) - .args(connection_helper_args.iter()) - .arg(fd.to_string()) - .spawn(); - let logger2 = logger.clone(); - match result { - Ok(mut child) => { - tokio::spawn(async move { - let child_status = child.wait().await; - slog::debug!(logger2, "helper process exited {:?}", child_status); - }); - } - Err(err) => { - slog::error!(logger, "Could not spawn helper process for connection from {:?}: {:?}", socket_addr, err); - } - } + slog::info!(logger, "Spawning connection helper: {:?} {:?}", helper, connection_helper_args); + #[cfg(unix)] + Self::spawn_helper(&logger, helper, &connection_helper_args, &tcp_stream, socket_addr); + #[cfg(not(unix))] + unimplemented!() } else { let result = controlchan::spawn_loop::((&options).into(), tcp_stream, None, None, shutdown_listener, failed_logins.clone()).await; @@ -82,4 +69,32 @@ where } } } + + #[cfg(unix)] + fn spawn_helper( + logger: &slog::Logger, + helper: &OsString, + connection_helper_args: &[OsString], + tcp_stream: &tokio::net::TcpStream, + socket_addr: SocketAddr, + ) { + let fd = tcp_stream.as_raw_fd(); + nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_SETFD(nix::fcntl::FdFlag::empty())).unwrap(); + let result = tokio::process::Command::new(helper) + .args(connection_helper_args.iter()) + .arg(fd.to_string()) + .spawn(); + let logger2 = logger.clone(); + match result { + Ok(mut child) => { + tokio::spawn(async move { + let child_status = child.wait().await; + slog::debug!(logger2, "helper process exited {:?}", child_status); + }); + } + Err(err) => { + slog::error!(logger, "Could not spawn helper process for connection from {:?}: {:?}", socket_addr, err); + } + } + } }