sirenia: Use EventLoop for syslog socket multiplexing.
BUG=b:168933287
TEST=trichechus runs in the manatee initramfs
Change-Id: Ibdcbbc9f7f0e16fb6f4df778cf22669be60e0d7f
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2453631
Commit-Queue: Allen Webb <allenwebb@google.com>
Tested-by: Allen Webb <allenwebb@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
diff --git a/sirenia/src/linux/mod.rs b/sirenia/src/linux/mod.rs
index d797629..5fce497 100644
--- a/sirenia/src/linux/mod.rs
+++ b/sirenia/src/linux/mod.rs
@@ -5,3 +5,4 @@
//! A module for Linux specific functionality like epoll and syslog handling.
pub mod events;
+pub mod syslog;
diff --git a/sirenia/src/linux/syslog.rs b/sirenia/src/linux/syslog.rs
new file mode 100644
index 0000000..bf06e36
--- /dev/null
+++ b/sirenia/src/linux/syslog.rs
@@ -0,0 +1,86 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! A syslog server interface for use with EventMultiplexer.
+
+use std::boxed::Box;
+use std::fs::remove_file;
+use std::io::{Error as IoError, Read};
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::unix::net::{UnixListener, UnixStream};
+use std::path::Path;
+
+use sys_util::{self, error, handle_eintr};
+
+use super::events::{AddEventSourceMutator, EventSource, Mutator, RemoveFdMutator};
+
+pub const SYSLOG_PATH: &str = "/dev/log";
+
+/// Encapsulates a connection with a a syslog client.
+struct SyslogClient(UnixStream);
+
+impl AsRawFd for SyslogClient {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
+ }
+}
+
+/// This currently just makes sure the read buffer doesn't fill up, but will eventually need to be
+/// written out to have a handler for the data is that is read from the stream.
+impl EventSource for SyslogClient {
+ fn on_event(&mut self) -> Result<Option<Box<dyn Mutator>>, String> {
+ let mut buffer = [0; 1024];
+ Ok(if handle_eintr!(self.0.read(&mut buffer)).is_err() {
+ Some(Box::new(RemoveFdMutator(self.0.as_raw_fd())))
+ } else {
+ None
+ })
+ }
+}
+
+/// Encapsulates a unix socket listener for a syslog server that accepts client connections.
+pub struct Syslog(UnixListener);
+
+impl Syslog {
+ /// Return true if there is already a syslog socket open at SYSLOG_PATH.
+ pub fn is_syslog_present() -> bool {
+ Path::new(SYSLOG_PATH).exists()
+ }
+
+ /// Binds a new unix socket listener at the SYSLOG_PATH.
+ pub fn new() -> Result<Self, IoError> {
+ Ok(Syslog(UnixListener::bind(Path::new(SYSLOG_PATH))?))
+ }
+}
+
+/// Cleanup the unix socket by removing SYSLOG_PATH whenever the Syslog is dropped.
+impl Drop for Syslog {
+ fn drop(&mut self) {
+ if let Err(e) = remove_file(SYSLOG_PATH) {
+ eprintln!("Failed to cleanup syslog: {:?}", e);
+ }
+ }
+}
+
+impl AsRawFd for Syslog {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
+ }
+}
+
+/// Creates a EventSource that adds any accept connections and returns a Mutator that will add the
+/// client connection to the EventMultiplexer when applied.
+impl EventSource for Syslog {
+ fn on_event(&mut self) -> Result<Option<Box<dyn Mutator>>, String> {
+ Ok(Some(match handle_eintr!(self.0.accept()) {
+ Ok((instance, _)) => Box::new(AddEventSourceMutator(Some(Box::new(SyslogClient(
+ instance,
+ ))))),
+ Err(e) => {
+ error!("syslog socket error: {:?}", e);
+ Box::new(RemoveFdMutator(self.0.as_raw_fd()))
+ }
+ }))
+ }
+}
diff --git a/sirenia/src/trichechus.rs b/sirenia/src/trichechus.rs
index 6534159..5201f9e 100644
--- a/sirenia/src/trichechus.rs
+++ b/sirenia/src/trichechus.rs
@@ -6,10 +6,8 @@
use std::env;
use std::fmt::{self, Debug, Display};
-use std::fs::remove_file;
-use std::io::{BufRead, BufReader, Error as IoError, Read};
-use std::os::unix::io::{AsRawFd, RawFd};
-use std::os::unix::net::{UnixListener, UnixStream};
+use std::io::{BufRead, BufReader};
+use std::os::unix::io::AsRawFd;
use std::path::Path;
use std::result::Result as StdResult;
use std::string::String;
@@ -18,13 +16,15 @@
use sirenia::build_info::BUILD_TIMESTAMP;
use sirenia::cli::initialize_common_arguments;
use sirenia::communication::{self, get_app_path, read_message, write_message, Request, Response};
+use sirenia::linux::events::EventMultiplexer;
+use sirenia::linux::syslog::Syslog;
use sirenia::sandbox::{self, Sandbox};
use sirenia::to_sys_util;
use sirenia::transport::{
IPServerTransport, ReadDebugSend, ServerTransport, Transport, TransportType,
VsockServerTransport, WriteDebugSend,
};
-use sys_util::{self, error, handle_eintr, info, pipe, syslog};
+use sys_util::{self, error, info, pipe, syslog};
#[derive(Debug)]
pub enum Error {
@@ -76,54 +76,21 @@
}
}
-const SYSLOG_PATH: &str = "/dev/log";
-
-struct Syslog(UnixListener);
-
-impl Syslog {
- fn new() -> StdResult<Self, IoError> {
- Ok(Syslog(UnixListener::bind(Path::new(SYSLOG_PATH))?))
- }
-}
-
-impl Drop for Syslog {
- fn drop(&mut self) {
- if let Err(e) = remove_file(SYSLOG_PATH) {
- eprintln!("Failed to cleanup syslog: {:?}", e);
- }
- }
-}
-
-impl AsRawFd for Syslog {
- fn as_raw_fd(&self) -> RawFd {
- self.0.as_raw_fd()
- }
-}
-
-fn handle_log_listener(listener: Syslog) {
- while let Ok((instance, _)) = handle_eintr!(listener.0.accept()) {
- spawn(move || {
- handle_log_instance(instance);
- });
- }
-}
-
-fn handle_log_instance(mut instance: UnixStream) {
- let mut buffer = [0; 1024];
- while handle_eintr!(instance.read(&mut buffer)).is_ok() {}
-}
-
// TODO: Figure out how to clean up TEEs that are no longer in use
// TODO: Figure out rate limiting and prevention against DOS attacks
// TODO: What happens if dugong crashes? How do we want to handle
fn main() -> Result<()> {
- let syslog_path = Path::new(SYSLOG_PATH);
- if !syslog_path.exists() {
+ if !Syslog::is_syslog_present() {
eprintln!("creating syslog");
let listener = Syslog::new().unwrap();
- eprintln!("reading syslog");
spawn(move || {
- handle_log_listener(listener);
+ let mut ctx = EventMultiplexer::new().unwrap();
+ ctx.add_event(Box::new(listener)).unwrap();
+ while !ctx.is_empty() {
+ if let Err(e) = ctx.run_once() {
+ eprintln!("{}", e);
+ };
+ }
});
} else {
eprintln!("syslog exists");