2021-03-29 15:59:14 +08:00
|
|
|
use super::{CursorData, ResultType};
|
2022-07-20 10:44:27 -07:00
|
|
|
pub use hbb_common::platform::linux::*;
|
2021-03-29 15:59:14 +08:00
|
|
|
use hbb_common::{allow_err, bail, log};
|
|
|
|
use libc::{c_char, c_int, c_void};
|
|
|
|
use std::{
|
|
|
|
cell::RefCell,
|
2022-10-12 16:06:15 +08:00
|
|
|
path::PathBuf,
|
2021-03-29 15:59:14 +08:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
Arc,
|
|
|
|
},
|
|
|
|
};
|
2022-07-20 10:44:27 -07:00
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
type Xdo = *const c_void;
|
|
|
|
|
2021-12-28 22:36:43 +08:00
|
|
|
pub const PA_SAMPLE_RATE: u32 = 48000;
|
2021-09-09 15:07:09 +08:00
|
|
|
static mut UNMODIFIED: bool = true;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
|
|
|
thread_local! {
|
|
|
|
static XDO: RefCell<Xdo> = RefCell::new(unsafe { xdo_new(std::ptr::null()) });
|
|
|
|
static DISPLAY: RefCell<*mut c_void> = RefCell::new(unsafe { XOpenDisplay(std::ptr::null())});
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
fn xdo_get_mouse_location(
|
|
|
|
xdo: Xdo,
|
|
|
|
x: *mut c_int,
|
|
|
|
y: *mut c_int,
|
|
|
|
screen_num: *mut c_int,
|
|
|
|
) -> c_int;
|
|
|
|
fn xdo_new(display: *const c_char) -> Xdo;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[link(name = "X11")]
|
|
|
|
extern "C" {
|
|
|
|
fn XOpenDisplay(display_name: *const c_char) -> *mut c_void;
|
2021-04-30 00:33:37 +08:00
|
|
|
// fn XCloseDisplay(d: *mut c_void) -> c_int;
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[link(name = "Xfixes")]
|
|
|
|
extern "C" {
|
|
|
|
// fn XFixesQueryExtension(dpy: *mut c_void, event: *mut c_int, error: *mut c_int) -> c_int;
|
|
|
|
fn XFixesGetCursorImage(dpy: *mut c_void) -> *const xcb_xfixes_get_cursor_image;
|
|
|
|
fn XFree(data: *mut c_void);
|
|
|
|
}
|
|
|
|
|
|
|
|
// /usr/include/X11/extensions/Xfixes.h
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct xcb_xfixes_get_cursor_image {
|
|
|
|
pub x: i16,
|
|
|
|
pub y: i16,
|
|
|
|
pub width: u16,
|
|
|
|
pub height: u16,
|
|
|
|
pub xhot: u16,
|
|
|
|
pub yhot: u16,
|
|
|
|
pub cursor_serial: libc::c_long,
|
|
|
|
pub pixels: *const libc::c_long,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_cursor_pos() -> Option<(i32, i32)> {
|
|
|
|
let mut res = None;
|
|
|
|
XDO.with(|xdo| {
|
|
|
|
if let Ok(xdo) = xdo.try_borrow_mut() {
|
|
|
|
if xdo.is_null() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let mut x: c_int = 0;
|
|
|
|
let mut y: c_int = 0;
|
|
|
|
unsafe {
|
|
|
|
xdo_get_mouse_location(*xdo, &mut x as _, &mut y as _, std::ptr::null_mut());
|
|
|
|
}
|
|
|
|
res = Some((x, y));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn reset_input_cache() {}
|
|
|
|
|
|
|
|
pub fn get_cursor() -> ResultType<Option<u64>> {
|
|
|
|
let mut res = None;
|
|
|
|
DISPLAY.with(|conn| {
|
|
|
|
if let Ok(d) = conn.try_borrow_mut() {
|
|
|
|
if !d.is_null() {
|
|
|
|
unsafe {
|
|
|
|
let img = XFixesGetCursorImage(*d);
|
|
|
|
if !img.is_null() {
|
|
|
|
res = Some((*img).cursor_serial as u64);
|
|
|
|
XFree(img as _);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
|
|
|
|
let mut res = None;
|
|
|
|
DISPLAY.with(|conn| {
|
|
|
|
if let Ok(ref mut d) = conn.try_borrow_mut() {
|
|
|
|
if !d.is_null() {
|
|
|
|
unsafe {
|
|
|
|
let img = XFixesGetCursorImage(**d);
|
|
|
|
if !img.is_null() && hcursor == (*img).cursor_serial as u64 {
|
|
|
|
let mut cd: CursorData = Default::default();
|
|
|
|
cd.hotx = (*img).xhot as _;
|
|
|
|
cd.hoty = (*img).yhot as _;
|
|
|
|
cd.width = (*img).width as _;
|
|
|
|
cd.height = (*img).height as _;
|
|
|
|
// to-do: how about if it is 0
|
|
|
|
cd.id = (*img).cursor_serial as _;
|
|
|
|
let pixels =
|
|
|
|
std::slice::from_raw_parts((*img).pixels, (cd.width * cd.height) as _);
|
2022-07-17 00:59:56 +08:00
|
|
|
// cd.colors.resize(pixels.len() * 4, 0);
|
|
|
|
let mut cd_colors = vec![0_u8; pixels.len() * 4];
|
2021-03-29 15:59:14 +08:00
|
|
|
for y in 0..cd.height {
|
|
|
|
for x in 0..cd.width {
|
|
|
|
let pos = (y * cd.width + x) as usize;
|
|
|
|
let p = pixels[pos];
|
|
|
|
let a = (p >> 24) & 0xff;
|
|
|
|
let r = (p >> 16) & 0xff;
|
|
|
|
let g = (p >> 8) & 0xff;
|
|
|
|
let b = (p >> 0) & 0xff;
|
|
|
|
if a == 0 {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let pos = pos * 4;
|
2022-07-17 00:59:56 +08:00
|
|
|
cd_colors[pos] = r as _;
|
|
|
|
cd_colors[pos + 1] = g as _;
|
|
|
|
cd_colors[pos + 2] = b as _;
|
|
|
|
cd_colors[pos + 3] = a as _;
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
2022-07-17 00:59:56 +08:00
|
|
|
cd.colors = cd_colors.into();
|
2021-03-29 15:59:14 +08:00
|
|
|
res = Some(cd);
|
|
|
|
}
|
|
|
|
if !img.is_null() {
|
|
|
|
XFree(img as _);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
match res {
|
|
|
|
Some(x) => Ok(x),
|
|
|
|
_ => bail!("Failed to get cursor image of {}", hcursor),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-07 01:27:21 +08:00
|
|
|
fn start_uinput_service() {
|
2022-07-20 09:50:08 -07:00
|
|
|
use crate::server::uinput::service;
|
2022-07-07 01:27:21 +08:00
|
|
|
std::thread::spawn(|| {
|
|
|
|
service::start_service_control();
|
|
|
|
});
|
|
|
|
std::thread::spawn(|| {
|
|
|
|
service::start_service_keyboard();
|
|
|
|
});
|
|
|
|
std::thread::spawn(|| {
|
|
|
|
service::start_service_mouse();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-10-17 03:06:06 -07:00
|
|
|
fn stop_server(server: &mut Option<std::process::Child>) {
|
|
|
|
if let Some(mut ps) = server.take() {
|
|
|
|
allow_err!(ps.kill());
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(30));
|
|
|
|
match ps.try_wait() {
|
|
|
|
Ok(Some(_status)) => {}
|
|
|
|
Ok(None) => {
|
|
|
|
let _res = ps.wait();
|
|
|
|
}
|
|
|
|
Err(e) => log::error!("error attempting to wait: {e}"),
|
|
|
|
}
|
2022-07-07 01:27:21 +08:00
|
|
|
}
|
2022-10-17 03:06:06 -07:00
|
|
|
}
|
2022-07-07 01:27:21 +08:00
|
|
|
|
2022-10-17 03:06:06 -07:00
|
|
|
fn set_x11_env(uid: &str) {
|
|
|
|
log::info!("uid of seat0: {}", uid);
|
|
|
|
let gdm = format!("/run/user/{}/gdm/Xauthority", uid);
|
|
|
|
let mut auth = get_env_tries("XAUTHORITY", uid, 10);
|
|
|
|
if auth.is_empty() {
|
|
|
|
auth = if std::path::Path::new(&gdm).exists() {
|
|
|
|
gdm
|
|
|
|
} else {
|
|
|
|
let username = get_active_username();
|
|
|
|
if username == "root" {
|
|
|
|
format!("/{}/.Xauthority", username)
|
|
|
|
} else {
|
|
|
|
let tmp = format!("/home/{}/.Xauthority", username);
|
|
|
|
if std::path::Path::new(&tmp).exists() {
|
|
|
|
tmp
|
|
|
|
} else {
|
|
|
|
format!("/var/lib/{}/.Xauthority", username)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2022-07-07 01:27:21 +08:00
|
|
|
}
|
2022-10-17 03:06:06 -07:00
|
|
|
let mut d = get_env("DISPLAY", uid);
|
|
|
|
if d.is_empty() {
|
|
|
|
d = get_display();
|
|
|
|
}
|
|
|
|
if d.is_empty() {
|
|
|
|
d = ":0".to_owned();
|
|
|
|
}
|
|
|
|
d = d.replace(&whoami::hostname(), "").replace("localhost", "");
|
|
|
|
log::info!("DISPLAY: {}", d);
|
|
|
|
log::info!("XAUTHORITY: {}", auth);
|
|
|
|
std::env::set_var("XAUTHORITY", auth);
|
|
|
|
std::env::set_var("DISPLAY", d);
|
|
|
|
}
|
2022-07-07 01:27:21 +08:00
|
|
|
|
2022-10-17 03:06:06 -07:00
|
|
|
fn stop_rustdesk_servers() {
|
2022-07-07 01:27:21 +08:00
|
|
|
let _ = run_cmds(format!(
|
2022-10-17 03:06:06 -07:00
|
|
|
r##"ps -ef | grep -E 'rustdesk +--server' | awk '{{printf("kill -9 %d\n", $2)}}' | bash"##,
|
2022-07-07 01:27:21 +08:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2022-10-17 03:06:06 -07:00
|
|
|
fn should_start_server(
|
|
|
|
try_x11: bool,
|
|
|
|
uid: &mut String,
|
2022-10-17 07:55:14 -07:00
|
|
|
cur_uid: String,
|
2022-10-17 03:06:06 -07:00
|
|
|
cm0: &mut bool,
|
|
|
|
last_restart: &mut std::time::Instant,
|
|
|
|
server: &mut Option<std::process::Child>,
|
|
|
|
) -> bool {
|
|
|
|
let cm = get_cm();
|
|
|
|
let mut start_new = false;
|
2022-10-17 07:55:14 -07:00
|
|
|
if cur_uid != *uid && !cur_uid.is_empty() {
|
|
|
|
*uid = cur_uid;
|
2022-10-17 03:06:06 -07:00
|
|
|
if try_x11 {
|
|
|
|
set_x11_env(&uid);
|
|
|
|
}
|
|
|
|
if let Some(ps) = server.as_mut() {
|
|
|
|
allow_err!(ps.kill());
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(30));
|
|
|
|
*last_restart = std::time::Instant::now();
|
|
|
|
}
|
|
|
|
} else if !cm
|
|
|
|
&& ((*cm0 && last_restart.elapsed().as_secs() > 60)
|
|
|
|
|| last_restart.elapsed().as_secs() > 3600)
|
2022-07-07 01:27:21 +08:00
|
|
|
{
|
2022-10-17 03:06:06 -07:00
|
|
|
// restart server if new connections all closed, or every one hour,
|
|
|
|
// as a workaround to resolve "SpotUdp" (dns resolve)
|
|
|
|
// and x server get displays failure issue
|
|
|
|
if let Some(ps) = server.as_mut() {
|
|
|
|
allow_err!(ps.kill());
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(30));
|
|
|
|
*last_restart = std::time::Instant::now();
|
|
|
|
log::info!("restart server");
|
2022-07-07 01:27:21 +08:00
|
|
|
}
|
|
|
|
}
|
2022-10-17 03:06:06 -07:00
|
|
|
if let Some(ps) = server.as_mut() {
|
2022-07-07 01:27:21 +08:00
|
|
|
match ps.try_wait() {
|
2022-10-17 03:06:06 -07:00
|
|
|
Ok(Some(_)) => {
|
|
|
|
*server = None;
|
|
|
|
start_new = true;
|
2022-07-07 01:27:21 +08:00
|
|
|
}
|
2022-10-17 03:06:06 -07:00
|
|
|
_ => {}
|
2022-07-07 01:27:21 +08:00
|
|
|
}
|
2022-10-17 03:06:06 -07:00
|
|
|
} else {
|
|
|
|
start_new = true;
|
2022-07-07 01:27:21 +08:00
|
|
|
}
|
2022-10-17 03:06:06 -07:00
|
|
|
*cm0 = cm;
|
|
|
|
start_new
|
2022-07-07 01:27:21 +08:00
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
pub fn start_os_service() {
|
2022-10-17 03:06:06 -07:00
|
|
|
stop_rustdesk_servers();
|
2022-07-07 01:27:21 +08:00
|
|
|
start_uinput_service();
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
let running = Arc::new(AtomicBool::new(true));
|
|
|
|
let r = running.clone();
|
|
|
|
let mut uid = "".to_owned();
|
|
|
|
let mut server: Option<std::process::Child> = None;
|
2022-10-17 03:06:06 -07:00
|
|
|
let mut user_server: Option<std::process::Child> = None;
|
2021-03-29 15:59:14 +08:00
|
|
|
if let Err(err) = ctrlc::set_handler(move || {
|
|
|
|
r.store(false, Ordering::SeqCst);
|
|
|
|
}) {
|
|
|
|
println!("Failed to set Ctrl-C handler: {}", err);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut cm0 = false;
|
|
|
|
let mut last_restart = std::time::Instant::now();
|
|
|
|
while running.load(Ordering::SeqCst) {
|
2022-10-17 07:55:14 -07:00
|
|
|
let (cur_uid, cur_user) = get_active_user_id_name();
|
2022-07-07 01:27:21 +08:00
|
|
|
let is_wayland = current_is_wayland();
|
|
|
|
|
2022-10-17 07:55:14 -07:00
|
|
|
if cur_user == "root" || !is_wayland {
|
2022-10-17 03:06:06 -07:00
|
|
|
stop_server(&mut user_server);
|
2022-07-07 01:27:21 +08:00
|
|
|
// try start subprocess "--server"
|
2022-10-17 07:55:14 -07:00
|
|
|
if should_start_server(
|
|
|
|
true,
|
|
|
|
&mut uid,
|
|
|
|
cur_uid,
|
|
|
|
&mut cm0,
|
|
|
|
&mut last_restart,
|
|
|
|
&mut server,
|
|
|
|
) {
|
2022-10-17 08:17:03 -07:00
|
|
|
// to-do: stop_server(&mut user_server); may not stop child correctly
|
|
|
|
// stop_rustdesk_servers() is just a temp solution here.
|
|
|
|
stop_rustdesk_servers();
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
|
2022-07-07 01:27:21 +08:00
|
|
|
match crate::run_me(vec!["--server"]) {
|
|
|
|
Ok(ps) => server = Some(ps),
|
|
|
|
Err(err) => {
|
|
|
|
log::error!("Failed to start server: {}", err);
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
2022-10-17 07:55:14 -07:00
|
|
|
} else if cur_user != "" {
|
|
|
|
if cur_user != "gdm" {
|
2022-07-07 01:27:21 +08:00
|
|
|
// try kill subprocess "--server"
|
|
|
|
stop_server(&mut server);
|
|
|
|
|
2022-10-17 03:06:06 -07:00
|
|
|
// try start subprocess "--server"
|
|
|
|
if should_start_server(
|
|
|
|
false,
|
|
|
|
&mut uid,
|
2022-10-17 07:55:14 -07:00
|
|
|
cur_uid.clone(),
|
2022-10-17 03:06:06 -07:00
|
|
|
&mut cm0,
|
|
|
|
&mut last_restart,
|
|
|
|
&mut user_server,
|
|
|
|
) {
|
2022-10-17 08:45:58 -07:00
|
|
|
stop_rustdesk_servers();
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
|
2022-10-17 07:55:14 -07:00
|
|
|
match run_as_user("--server", Some((cur_uid, cur_user))) {
|
2022-10-17 03:06:06 -07:00
|
|
|
Ok(ps) => user_server = ps,
|
|
|
|
Err(err) => {
|
|
|
|
log::error!("Failed to start server: {}", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-07 01:27:21 +08:00
|
|
|
}
|
|
|
|
} else {
|
2022-10-17 08:17:03 -07:00
|
|
|
stop_rustdesk_servers();
|
2022-10-17 08:45:58 -07:00
|
|
|
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
|
2022-10-17 03:06:06 -07:00
|
|
|
stop_server(&mut user_server);
|
2022-07-07 01:27:21 +08:00
|
|
|
stop_server(&mut server);
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
|
|
|
|
}
|
|
|
|
|
2022-10-17 03:06:06 -07:00
|
|
|
if let Some(ps) = user_server.take().as_mut() {
|
|
|
|
allow_err!(ps.kill());
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
if let Some(ps) = server.take().as_mut() {
|
|
|
|
allow_err!(ps.kill());
|
|
|
|
}
|
2022-01-17 12:05:06 +08:00
|
|
|
log::info!("Exit");
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-10-17 07:55:14 -07:00
|
|
|
pub fn get_active_user_id_name() -> (String, String) {
|
|
|
|
let vec_id_name = get_values_of_seat0([1, 2].to_vec());
|
|
|
|
(vec_id_name[0].clone(), vec_id_name[1].clone())
|
|
|
|
}
|
|
|
|
|
2022-03-08 15:42:58 +08:00
|
|
|
pub fn get_active_userid() -> String {
|
2022-10-17 07:55:14 -07:00
|
|
|
get_values_of_seat0([1].to_vec())[0].clone()
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_cm() -> bool {
|
|
|
|
if let Ok(output) = std::process::Command::new("ps").args(vec!["aux"]).output() {
|
|
|
|
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
|
|
|
if line.contains(&format!(
|
|
|
|
"{} --cm",
|
|
|
|
std::env::current_exe()
|
|
|
|
.unwrap_or("".into())
|
|
|
|
.to_string_lossy()
|
|
|
|
)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_display() -> String {
|
|
|
|
let user = get_active_username();
|
2021-04-30 00:33:37 +08:00
|
|
|
log::debug!("w {}", &user);
|
2021-03-29 15:59:14 +08:00
|
|
|
if let Ok(output) = std::process::Command::new("w").arg(&user).output() {
|
|
|
|
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
2021-04-30 00:33:37 +08:00
|
|
|
log::debug!(" {}", line);
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut iter = line.split_whitespace();
|
2021-04-30 00:33:37 +08:00
|
|
|
let b = iter.nth(2);
|
|
|
|
if let Some(b) = b {
|
|
|
|
if b.starts_with(":") {
|
|
|
|
return b.to_owned();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// above not work for gdm user
|
2021-04-30 00:33:37 +08:00
|
|
|
log::debug!("ls -l /tmp/.X11-unix/");
|
2021-06-10 12:19:23 +08:00
|
|
|
let mut last = "".to_owned();
|
2021-03-29 15:59:14 +08:00
|
|
|
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() {
|
2021-04-30 00:33:37 +08:00
|
|
|
log::debug!(" {}", line);
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut iter = line.split_whitespace();
|
2021-06-10 12:19:23 +08:00
|
|
|
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;
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-06-10 12:19:23 +08:00
|
|
|
last
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_login_wayland() -> bool {
|
|
|
|
if let Ok(contents) = std::fs::read_to_string("/etc/gdm3/custom.conf") {
|
|
|
|
contents.contains("#WaylandEnable=false")
|
2021-06-04 21:04:40 +08:00
|
|
|
} else if let Ok(contents) = std::fs::read_to_string("/etc/gdm/custom.conf") {
|
|
|
|
contents.contains("#WaylandEnable=false")
|
2021-03-29 15:59:14 +08:00
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fix_login_wayland() {
|
2021-06-04 21:04:40 +08:00
|
|
|
let mut file = "/etc/gdm3/custom.conf".to_owned();
|
|
|
|
if !std::path::Path::new(&file).exists() {
|
|
|
|
file = "/etc/gdm/custom.conf".to_owned();
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
match std::process::Command::new("pkexec")
|
|
|
|
.args(vec![
|
|
|
|
"sed",
|
|
|
|
"-i",
|
|
|
|
"s/#WaylandEnable=false/WaylandEnable=false/g",
|
2021-10-01 22:48:04 +03:30
|
|
|
&file,
|
2021-03-29 15:59:14 +08:00
|
|
|
])
|
|
|
|
.output()
|
|
|
|
{
|
|
|
|
Ok(x) => {
|
|
|
|
let x = String::from_utf8_lossy(&x.stderr);
|
|
|
|
if !x.is_empty() {
|
|
|
|
log::error!("fix_login_wayland failed: {}", x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
log::error!("fix_login_wayland failed: {}", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-09 15:07:09 +08:00
|
|
|
pub fn current_is_wayland() -> bool {
|
|
|
|
let dtype = get_display_server();
|
2021-10-01 22:48:04 +03:30
|
|
|
return "wayland" == dtype && unsafe { UNMODIFIED };
|
2021-09-09 15:07:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn modify_default_login() -> String {
|
|
|
|
let dsession = std::env::var("DESKTOP_SESSION").unwrap();
|
|
|
|
let user_name = std::env::var("USERNAME").unwrap();
|
2022-05-27 11:07:24 +08:00
|
|
|
if let Ok(x) = run_cmds("ls /usr/share/* | grep ${DESKTOP_SESSION}-xorg.desktop".to_owned()) {
|
2021-09-09 15:07:09 +08:00
|
|
|
if x.trim_end().to_string() != "" {
|
|
|
|
match std::process::Command::new("pkexec")
|
|
|
|
.args(vec![
|
|
|
|
"sed",
|
|
|
|
"-i",
|
|
|
|
&format!("s/={0}$/={0}-xorg/g", &dsession),
|
2021-10-01 22:48:04 +03:30
|
|
|
&format!("/var/lib/AccountsService/users/{}", &user_name),
|
2021-09-09 15:07:09 +08:00
|
|
|
])
|
|
|
|
.output()
|
|
|
|
{
|
|
|
|
Ok(x) => {
|
|
|
|
let x = String::from_utf8_lossy(&x.stderr);
|
|
|
|
if !x.is_empty() {
|
|
|
|
log::error!("modify_default_login failed: {}", x);
|
|
|
|
return "Fix failed! Please re-login with X server manually".to_owned();
|
|
|
|
} else {
|
2021-10-01 22:48:04 +03:30
|
|
|
unsafe {
|
|
|
|
UNMODIFIED = false;
|
|
|
|
}
|
2021-09-09 15:07:09 +08:00
|
|
|
return "".to_owned();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
log::error!("modify_default_login failed: {}", err);
|
|
|
|
return "Fix failed! Please re-login with X server manually".to_owned();
|
|
|
|
}
|
|
|
|
}
|
2022-05-27 11:07:24 +08:00
|
|
|
} else if let Ok(z) =
|
2021-10-01 22:48:04 +03:30
|
|
|
run_cmds("ls /usr/share/* | grep ${DESKTOP_SESSION:0:-8}.desktop".to_owned())
|
|
|
|
{
|
2021-09-09 15:07:09 +08:00
|
|
|
if z.trim_end().to_string() != "" {
|
|
|
|
match std::process::Command::new("pkexec")
|
|
|
|
.args(vec![
|
|
|
|
"sed",
|
|
|
|
"-i",
|
2021-10-01 22:48:04 +03:30
|
|
|
&format!("s/={}$/={}/g", &dsession, &dsession[..dsession.len() - 8]),
|
|
|
|
&format!("/var/lib/AccountsService/users/{}", &user_name),
|
2021-09-09 15:07:09 +08:00
|
|
|
])
|
|
|
|
.output()
|
|
|
|
{
|
|
|
|
Ok(x) => {
|
|
|
|
let x = String::from_utf8_lossy(&x.stderr);
|
|
|
|
if !x.is_empty() {
|
|
|
|
log::error!("modify_default_login failed: {}", x);
|
|
|
|
return "Fix failed! Please re-login with X server manually".to_owned();
|
|
|
|
} else {
|
2021-10-01 22:48:04 +03:30
|
|
|
unsafe {
|
|
|
|
UNMODIFIED = false;
|
|
|
|
}
|
2021-09-09 15:07:09 +08:00
|
|
|
return "".to_owned();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
log::error!("modify_default_login failed: {}", err);
|
|
|
|
return "Fix failed! Please re-login with X server manually".to_owned();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "Fix failed! Please re-login with X server manually".to_owned();
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
// to-do: test the other display manager
|
|
|
|
fn _get_display_manager() -> String {
|
|
|
|
if let Ok(x) = std::fs::read_to_string("/etc/X11/default-display-manager") {
|
|
|
|
if let Some(x) = x.split("/").last() {
|
|
|
|
return x.to_owned();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"gdm3".to_owned()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_active_username() -> String {
|
2022-10-17 07:55:14 -07:00
|
|
|
get_values_of_seat0([2].to_vec())[0].clone()
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-10-12 16:06:15 +08:00
|
|
|
pub fn get_active_user_home() -> Option<PathBuf> {
|
|
|
|
let username = get_active_username();
|
|
|
|
if !username.is_empty() {
|
|
|
|
let home = PathBuf::from(format!("/home/{}", username));
|
|
|
|
if home.exists() {
|
|
|
|
return Some(home);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
pub fn is_prelogin() -> bool {
|
|
|
|
let n = get_active_userid().len();
|
|
|
|
n < 4 && n > 1
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_root() -> bool {
|
|
|
|
crate::username() == "root"
|
|
|
|
}
|
|
|
|
|
2022-09-07 20:08:12 +08:00
|
|
|
fn is_opensuse() -> bool {
|
|
|
|
if let Ok(res) = run_cmds("cat /etc/os-release | grep opensuse".to_owned()) {
|
|
|
|
if !res.is_empty() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2022-10-17 07:55:14 -07:00
|
|
|
pub fn run_as_user(
|
|
|
|
arg: &str,
|
|
|
|
user: Option<(String, String)>,
|
|
|
|
) -> ResultType<Option<std::process::Child>> {
|
|
|
|
let (uid, username) = match user {
|
|
|
|
Some(id_name) => id_name,
|
|
|
|
None => get_active_user_id_name(),
|
|
|
|
};
|
2021-03-29 15:59:14 +08:00
|
|
|
let cmd = std::env::current_exe()?;
|
2022-09-07 20:08:12 +08:00
|
|
|
let xdg = &format!("XDG_RUNTIME_DIR=/run/user/{}", uid) as &str;
|
2022-10-17 07:55:14 -07:00
|
|
|
let mut args = vec![xdg, "-u", &username, cmd.to_str().unwrap_or(""), arg];
|
2022-05-05 01:33:49 +08:00
|
|
|
// -E required for opensuse
|
2022-09-07 20:08:12 +08:00
|
|
|
if is_opensuse() {
|
|
|
|
args.insert(0, "-E");
|
|
|
|
}
|
|
|
|
|
|
|
|
let task = std::process::Command::new("sudo").args(args).spawn()?;
|
2021-03-29 15:59:14 +08:00
|
|
|
Ok(Some(task))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_pa_monitor() -> String {
|
|
|
|
get_pa_sources()
|
|
|
|
.drain(..)
|
|
|
|
.map(|x| x.0)
|
|
|
|
.filter(|x| x.contains("monitor"))
|
|
|
|
.next()
|
|
|
|
.unwrap_or("".to_owned())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_pa_source_name(desc: &str) -> String {
|
|
|
|
get_pa_sources()
|
|
|
|
.drain(..)
|
|
|
|
.filter(|x| x.1 == desc)
|
|
|
|
.map(|x| x.0)
|
|
|
|
.next()
|
|
|
|
.unwrap_or("".to_owned())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_pa_sources() -> Vec<(String, String)> {
|
|
|
|
use pulsectl::controllers::*;
|
|
|
|
let mut out = Vec::new();
|
|
|
|
match SourceController::create() {
|
|
|
|
Ok(mut handler) => {
|
|
|
|
if let Ok(devices) = handler.list_devices() {
|
|
|
|
for dev in devices.clone() {
|
|
|
|
out.push((
|
|
|
|
dev.name.unwrap_or("".to_owned()),
|
|
|
|
dev.description.unwrap_or("".to_owned()),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
log::error!("Failed to get_pa_sources: {:?}", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn lock_screen() {
|
2022-05-12 17:35:25 +08:00
|
|
|
std::process::Command::new("xdg-screensaver")
|
|
|
|
.arg("lock")
|
|
|
|
.spawn()
|
|
|
|
.ok();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-01-15 16:31:21 +08:00
|
|
|
pub fn toggle_blank_screen(_v: bool) {
|
2021-03-29 15:59:14 +08:00
|
|
|
// https://unix.stackexchange.com/questions/17170/disable-keyboard-mouse-input-on-unix-under-x
|
|
|
|
}
|
|
|
|
|
2022-01-15 16:31:21 +08:00
|
|
|
pub fn block_input(_v: bool) -> bool {
|
|
|
|
true
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_installed() -> bool {
|
|
|
|
true
|
|
|
|
}
|
2021-04-30 00:33:37 +08:00
|
|
|
|
2021-06-08 17:54:25 +08:00
|
|
|
fn get_env_tries(name: &str, uid: &str, n: usize) -> String {
|
|
|
|
for _ in 0..n {
|
|
|
|
let x = get_env(name, uid);
|
|
|
|
if !x.is_empty() {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(300));
|
|
|
|
}
|
|
|
|
"".to_owned()
|
|
|
|
}
|
|
|
|
|
2021-04-30 00:33:37 +08:00
|
|
|
fn get_env(name: &str, uid: &str) -> String {
|
2021-12-25 01:07:41 +08:00
|
|
|
let cmd = format!("ps -u {} -o pid= | xargs -I__ cat /proc/__/environ 2>/dev/null | tr '\\0' '\\n' | grep '^{}=' | tail -1 | sed 's/{}=//g'", uid, name, name);
|
2021-04-30 00:33:37 +08:00
|
|
|
log::debug!("Run: {}", &cmd);
|
2022-05-27 11:07:24 +08:00
|
|
|
if let Ok(x) = run_cmds(cmd) {
|
2021-04-30 00:33:37 +08:00
|
|
|
x.trim_end().to_string()
|
|
|
|
} else {
|
|
|
|
"".to_owned()
|
|
|
|
}
|
|
|
|
}
|
2022-05-10 01:08:21 +08:00
|
|
|
|
|
|
|
#[link(name = "gtk-3")]
|
|
|
|
extern "C" {
|
|
|
|
fn gtk_main_quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn quit_gui() {
|
|
|
|
unsafe { gtk_main_quit() };
|
|
|
|
}
|
2022-08-19 15:44:19 +08:00
|
|
|
|
|
|
|
pub fn check_super_user_permission() -> ResultType<bool> {
|
2022-09-13 18:10:20 +08:00
|
|
|
let file = "/usr/share/rustdesk/files/polkit";
|
|
|
|
let arg;
|
|
|
|
if std::path::Path::new(file).is_file() {
|
|
|
|
arg = file;
|
|
|
|
} else {
|
|
|
|
arg = "echo";
|
|
|
|
}
|
|
|
|
let status = std::process::Command::new("pkexec").arg(arg).status()?;
|
2022-08-19 15:44:19 +08:00
|
|
|
Ok(status.success() && status.code() == Some(0))
|
|
|
|
}
|