forked from rust-lang/rustup
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrustup-init.rs
More file actions
159 lines (145 loc) · 5.54 KB
/
rustup-init.rs
File metadata and controls
159 lines (145 loc) · 5.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! The main Rustup command-line interface
//!
//! The rustup binary is a chimera, changing its behavior based on the
//! name of the binary. This is used most prominently to enable
//! Rustup's tool 'proxies' - that is, rustup itself and the rustup
//! proxies are the same binary: when the binary is called 'rustup' or
//! 'rustup.exe' it offers the Rustup command-line interface, and
//! when it is called 'rustc' it behaves as a proxy to 'rustc'.
//!
//! This scheme is further used to distinguish the Rustup installer,
//! called 'rustup-init', which is again just the rustup binary under a
//! different name.
#![recursion_limit = "1024"]
use std::process::ExitCode;
use anyhow::{Context, Result, anyhow};
use cfg_if::cfg_if;
// Public macros require availability of the internal symbols
use rs_tracing::{
close_trace_file, close_trace_file_internal, open_trace_file, trace_to_file_internal,
};
use tracing_subscriber::{EnvFilter, Registry, reload::Handle};
use rustup::cli::common;
use rustup::cli::proxy_mode;
use rustup::cli::rustup_mode;
#[cfg(windows)]
use rustup::cli::self_update;
use rustup::cli::setup_mode;
use rustup::env_var::RUST_RECURSION_COUNT_MAX;
use rustup::errors::RustupError;
use rustup::is_proxyable_tools;
use rustup::process::Process;
use rustup::utils;
#[tokio::main]
async fn main() -> Result<ExitCode> {
#[cfg(windows)]
pre_rustup_main_init();
let process = Process::os();
#[cfg(feature = "otel")]
opentelemetry::global::set_text_map_propagator(
opentelemetry_sdk::propagation::TraceContextPropagator::new(),
);
let (subscriber, console_filter) = rustup::cli::log::tracing_subscriber(&process);
tracing::subscriber::set_global_default(subscriber)?;
let result = run_rustup(&process, console_filter).await;
// We're tracing, so block until all spans are exported.
#[cfg(feature = "otel")]
opentelemetry::global::shutdown_tracer_provider();
match result {
Err(e) => {
common::report_error(&e, &process);
std::process::exit(1)
}
Ok(utils::ExitCode(c)) => std::process::exit(c),
}
}
#[tracing::instrument(level = "trace")]
async fn run_rustup(
process: &Process,
console_filter: Handle<EnvFilter, Registry>,
) -> Result<utils::ExitCode> {
if let Ok(dir) = process.var("RUSTUP_TRACE_DIR") {
open_trace_file!(dir)?;
}
let result = run_rustup_inner(process, console_filter).await;
if process.var("RUSTUP_TRACE_DIR").is_ok() {
close_trace_file!();
}
result
}
#[tracing::instrument(level = "trace", err(level = "trace"))]
async fn run_rustup_inner(
process: &Process,
console_filter: Handle<EnvFilter, Registry>,
) -> Result<utils::ExitCode> {
// Guard against infinite proxy recursion. This mostly happens due to
// bugs in rustup.
do_recursion_guard(process)?;
// Before we do anything else, ensure we know where we are and who we
// are because otherwise we cannot proceed usefully.
let current_dir = process
.current_dir()
.context(RustupError::LocatingWorkingDir)?;
utils::current_exe()?;
match process.name().as_deref() {
Some("rustup") => rustup_mode::main(current_dir, process, console_filter).await,
Some(n) if n.starts_with("rustup-setup") || n.starts_with("rustup-init") => {
// NB: The above check is only for the prefix of the file
// name. Browsers rename duplicates to
// e.g. rustup-setup(2), and this allows all variations
// to work.
setup_mode::main(current_dir, process, console_filter).await
}
Some(n) if n.starts_with("rustup-gc-") => {
// This is the final uninstallation stage on windows where
// rustup deletes its own exe
cfg_if! {
if #[cfg(windows)] {
self_update::complete_windows_uninstall(process)
} else {
unreachable!("Attempted to use Windows-specific code on a non-Windows platform. Aborting.")
}
}
}
Some(n) => {
is_proxyable_tools(n)?;
proxy_mode::main(n, current_dir, process)
.await
.map(utils::ExitCode::from)
}
None => {
// Weird case. No arg0, or it's unparsable.
Err(rustup::cli::errors::CLIError::NoExeName.into())
}
}
}
fn do_recursion_guard(process: &Process) -> Result<()> {
let recursion_count = process
.var("RUST_RECURSION_COUNT")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(0);
if recursion_count > RUST_RECURSION_COUNT_MAX {
return Err(anyhow!("infinite recursion detected"));
}
Ok(())
}
/// Windows pre-main security mitigations.
///
/// This attempts to defend against malicious DLLs that may sit alongside
/// rustup-init in the user's download folder.
#[cfg(windows)]
pub fn pre_rustup_main_init() {
use windows_sys::Win32::System::LibraryLoader::{
LOAD_LIBRARY_SEARCH_SYSTEM32, SetDefaultDllDirectories,
};
// Default to loading delay loaded DLLs from the system directory.
// For DLLs loaded at load time, this relies on the `delayload` linker flag.
// This is only necessary prior to Windows 10 RS1. See build.rs for details.
unsafe {
let result = SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32);
// SetDefaultDllDirectories should never fail if given valid arguments.
// But just to be safe and to catch mistakes, assert that it succeeded.
assert_ne!(result, 0);
}
}