refact linux desktop env
Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
parent
5e79481860
commit
30375a9853
@ -1,4 +1,3 @@
|
|||||||
use super::linux_desktop::{get_desktop_env, Desktop};
|
|
||||||
use super::{CursorData, ResultType};
|
use super::{CursorData, ResultType};
|
||||||
use desktop::Desktop;
|
use desktop::Desktop;
|
||||||
pub use hbb_common::platform::linux::*;
|
pub use hbb_common::platform::linux::*;
|
||||||
@ -297,6 +296,7 @@ fn force_stop_server() {
|
|||||||
pub fn start_os_service() {
|
pub fn start_os_service() {
|
||||||
stop_rustdesk_servers();
|
stop_rustdesk_servers();
|
||||||
start_uinput_service();
|
start_uinput_service();
|
||||||
|
start_check_desktop_env();
|
||||||
|
|
||||||
let running = Arc::new(AtomicBool::new(true));
|
let running = Arc::new(AtomicBool::new(true));
|
||||||
let r = running.clone();
|
let r = running.clone();
|
||||||
@ -371,6 +371,8 @@ pub fn start_os_service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stop_check_desktop_env();
|
||||||
|
|
||||||
if let Some(ps) = user_server.take().as_mut() {
|
if let Some(ps) = user_server.take().as_mut() {
|
||||||
allow_err!(ps.kill());
|
allow_err!(ps.kill());
|
||||||
}
|
}
|
||||||
|
@ -17,188 +17,161 @@ use users::{get_user_by_name, os::unix::UserExt, User};
|
|||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref DESKTOP_RUNNING: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
|
static ref DESKTOP_RUNNING: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
|
||||||
static ref DESKTOP_ENV: Arc<Mutex<Desktop>> = Arc::new(Mutex::new(Desktop::new()));
|
static ref DESKTOP_MANAGER: Arc<Mutex<Option<DesktopManager>>> = Arc::new(Mutex::new(None));
|
||||||
static ref CHILD_FLAGS: Arc<Mutex<Option<ChildFlags>>> = Arc::new(Mutex::new(None));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const VIRTUAL_X11_DESKTOP: &str = "xfce4";
|
|
||||||
pub const VIRTUAL_X11_DESKTOP_START: &str = "startxfce4";
|
|
||||||
pub const XFCE4_PANEL: &str = "xfce4-panel";
|
|
||||||
pub const GNOME_SESSION_BINARY: &str = "gnome-session-binary";
|
|
||||||
pub const ENV_DESKTOP_PROTOCAL: &str = "RUSTDESK_PROTOCAL";
|
|
||||||
pub const ENV_DESKTOP_PROTOCAL_WAYLAND: &str = "wayland";
|
|
||||||
pub const ENV_DESKTOP_PROTOCAL__X11: &str = "x11";
|
|
||||||
pub const ENV_DESKTOP_PROTOCAL_UNKNOWN: &str = "unknown";
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
||||||
pub enum Protocal {
|
|
||||||
Wayland,
|
|
||||||
X11, // Xorg
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Desktop {
|
|
||||||
pub sid: String,
|
|
||||||
pub protocal: Protocal,
|
|
||||||
pub username: String,
|
|
||||||
pub uid: String,
|
|
||||||
pub display: String,
|
|
||||||
pub xauth: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ChildFlags {
|
struct DesktopManager {
|
||||||
|
x11_username: String,
|
||||||
|
child_username: String,
|
||||||
child_exit: Arc<AtomicBool>,
|
child_exit: Arc<AtomicBool>,
|
||||||
is_child_running: Arc<AtomicBool>,
|
is_child_running: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_update_env() {
|
fn check_desktop_manager() {
|
||||||
let mut child_flags = CHILD_FLAGS.lock().unwrap();
|
let mut desktop_manager = DESKTOP_MANAGER.lock().unwrap();
|
||||||
let mut desktop = DESKTOP_ENV.lock().unwrap();
|
if let Some(desktop_manager) = &mut (*desktop_manager) {
|
||||||
|
if desktop_manager.is_child_running.load(Ordering::SeqCst) {
|
||||||
if let Some(child_flags) = &mut (*child_flags) {
|
|
||||||
if child_flags.is_child_running.load(Ordering::SeqCst) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
child_flags.child_exit.store(true, Ordering::SeqCst);
|
desktop_manager.child_exit.store(true, Ordering::SeqCst);
|
||||||
}
|
|
||||||
|
|
||||||
if !desktop.sid.is_empty() && is_active(&desktop.sid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let old_desktop = desktop.clone();
|
|
||||||
desktop.refresh();
|
|
||||||
if !desktop.is_same_env(&old_desktop) {
|
|
||||||
desktop.update_env();
|
|
||||||
log::debug!("desktop env changed, {:?}", &desktop);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --server process
|
||||||
pub fn start_xdesktop() {
|
pub fn start_xdesktop() {
|
||||||
std::thread::spawn(|| {
|
std::thread::spawn(|| {
|
||||||
if wait_xdesktop(20) {
|
*DESKTOP_MANAGER.lock().unwrap() = Some(DesktopManager::new());
|
||||||
log::info!("Wait desktop: default");
|
|
||||||
} else {
|
|
||||||
log::info!("Wait desktop: none");
|
|
||||||
}
|
|
||||||
*CHILD_FLAGS.lock().unwrap() = Some(ChildFlags::new());
|
|
||||||
|
|
||||||
let interval = time::Duration::from_millis(super::SERVICE_INTERVAL);
|
let interval = time::Duration::from_millis(super::SERVICE_INTERVAL);
|
||||||
DESKTOP_RUNNING.store(true, Ordering::SeqCst);
|
DESKTOP_RUNNING.store(true, Ordering::SeqCst);
|
||||||
while DESKTOP_RUNNING.load(Ordering::SeqCst) {
|
while DESKTOP_RUNNING.load(Ordering::SeqCst) {
|
||||||
check_update_env();
|
check_desktop_manager();
|
||||||
std::thread::sleep(interval);
|
std::thread::sleep(interval);
|
||||||
}
|
}
|
||||||
log::info!("xdesktop update thread exit");
|
log::info!("xdesktop child thread exit");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_xdesktop() {
|
pub fn stop_xdesktop() {
|
||||||
DESKTOP_RUNNING.store(false, Ordering::SeqCst);
|
DESKTOP_RUNNING.store(false, Ordering::SeqCst);
|
||||||
|
*DESKTOP_MANAGER.lock().unwrap() = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
pub fn try_start_x_session(username: &str, password: &str) -> ResultType<(String, bool)> {
|
||||||
pub fn get_desktop_env() -> Desktop {
|
let mut desktop_manager = DESKTOP_MANAGER.lock().unwrap();
|
||||||
DESKTOP_ENV.lock().unwrap().clone()
|
if let Some(desktop_manager) = &mut (*desktop_manager) {
|
||||||
}
|
if !desktop_manager.x11_username.is_empty() {
|
||||||
|
return Ok((desktop_manager.x11_username.clone(), true));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn try_start_x_session(username: &str, password: &str) -> ResultType<Desktop> {
|
let _ = desktop_manager.try_start_x_session(username, password)?;
|
||||||
let mut child_flags = CHILD_FLAGS.lock().unwrap();
|
|
||||||
let mut desktop_lock = DESKTOP_ENV.lock().unwrap();
|
|
||||||
let mut desktop = Desktop::new();
|
|
||||||
if let Some(child_flags) = &mut (*child_flags) {
|
|
||||||
let _ = child_flags.try_start_x_session(&mut desktop, username, password)?;
|
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"try_start_x_session, username: {}, {:?}",
|
"try_start_x_session, username: {}, {:?}",
|
||||||
&username,
|
&username,
|
||||||
&child_flags
|
&desktop_manager
|
||||||
);
|
);
|
||||||
*desktop_lock = desktop.clone();
|
Ok((
|
||||||
Ok(desktop)
|
desktop_manager.child_username.clone(),
|
||||||
|
desktop_manager.is_running(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
bail!(crate::server::LOGIN_MSG_XDESKTOP_NOT_INITED);
|
bail!(crate::server::LOGIN_MSG_XDESKTOP_NOT_INITED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_xdesktop(timeout_secs: u64) -> bool {
|
pub fn get_username() -> String {
|
||||||
let wait_begin = Instant::now();
|
match &*DESKTOP_MANAGER.lock().unwrap() {
|
||||||
while wait_begin.elapsed().as_secs() < timeout_secs {
|
Some(manager) => {
|
||||||
let uid = &get_values_of_seat0(&[1])[0];
|
if !manager.x11_username.is_empty() {
|
||||||
if !uid.is_empty() {
|
manager.x11_username.clone()
|
||||||
return true;
|
} else {
|
||||||
|
if manager.is_running() && !manager.child_username.is_empty() {
|
||||||
|
manager.child_username.clone()
|
||||||
|
} else {
|
||||||
|
"".to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
None => "".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Ok(output) = run_cmds(format!(
|
impl Drop for DesktopManager {
|
||||||
"ps -ef | grep -v 'grep' | grep -E 'gnome-session-binary|{}'",
|
fn drop(&mut self) {
|
||||||
XFCE4_PANEL
|
self.stop_children();
|
||||||
)) {
|
}
|
||||||
if !output.is_empty() {
|
}
|
||||||
log::info!("wait xdesktop: find xclient {}", &output);
|
|
||||||
return true;
|
impl DesktopManager {
|
||||||
|
fn fatal_exit() {
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut x11_username = "".to_owned();
|
||||||
|
let seat0_values = get_values_of_seat0(&[0, 1, 2]);
|
||||||
|
if !seat0_values[0].is_empty() {
|
||||||
|
if "x11" == get_display_server_of_session(&seat0_values[1]) {
|
||||||
|
x11_username = seat0_values[2].clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::thread::sleep(Duration::from_millis(super::SERVICE_INTERVAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Desktop {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let xauth = get_env_var("XAUTHORITY");
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
sid: "".to_owned(),
|
x11_username,
|
||||||
protocal: Protocal::Unknown,
|
child_username: "".to_owned(),
|
||||||
username: "".to_owned(),
|
child_exit: Arc::new(AtomicBool::new(true)),
|
||||||
uid: "".to_owned(),
|
is_child_running: Arc::new(AtomicBool::new(false)),
|
||||||
display: "".to_owned(),
|
|
||||||
xauth: if xauth.is_empty() {
|
|
||||||
"/tmp/.Xauthority".to_owned()
|
|
||||||
} else {
|
|
||||||
xauth
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_env(&self) {
|
#[inline]
|
||||||
if self.is_x11() {
|
fn get_xauth() -> String {
|
||||||
std::env::set_var("DISPLAY", &self.display);
|
let xauth = get_env_var("XAUTHORITY");
|
||||||
std::env::set_var("XAUTHORITY", &self.xauth);
|
if xauth.is_empty() {
|
||||||
std::env::set_var(ENV_DESKTOP_PROTOCAL, &self.protocal.to_string());
|
"/tmp/.Xauthority".to_owned()
|
||||||
} else {
|
} else {
|
||||||
std::env::set_var("DISPLAY", "");
|
xauth
|
||||||
std::env::set_var("XAUTHORITY", "");
|
|
||||||
std::env::set_var(ENV_DESKTOP_PROTOCAL, &self.protocal.to_string());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_same_env(&self, other: &Self) -> bool {
|
#[inline]
|
||||||
self.sid == other.sid
|
fn is_running(&self) -> bool {
|
||||||
&& self.protocal == other.protocal
|
self.is_child_running.load(Ordering::SeqCst)
|
||||||
&& self.uid == other.uid
|
|
||||||
&& self.display == other.display
|
|
||||||
&& self.xauth == other.xauth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
fn try_start_x_session(&mut self, username: &str, password: &str) -> ResultType<()> {
|
||||||
pub fn is_x11(&self) -> bool {
|
match get_user_by_name(username) {
|
||||||
self.protocal == Protocal::X11
|
Some(userinfo) => {
|
||||||
}
|
let mut client = pam::Client::with_password(pam_get_service_name())?;
|
||||||
|
client
|
||||||
|
.conversation_mut()
|
||||||
|
.set_credentials(username, password);
|
||||||
|
match client.authenticate() {
|
||||||
|
Ok(_) => {
|
||||||
|
if self.is_running() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
match self.start_x_session(&userinfo, username, password) {
|
||||||
pub fn is_wayland(&self) -> bool {
|
Ok(_) => {
|
||||||
self.protocal == Protocal::Wayland
|
log::info!("Succeeded to start x11");
|
||||||
}
|
self.child_username = username.to_string();
|
||||||
|
Ok(())
|
||||||
#[inline]
|
}
|
||||||
pub fn is_ready(&self) -> bool {
|
Err(e) => {
|
||||||
match self.protocal {
|
bail!("failed to start x session, {}", e);
|
||||||
Protocal::X11 | Protocal::Wayland => true,
|
}
|
||||||
_ => false,
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
bail!("failed to check user pass for {}, {}", username, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
bail!("failed to get userinfo of {}", username);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,83 +193,131 @@ impl Desktop {
|
|||||||
|| Path::new(&format!("/tmp/.X{}-lock", display)).exists()
|
|| Path::new(&format!("/tmp/.X{}-lock", display)).exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_display(&mut self) {
|
fn start_x_session(
|
||||||
self.display = get_env_tries("DISPLAY", &self.uid, GNOME_SESSION_BINARY, 10);
|
&mut self,
|
||||||
if self.display.is_empty() {
|
userinfo: &User,
|
||||||
self.display = get_env_tries("DISPLAY", &self.uid, XFCE4_PANEL, 10);
|
username: &str,
|
||||||
}
|
password: &str,
|
||||||
if self.display.is_empty() {
|
) -> ResultType<()> {
|
||||||
self.display = Self::get_display_by_user(&self.username);
|
self.stop_children();
|
||||||
}
|
|
||||||
if self.display.is_empty() {
|
|
||||||
self.display = ":0".to_owned();
|
|
||||||
}
|
|
||||||
self.display = self
|
|
||||||
.display
|
|
||||||
.replace(&whoami::hostname(), "")
|
|
||||||
.replace("localhost", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_xauth(&mut self) {
|
let display_num = Self::get_avail_display()?;
|
||||||
self.xauth = get_env_tries("XAUTHORITY", &self.uid, GNOME_SESSION_BINARY, 10);
|
// "xServer_ip:display_num.screen_num"
|
||||||
if self.xauth.is_empty() {
|
|
||||||
get_env_tries("XAUTHORITY", &self.uid, XFCE4_PANEL, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
let gdm = format!("/run/user/{}/gdm/Xauthority", self.uid);
|
let uid = userinfo.uid();
|
||||||
if self.xauth.is_empty() {
|
let gid = userinfo.primary_group_id();
|
||||||
self.xauth = if std::path::Path::new(&gdm).exists() {
|
let envs = HashMap::from([
|
||||||
gdm
|
("SHELL", userinfo.shell().to_string_lossy().to_string()),
|
||||||
} else {
|
("PATH", "/sbin:/bin:/usr/bin:/usr/local/bin".to_owned()),
|
||||||
let username = &self.username;
|
("USER", username.to_string()),
|
||||||
if username == "root" {
|
("UID", userinfo.uid().to_string()),
|
||||||
format!("/{}/.Xauthority", username)
|
("HOME", userinfo.home_dir().to_string_lossy().to_string()),
|
||||||
|
(
|
||||||
|
"XDG_RUNTIME_DIR",
|
||||||
|
format!("/run/user/{}", userinfo.uid().to_string()),
|
||||||
|
),
|
||||||
|
// ("DISPLAY", self.display.clone()),
|
||||||
|
// ("XAUTHORITY", self.xauth.clone()),
|
||||||
|
// (ENV_DESKTOP_PROTOCAL, XProtocal::X11.to_string()),
|
||||||
|
]);
|
||||||
|
self.child_exit.store(false, Ordering::SeqCst);
|
||||||
|
let is_child_running = self.is_child_running.clone();
|
||||||
|
|
||||||
|
let (tx_res, rx_res) = sync_channel(1);
|
||||||
|
let password = password.to_string();
|
||||||
|
let username = username.to_string();
|
||||||
|
// start x11
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
match Self::start_x_session_thread(
|
||||||
|
tx_res.clone(),
|
||||||
|
is_child_running,
|
||||||
|
uid,
|
||||||
|
gid,
|
||||||
|
display_num,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
envs,
|
||||||
|
) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to start x session thread");
|
||||||
|
allow_err!(tx_res.send(format!("Failed to start x session thread, {}", e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// wait x11
|
||||||
|
match rx_res.recv_timeout(Duration::from_millis(10_000)) {
|
||||||
|
Ok(res) => {
|
||||||
|
if res == "" {
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let tmp = format!("/home/{}/.Xauthority", username);
|
bail!(res)
|
||||||
if std::path::Path::new(&tmp).exists() {
|
|
||||||
tmp
|
|
||||||
} else {
|
|
||||||
format!("/var/lib/{}/.Xauthority", username)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
Err(e) => {
|
||||||
|
bail!("Failed to recv x11 result {}", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_display_by_user(user: &str) -> String {
|
#[inline]
|
||||||
// log::debug!("w {}", &user);
|
fn display_from_num(num: u32) -> String {
|
||||||
if let Ok(output) = std::process::Command::new("w").arg(&user).output() {
|
format!(":{num}")
|
||||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
}
|
||||||
let mut iter = line.split_whitespace();
|
|
||||||
let b = iter.nth(2);
|
fn start_x_session_thread(
|
||||||
if let Some(b) = b {
|
tx_res: SyncSender<String>,
|
||||||
if b.starts_with(":") {
|
is_child_running: Arc<AtomicBool>,
|
||||||
return b.to_owned();
|
uid: u32,
|
||||||
|
gid: u32,
|
||||||
|
display_num: u32,
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
|
envs: HashMap<&str, String>,
|
||||||
|
) -> ResultType<()> {
|
||||||
|
let mut client = pam::Client::with_password(pam_get_service_name())?;
|
||||||
|
client
|
||||||
|
.conversation_mut()
|
||||||
|
.set_credentials(&username, &password);
|
||||||
|
client.authenticate()?;
|
||||||
|
|
||||||
|
client.set_item(pam::PamItemType::TTY, &Self::display_from_num(display_num))?;
|
||||||
|
client.open_session()?;
|
||||||
|
|
||||||
|
// fixme: FreeBSD kernel needs to login here.
|
||||||
|
// see: https://github.com/neutrinolabs/xrdp/blob/a64573b596b5fb07ca3a51590c5308d621f7214e/sesman/session.c#L556
|
||||||
|
|
||||||
|
let (child_xorg, child_wm) = Self::start_x11(uid, gid, username, display_num, &envs)?;
|
||||||
|
is_child_running.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
log::info!("Start xorg and wm done, notify and wait xtop x11");
|
||||||
|
allow_err!(tx_res.send("".to_owned()));
|
||||||
|
|
||||||
|
Self::wait_stop_x11(child_xorg, child_wm);
|
||||||
|
log::info!("Wait x11 stop done");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_xorg_exit(child_xorg: &mut Child) -> ResultType<String> {
|
||||||
|
if let Ok(_) = child_xorg.kill() {
|
||||||
|
for _ in 0..3 {
|
||||||
|
match child_xorg.try_wait() {
|
||||||
|
Ok(Some(status)) => return Ok(format!("Xorg exit with {}", status)),
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(e) => {
|
||||||
|
// fatal error
|
||||||
|
log::error!("Failed to wait xorg process, {}", e);
|
||||||
|
bail!("Failed to wait xorg process, {}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1_000));
|
||||||
}
|
}
|
||||||
|
log::error!("Failed to wait xorg process, not exit");
|
||||||
|
bail!("Failed to wait xorg process, not exit")
|
||||||
|
} else {
|
||||||
|
Ok("Xorg is already exited".to_owned())
|
||||||
}
|
}
|
||||||
// above not work for gdm user
|
|
||||||
//log::debug!("ls -l /tmp/.X11-unix/");
|
|
||||||
let mut last = "".to_owned();
|
|
||||||
if let Ok(output) = std::process::Command::new("ls")
|
|
||||||
.args(vec!["-l", "/tmp/.X11-unix/"])
|
|
||||||
.output()
|
|
||||||
{
|
|
||||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
|
||||||
let mut iter = line.split_whitespace();
|
|
||||||
let user_field = iter.nth(2);
|
|
||||||
if let Some(x) = iter.last() {
|
|
||||||
if x.starts_with("X") {
|
|
||||||
last = x.replace("X", ":").to_owned();
|
|
||||||
if user_field == Some(&user) {
|
|
||||||
return last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_xauth_cookie(
|
fn add_xauth_cookie(
|
||||||
@ -343,233 +364,28 @@ impl Desktop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refresh(&mut self) {
|
|
||||||
*self = Self::new();
|
|
||||||
|
|
||||||
let seat0_values = get_values_of_seat0(&[0, 1, 2]);
|
|
||||||
if seat0_values[0].is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.sid = seat0_values[0].clone();
|
|
||||||
self.uid = seat0_values[1].clone();
|
|
||||||
self.username = seat0_values[2].clone();
|
|
||||||
self.protocal = get_display_server_of_session(&self.sid).into();
|
|
||||||
self.get_display();
|
|
||||||
self.get_xauth();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for ChildFlags {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.stop_children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ChildFlags {
|
|
||||||
fn fatal_exit() {
|
|
||||||
std::process::exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
child_exit: Arc::new(AtomicBool::new(true)),
|
|
||||||
is_child_running: Arc::new(AtomicBool::new(false)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_start_x_session(
|
|
||||||
&mut self,
|
|
||||||
desktop: &mut Desktop,
|
|
||||||
username: &str,
|
|
||||||
password: &str,
|
|
||||||
) -> ResultType<()> {
|
|
||||||
match get_user_by_name(username) {
|
|
||||||
Some(userinfo) => {
|
|
||||||
let mut client = pam::Client::with_password(pam_get_service_name())?;
|
|
||||||
client
|
|
||||||
.conversation_mut()
|
|
||||||
.set_credentials(username, password);
|
|
||||||
match client.authenticate() {
|
|
||||||
Ok(_) => {
|
|
||||||
if desktop.is_x11() && desktop.username == username {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// to-do: sid is empty if xorg is managed by this process
|
|
||||||
desktop.sid = "".to_owned();
|
|
||||||
desktop.username = username.to_string();
|
|
||||||
desktop.uid = userinfo.uid().to_string();
|
|
||||||
desktop.protocal = Protocal::Unknown;
|
|
||||||
match self.start_x_session(desktop, &userinfo, password) {
|
|
||||||
Ok(_) => {
|
|
||||||
log::info!("Succeeded to start x11, update env {:?}", &desktop);
|
|
||||||
desktop.update_env();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
*desktop = Desktop::new();
|
|
||||||
desktop.update_env();
|
|
||||||
bail!("failed to start x session, {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
bail!("failed to check user pass for {}, {}", username, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
bail!("failed to get userinfo of {}", username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_x_session(
|
|
||||||
&mut self,
|
|
||||||
desktop: &mut Desktop,
|
|
||||||
userinfo: &User,
|
|
||||||
password: &str,
|
|
||||||
) -> ResultType<()> {
|
|
||||||
self.stop_children();
|
|
||||||
|
|
||||||
let display_num = Desktop::get_avail_display()?;
|
|
||||||
// "xServer_ip:display_num.screen_num"
|
|
||||||
desktop.display = format!(":{}", display_num);
|
|
||||||
|
|
||||||
let uid = userinfo.uid();
|
|
||||||
let gid = userinfo.primary_group_id();
|
|
||||||
let envs = HashMap::from([
|
|
||||||
("SHELL", userinfo.shell().to_string_lossy().to_string()),
|
|
||||||
("PATH", "/sbin:/bin:/usr/bin:/usr/local/bin".to_owned()),
|
|
||||||
("USER", desktop.username.clone()),
|
|
||||||
("UID", userinfo.uid().to_string()),
|
|
||||||
("HOME", userinfo.home_dir().to_string_lossy().to_string()),
|
|
||||||
(
|
|
||||||
"XDG_RUNTIME_DIR",
|
|
||||||
format!("/run/user/{}", userinfo.uid().to_string()),
|
|
||||||
),
|
|
||||||
// ("DISPLAY", self.display.clone()),
|
|
||||||
// ("XAUTHORITY", self.xauth.clone()),
|
|
||||||
// (ENV_DESKTOP_PROTOCAL, XProtocal::X11.to_string()),
|
|
||||||
]);
|
|
||||||
let desktop_clone = desktop.clone();
|
|
||||||
self.child_exit.store(false, Ordering::SeqCst);
|
|
||||||
let is_child_running = self.is_child_running.clone();
|
|
||||||
|
|
||||||
let (tx_res, rx_res) = sync_channel(1);
|
|
||||||
let password = password.to_string();
|
|
||||||
// start x11
|
|
||||||
std::thread::spawn(move || {
|
|
||||||
match Self::start_x_session_thread(
|
|
||||||
tx_res.clone(),
|
|
||||||
is_child_running,
|
|
||||||
desktop_clone,
|
|
||||||
uid,
|
|
||||||
gid,
|
|
||||||
display_num,
|
|
||||||
password,
|
|
||||||
envs,
|
|
||||||
) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Failed to start x session thread");
|
|
||||||
allow_err!(tx_res.send(format!("Failed to start x session thread, {}", e)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// wait x11
|
|
||||||
match rx_res.recv_timeout(Duration::from_millis(10_000)) {
|
|
||||||
Ok(res) => {
|
|
||||||
if res == "" {
|
|
||||||
desktop.protocal = Protocal::X11;
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
bail!(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
bail!("Failed to recv x11 result {}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_x_session_thread(
|
|
||||||
tx_res: SyncSender<String>,
|
|
||||||
is_child_running: Arc<AtomicBool>,
|
|
||||||
desktop: Desktop,
|
|
||||||
uid: u32,
|
|
||||||
gid: u32,
|
|
||||||
display_num: u32,
|
|
||||||
password: String,
|
|
||||||
envs: HashMap<&str, String>,
|
|
||||||
) -> ResultType<()> {
|
|
||||||
let mut client = pam::Client::with_password(pam_get_service_name())?;
|
|
||||||
client
|
|
||||||
.conversation_mut()
|
|
||||||
.set_credentials(&desktop.username, &password);
|
|
||||||
client.authenticate()?;
|
|
||||||
|
|
||||||
client.set_item(pam::PamItemType::TTY, &desktop.display)?;
|
|
||||||
client.open_session()?;
|
|
||||||
|
|
||||||
// fixme: FreeBSD kernel needs to login here.
|
|
||||||
// see: https://github.com/neutrinolabs/xrdp/blob/a64573b596b5fb07ca3a51590c5308d621f7214e/sesman/session.c#L556
|
|
||||||
|
|
||||||
let (child_xorg, child_wm) = Self::start_x11(&desktop, uid, gid, display_num, &envs)?;
|
|
||||||
is_child_running.store(true, Ordering::SeqCst);
|
|
||||||
|
|
||||||
log::info!("Start xorg and wm done, notify and wait xtop x11");
|
|
||||||
allow_err!(tx_res.send("".to_owned()));
|
|
||||||
|
|
||||||
Self::wait_stop_x11(child_xorg, child_wm);
|
|
||||||
log::info!("Wait x11 stop done");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wait_xorg_exit(child_xorg: &mut Child) -> ResultType<String> {
|
|
||||||
if let Ok(_) = child_xorg.kill() {
|
|
||||||
for _ in 0..3 {
|
|
||||||
match child_xorg.try_wait() {
|
|
||||||
Ok(Some(status)) => return Ok(format!("Xorg exit with {}", status)),
|
|
||||||
Ok(None) => {}
|
|
||||||
Err(e) => {
|
|
||||||
// fatal error
|
|
||||||
log::error!("Failed to wait xorg process, {}", e);
|
|
||||||
bail!("Failed to wait xorg process, {}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1_000));
|
|
||||||
}
|
|
||||||
log::error!("Failed to wait xorg process, not exit");
|
|
||||||
bail!("Failed to wait xorg process, not exit")
|
|
||||||
} else {
|
|
||||||
Ok("Xorg is already exited".to_owned())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_x11(
|
fn start_x11(
|
||||||
desktop: &Desktop,
|
|
||||||
uid: u32,
|
uid: u32,
|
||||||
gid: u32,
|
gid: u32,
|
||||||
|
username: String,
|
||||||
display_num: u32,
|
display_num: u32,
|
||||||
envs: &HashMap<&str, String>,
|
envs: &HashMap<&str, String>,
|
||||||
) -> ResultType<(Child, Child)> {
|
) -> ResultType<(Child, Child)> {
|
||||||
log::debug!("envs of user {}: {:?}", &desktop.username, &envs);
|
log::debug!("envs of user {}: {:?}", &username, &envs);
|
||||||
|
|
||||||
Desktop::add_xauth_cookie(&desktop.xauth, &desktop.display, uid, gid, &envs)?;
|
let xauth = Self::get_xauth();
|
||||||
|
let display = Self::display_from_num(display_num);
|
||||||
|
|
||||||
|
Self::add_xauth_cookie(&xauth, &display, uid, gid, &envs)?;
|
||||||
|
|
||||||
// Start Xorg
|
// Start Xorg
|
||||||
let mut child_xorg =
|
let mut child_xorg = Self::start_x_server(&xauth, &display, uid, gid, &envs)?;
|
||||||
Self::start_x_server(&desktop.xauth, &desktop.display, uid, gid, &envs)?;
|
|
||||||
|
|
||||||
log::info!("xorg started, wait 10 secs to ensuer x server is running");
|
log::info!("xorg started, wait 10 secs to ensuer x server is running");
|
||||||
|
|
||||||
let max_wait_secs = 10;
|
let max_wait_secs = 10;
|
||||||
// wait x server running
|
// wait x server running
|
||||||
if let Err(e) = Desktop::wait_x_server_running(child_xorg.id(), display_num, max_wait_secs)
|
if let Err(e) = Self::wait_x_server_running(child_xorg.id(), display_num, max_wait_secs) {
|
||||||
{
|
|
||||||
match Self::wait_xorg_exit(&mut child_xorg) {
|
match Self::wait_xorg_exit(&mut child_xorg) {
|
||||||
Ok(msg) => log::info!("{}", msg),
|
Ok(msg) => log::info!("{}", msg),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -582,12 +398,12 @@ impl ChildFlags {
|
|||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"xorg is running, start x window manager with DISPLAY: {}, XAUTHORITY: {}",
|
"xorg is running, start x window manager with DISPLAY: {}, XAUTHORITY: {}",
|
||||||
&desktop.display,
|
&display,
|
||||||
&desktop.xauth
|
&xauth
|
||||||
);
|
);
|
||||||
|
|
||||||
std::env::set_var("DISPLAY", &desktop.display);
|
std::env::set_var("DISPLAY", &display);
|
||||||
std::env::set_var("XAUTHORITY", &desktop.xauth);
|
std::env::set_var("XAUTHORITY", &xauth);
|
||||||
// start window manager (startwm.sh)
|
// start window manager (startwm.sh)
|
||||||
let child_wm = match Self::start_x_window_manager(uid, gid, &envs) {
|
let child_wm = match Self::start_x_window_manager(uid, gid, &envs) {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
@ -707,10 +523,10 @@ impl ChildFlags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_wait_stop_x11(child_xorg: &mut Child, child_wm: &mut Child) -> bool {
|
fn try_wait_stop_x11(child_xorg: &mut Child, child_wm: &mut Child) -> bool {
|
||||||
let mut child_flags = CHILD_FLAGS.lock().unwrap();
|
let mut desktop_manager = DESKTOP_MANAGER.lock().unwrap();
|
||||||
let mut exited = true;
|
let mut exited = true;
|
||||||
if let Some(child_flags) = &mut (*child_flags) {
|
if let Some(desktop_manager) = &mut (*desktop_manager) {
|
||||||
if child_flags.child_exit.load(Ordering::SeqCst) {
|
if desktop_manager.child_exit.load(Ordering::SeqCst) {
|
||||||
exited = true;
|
exited = true;
|
||||||
} else {
|
} else {
|
||||||
exited = Self::try_wait_x11_child_exit(child_xorg, child_wm);
|
exited = Self::try_wait_x11_child_exit(child_xorg, child_wm);
|
||||||
@ -718,8 +534,10 @@ impl ChildFlags {
|
|||||||
if exited {
|
if exited {
|
||||||
println!("=============================MYDEBUG begin to wait x11 children exit");
|
println!("=============================MYDEBUG begin to wait x11 children exit");
|
||||||
Self::wait_x11_children_exit(child_xorg, child_wm);
|
Self::wait_x11_children_exit(child_xorg, child_wm);
|
||||||
child_flags.is_child_running.store(false, Ordering::SeqCst);
|
desktop_manager
|
||||||
child_flags.child_exit.store(true, Ordering::SeqCst);
|
.is_child_running
|
||||||
|
.store(false, Ordering::SeqCst);
|
||||||
|
desktop_manager.child_exit.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exited
|
exited
|
||||||
@ -843,23 +661,3 @@ fn pam_get_service_name() -> &'static str {
|
|||||||
"gdm"
|
"gdm"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Protocal {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
match self {
|
|
||||||
Protocal::X11 => ENV_DESKTOP_PROTOCAL__X11.to_owned(),
|
|
||||||
Protocal::Wayland => ENV_DESKTOP_PROTOCAL_WAYLAND.to_owned(),
|
|
||||||
Protocal::Unknown => ENV_DESKTOP_PROTOCAL_UNKNOWN.to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for Protocal {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
match &value as &str {
|
|
||||||
ENV_DESKTOP_PROTOCAL__X11 => Protocal::X11,
|
|
||||||
ENV_DESKTOP_PROTOCAL_WAYLAND => Protocal::Wayland,
|
|
||||||
_ => Protocal::Unknown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,7 +18,7 @@ pub mod delegate;
|
|||||||
pub mod linux;
|
pub mod linux;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub mod linux_desktop;
|
pub mod linux_desktop_manager;
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
use hbb_common::{message_proto::CursorData, ResultType};
|
use hbb_common::{message_proto::CursorData, ResultType};
|
||||||
|
@ -73,7 +73,7 @@ impl RendezvousMediator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
crate::platform::linux_desktop::start_xdesktop();
|
crate::platform::linux_desktop_manager::start_xdesktop();
|
||||||
SHOULD_EXIT.store(false, Ordering::SeqCst);
|
SHOULD_EXIT.store(false, Ordering::SeqCst);
|
||||||
while !SHOULD_EXIT.load(Ordering::SeqCst) {
|
while !SHOULD_EXIT.load(Ordering::SeqCst) {
|
||||||
Config::reset_online();
|
Config::reset_online();
|
||||||
@ -100,7 +100,7 @@ impl RendezvousMediator {
|
|||||||
sleep(1.).await;
|
sleep(1.).await;
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
crate::platform::linux_desktop::stop_xdesktop();
|
crate::platform::linux_desktop_manager::stop_xdesktop();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(server: ServerPtr, host: String) -> ResultType<()> {
|
pub async fn start(server: ServerPtr, host: String) -> ResultType<()> {
|
||||||
|
@ -1074,18 +1074,19 @@ impl Connection {
|
|||||||
fn try_start_desktop(_username: &str, _passsword: &str) -> String {
|
fn try_start_desktop(_username: &str, _passsword: &str) -> String {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
if _username.is_empty() {
|
if _username.is_empty() {
|
||||||
let desktop = crate::platform::linux_desktop::get_desktop_env();
|
let username = crate::platform::linux_desktop_manager::get_username();
|
||||||
if desktop.is_ready() {
|
if username.is_empty() {
|
||||||
""
|
|
||||||
} else {
|
|
||||||
LOGIN_MSG_XSESSION_NOT_READY
|
LOGIN_MSG_XSESSION_NOT_READY
|
||||||
|
} else {
|
||||||
|
""
|
||||||
}
|
}
|
||||||
.to_owned()
|
.to_owned()
|
||||||
} else {
|
} else {
|
||||||
match crate::platform::linux_desktop::try_start_x_session(_username, _passsword) {
|
match crate::platform::linux_desktop_manager::try_start_x_session(_username, _passsword)
|
||||||
Ok(desktop) => {
|
{
|
||||||
if desktop.is_ready() {
|
Ok((username, x11_ready)) => {
|
||||||
if _username != desktop.username {
|
if x11_ready {
|
||||||
|
if _username != username {
|
||||||
LOGIN_MSG_XSESSION_ANOTHER_USER_READTY.to_owned()
|
LOGIN_MSG_XSESSION_ANOTHER_USER_READTY.to_owned()
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
"".to_owned()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user