diff --git a/ph-init/src/audio.rs b/ph-init/src/audio.rs new file mode 100644 index 0000000..cc83cae --- /dev/null +++ b/ph-init/src/audio.rs @@ -0,0 +1,71 @@ +use std::fs; +use crate::{Error, sys, warn}; +use crate::error::Result; +use std::path::Path; + +const DAEMON_CONF: &str = r#" +log-target = file:/tmp/pulseaudio.log +log-level = debug +"#; + +// If extra-arguments is not set, pulseaudio will be launched with +// '--log-target=syslog' which overrides the log settings in daemon.conf +const CLIENT_CONF: &str = r#" +autospawn = yes +daemon-binary = /usr/bin/pulseaudio +extra-arguments = -- +"#; + +const DEFAULT_PA: &str = r#" +load-module module-device-restore +load-module module-stream-restore +load-module module-card-restore + +load-module module-alsa-sink device=hw:0,0 +load-module module-native-protocol-unix +load-module module-always-sink +"#; + +const SOUND_DEVICES_PATH: &str = "/dev/snd"; +const PULSE_RUN_PATH: &str = "/run/ph/pulse"; + +pub struct AudioSupport; + +impl AudioSupport { + pub fn setup() -> Result<()> { + if Path::new(SOUND_DEVICES_PATH).exists() { + Self::setup_sound_devices()?; + Self::setup_pulse_audio_config()?; + } + Ok(()) + } + + fn setup_sound_devices() -> Result<()> { + for entry in fs::read_dir(SOUND_DEVICES_PATH) + .map_err(Error::DevSndReadDir)? { + let entry = entry.map_err(Error::DevSndReadDir)?; + let path = entry.path(); + if let Some(path_str) = path.as_os_str().to_str() { + sys::chmod(path_str, 0o666)?; + } + } + Ok(()) + } + + fn write_config_file(name: &str, content: &str) -> Result<()> { + let pulse_run_path = Path::new(PULSE_RUN_PATH); + fs::write(pulse_run_path.join(name), content) + .map_err(Error::PulseAudioConfigWrite) + } + + fn setup_pulse_audio_config() -> Result<()> { + fs::create_dir_all(PULSE_RUN_PATH) + .map_err(Error::PulseAudioConfigWrite)?; + Self::write_config_file("daemon.conf", DAEMON_CONF)?; + Self::write_config_file("client.conf", CLIENT_CONF)?; + Self::write_config_file("default.pa", DEFAULT_PA)?; + sys::bind_mount(PULSE_RUN_PATH, "/etc/pulse")?; + Ok(()) + } +} + diff --git a/ph-init/src/error.rs b/ph-init/src/error.rs index 5dc6492..ed899a7 100644 --- a/ph-init/src/error.rs +++ b/ph-init/src/error.rs @@ -30,6 +30,8 @@ pub enum Error { MountOverlay(io::Error), #[error("failed to move mount from {0} to {1}: {2}")] MoveMount(String, String, io::Error), + #[error("failed to bind mount from {0} to {1}: {2}")] + BindMount(String, String, io::Error), #[error("failed to mount 9p volume {0} at {1}: {2}")] Mount9P(String, String, io::Error), #[error("failed to unmount {0}: {1}")] @@ -68,6 +70,10 @@ pub enum Error { WriteBashrc(io::Error), #[error("error configuring network: {0}")] NetworkConfigure(netlink::Error), + #[error("error reading /dev/snd: {0}")] + DevSndReadDir(io::Error), + #[error("error writing pulse audio config file: {0}")] + PulseAudioConfigWrite(io::Error), } pub type Result = result::Result; \ No newline at end of file diff --git a/ph-init/src/init.rs b/ph-init/src/init.rs index 9475183..5e2f12e 100644 --- a/ph-init/src/init.rs +++ b/ph-init/src/init.rs @@ -9,6 +9,7 @@ use std::collections::BTreeMap; use std::io::Read; use std::net::Ipv4Addr; use std::str::FromStr; +use crate::audio::AudioSupport; use crate::netlink::NetlinkSocket; const BASHRC: &str = r#" @@ -117,6 +118,8 @@ impl InitServer { mkdir("/run/user/1000")?; chown("/run/user/1000", 1000,1000)?; + AudioSupport::setup()?; + self.mount_home_if_exists()?; Logger::set_file_output("/run/phinit.log") .map_err(Error::OpenLogFailed)?; diff --git a/ph-init/src/main.rs b/ph-init/src/main.rs index ff33a1a..9afb5fc 100644 --- a/ph-init/src/main.rs +++ b/ph-init/src/main.rs @@ -1,6 +1,7 @@ #[macro_use] extern crate lazy_static; +mod audio; #[macro_use] mod log; mod error; diff --git a/ph-init/src/sys.rs b/ph-init/src/sys.rs index a2a6a31..16eda2f 100644 --- a/ph-init/src/sys.rs +++ b/ph-init/src/sys.rs @@ -69,6 +69,11 @@ pub fn move_mount(source: &str, target: &str) -> Result<()> { .map_err(|e| Error::MoveMount(source.to_string(), target.to_string(), e)) } +pub fn bind_mount(source: &str, target: &str) -> Result<()> { + mount(source, target, "", libc::MS_BIND, None) + .map_err(|e| Error::BindMount(source.to_string(), target.to_string(), e)) +} + pub fn mount_9p(name: &str, target: &str) -> Result<()> { const MS_LAZYTIME: libc::c_ulong = 1 << 25; mount(name, target, "9p",