1use core::{cell::UnsafeCell, ffi::CStr, mem::MaybeUninit, ptr::NonNull};
7
8#[cfg(not(any(feature = "std", feature = "rustc-dep-of-std")))]
9extern crate alloc;
10use crate::{
11 alloc::GLOBAL_SYSTEM_ALLOCATOR,
12 syscalls::{self, define_syscall},
13};
14use alloc::boxed::Box;
15use alloc::vec::Vec;
16use safa_abi::{
17 errors::ErrorStatus,
18 raw::{processes::TaskMetadata, NonNullSlice, Optional, RawSlice, RawSliceMut},
19};
20
21use crate::{syscalls::err_from_u16, syscalls::SyscallNum, Lazy};
22use alloc::ffi::CString;
23#[derive(Debug, Clone, Copy)]
26struct RawArgs {
27 args: NonNull<[NonNullSlice<u8>]>,
28}
29
30impl RawArgs {
31 const fn new(args: NonNull<[NonNullSlice<u8>]>) -> Self {
32 Self { args }
33 }
34
35 fn len(&self) -> usize {
36 unsafe { self.args.as_ref().len() }
37 }
38
39 fn get(&self, index: usize) -> Option<NonNullSlice<u8>> {
40 unsafe { self.args.as_ref().get(index).copied() }
41 }
42
43 unsafe fn into_slice(self) -> &'static [NonNullSlice<u8>] {
44 unsafe { self.args.as_ref() }
45 }
46}
47
48struct RawArgsStatic(UnsafeCell<MaybeUninit<Option<RawArgs>>>);
49unsafe impl Sync for RawArgsStatic {}
50
51impl RawArgsStatic {
52 const fn new() -> Self {
53 Self(UnsafeCell::new(MaybeUninit::uninit()))
54 }
55
56 unsafe fn init(&self, args: Option<RawArgs>) {
57 unsafe {
58 self.0.get().write(MaybeUninit::new(args));
59 }
60 }
61
62 unsafe fn get(&self, index: usize) -> Option<NonNullSlice<u8>> {
63 unsafe { (*self.0.get()).assume_init()?.get(index) }
64 }
65
66 unsafe fn len(&self) -> usize {
67 if let Some(args) = unsafe { (*self.0.get()).assume_init() } {
68 args.len()
69 } else {
70 0
71 }
72 }
73
74 unsafe fn get_raw(&self) -> Option<RawArgs> {
75 unsafe { (*self.0.get()).assume_init() }
76 }
77
78 unsafe fn as_slice(&self) -> &'static [NonNullSlice<u8>] {
79 unsafe {
80 if let Some(raw) = self.get_raw() {
81 raw.into_slice()
82 } else {
83 &mut []
84 }
85 }
86 }
87}
88
89static RAW_ARGS: RawArgsStatic = RawArgsStatic::new();
90
91#[cfg_attr(
93 not(any(feature = "std", feature = "rustc-dep-of-std")),
94 unsafe(no_mangle)
95)]
96#[inline(always)]
97pub extern "C" fn sysget_argc() -> usize {
98 unsafe { RAW_ARGS.len() }
99}
100
101#[cfg_attr(
103 not(any(feature = "std", feature = "rustc-dep-of-std")),
104 unsafe(no_mangle)
105)]
106#[inline(always)]
107pub extern "C" fn sysget_arg(index: usize) -> Optional<NonNullSlice<u8>> {
108 unsafe { RAW_ARGS.get(index).into() }
109}
110
111struct EnvVars {
114 env: Vec<(Box<[u8]>, Box<CStr>)>,
115 size_hint: usize,
118}
119
120impl EnvVars {
121 pub const fn new() -> Self {
122 Self {
123 env: Vec::new(),
124 size_hint: 0,
125 }
126 }
127
128 pub fn get(&self, key: &[u8]) -> Option<&[u8]> {
129 for (k, v) in &self.env {
130 if &**k == key {
131 return Some(v.to_bytes());
132 }
133 }
134 None
135 }
136
137 #[inline(always)]
141 pub unsafe fn push(&mut self, key: &[u8], value: &[u8]) {
142 let cstr = CString::new(value)
143 .unwrap_or_else(|_| CStr::from_bytes_until_nul(value).unwrap().into());
144
145 self.env
146 .push((key.to_vec().into_boxed_slice(), cstr.into_boxed_c_str()));
147
148 self.size_hint += key.len() + value.len() + 1;
149 }
150
151 #[inline(always)]
152 pub fn set(&mut self, key: &[u8], value: &[u8]) {
153 for (k, v) in &mut self.env {
154 if &**k == key {
155 let old_len = v.count_bytes();
156
157 let new_value = CString::new(value)
158 .unwrap_or_else(|_| CStr::from_bytes_until_nul(value).unwrap().into());
159 *v = new_value.into_boxed_c_str();
160 self.size_hint -= old_len;
161 self.size_hint += value.len();
162 return;
163 }
164 }
165
166 unsafe {
167 self.push(key, value);
168 }
169 }
170
171 #[inline(always)]
172 pub fn remove(&mut self, key: &[u8]) {
173 for (i, (k, v)) in self.env.iter().enumerate() {
174 if &**k == key {
175 self.size_hint -= key.len() + 1 + v.count_bytes();
177 self.env.swap_remove(i);
178 return;
179 }
180 }
181 }
182
183 unsafe fn insert_raw(&mut self, raw: &[NonNullSlice<u8>]) {
187 self.env.reserve(raw.len());
188
189 for slice in raw {
190 let slice = slice.into_slice_mut();
191 let mut spilt = slice.splitn(2, |c| *c == b'=');
192
193 let Some(key) = spilt.next() else {
194 continue;
195 };
196
197 let value = spilt.next();
198 let value = value.unwrap_or_default();
199
200 self.push(key, value);
201 }
202 }
203
204 pub fn clear(&mut self) {
205 self.env.clear();
206 self.size_hint = 0;
207 }
208
209 fn duplicate(&self) -> (Vec<u8>, Vec<RawSlice<u8>>) {
210 let mut buf: Vec<u8> = Vec::with_capacity(self.size_hint);
211 let mut slices = Vec::with_capacity(self.env.len());
212
213 for (key, value) in &self.env {
214 let ptr = unsafe { buf.as_mut_ptr().add(buf.len()) };
215 slices.push(unsafe {
216 RawSlice::from_raw_parts(ptr, key.len() + 1 + value.count_bytes())
217 });
218
219 buf.extend_from_slice(key);
220 buf.push(b'=');
221 buf.extend_from_slice(value.to_bytes_with_nul());
222 }
223
224 (buf, slices)
225 }
226}
227
228static RAW_ENV: RawArgsStatic = RawArgsStatic::new();
230
231static ENV: Lazy<UnsafeCell<EnvVars>> = Lazy::new(|| {
233 let mut env = EnvVars::new();
234 unsafe { env.insert_raw(RAW_ENV.as_slice()) };
235 UnsafeCell::new(env)
236});
237
238#[inline]
241pub fn env_get_all() -> &'static [(Box<[u8]>, Box<CStr>)] {
242 let env = unsafe { &*ENV.get() };
243 &env.env
244}
245
246#[inline]
247pub fn env_get(key: &[u8]) -> Option<&[u8]> {
248 let env = unsafe { &*ENV.get() };
249 env.get(key)
250}
251
252#[inline]
253pub fn env_set(key: &[u8], value: &[u8]) {
254 let env = unsafe { &mut *ENV.get() };
255 env.set(key, value);
256}
257
258#[inline]
259pub fn env_remove(key: &[u8]) {
260 let env = unsafe { &mut *ENV.get() };
261 env.remove(key);
262}
263
264#[inline]
270pub(crate) unsafe fn duplicate_env() -> (Vec<u8>, Vec<RawSlice<u8>>) {
271 let env = unsafe { &*ENV.get() };
272 env.duplicate()
273}
274
275#[inline]
276pub fn env_clear() {
277 let env = unsafe { &mut *ENV.get() };
278 env.clear();
279}
280
281#[cfg_attr(
282 not(any(feature = "std", feature = "rustc-dep-of-std")),
283 unsafe(no_mangle)
284)]
285pub extern "C" fn sysenv_get(key: RawSlice<u8>) -> Optional<RawSlice<u8>> {
287 unsafe {
288 let Some(key) = key.into_slice() else {
289 return Optional::None;
290 };
291
292 env_get(key).map(|slice| RawSlice::from_slice(slice)).into()
293 }
294}
295
296#[cfg_attr(
297 not(any(feature = "std", feature = "rustc-dep-of-std")),
298 unsafe(no_mangle)
299)]
300pub extern "C" fn sysenv_set(key: RawSlice<u8>, value: RawSlice<u8>) {
302 unsafe {
303 let Some(key) = key.into_slice() else {
304 return;
305 };
306 let value = if let Some(value) = value.into_slice() {
307 value
308 } else {
309 &[]
310 };
311
312 env_set(key, value);
313 }
314}
315
316#[cfg_attr(
317 not(any(feature = "std", feature = "rustc-dep-of-std")),
318 unsafe(no_mangle)
319)]
320pub extern "C" fn sysenv_remove(key: RawSlice<u8>) {
322 unsafe {
323 let Some(key) = key.into_slice() else {
324 return;
325 };
326
327 env_remove(key);
328 }
329}
330
331#[cfg_attr(
332 not(any(feature = "std", feature = "rustc-dep-of-std")),
333 unsafe(no_mangle)
334)]
335pub extern "C" fn sysenv_clear() {
337 env_clear();
338}
339
340pub struct ArgsIter {
342 args: &'static [NonNullSlice<u8>],
343 index: usize,
344}
345
346impl ArgsIter {
347 pub fn get() -> Self {
348 let args = unsafe { RAW_ARGS.as_slice() };
349 Self { args, index: 0 }
350 }
351
352 pub fn get_index(&self, index: usize) -> Option<NonNullSlice<u8>> {
353 self.args.get(index).copied()
354 }
355
356 pub fn next(&mut self) -> Option<NonNullSlice<u8>> {
357 if self.index < self.args.len() {
358 let arg = self.args[self.index];
359 self.index += 1;
360 Some(arg)
361 } else {
362 None
363 }
364 }
365 pub fn total_len(&self) -> usize {
367 self.args.len()
368 }
369 pub fn len(&self) -> usize {
371 self.total_len() - self.index
372 }
373}
374
375static META: Lazy<TaskMetadata> =
376 Lazy::new(|| meta_take().expect("failed to take ownership of the task metadata"));
377
378static STDIN: Lazy<usize> = Lazy::new(|| {
381 let stdin: Option<usize> = META.stdin.into();
382 if let Some(stdin) = stdin {
383 stdin
384 } else {
385 syscalls::open("dev:/tty").expect("failed to fall back to `dev:/tty` for stdin")
386 }
387});
388
389static STDOUT: Lazy<usize> = Lazy::new(|| {
390 let stdout: Option<usize> = META.stdout.into();
391 if let Some(stdout) = stdout {
392 stdout
393 } else {
394 syscalls::open("dev:/tty").expect("failed to fall back to `dev:/tty` for stdout")
395 }
396});
397
398use syscalls::types::SyscallResult;
399static STDERR: Lazy<usize> = Lazy::new(|| {
400 let stderr: Option<usize> = META.stderr.into();
401 if let Some(stderr) = stderr {
402 stderr
403 } else {
404 syscalls::open("dev:/tty").expect("failed to fall back to `dev:/tty` for stderr")
405 }
406});
407
408define_syscall!(SyscallNum::SysMetaTake => {
409 sysmeta_take(dest_task: *mut TaskMetadata)
413});
414
415#[inline]
416pub fn meta_take() -> Result<TaskMetadata, ErrorStatus> {
417 let mut dest_meta: TaskMetadata = unsafe { core::mem::zeroed() };
418 err_from_u16!(sysmeta_take(&raw mut dest_meta), dest_meta)
419}
420
421#[cfg_attr(
423 not(any(feature = "std", feature = "rustc-dep-of-std")),
424 unsafe(no_mangle)
425)]
426#[inline(always)]
427pub extern "C" fn sysmeta_stdout() -> usize {
428 **STDOUT
429}
430
431#[cfg_attr(
433 not(any(feature = "std", feature = "rustc-dep-of-std")),
434 unsafe(no_mangle)
435)]
436#[inline(always)]
437pub extern "C" fn sysmeta_stderr() -> usize {
438 **STDERR
439}
440
441#[cfg_attr(
443 not(any(feature = "std", feature = "rustc-dep-of-std")),
444 unsafe(no_mangle)
445)]
446#[inline(always)]
447pub extern "C" fn sysmeta_stdin() -> usize {
448 **STDIN
449}
450
451fn init_args(args: RawSliceMut<NonNullSlice<u8>>) {
454 unsafe {
455 let slice = args
456 .into_slice_mut()
457 .map(|inner| RawArgs::new(NonNull::new_unchecked(inner as *mut _)));
458 RAW_ARGS.init(slice)
459 }
460}
461
462fn init_env(env: RawSliceMut<NonNullSlice<u8>>) {
463 unsafe {
464 let slice = env
465 .into_slice_mut()
466 .map(|inner| RawArgs::new(NonNull::new_unchecked(inner as *mut _)));
467 RAW_ENV.init(slice)
468 }
469}
470
471#[cfg_attr(
473 not(any(feature = "std", feature = "rustc-dep-of-std")),
474 unsafe(no_mangle)
475)]
476#[inline(always)]
477pub extern "C" fn sysapi_init(
478 args: RawSliceMut<NonNullSlice<u8>>,
479 env: RawSliceMut<NonNullSlice<u8>>,
480) {
481 init_args(args);
482 init_env(env);
483}
484
485#[cfg_attr(
491 not(any(feature = "std", feature = "rustc-dep-of-std")),
492 unsafe(no_mangle)
493)]
494pub unsafe extern "C" fn _c_api_init(
495 args: RawSliceMut<NonNullSlice<u8>>,
496 env: RawSliceMut<NonNullSlice<u8>>,
497 main: extern "C" fn(argc: i32, argv: *const NonNull<u8>) -> i32,
498) -> ! {
499 sysapi_init(args, env);
500
501 fn c_main_args(args: RawSliceMut<NonNullSlice<u8>>) -> (i32, *const NonNull<u8>) {
503 let argv_slice = unsafe { args.into_slice_mut().unwrap_or_default() };
504 if argv_slice.is_empty() {
505 return (0, core::ptr::null());
506 }
507
508 let bytes = args.len() * size_of::<usize>();
509
510 let c_argv_bytes = GLOBAL_SYSTEM_ALLOCATOR.allocate(bytes).unwrap();
511 let c_argv_slice = unsafe {
512 core::slice::from_raw_parts_mut(c_argv_bytes.as_ptr() as *mut NonNull<u8>, args.len())
513 };
514
515 for (i, arg) in argv_slice.iter().enumerate() {
516 c_argv_slice[i] = arg.as_non_null();
517 }
518
519 (args.len() as i32, c_argv_slice.as_ptr())
520 }
521
522 let (argc, argv) = c_main_args(args);
523 let result = main(argc, argv);
524 syscalls::exit(result as usize)
525}