mirror of
https://github.com/coastalwhite/lemurs
synced 2024-11-25 19:40:18 +00:00
Move SessionProcess and start on docs
This commit is contained in:
parent
40058a81d0
commit
6e8f64439d
4 changed files with 146 additions and 74 deletions
|
@ -1,6 +1,37 @@
|
|||
//! # API Example
|
||||
//! *LeMuRS*-core or *Login Manager RuSt* abstracts the complicated behavior needed when creating
|
||||
//! Login/Display Manager for \*nix systems.
|
||||
//!
|
||||
//! The library is compatible works for systems with and without SystemD. It aims to provide
|
||||
//! low-level control of the its functionality while not requiring the user to know all the details
|
||||
//! about the session open process.
|
||||
//!
|
||||
//! This library provides 2 main functionalities.
|
||||
//! 1. [Authentication](#authentication): verification of login credentials
|
||||
//! 2. [Session Environments](#session-environments): opening a X11, Wayland or Shell environment
|
||||
//!
|
||||
//! ## Basic example without Authentication
|
||||
//!
|
||||
//! The code below illustrates a basic example of how to use the libary. This example does not
|
||||
//! verify the user credentials. It performs something very similar to the
|
||||
//! [`startx`](https://www.x.org/releases/X11R7.5/doc/man/man1/startx.1.html) binary.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! // Fetch the information for the currently active user
|
||||
//! let user_info = UserInfo::active_user()?;
|
||||
//!
|
||||
//! // Define what you want the session to start into
|
||||
//! let session_environment = SessionEnvironment::X11(
|
||||
//! &format!("{}/.xinitrc", std::env::get("HOME")?)
|
||||
//! );
|
||||
//!
|
||||
//! // Start a session environment
|
||||
//! open_session(&user_info, &session_environment)?.wait()?;
|
||||
//! ```
|
||||
//!
|
||||
//! ## Basic example with Authentication
|
||||
//!
|
||||
//! ```no_run
|
||||
//! // TODO: Provide your own methods for fetching the user creditionals
|
||||
//! let username = "johndoe";
|
||||
//! let pasword = "*******";
|
||||
//!
|
||||
|
@ -15,9 +46,19 @@
|
|||
//! )?;
|
||||
//!
|
||||
//! // Start a session environment
|
||||
//! start_session(session_user, &session_environment);
|
||||
//! open_authenticated_session(
|
||||
//! session_user,
|
||||
//! &session_environment
|
||||
//! )?.wait()?;
|
||||
//! ```
|
||||
//!
|
||||
//! ## Authentication
|
||||
//!
|
||||
//! ## Session Environments
|
||||
//!
|
||||
//! # API Example
|
||||
//!
|
||||
//!
|
||||
//! # API Expanded
|
||||
//!
|
||||
//! ```no_run
|
||||
|
@ -48,7 +89,6 @@ use libc::uid_t;
|
|||
use nix::unistd::{Gid, Uid};
|
||||
use std::env;
|
||||
use std::fmt::Display;
|
||||
use std::process::Child;
|
||||
|
||||
use crate::session_environment::env_variables::{
|
||||
set_basic_variables, set_display, set_seat_vars, set_session_params, set_session_vars,
|
||||
|
@ -185,11 +225,11 @@ pub fn authenticate<'a>(
|
|||
/// In contrast to the [`open_session`] function, this function also allows for finer control of
|
||||
/// the internal operations with the `context` argument. See the [`StartSessionContext`]
|
||||
/// documentation for further explanation of what parameters can be controlled.
|
||||
pub fn open_session_with_context(
|
||||
pub fn open_session_with_context<'a>(
|
||||
user_info: &UserInfo,
|
||||
session_environment: &SessionEnvironment,
|
||||
context: &StartSessionContext,
|
||||
) -> Result<SessionProcess<Child>, EnvironmentStartError> {
|
||||
) -> Result<SessionProcess<'a>, EnvironmentStartError> {
|
||||
let tty = context.tty;
|
||||
|
||||
let mut env_container = EnvironmentContainer::take_snapshot();
|
||||
|
@ -204,7 +244,8 @@ pub fn open_session_with_context(
|
|||
set_basic_variables(&mut env_container, username, homedir, shell);
|
||||
set_xdg_common_paths(&mut env_container, homedir);
|
||||
|
||||
session_environment.spawn(user_info)
|
||||
unimplemented!()
|
||||
// session_environment.spawn(user_info)
|
||||
}
|
||||
|
||||
/// Open a `session_environment` with the given `user_info` and return a handler to the opened
|
||||
|
@ -223,10 +264,10 @@ pub fn open_session_with_context(
|
|||
/// the default [`StartSessionContext`]. The default settings can be found in the documentation of
|
||||
/// [`StartSessionContext`]. If more control is needed, the [`open_session_with_context`] can be
|
||||
/// used.
|
||||
pub fn open_session(
|
||||
pub fn open_session<'a>(
|
||||
user_info: &UserInfo,
|
||||
session_environment: &SessionEnvironment,
|
||||
) -> Result<SessionProcess<Child>, EnvironmentStartError> {
|
||||
) -> Result<SessionProcess<'a>, EnvironmentStartError> {
|
||||
let context = StartSessionContext::default();
|
||||
open_session_with_context(user_info, session_environment, &context)
|
||||
}
|
||||
|
@ -246,12 +287,10 @@ pub fn open_authenticated_session_with_context<'a>(
|
|||
session_user: SessionUser<'a>,
|
||||
session_environment: &SessionEnvironment,
|
||||
context: &StartSessionContext,
|
||||
) -> Result<SessionProcess<Child>, EnvironmentStartError> {
|
||||
let session_process =
|
||||
open_session_with_context(session_user.as_user_info(), session_environment, context)?;
|
||||
|
||||
// Insert the pid into the UTMPX entry, if needed
|
||||
session_user.set_pid(session_process.pid());
|
||||
) -> Result<SessionProcess<'a>, EnvironmentStartError> {
|
||||
let mut session_process = open_session_with_context(session_user.as_user_info(), session_environment, context)?;
|
||||
|
||||
session_process.authenticate(session_user);
|
||||
|
||||
Ok(session_process)
|
||||
}
|
||||
|
@ -271,7 +310,7 @@ pub fn open_authenticated_session_with_context<'a>(
|
|||
pub fn open_authenticated_session<'a>(
|
||||
session_user: SessionUser<'a>,
|
||||
session_environment: &SessionEnvironment,
|
||||
) -> Result<SessionProcess<Child>, EnvironmentStartError> {
|
||||
) -> Result<SessionProcess<'a>, EnvironmentStartError> {
|
||||
let context = StartSessionContext::default();
|
||||
open_authenticated_session_with_context(session_user, session_environment, &context)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::io;
|
|||
use std::os::unix::process::CommandExt;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
|
||||
use crate::auth::SessionUser;
|
||||
use crate::session_environment::wayland::WaylandStartContext;
|
||||
use crate::session_environment::x11::X11StartContext;
|
||||
use crate::{can_run, RunError, UserInfo};
|
||||
|
@ -76,11 +77,23 @@ pub enum SessionType {
|
|||
Shell,
|
||||
}
|
||||
|
||||
pub struct SessionProcess<'a> {
|
||||
type_specific_content: SessionProcessContent,
|
||||
session_user: Option<SessionUser<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SessionProcess<T> {
|
||||
X11 { server: Child, client: T },
|
||||
Wayland(T),
|
||||
Shell(T),
|
||||
pub enum SessionProcessContent {
|
||||
X11 { server: Child, client: Child },
|
||||
Wayland(Child),
|
||||
Shell(Child),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SessionCommand {
|
||||
X11 { server: Child, client: Command },
|
||||
Wayland(Command),
|
||||
Shell(Command),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -140,22 +153,22 @@ impl SessionType {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> SessionProcess<T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
match self {
|
||||
Self::X11 { client, .. } | Self::Wayland(client) | Self::Shell(client) => &client,
|
||||
}
|
||||
}
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
match self {
|
||||
Self::X11 { ref mut client, .. }
|
||||
| Self::Wayland(ref mut client)
|
||||
| Self::Shell(ref mut client) => client,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> SessionProcess<'a> {
|
||||
fn as_ref(&self) -> &Child {
|
||||
use SessionProcessContent::*;
|
||||
|
||||
match &self.type_specific_content {
|
||||
X11 { client, .. } | Wayland(client) | Shell(client) => &client,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn authenticate(&mut self, session_user: SessionUser<'a>) {
|
||||
// Insert the pid into the UTMPX entry, if needed
|
||||
session_user.set_pid(self.pid());
|
||||
|
||||
self.session_user = Some(session_user);
|
||||
}
|
||||
|
||||
impl SessionProcess<Child> {
|
||||
pub fn pid(&self) -> u32 {
|
||||
self.as_ref().id()
|
||||
}
|
||||
|
@ -164,15 +177,17 @@ impl SessionProcess<Child> {
|
|||
self,
|
||||
f: impl Fn(Child) -> Result<(), EnvironmentStartError>,
|
||||
) -> Result<(), EnvironmentStartError> {
|
||||
match self {
|
||||
Self::X11 { mut server, client } => {
|
||||
use SessionProcessContent::*;
|
||||
|
||||
match self.type_specific_content {
|
||||
X11 { mut server, client } => {
|
||||
f(client)?;
|
||||
server.kill().map_err(|err| {
|
||||
error!("Failed to kill X11 server, Reason: '{}'", err);
|
||||
EnvironmentStartError::X11ServerKillFailed
|
||||
})
|
||||
}
|
||||
Self::Wayland(client) | Self::Shell(client) => f(client),
|
||||
Wayland(client) | Shell(client) => f(client),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,7 +238,24 @@ impl SessionProcess<Child> {
|
|||
}
|
||||
}
|
||||
|
||||
impl SessionProcess<Command> {
|
||||
impl<'a> From<SessionProcessContent> for SessionProcess<'a> {
|
||||
fn from(type_specific_content: SessionProcessContent) -> Self {
|
||||
SessionProcess {
|
||||
type_specific_content,
|
||||
session_user: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SessionCommand {
|
||||
fn as_mut(&mut self) -> &mut Command {
|
||||
match self {
|
||||
Self::X11 { ref mut client, .. }
|
||||
| Self::Wayland(ref mut client)
|
||||
| Self::Shell(ref mut client) => client,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pipe_output(&mut self) {
|
||||
self.as_mut().stdout(Stdio::piped()).stderr(Stdio::piped());
|
||||
}
|
||||
|
@ -251,14 +283,17 @@ impl SessionProcess<Command> {
|
|||
unsafe { self.as_mut().pre_exec(to_session_user_env) };
|
||||
}
|
||||
|
||||
pub fn spawn(self) -> io::Result<SessionProcess<Child>> {
|
||||
Ok(match self {
|
||||
Self::X11 { server, mut client } => SessionProcess::X11 {
|
||||
server,
|
||||
client: client.spawn()?,
|
||||
pub fn spawn<'a>(self) -> io::Result<SessionProcess<'a>> {
|
||||
Ok(SessionProcess {
|
||||
type_specific_content: match self {
|
||||
Self::X11 { server, mut client } => SessionProcessContent::X11 {
|
||||
server,
|
||||
client: client.spawn()?,
|
||||
},
|
||||
Self::Wayland(mut client) => SessionProcessContent::Wayland(client.spawn()?),
|
||||
Self::Shell(mut client) => SessionProcessContent::Shell(client.spawn()?),
|
||||
},
|
||||
Self::Wayland(mut client) => SessionProcess::Wayland(client.spawn()?),
|
||||
Self::Shell(mut client) => SessionProcess::Shell(client.spawn()?),
|
||||
session_user: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -272,10 +307,7 @@ impl SessionEnvironment {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn spawn(
|
||||
&self,
|
||||
session_user: &UserInfo,
|
||||
) -> Result<SessionProcess<Child>, EnvironmentStartError> {
|
||||
pub fn spawn(&self, session_user: &UserInfo) -> Result<SessionProcess, EnvironmentStartError> {
|
||||
let context = EnvironmentContext::default();
|
||||
self.spawn_with_context(session_user, &context)
|
||||
}
|
||||
|
@ -284,7 +316,7 @@ impl SessionEnvironment {
|
|||
&self,
|
||||
session_user: &UserInfo,
|
||||
context: &EnvironmentContext<'a>,
|
||||
) -> Result<SessionProcess<Child>, EnvironmentStartError> {
|
||||
) -> Result<SessionProcess, EnvironmentStartError> {
|
||||
let result = self.internal_spawn_with_context(session_user, context);
|
||||
|
||||
info!("Switch back to Lemurs virtual terminal");
|
||||
|
@ -301,59 +333,59 @@ impl SessionEnvironment {
|
|||
&self,
|
||||
user_info: &UserInfo,
|
||||
context: &EnvironmentContext<'a>,
|
||||
) -> Result<SessionProcess<Child>, EnvironmentStartError> {
|
||||
) -> Result<SessionProcess, EnvironmentStartError> {
|
||||
can_run()?;
|
||||
|
||||
let uid = user_info.user_id();
|
||||
let gid = user_info.group_id();
|
||||
let groups = user_info.groups().to_owned();
|
||||
|
||||
let mut session_process = match self {
|
||||
let mut session_command = match self {
|
||||
SessionEnvironment::X11(initializer) => {
|
||||
let context = X11StartContext::from(context);
|
||||
let mut session_process = initializer
|
||||
let mut session_command = initializer
|
||||
.start_x11(user_info, &context)
|
||||
.map_err(EnvironmentStartError::X11Start)?;
|
||||
|
||||
// Pipe the stdout and stderr to us so we can read it.
|
||||
session_process.pipe_output();
|
||||
session_command.pipe_output();
|
||||
|
||||
session_process
|
||||
session_command
|
||||
}
|
||||
SessionEnvironment::Wayland(initializer) => {
|
||||
let context = WaylandStartContext::from(context);
|
||||
let mut session_process = initializer
|
||||
let mut session_command = initializer
|
||||
.start_wayland(user_info, &context)
|
||||
.map_err(EnvironmentStartError::WaylandStart)?;
|
||||
|
||||
// Pipe the stdout and stderr to us so we can read it.
|
||||
session_process.pipe_output();
|
||||
session_command.pipe_output();
|
||||
|
||||
session_process
|
||||
session_command
|
||||
}
|
||||
SessionEnvironment::Shell => {
|
||||
info!("Starting TTY shell");
|
||||
|
||||
let shell = &user_info.shell();
|
||||
|
||||
let mut session_process = SessionProcess::Shell(Command::new(shell));
|
||||
session_process.inherit_io();
|
||||
session_process
|
||||
let mut session_command = SessionCommand::Shell(Command::new(shell));
|
||||
|
||||
session_command.inherit_io();
|
||||
|
||||
session_command
|
||||
}
|
||||
};
|
||||
|
||||
session_process.lower_permission_pre_exec(uid, gid, groups);
|
||||
session_command.lower_permission_pre_exec(uid, gid, groups);
|
||||
|
||||
// Actually spawn the initializer process
|
||||
let session_process = match session_process.spawn() {
|
||||
Ok(cmd) => cmd,
|
||||
match session_command.spawn() {
|
||||
Ok(cmd) => Ok(cmd.into()),
|
||||
Err(err) => {
|
||||
error!("Failed to start initializer. Reason '{}'", err);
|
||||
return Err(EnvironmentStartError::InitializerFailed);
|
||||
Err(EnvironmentStartError::InitializerFailed)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(session_process)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::process::Command;
|
|||
|
||||
use crate::UserInfo;
|
||||
|
||||
use super::{EnvironmentContext, SessionInitializer, SessionProcess};
|
||||
use super::{EnvironmentContext, SessionInitializer, SessionCommand};
|
||||
|
||||
const WAYLAND_SESSIONS_DIR: &str = "/etc/lemurs/wayland";
|
||||
|
||||
|
@ -44,7 +44,7 @@ impl SessionInitializer {
|
|||
&self,
|
||||
_user_info: &UserInfo,
|
||||
context: &WaylandStartContext,
|
||||
) -> Result<SessionProcess<Command>, WaylandStartError> {
|
||||
) -> Result<SessionCommand, WaylandStartError> {
|
||||
info!("Starting Wayland session '{}'", self.name);
|
||||
|
||||
let mut initializer = Command::new(context.system_shell);
|
||||
|
@ -52,7 +52,7 @@ impl SessionInitializer {
|
|||
// Make it run the initializer
|
||||
initializer.arg("-c").arg(&self.path);
|
||||
|
||||
Ok(SessionProcess::Wayland(initializer))
|
||||
Ok(SessionCommand::Wayland(initializer))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,9 @@ use std::path::PathBuf;
|
|||
use log::{error, info, warn};
|
||||
|
||||
use crate::UserInfo;
|
||||
use crate::session_environment::SessionCommand;
|
||||
|
||||
use super::{EnvironmentContext, SessionInitializer, SessionProcess};
|
||||
use super::{EnvironmentContext, SessionInitializer};
|
||||
|
||||
const SERVER_QUERY_NUM_OF_TRIES: usize = 10;
|
||||
const SERVER_QUERY_TIMEOUT: Duration = Duration::from_millis(1000);
|
||||
|
@ -204,7 +205,7 @@ impl SessionInitializer {
|
|||
&self,
|
||||
user_info: &UserInfo,
|
||||
context: &X11StartContext,
|
||||
) -> Result<SessionProcess<Command>, X11StartError> {
|
||||
) -> Result<SessionCommand, X11StartError> {
|
||||
info!("Starting X11 session '{}'", self.name);
|
||||
|
||||
// Start the X Server
|
||||
|
@ -219,7 +220,7 @@ impl SessionInitializer {
|
|||
self.path.display()
|
||||
));
|
||||
|
||||
Ok(SessionProcess::X11 {
|
||||
Ok(SessionCommand::X11 {
|
||||
server,
|
||||
client: initializer,
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue