tauri/process.rs
1// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5//! Types and functions related to child processes management.
6
7use crate::Env;
8
9use std::path::PathBuf;
10
11/// Finds the current running binary's path.
12///
13/// With exception to any following platform-specific behavior, the path is cached as soon as
14/// possible, and then used repeatedly instead of querying for a new path every time this function
15/// is called.
16///
17/// # Platform-specific behavior
18///
19/// ## Linux
20///
21/// On Linux, this function will **attempt** to detect if it's currently running from a
22/// valid [AppImage] and use that path instead.
23///
24/// ## macOS
25///
26/// On `macOS`, this function will return an error if the original path contained any symlinks
27/// due to less protection on macOS regarding symlinks. This behavior can be disabled by setting the
28/// `process-relaunch-dangerous-allow-symlink-macos` feature, although it is *highly discouraged*.
29///
30/// # Security
31///
32/// See [`tauri_utils::platform::current_exe`] for possible security implications.
33///
34/// # Examples
35///
36/// ```rust,no_run
37/// use tauri::{process::current_binary, Env, Manager};
38/// let current_binary_path = current_binary(&Env::default()).unwrap();
39///
40/// tauri::Builder::default()
41/// .setup(|app| {
42/// let current_binary_path = current_binary(&app.env())?;
43/// Ok(())
44/// });
45/// ```
46///
47/// [AppImage]: https://appimage.org/
48pub fn current_binary(_env: &Env) -> std::io::Result<PathBuf> {
49 // if we are running from an AppImage, we ONLY want the set AppImage path
50 #[cfg(target_os = "linux")]
51 if let Some(app_image_path) = &_env.appimage {
52 return Ok(PathBuf::from(app_image_path));
53 }
54
55 tauri_utils::platform::current_exe()
56}
57
58/// Restarts the currently running binary.
59///
60/// See [`current_binary`] for platform specific behavior, and
61/// [`tauri_utils::platform::current_exe`] for possible security implications.
62///
63/// # Examples
64///
65/// ```rust,no_run
66/// use tauri::{process::restart, Env, Manager};
67///
68/// tauri::Builder::default()
69/// .setup(|app| {
70/// restart(&app.env());
71/// Ok(())
72/// });
73/// ```
74pub fn restart(env: &Env) -> ! {
75 use std::process::{exit, Command};
76
77 if let Ok(path) = current_binary(env) {
78 // on macOS on updates the binary name might have changed
79 // so we'll read the Contents/Info.plist file to determine the binary path
80 #[cfg(target_os = "macos")]
81 restart_macos_app(&path, env);
82
83 if let Err(e) = Command::new(path).args(env.args_os.iter().skip(1)).spawn() {
84 log::error!("failed to restart app: {e}");
85 }
86 }
87
88 exit(0);
89}
90
91#[cfg(target_os = "macos")]
92fn restart_macos_app(current_binary: &std::path::Path, env: &Env) {
93 use std::process::{exit, Command};
94
95 if let Some(macos_directory) = current_binary.parent() {
96 if macos_directory.components().next_back()
97 != Some(std::path::Component::Normal(std::ffi::OsStr::new("MacOS")))
98 {
99 return;
100 }
101
102 if let Some(contents_directory) = macos_directory.parent() {
103 if contents_directory.components().next_back()
104 != Some(std::path::Component::Normal(std::ffi::OsStr::new(
105 "Contents",
106 )))
107 {
108 return;
109 }
110
111 if let Ok(info_plist) =
112 plist::from_file::<_, plist::Dictionary>(contents_directory.join("Info.plist"))
113 {
114 if let Some(binary_name) = info_plist
115 .get("CFBundleExecutable")
116 .and_then(|v| v.as_string())
117 {
118 if let Err(e) = Command::new(macos_directory.join(binary_name))
119 .args(env.args_os.iter().skip(1))
120 .spawn()
121 {
122 log::error!("failed to restart app: {e}");
123 }
124
125 exit(0);
126 }
127 }
128 }
129 }
130}