syd/
lib.rs

1//
2// libsyd: Rust-based C library for syd interaction via /dev/syd
3// lib/src/lib.rs: syd API C Library
4//
5// Copyright (c) 2023, 2024, 2025 Ali Polatel <alip@chesswob.org>
6//
7// SPDX-License-Identifier: LGPL-3.0
8
9//! # libsyd - syd API Rust Library
10//!
11//! `libsyd` is a C library written in Rust that implements the syd
12//! stat API, providing an interface to the `/dev/syd` of syd. It
13//! allows for runtime configuration and interaction with the syd
14//! sandboxing environment.
15//!
16//! ## Overview
17//! The library is designed to interact with the syd sandboxing
18//! environment, offering functionalities to check and modify the state
19//! of the sandbox lock, and perform system calls to `/dev/syd`.
20//!
21//! For more detailed information and usage instructions, refer to the syd
22//! manual, available at [syd Manual](http://man.exherbolinux.org/syd.2.html).
23//!
24//! ## Author
25//! Ali Polatel <alip@chesswob.org>
26
27// We like safe, clean and simple code with documentation.
28#![deny(missing_docs)]
29#![deny(clippy::allow_attributes_without_reason)]
30#![deny(clippy::arithmetic_side_effects)]
31#![deny(clippy::as_ptr_cast_mut)]
32#![deny(clippy::as_underscore)]
33#![deny(clippy::assertions_on_result_states)]
34#![deny(clippy::borrow_as_ptr)]
35#![deny(clippy::branches_sharing_code)]
36#![deny(clippy::case_sensitive_file_extension_comparisons)]
37#![deny(clippy::cast_lossless)]
38#![deny(clippy::cast_possible_truncation)]
39#![deny(clippy::cast_possible_wrap)]
40#![deny(clippy::cast_precision_loss)]
41#![deny(clippy::cast_ptr_alignment)]
42#![deny(clippy::cast_sign_loss)]
43#![deny(clippy::checked_conversions)]
44#![deny(clippy::clear_with_drain)]
45#![deny(clippy::clone_on_ref_ptr)]
46#![deny(clippy::cloned_instead_of_copied)]
47#![deny(clippy::cognitive_complexity)]
48#![deny(clippy::collection_is_never_read)]
49#![deny(clippy::copy_iterator)]
50#![deny(clippy::create_dir)]
51#![deny(clippy::dbg_macro)]
52#![deny(clippy::debug_assert_with_mut_call)]
53#![deny(clippy::decimal_literal_representation)]
54#![deny(clippy::default_trait_access)]
55#![deny(clippy::default_union_representation)]
56#![deny(clippy::derive_partial_eq_without_eq)]
57#![deny(clippy::doc_link_with_quotes)]
58#![deny(clippy::doc_markdown)]
59#![deny(clippy::explicit_into_iter_loop)]
60#![deny(clippy::explicit_iter_loop)]
61#![deny(clippy::fallible_impl_from)]
62#![deny(clippy::missing_safety_doc)]
63#![deny(clippy::undocumented_unsafe_blocks)]
64
65use std::{
66    ffi::{CStr, OsStr, OsString},
67    fmt,
68    fs::{symlink_metadata, Metadata},
69    os::{
70        fd::RawFd,
71        raw::{c_char, c_int},
72        unix::{
73            ffi::OsStrExt,
74            fs::{FileTypeExt, MetadataExt},
75        },
76    },
77    path::{Path, PathBuf},
78};
79
80/// `lock_state_t_t` type represents possible states for the sandbox lock.
81#[allow(non_camel_case_types)]
82pub type lock_state_t = u8;
83
84/// The sandbox lock is off, allowing all sandbox commands.
85pub const LOCK_OFF: lock_state_t = 0;
86/// The sandbox lock is set to on for all processes except the initial
87/// process (syd exec child).
88pub const LOCK_EXEC: lock_state_t = 1;
89/// The sandbox lock is on, disallowing all sandbox commands.
90pub const LOCK_ON: lock_state_t = 2;
91
92// An enumeration of the possible states for the sandbox lock.
93#[repr(u8)]
94#[derive(Copy, Clone, Debug)]
95enum LockState {
96    // The sandbox lock is off, allowing all sandbox commands.
97    Off = LOCK_OFF,
98    // The sandbox lock is set to on for all processes except the initial
99    // process (syd exec child).
100    Exec = LOCK_EXEC,
101    // The sandbox lock is on, disallowing all sandbox commands.
102    On = LOCK_ON,
103}
104
105impl TryFrom<lock_state_t> for LockState {
106    type Error = ();
107
108    fn try_from(value: lock_state_t) -> Result<Self, Self::Error> {
109        match value {
110            LOCK_OFF => Ok(LockState::Off),
111            LOCK_EXEC => Ok(LockState::Exec),
112            LOCK_ON => Ok(LockState::On),
113            _ => Err(()),
114        }
115    }
116}
117
118impl fmt::Display for LockState {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        let state_str = match self {
121            LockState::Off => "off",
122            LockState::Exec => "exec",
123            LockState::On => "on",
124        };
125        write!(f, "{state_str}")
126    }
127}
128
129/// `action_t` type represents possible sandboxing action values.
130#[allow(non_camel_case_types)]
131pub type action_t = u8;
132
133/// Allow system call.
134pub const ACTION_ALLOW: action_t = 0;
135/// Allow system call and warn.
136pub const ACTION_WARN: action_t = 1;
137/// Deny system call silently.
138pub const ACTION_FILTER: action_t = 2;
139/// Deny system call and warn.
140pub const ACTION_DENY: action_t = 3;
141/// Deny system call, warn and panic the current Syd thread.
142pub const ACTION_PANIC: action_t = 4;
143/// Deny system call, warn and stop the offending process.
144pub const ACTION_STOP: action_t = 5;
145/// Deny system call, warn and abort the offending process.
146pub const ACTION_ABORT: action_t = 6;
147/// Deny system call, warn and kill the offending process.
148pub const ACTION_KILL: action_t = 7;
149/// Warn, and exit Syd immediately with deny errno as exit value.
150pub const ACTION_EXIT: action_t = 8;
151
152// An enumeration of the possible actions for sandboxing.
153#[repr(u8)]
154#[derive(Copy, Clone, Debug)]
155enum Action {
156    // Allow system call.
157    Allow = ACTION_ALLOW,
158    // Allow system call and warn.
159    Warn = ACTION_WARN,
160    // Deny system call silently.
161    Filter = ACTION_FILTER,
162    // Deny system call and warn.
163    Deny = ACTION_DENY,
164    // Deny system call, warn and panic the current Syd thread.
165    Panic = ACTION_PANIC,
166    // Deny system call, warn and stop the offending process.
167    Stop = ACTION_STOP,
168    // Deny system call, warn and abort offending process.
169    Abort = ACTION_ABORT,
170    // Deny system call, warn and kill the offending process.
171    Kill = ACTION_KILL,
172    // Warn, and exit Syd immediately with deny errno as exit value.
173    Exit = ACTION_EXIT,
174}
175
176impl TryFrom<action_t> for Action {
177    type Error = ();
178
179    fn try_from(value: action_t) -> Result<Self, Self::Error> {
180        match value {
181            ACTION_ALLOW => Ok(Action::Allow),
182            ACTION_WARN => Ok(Action::Warn),
183            ACTION_FILTER => Ok(Action::Filter),
184            ACTION_DENY => Ok(Action::Deny),
185            ACTION_PANIC => Ok(Action::Panic),
186            ACTION_STOP => Ok(Action::Stop),
187            ACTION_ABORT => Ok(Action::Abort),
188            ACTION_KILL => Ok(Action::Kill),
189            ACTION_EXIT => Ok(Action::Exit),
190            _ => Err(()),
191        }
192    }
193}
194
195impl fmt::Display for Action {
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        let action_str = match self {
198            Action::Allow => "allow",
199            Action::Warn => "warn",
200            Action::Filter => "filter",
201            Action::Deny => "deny",
202            Action::Panic => "panic",
203            Action::Stop => "stop",
204            Action::Abort => "abort",
205            Action::Kill => "kill",
206            Action::Exit => "exit",
207        };
208        write!(f, "{action_str}")
209    }
210}
211
212const EFAULT: i32 = 14;
213const EINVAL: i32 = 22;
214
215#[inline(always)]
216fn check_stat(stat: &Metadata) -> bool {
217    if !stat.file_type().is_char_device() {
218        return false;
219    }
220
221    let rdev = stat.rdev();
222
223    let major = (rdev >> 8) & 0xff;
224    let minor = rdev & 0xff;
225
226    // dev/null
227    major == 1 && minor == 3
228}
229
230fn stat<P: AsRef<Path>>(path: P) -> c_int {
231    match symlink_metadata(path) {
232        Ok(stat) if check_stat(&stat) => 0,
233        Ok(_) => -EINVAL,
234        Err(error) => match error.raw_os_error() {
235            Some(e) => e.checked_neg().unwrap_or(-EINVAL),
236            None => -EINVAL,
237        },
238    }
239}
240
241fn esyd<P: AsRef<Path>>(rule: P, elem: *const c_char, op: u8) -> c_int {
242    if !matches!(op, b'+' | b'-' | b'^' | b':') {
243        return -EINVAL;
244    }
245
246    if elem.is_null() {
247        return -EFAULT;
248    }
249
250    // SAFETY: Trust that `elem` is a null-terminated string.
251    let elem = unsafe { CStr::from_ptr(elem) };
252    let elem = OsStr::from_bytes(elem.to_bytes());
253
254    // Manually concatenate the path segments
255    let mut path = OsString::from("/dev/syd/");
256    path.push(rule.as_ref());
257    path.push(OsStr::from_bytes(&[op]));
258    path.push(elem);
259
260    // Convert the OsString to PathBuf
261    let path = PathBuf::from(path);
262
263    stat(path)
264}
265
266/// Performs a syd API check
267///
268/// The caller is advised to perform this check before
269/// calling any other syd API calls.
270///
271/// Returns API number on success, negated errno on failure.
272#[no_mangle]
273pub extern "C" fn syd_api() -> c_int {
274    match stat("/dev/syd/3") {
275        0 => 3,
276        n => n,
277    }
278}
279
280/// Performs an lstat system call on the file "/dev/syd".
281///
282/// Returns 0 on success, negated errno on failure.
283#[no_mangle]
284pub extern "C" fn syd_check() -> c_int {
285    stat("/dev/syd")
286}
287
288/// Causes syd to exit immediately with code 127
289///
290/// Returns 0 on success, negated errno on failure.
291#[no_mangle]
292pub extern "C" fn syd_panic() -> c_int {
293    stat("/dev/syd/panic")
294}
295
296/// Causes syd to reset sandboxing to the default state.
297/// Allowlists, denylists and filters are going to be cleared.
298///
299/// Returns 0 on success, negated errno on failure.
300#[no_mangle]
301pub extern "C" fn syd_reset() -> c_int {
302    stat("/dev/syd/reset")
303}
304
305/// Causes syd to read configuration from the given file descriptor.
306///
307/// Returns 0 on success, negated errno on failure.
308#[no_mangle]
309pub extern "C" fn syd_load(fd: c_int) -> c_int {
310    let fd = match RawFd::try_from(fd) {
311        Ok(fd) if fd < 0 => return -EINVAL,
312        Ok(fd) => fd,
313        Err(_) => return -EINVAL,
314    };
315    stat(&format!("/dev/syd/load/{fd}"))
316}
317
318/// Sets the state of the sandbox lock.
319///
320/// state: The desired state of the sandbox lock.
321///
322/// Returns 0 on success, negated errno on failure.
323#[no_mangle]
324pub extern "C" fn syd_lock(state: lock_state_t) -> c_int {
325    // Convert lock_state_t enum to corresponding lock state string.
326    let state = match LockState::try_from(state) {
327        Ok(state) => state,
328        Err(_) => return -EINVAL,
329    };
330
331    stat(&format!("/dev/syd/lock:{state}"))
332}
333
334/// Checks if stat sandboxing is enabled.
335///
336/// Returns true if stat sandboxing is enabled, false otherwise.
337#[no_mangle]
338pub extern "C" fn syd_enabled_stat() -> bool {
339    stat("/dev/syd/sandbox/stat?") == 0
340}
341
342/// Enable stat sandboxing.
343///
344/// Returns 0 on success, negated errno on failure.
345#[no_mangle]
346pub extern "C" fn syd_enable_stat() -> c_int {
347    stat("/dev/syd/sandbox/stat:on")
348}
349
350/// Disable stat sandboxing.
351///
352/// Returns 0 on success, negated errno on failure.
353#[no_mangle]
354pub extern "C" fn syd_disable_stat() -> c_int {
355    stat("/dev/syd/sandbox/stat:off")
356}
357
358/// Checks if read sandboxing is enabled.
359///
360/// Returns true if read sandboxing is enabled, false otherwise.
361#[no_mangle]
362pub extern "C" fn syd_enabled_read() -> bool {
363    stat("/dev/syd/sandbox/read?") == 0
364}
365
366/// Enable read sandboxing.
367///
368/// Returns 0 on success, negated errno on failure.
369#[no_mangle]
370pub extern "C" fn syd_enable_read() -> c_int {
371    stat("/dev/syd/sandbox/read:on")
372}
373
374/// Disable read sandboxing.
375///
376/// Returns 0 on success, negated errno on failure.
377#[no_mangle]
378pub extern "C" fn syd_disable_read() -> c_int {
379    stat("/dev/syd/sandbox/read:off")
380}
381
382/// Checks if write sandboxing is enabled.
383///
384/// Returns true if write sandboxing is enabled, false otherwise.
385#[no_mangle]
386pub extern "C" fn syd_enabled_write() -> bool {
387    stat("/dev/syd/sandbox/write?") == 0
388}
389
390/// Enable write sandboxing.
391///
392/// Returns 0 on success, negated errno on failure.
393#[no_mangle]
394pub extern "C" fn syd_enable_write() -> c_int {
395    stat("/dev/syd/sandbox/write:on")
396}
397
398/// Disable write sandboxing.
399///
400/// Returns 0 on success, negated errno on failure.
401#[no_mangle]
402pub extern "C" fn syd_disable_write() -> c_int {
403    stat("/dev/syd/sandbox/write:off")
404}
405
406/// Checks if exec sandboxing is enabled.
407///
408/// Returns true if exec sandboxing is enabled, false otherwise.
409#[no_mangle]
410pub extern "C" fn syd_enabled_exec() -> bool {
411    stat("/dev/syd/sandbox/exec?") == 0
412}
413
414/// Enable exec sandboxing.
415///
416/// Returns 0 on success, negated errno on failure.
417#[no_mangle]
418pub extern "C" fn syd_enable_exec() -> c_int {
419    stat("/dev/syd/sandbox/exec:on")
420}
421
422/// Disable exec sandboxing.
423///
424/// Returns 0 on success, negated errno on failure.
425#[no_mangle]
426pub extern "C" fn syd_disable_exec() -> c_int {
427    stat("/dev/syd/sandbox/exec:off")
428}
429
430/// Checks if ioctl sandboxing is enabled.
431///
432/// Returns true if ioctl sandboxing is enabled, false otherwise.
433#[no_mangle]
434pub extern "C" fn syd_enabled_ioctl() -> bool {
435    stat("/dev/syd/sandbox/ioctl?") == 0
436}
437
438/// Enable ioctl sandboxing.
439///
440/// Returns 0 on success, negated errno on failure.
441#[no_mangle]
442pub extern "C" fn syd_enable_ioctl() -> c_int {
443    stat("/dev/syd/sandbox/ioctl:on")
444}
445
446/// Disable ioctl sandboxing.
447///
448/// Returns 0 on success, negated errno on failure.
449#[no_mangle]
450pub extern "C" fn syd_disable_ioctl() -> c_int {
451    stat("/dev/syd/sandbox/ioctl:off")
452}
453
454/// Checks if create sandboxing is enabled.
455///
456/// Returns true if create sandboxing is enabled, false otherwise.
457#[no_mangle]
458pub extern "C" fn syd_enabled_create() -> bool {
459    stat("/dev/syd/sandbox/create?") == 0
460}
461
462/// Enable create sandboxing.
463///
464/// Returns 0 on success, negated errno on failure.
465#[no_mangle]
466pub extern "C" fn syd_enable_create() -> c_int {
467    stat("/dev/syd/sandbox/create:on")
468}
469
470/// Disable create sandboxing.
471///
472/// Returns 0 on success, negated errno on failure.
473#[no_mangle]
474pub extern "C" fn syd_disable_create() -> c_int {
475    stat("/dev/syd/sandbox/create:off")
476}
477
478/// Checks if delete sandboxing is enabled.
479///
480/// Returns true if delete sandboxing is enabled, false otherwise.
481#[no_mangle]
482pub extern "C" fn syd_enabled_delete() -> bool {
483    stat("/dev/syd/sandbox/delete?") == 0
484}
485
486/// Enable delete sandboxing.
487///
488/// Returns 0 on success, negated errno on failure.
489#[no_mangle]
490pub extern "C" fn syd_enable_delete() -> c_int {
491    stat("/dev/syd/sandbox/delete:on")
492}
493
494/// Disable delete sandboxing.
495///
496/// Returns 0 on success, negated errno on failure.
497#[no_mangle]
498pub extern "C" fn syd_disable_delete() -> c_int {
499    stat("/dev/syd/sandbox/delete:off")
500}
501
502/// Checks if rename sandboxing is enabled.
503///
504/// Returns true if rename sandboxing is enabled, false otherwise.
505#[no_mangle]
506pub extern "C" fn syd_enabled_rename() -> bool {
507    stat("/dev/syd/sandbox/rename?") == 0
508}
509
510/// Enable rename sandboxing.
511///
512/// Returns 0 on success, negated errno on failure.
513#[no_mangle]
514pub extern "C" fn syd_enable_rename() -> c_int {
515    stat("/dev/syd/sandbox/rename:on")
516}
517
518/// Disable rename sandboxing.
519///
520/// Returns 0 on success, negated errno on failure.
521#[no_mangle]
522pub extern "C" fn syd_disable_rename() -> c_int {
523    stat("/dev/syd/sandbox/rename:off")
524}
525
526/// Checks if symlink sandboxing is enabled.
527///
528/// Returns true if symlink sandboxing is enabled, false otherwise.
529#[no_mangle]
530pub extern "C" fn syd_enabled_symlink() -> bool {
531    stat("/dev/syd/sandbox/symlink?") == 0
532}
533
534/// Enable symlink sandboxing.
535///
536/// Returns 0 on success, negated errno on failure.
537#[no_mangle]
538pub extern "C" fn syd_enable_symlink() -> c_int {
539    stat("/dev/syd/sandbox/symlink:on")
540}
541
542/// Disable symlink sandboxing.
543///
544/// Returns 0 on success, negated errno on failure.
545#[no_mangle]
546pub extern "C" fn syd_disable_symlink() -> c_int {
547    stat("/dev/syd/sandbox/symlink:off")
548}
549
550/// Checks if truncate sandboxing is enabled.
551///
552/// Returns true if truncate sandboxing is enabled, false otherwise.
553#[no_mangle]
554pub extern "C" fn syd_enabled_truncate() -> bool {
555    stat("/dev/syd/sandbox/truncate?") == 0
556}
557
558/// Enable truncate sandboxing.
559///
560/// Returns 0 on success, negated errno on failure.
561#[no_mangle]
562pub extern "C" fn syd_enable_truncate() -> c_int {
563    stat("/dev/syd/sandbox/truncate:on")
564}
565
566/// Disable truncate sandboxing.
567///
568/// Returns 0 on success, negated errno on failure.
569#[no_mangle]
570pub extern "C" fn syd_disable_truncate() -> c_int {
571    stat("/dev/syd/sandbox/truncate:off")
572}
573
574/// Checks if chdir sandboxing is enabled.
575///
576/// Returns true if chdir sandboxing is enabled, false otherwise.
577#[no_mangle]
578pub extern "C" fn syd_enabled_chdir() -> bool {
579    stat("/dev/syd/sandbox/chdir?") == 0
580}
581
582/// Enable chdir sandboxing.
583///
584/// Returns 0 on success, negated errno on failure.
585#[no_mangle]
586pub extern "C" fn syd_enable_chdir() -> c_int {
587    stat("/dev/syd/sandbox/chdir:on")
588}
589
590/// Disable chdir sandboxing.
591///
592/// Returns 0 on success, negated errno on failure.
593#[no_mangle]
594pub extern "C" fn syd_disable_chdir() -> c_int {
595    stat("/dev/syd/sandbox/chdir:off")
596}
597
598/// Checks if readdir sandboxing is enabled.
599///
600/// Returns true if readdir sandboxing is enabled, false otherwise.
601#[no_mangle]
602pub extern "C" fn syd_enabled_readdir() -> bool {
603    stat("/dev/syd/sandbox/readdir?") == 0
604}
605
606/// Enable readdir sandboxing.
607///
608/// Returns 0 on success, negated errno on failure.
609#[no_mangle]
610pub extern "C" fn syd_enable_readdir() -> c_int {
611    stat("/dev/syd/sandbox/readdir:on")
612}
613
614/// Disable readdir sandboxing.
615///
616/// Returns 0 on success, negated errno on failure.
617#[no_mangle]
618pub extern "C" fn syd_disable_readdir() -> c_int {
619    stat("/dev/syd/sandbox/readdir:off")
620}
621
622/// Checks if mkdir sandboxing is enabled.
623///
624/// Returns true if mkdir sandboxing is enabled, false otherwise.
625#[no_mangle]
626pub extern "C" fn syd_enabled_mkdir() -> bool {
627    stat("/dev/syd/sandbox/mkdir?") == 0
628}
629
630/// Enable mkdir sandboxing.
631///
632/// Returns 0 on success, negated errno on failure.
633#[no_mangle]
634pub extern "C" fn syd_enable_mkdir() -> c_int {
635    stat("/dev/syd/sandbox/mkdir:on")
636}
637
638/// Disable mkdir sandboxing.
639///
640/// Returns 0 on success, negated errno on failure.
641#[no_mangle]
642pub extern "C" fn syd_disable_mkdir() -> c_int {
643    stat("/dev/syd/sandbox/mkdir:off")
644}
645
646/// Checks if rmdir sandboxing is enabled.
647///
648/// Returns true if rmdir sandboxing is enabled, false otherwise.
649#[no_mangle]
650pub extern "C" fn syd_enabled_rmdir() -> bool {
651    stat("/dev/syd/sandbox/rmdir?") == 0
652}
653
654/// Enable rmdir sandboxing.
655///
656/// Returns 0 on success, negated errno on failure.
657#[no_mangle]
658pub extern "C" fn syd_enable_rmdir() -> c_int {
659    stat("/dev/syd/sandbox/rmdir:on")
660}
661
662/// Disable rmdir sandboxing.
663///
664/// Returns 0 on success, negated errno on failure.
665#[no_mangle]
666pub extern "C" fn syd_disable_rmdir() -> c_int {
667    stat("/dev/syd/sandbox/rmdir:off")
668}
669
670/// Checks if chown sandboxing is enabled.
671///
672/// Returns true if chown sandboxing is enabled, false otherwise.
673#[no_mangle]
674pub extern "C" fn syd_enabled_chown() -> bool {
675    stat("/dev/syd/sandbox/chown?") == 0
676}
677
678/// Enable chown sandboxing.
679///
680/// Returns 0 on success, negated errno on failure.
681#[no_mangle]
682pub extern "C" fn syd_enable_chown() -> c_int {
683    stat("/dev/syd/sandbox/chown:on")
684}
685
686/// Disable chown sandboxing.
687///
688/// Returns 0 on success, negated errno on failure.
689#[no_mangle]
690pub extern "C" fn syd_disable_chown() -> c_int {
691    stat("/dev/syd/sandbox/chown:off")
692}
693
694/// Checks if chgrp sandboxing is enabled.
695///
696/// Returns true if chgrp sandboxing is enabled, false otherwise.
697#[no_mangle]
698pub extern "C" fn syd_enabled_chgrp() -> bool {
699    stat("/dev/syd/sandbox/chgrp?") == 0
700}
701
702/// Enable chgrp sandboxing.
703///
704/// Returns 0 on success, negated errno on failure.
705#[no_mangle]
706pub extern "C" fn syd_enable_chgrp() -> c_int {
707    stat("/dev/syd/sandbox/chgrp:on")
708}
709
710/// Disable chgrp sandboxing.
711///
712/// Returns 0 on success, negated errno on failure.
713#[no_mangle]
714pub extern "C" fn syd_disable_chgrp() -> c_int {
715    stat("/dev/syd/sandbox/chgrp:off")
716}
717
718/// Checks if chmod sandboxing is enabled.
719///
720/// Returns true if chmod sandboxing is enabled, false otherwise.
721#[no_mangle]
722pub extern "C" fn syd_enabled_chmod() -> bool {
723    stat("/dev/syd/sandbox/chmod?") == 0
724}
725
726/// Enable chmod sandboxing.
727///
728/// Returns 0 on success, negated errno on failure.
729#[no_mangle]
730pub extern "C" fn syd_enable_chmod() -> c_int {
731    stat("/dev/syd/sandbox/chmod:on")
732}
733
734/// Disable chmod sandboxing.
735///
736/// Returns 0 on success, negated errno on failure.
737#[no_mangle]
738pub extern "C" fn syd_disable_chmod() -> c_int {
739    stat("/dev/syd/sandbox/chmod:off")
740}
741
742/// Checks if chattr sandboxing is enabled.
743///
744/// Returns true if chattr sandboxing is enabled, false otherwise.
745#[no_mangle]
746pub extern "C" fn syd_enabled_chattr() -> bool {
747    stat("/dev/syd/sandbox/chattr?") == 0
748}
749
750/// Enable chattr sandboxing.
751///
752/// Returns 0 on success, negated errno on failure.
753#[no_mangle]
754pub extern "C" fn syd_enable_chattr() -> c_int {
755    stat("/dev/syd/sandbox/chattr:on")
756}
757
758/// Disable chattr sandboxing.
759///
760/// Returns 0 on success, negated errno on failure.
761#[no_mangle]
762pub extern "C" fn syd_disable_chattr() -> c_int {
763    stat("/dev/syd/sandbox/chattr:off")
764}
765
766/// Checks if chroot sandboxing is enabled.
767///
768/// Returns true if chroot sandboxing is enabled, false otherwise.
769#[no_mangle]
770pub extern "C" fn syd_enabled_chroot() -> bool {
771    stat("/dev/syd/sandbox/chroot?") == 0
772}
773
774/// Enable chroot sandboxing.
775///
776/// Returns 0 on success, negated errno on failure.
777#[no_mangle]
778pub extern "C" fn syd_enable_chroot() -> c_int {
779    stat("/dev/syd/sandbox/chroot:on")
780}
781
782/// Disable chroot sandboxing.
783///
784/// Returns 0 on success, negated errno on failure.
785#[no_mangle]
786pub extern "C" fn syd_disable_chroot() -> c_int {
787    stat("/dev/syd/sandbox/chroot:off")
788}
789
790/// Checks if utime sandboxing is enabled.
791///
792/// Returns true if utime sandboxing is enabled, false otherwise.
793#[no_mangle]
794pub extern "C" fn syd_enabled_utime() -> bool {
795    stat("/dev/syd/sandbox/utime?") == 0
796}
797
798/// Enable utime sandboxing.
799///
800/// Returns 0 on success, negated errno on failure.
801#[no_mangle]
802pub extern "C" fn syd_enable_utime() -> c_int {
803    stat("/dev/syd/sandbox/utime:on")
804}
805
806/// Disable utime sandboxing.
807///
808/// Returns 0 on success, negated errno on failure.
809#[no_mangle]
810pub extern "C" fn syd_disable_utime() -> c_int {
811    stat("/dev/syd/sandbox/utime:off")
812}
813
814/// Checks if mkdev sandboxing is enabled.
815///
816/// Returns true if mkdev sandboxing is enabled, false otherwise.
817#[no_mangle]
818pub extern "C" fn syd_enabled_mkdev() -> bool {
819    stat("/dev/syd/sandbox/mkdev?") == 0
820}
821
822/// Enable mkdev sandboxing.
823///
824/// Returns 0 on success, negated errno on failure.
825#[no_mangle]
826pub extern "C" fn syd_enable_mkdev() -> c_int {
827    stat("/dev/syd/sandbox/mkdev:on")
828}
829
830/// Disable mkdev sandboxing.
831///
832/// Returns 0 on success, negated errno on failure.
833#[no_mangle]
834pub extern "C" fn syd_disable_mkdev() -> c_int {
835    stat("/dev/syd/sandbox/mkdev:off")
836}
837
838/// Checks if mkfifo sandboxing is enabled.
839///
840/// Returns true if mkfifo sandboxing is enabled, false otherwise.
841#[no_mangle]
842pub extern "C" fn syd_enabled_mkfifo() -> bool {
843    stat("/dev/syd/sandbox/mkfifo?") == 0
844}
845
846/// Enable mkfifo sandboxing.
847///
848/// Returns 0 on success, negated errno on failure.
849#[no_mangle]
850pub extern "C" fn syd_enable_mkfifo() -> c_int {
851    stat("/dev/syd/sandbox/mkfifo:on")
852}
853
854/// Disable mkfifo sandboxing.
855///
856/// Returns 0 on success, negated errno on failure.
857#[no_mangle]
858pub extern "C" fn syd_disable_mkfifo() -> c_int {
859    stat("/dev/syd/sandbox/mkfifo:off")
860}
861
862/// Checks if mktemp sandboxing is enabled.
863///
864/// Returns true if mktemp sandboxing is enabled, false otherwise.
865#[no_mangle]
866pub extern "C" fn syd_enabled_mktemp() -> bool {
867    stat("/dev/syd/sandbox/mktemp?") == 0
868}
869
870/// Enable mktemp sandboxing.
871///
872/// Returns 0 on success, negated errno on failure.
873#[no_mangle]
874pub extern "C" fn syd_enable_mktemp() -> c_int {
875    stat("/dev/syd/sandbox/mktemp:on")
876}
877
878/// Disable mktemp sandboxing.
879///
880/// Returns 0 on success, negated errno on failure.
881#[no_mangle]
882pub extern "C" fn syd_disable_mktemp() -> c_int {
883    stat("/dev/syd/sandbox/mktemp:off")
884}
885
886/// Checks if net sandboxing is enabled.
887///
888/// Returns true if net sandboxing is enabled, false otherwise.
889#[no_mangle]
890pub extern "C" fn syd_enabled_net() -> bool {
891    stat("/dev/syd/sandbox/net?") == 0
892}
893
894/// Enable net sandboxing.
895///
896/// Returns 0 on success, negated errno on failure.
897#[no_mangle]
898pub extern "C" fn syd_enable_net() -> c_int {
899    stat("/dev/syd/sandbox/net:on")
900}
901
902/// Disable net sandboxing.
903///
904/// Returns 0 on success, negated errno on failure.
905#[no_mangle]
906pub extern "C" fn syd_disable_net() -> c_int {
907    stat("/dev/syd/sandbox/net:off")
908}
909
910/// Checks if memory sandboxing is enabled.
911///
912/// Returns true if memory sandboxing is enabled, false otherwise.
913#[no_mangle]
914pub extern "C" fn syd_enabled_mem() -> bool {
915    stat("/dev/syd/sandbox/mem?") == 0
916}
917
918/// Enable memory sandboxing.
919///
920/// Returns 0 on success, negated errno on failure.
921#[no_mangle]
922pub extern "C" fn syd_enable_mem() -> c_int {
923    stat("/dev/syd/sandbox/mem:on")
924}
925
926/// Disable memory sandboxing.
927///
928/// Returns 0 on success, negated errno on failure.
929#[no_mangle]
930pub extern "C" fn syd_disable_mem() -> c_int {
931    stat("/dev/syd/sandbox/mem:off")
932}
933
934/// Checks if PID sandboxing is enabled.
935///
936/// Returns true if PID sandboxing is enabled, false otherwise.
937#[no_mangle]
938pub extern "C" fn syd_enabled_pid() -> bool {
939    stat("/dev/syd/sandbox/pid?") == 0
940}
941
942/// Enable PID sandboxing.
943///
944/// Returns 0 on success, negated errno on failure.
945#[no_mangle]
946pub extern "C" fn syd_enable_pid() -> c_int {
947    stat("/dev/syd/sandbox/pid:on")
948}
949
950/// Disable PID sandboxing.
951///
952/// Returns 0 on success, negated errno on failure.
953#[no_mangle]
954pub extern "C" fn syd_disable_pid() -> c_int {
955    stat("/dev/syd/sandbox/pid:off")
956}
957
958/// Checks if lock sandboxing is enabled.
959///
960/// Returns true if lock sandboxing is enabled, false otherwise.
961#[no_mangle]
962pub extern "C" fn syd_enabled_lock() -> bool {
963    stat("/dev/syd/sandbox/lock?") == 0
964}
965
966/// Checks if crypt sandboxing is enabled.
967///
968/// Returns true if crypt sandboxing is enabled, false otherwise.
969#[no_mangle]
970pub extern "C" fn syd_enabled_crypt() -> bool {
971    stat("/dev/syd/sandbox/crypt?") == 0
972}
973
974/// Checks if proxy sandboxing is enabled.
975///
976/// Returns true if proxy sandboxing is enabled, false otherwise.
977#[no_mangle]
978pub extern "C" fn syd_enabled_proxy() -> bool {
979    stat("/dev/syd/sandbox/proxy?") == 0
980}
981
982/// Checks if force sandboxing is enabled.
983///
984/// Returns true if force sandboxing is enabled, false otherwise.
985#[no_mangle]
986pub extern "C" fn syd_enabled_force() -> bool {
987    stat("/dev/syd/sandbox/force?") == 0
988}
989
990/// Enable force sandboxing.
991///
992/// Returns 0 on success, negated errno on failure.
993#[no_mangle]
994pub extern "C" fn syd_enable_force() -> c_int {
995    stat("/dev/syd/sandbox/force:on")
996}
997
998/// Disable force sandboxing.
999///
1000/// Returns 0 on success, negated errno on failure.
1001#[no_mangle]
1002pub extern "C" fn syd_disable_force() -> c_int {
1003    stat("/dev/syd/sandbox/force:off")
1004}
1005
1006/// Checks if TPE sandboxing is enabled.
1007///
1008/// Returns true if TPE sandboxing is enabled, false otherwise.
1009#[no_mangle]
1010pub extern "C" fn syd_enabled_tpe() -> bool {
1011    stat("/dev/syd/sandbox/tpe?") == 0
1012}
1013
1014/// Enable TPE sandboxing.
1015///
1016/// Returns 0 on success, negated errno on failure.
1017#[no_mangle]
1018pub extern "C" fn syd_enable_tpe() -> c_int {
1019    stat("/dev/syd/sandbox/tpe:on")
1020}
1021
1022/// Disable TPE sandboxing.
1023///
1024/// Returns 0 on success, negated errno on failure.
1025#[no_mangle]
1026pub extern "C" fn syd_disable_tpe() -> c_int {
1027    stat("/dev/syd/sandbox/tpe:off")
1028}
1029
1030/// Set the default action for Stat Sandboxing.
1031#[no_mangle]
1032pub extern "C" fn syd_default_stat(action: action_t) -> c_int {
1033    // Convert action_t enum to corresponding action string.
1034    let action = match Action::try_from(action) {
1035        Ok(action) => action,
1036        Err(_) => return -EINVAL,
1037    };
1038    stat(&format!("/dev/syd/default/stat:{action}"))
1039}
1040
1041/// Set the default action for Read Sandboxing.
1042#[no_mangle]
1043pub extern "C" fn syd_default_read(action: action_t) -> c_int {
1044    // Convert action_t enum to corresponding action string.
1045    let action = match Action::try_from(action) {
1046        Ok(action) => action,
1047        Err(_) => return -EINVAL,
1048    };
1049    stat(&format!("/dev/syd/default/read:{action}"))
1050}
1051
1052/// Set the default action for Write Sandboxing.
1053#[no_mangle]
1054pub extern "C" fn syd_default_write(action: action_t) -> c_int {
1055    // Convert action_t enum to corresponding action string.
1056    let action = match Action::try_from(action) {
1057        Ok(action) => action,
1058        Err(_) => return -EINVAL,
1059    };
1060    stat(&format!("/dev/syd/default/write:{action}"))
1061}
1062
1063/// Set the default action for Exec Sandboxing.
1064#[no_mangle]
1065pub extern "C" fn syd_default_exec(action: action_t) -> c_int {
1066    // Convert action_t enum to corresponding action string.
1067    let action = match Action::try_from(action) {
1068        Ok(action) => action,
1069        Err(_) => return -EINVAL,
1070    };
1071    stat(&format!("/dev/syd/default/exec:{action}"))
1072}
1073
1074/// Set the default action for Ioctl Sandboxing.
1075#[no_mangle]
1076pub extern "C" fn syd_default_ioctl(action: action_t) -> c_int {
1077    // Convert action_t enum to corresponding action string.
1078    let action = match Action::try_from(action) {
1079        Ok(action) => action,
1080        Err(_) => return -EINVAL,
1081    };
1082    stat(&format!("/dev/syd/default/ioctl:{action}"))
1083}
1084
1085/// Set the default action for Create Sandboxing.
1086#[no_mangle]
1087pub extern "C" fn syd_default_create(action: action_t) -> c_int {
1088    // Convert action_t enum to corresponding action string.
1089    let action = match Action::try_from(action) {
1090        Ok(action) => action,
1091        Err(_) => return -EINVAL,
1092    };
1093    stat(&format!("/dev/syd/default/create:{action}"))
1094}
1095
1096/// Set the default action for Delete Sandboxing.
1097#[no_mangle]
1098pub extern "C" fn syd_default_delete(action: action_t) -> c_int {
1099    // Convert action_t enum to corresponding action string.
1100    let action = match Action::try_from(action) {
1101        Ok(action) => action,
1102        Err(_) => return -EINVAL,
1103    };
1104    stat(&format!("/dev/syd/default/delete:{action}"))
1105}
1106
1107/// Set the default action for Rename Sandboxing.
1108#[no_mangle]
1109pub extern "C" fn syd_default_rename(action: action_t) -> c_int {
1110    // Convert action_t enum to corresponding action string.
1111    let action = match Action::try_from(action) {
1112        Ok(action) => action,
1113        Err(_) => return -EINVAL,
1114    };
1115    stat(&format!("/dev/syd/default/rename:{action}"))
1116}
1117
1118/// Set the default action for Symlink Sandboxing.
1119#[no_mangle]
1120pub extern "C" fn syd_default_symlink(action: action_t) -> c_int {
1121    // Convert action_t enum to corresponding action string.
1122    let action = match Action::try_from(action) {
1123        Ok(action) => action,
1124        Err(_) => return -EINVAL,
1125    };
1126    stat(&format!("/dev/syd/default/symlink:{action}"))
1127}
1128
1129/// Set the default action for Truncate Sandboxing.
1130#[no_mangle]
1131pub extern "C" fn syd_default_truncate(action: action_t) -> c_int {
1132    // Convert action_t enum to corresponding action string.
1133    let action = match Action::try_from(action) {
1134        Ok(action) => action,
1135        Err(_) => return -EINVAL,
1136    };
1137    stat(&format!("/dev/syd/default/truncate:{action}"))
1138}
1139
1140/// Set the default action for Chdir Sandboxing.
1141#[no_mangle]
1142pub extern "C" fn syd_default_chdir(action: action_t) -> c_int {
1143    // Convert action_t enum to corresponding action string.
1144    let action = match Action::try_from(action) {
1145        Ok(action) => action,
1146        Err(_) => return -EINVAL,
1147    };
1148    stat(&format!("/dev/syd/default/chdir:{action}"))
1149}
1150
1151/// Set the default action for Readdir Sandboxing.
1152#[no_mangle]
1153pub extern "C" fn syd_default_readdir(action: action_t) -> c_int {
1154    // Convert action_t enum to corresponding action string.
1155    let action = match Action::try_from(action) {
1156        Ok(action) => action,
1157        Err(_) => return -EINVAL,
1158    };
1159    stat(&format!("/dev/syd/default/readdir:{action}"))
1160}
1161
1162/// Set the default action for Mkdir Sandboxing.
1163#[no_mangle]
1164pub extern "C" fn syd_default_mkdir(action: action_t) -> c_int {
1165    // Convert action_t enum to corresponding action string.
1166    let action = match Action::try_from(action) {
1167        Ok(action) => action,
1168        Err(_) => return -EINVAL,
1169    };
1170    stat(&format!("/dev/syd/default/mkdir:{action}"))
1171}
1172
1173/// Set the default action for Rmdir Sandboxing.
1174#[no_mangle]
1175pub extern "C" fn syd_default_rmdir(action: action_t) -> c_int {
1176    // Convert action_t enum to corresponding action string.
1177    let action = match Action::try_from(action) {
1178        Ok(action) => action,
1179        Err(_) => return -EINVAL,
1180    };
1181    stat(&format!("/dev/syd/default/rmdir:{action}"))
1182}
1183
1184/// Set the default action for Chown Sandboxing.
1185#[no_mangle]
1186pub extern "C" fn syd_default_chown(action: action_t) -> c_int {
1187    // Convert action_t enum to corresponding action string.
1188    let action = match Action::try_from(action) {
1189        Ok(action) => action,
1190        Err(_) => return -EINVAL,
1191    };
1192    stat(&format!("/dev/syd/default/chown:{action}"))
1193}
1194
1195/// Set the default action for Chgrp Sandboxing.
1196#[no_mangle]
1197pub extern "C" fn syd_default_chgrp(action: action_t) -> c_int {
1198    // Convert action_t enum to corresponding action string.
1199    let action = match Action::try_from(action) {
1200        Ok(action) => action,
1201        Err(_) => return -EINVAL,
1202    };
1203    stat(&format!("/dev/syd/default/chgrp:{action}"))
1204}
1205
1206/// Set the default action for Chmod Sandboxing.
1207#[no_mangle]
1208pub extern "C" fn syd_default_chmod(action: action_t) -> c_int {
1209    // Convert action_t enum to corresponding action string.
1210    let action = match Action::try_from(action) {
1211        Ok(action) => action,
1212        Err(_) => return -EINVAL,
1213    };
1214    stat(&format!("/dev/syd/default/chmod:{action}"))
1215}
1216
1217/// Set the default action for Chattr Sandboxing.
1218#[no_mangle]
1219pub extern "C" fn syd_default_chattr(action: action_t) -> c_int {
1220    // Convert action_t enum to corresponding action string.
1221    let action = match Action::try_from(action) {
1222        Ok(action) => action,
1223        Err(_) => return -EINVAL,
1224    };
1225    stat(&format!("/dev/syd/default/chattr:{action}"))
1226}
1227
1228/// Set the default action for Chroot Sandboxing.
1229#[no_mangle]
1230pub extern "C" fn syd_default_chroot(action: action_t) -> c_int {
1231    // Convert action_t enum to corresponding action string.
1232    let action = match Action::try_from(action) {
1233        Ok(action) => action,
1234        Err(_) => return -EINVAL,
1235    };
1236    stat(&format!("/dev/syd/default/chroot:{action}"))
1237}
1238
1239/// Set the default action for Utime Sandboxing.
1240#[no_mangle]
1241pub extern "C" fn syd_default_utime(action: action_t) -> c_int {
1242    // Convert action_t enum to corresponding action string.
1243    let action = match Action::try_from(action) {
1244        Ok(action) => action,
1245        Err(_) => return -EINVAL,
1246    };
1247    stat(&format!("/dev/syd/default/utime:{action}"))
1248}
1249
1250/// Set the default action for Mkdev Sandboxing.
1251#[no_mangle]
1252pub extern "C" fn syd_default_mkdev(action: action_t) -> c_int {
1253    // Convert action_t enum to corresponding action string.
1254    let action = match Action::try_from(action) {
1255        Ok(action) => action,
1256        Err(_) => return -EINVAL,
1257    };
1258    stat(&format!("/dev/syd/default/mkdev:{action}"))
1259}
1260
1261/// Set the default action for Mkfifo Sandboxing.
1262#[no_mangle]
1263pub extern "C" fn syd_default_mkfifo(action: action_t) -> c_int {
1264    // Convert action_t enum to corresponding action string.
1265    let action = match Action::try_from(action) {
1266        Ok(action) => action,
1267        Err(_) => return -EINVAL,
1268    };
1269    stat(&format!("/dev/syd/default/mkfifo:{action}"))
1270}
1271
1272/// Set the default action for Mktemp Sandboxing.
1273#[no_mangle]
1274pub extern "C" fn syd_default_mktemp(action: action_t) -> c_int {
1275    // Convert action_t enum to corresponding action string.
1276    let action = match Action::try_from(action) {
1277        Ok(action) => action,
1278        Err(_) => return -EINVAL,
1279    };
1280    stat(&format!("/dev/syd/default/mktemp:{action}"))
1281}
1282
1283/// Set the default action for Network Sandboxing.
1284#[no_mangle]
1285pub extern "C" fn syd_default_net(action: action_t) -> c_int {
1286    // Convert action_t enum to corresponding action string.
1287    let action = match Action::try_from(action) {
1288        Ok(action) => action,
1289        Err(_) => return -EINVAL,
1290    };
1291    stat(&format!("/dev/syd/default/net:{action}"))
1292}
1293
1294/// Set the default action for IP blocklist violations.
1295#[no_mangle]
1296pub extern "C" fn syd_default_block(action: action_t) -> c_int {
1297    // Convert action_t enum to corresponding action string.
1298    let action = match Action::try_from(action) {
1299        Ok(action) => action,
1300        Err(_) => return -EINVAL,
1301    };
1302    stat(&format!("/dev/syd/default/block:{action}"))
1303}
1304
1305/// Set the default action for Memory Sandboxing.
1306#[no_mangle]
1307pub extern "C" fn syd_default_mem(action: action_t) -> c_int {
1308    // Convert action_t enum to corresponding action string.
1309    let action = match Action::try_from(action) {
1310        Ok(action) => action,
1311        Err(_) => return -EINVAL,
1312    };
1313    stat(&format!("/dev/syd/default/mem:{action}"))
1314}
1315
1316/// Set the default action for PID Sandboxing.
1317#[no_mangle]
1318pub extern "C" fn syd_default_pid(action: action_t) -> c_int {
1319    // Convert action_t enum to corresponding action string.
1320    let action = match Action::try_from(action) {
1321        Ok(action) => action,
1322        Err(_) => return -EINVAL,
1323    };
1324    stat(&format!("/dev/syd/default/pid:{action}"))
1325}
1326
1327/// Set the default action for Force Sandboxing.
1328#[no_mangle]
1329pub extern "C" fn syd_default_force(action: action_t) -> c_int {
1330    // Convert action_t enum to corresponding action string.
1331    let action = match Action::try_from(action) {
1332        Ok(action) => action,
1333        Err(_) => return -EINVAL,
1334    };
1335    stat(&format!("/dev/syd/default/force:{action}"))
1336}
1337
1338/// Set the default action for SegvGuard
1339#[no_mangle]
1340pub extern "C" fn syd_default_segvguard(action: action_t) -> c_int {
1341    // Convert action_t enum to corresponding action string.
1342    let action = match Action::try_from(action) {
1343        Ok(action) => action,
1344        Err(_) => return -EINVAL,
1345    };
1346    stat(&format!("/dev/syd/default/segvguard:{action}"))
1347}
1348
1349/// Set the default action for TPE Sandboxing.
1350#[no_mangle]
1351pub extern "C" fn syd_default_tpe(action: action_t) -> c_int {
1352    // Convert action_t enum to corresponding action string.
1353    let action = match Action::try_from(action) {
1354        Ok(action) => action,
1355        Err(_) => return -EINVAL,
1356    };
1357    stat(&format!("/dev/syd/default/tpe:{action}"))
1358}
1359
1360/// Adds a request to the _ioctl_(2) denylist.
1361#[no_mangle]
1362pub extern "C" fn syd_ioctl_deny(request: u64) -> c_int {
1363    stat(&format!("/dev/syd/ioctl/deny+{request}"))
1364}
1365
1366/// Adds an entry to the Integrity Force map for Force Sandboxing.
1367///
1368/// # Safety
1369///
1370/// This function is marked `unsafe` because it dereferences raw
1371/// pointers, which is inherently unsafe in Rust.
1372///
1373/// The caller must ensure the following conditions are met to safely
1374/// use this function:
1375///
1376/// 1. The `path` pointer must point to a valid, null-terminated C-style
1377///    string.
1378/// 2. The `hash` pointer must point to a valid, null-terminated C-style
1379///    string.
1380#[no_mangle]
1381pub unsafe extern "C" fn syd_force_add(
1382    path: *const c_char,
1383    hash: *const c_char,
1384    action: action_t,
1385) -> c_int {
1386    // Convert action_t enum to corresponding action string.
1387    let action = match Action::try_from(action) {
1388        Ok(action) => action,
1389        Err(_) => return -EINVAL,
1390    };
1391
1392    if path.is_null() || hash.is_null() {
1393        return -EFAULT;
1394    }
1395
1396    // SAFETY: Trust that `path` and `hash` are a null-terminated strings.
1397    let path = unsafe { CStr::from_ptr(path) };
1398    // SAFETY: ditto
1399    let hash = unsafe { CStr::from_ptr(hash) };
1400    let path = match path.to_str() {
1401        Ok(s) => s,
1402        Err(_) => return -EINVAL,
1403    };
1404    let hash = match hash.to_str() {
1405        Ok(s) => s,
1406        Err(_) => return -EINVAL,
1407    };
1408
1409    // Call the stat function with the formatted string.
1410    stat(format!("/dev/syd/force+{path}:{hash}:{action}"))
1411}
1412
1413/// Removes an entry from the Integrity Force map for Force Sandboxing.
1414/// # Safety
1415///
1416/// This function is marked `unsafe` because it dereferences raw
1417/// pointers, which is inherently unsafe in Rust.
1418///
1419/// The caller must ensure the following conditions are met to safely
1420/// use this function:
1421///
1422/// 1. The `path` pointer must point to a valid, null-terminated C-style
1423///    string.
1424#[no_mangle]
1425pub unsafe extern "C" fn syd_force_del(path: *const c_char) -> c_int {
1426    if path.is_null() {
1427        return -EFAULT;
1428    }
1429
1430    // SAFETY: Trust that `path` is a null-terminated string.
1431    let path = unsafe { CStr::from_ptr(path) };
1432    let path = match path.to_str() {
1433        Ok(s) => s,
1434        Err(_) => return -EINVAL,
1435    };
1436
1437    // Call the stat function with the formatted string.
1438    stat(format!("/dev/syd/force-{path}"))
1439}
1440
1441/// Clears the Integrity Force map for Force Sandboxing.
1442#[no_mangle]
1443pub extern "C" fn syd_force_clr() -> c_int {
1444    stat("/dev/syd/force^")
1445}
1446
1447/// Adds to the given actionlist of stat sandboxing.
1448///
1449/// Returns 0 on success, negated errno on failure.
1450#[no_mangle]
1451pub extern "C" fn syd_stat_add(action: action_t, glob: *const c_char) -> c_int {
1452    // Convert action_t enum to corresponding action string.
1453    let action = match Action::try_from(action) {
1454        Ok(action) => action,
1455        Err(_) => return -EINVAL,
1456    };
1457
1458    // Call magic function with add operator.
1459    esyd(&format!("{action}/stat"), glob, b'+')
1460}
1461
1462/// Removes the first instance from the end of the given actionlist of
1463/// stat sandboxing.
1464///
1465/// Returns 0 on success, negated errno on failure.
1466#[no_mangle]
1467pub extern "C" fn syd_stat_del(action: action_t, glob: *const c_char) -> c_int {
1468    // Convert action_t enum to corresponding action string.
1469    let action = match Action::try_from(action) {
1470        Ok(action) => action,
1471        Err(_) => return -EINVAL,
1472    };
1473
1474    // Call magic function with del operator.
1475    esyd(&format!("{action}/stat"), glob, b'-')
1476}
1477
1478/// Removes all matching patterns from the given actionlist of stat sandboxing.
1479///
1480/// Returns 0 on success, negated errno on failure.
1481#[no_mangle]
1482pub extern "C" fn syd_stat_rem(action: action_t, glob: *const c_char) -> c_int {
1483    // Convert action_t enum to corresponding action string.
1484    let action = match Action::try_from(action) {
1485        Ok(action) => action,
1486        Err(_) => return -EINVAL,
1487    };
1488
1489    // Call magic function with rem operator.
1490    esyd(&format!("{action}/stat"), glob, b'^')
1491}
1492
1493/// Adds to the given actionlist of read sandboxing.
1494///
1495/// Returns 0 on success, negated errno on failure.
1496#[no_mangle]
1497pub extern "C" fn syd_read_add(action: action_t, glob: *const c_char) -> c_int {
1498    // Convert action_t enum to corresponding action string.
1499    let action = match Action::try_from(action) {
1500        Ok(action) => action,
1501        Err(_) => return -EINVAL,
1502    };
1503
1504    // Call magic function with add operator.
1505    esyd(&format!("{action}/read"), glob, b'+')
1506}
1507
1508/// Removes the first instance from the end of the given actionlist of
1509/// read sandboxing.
1510///
1511/// Returns 0 on success, negated errno on failure.
1512#[no_mangle]
1513pub extern "C" fn syd_read_del(action: action_t, glob: *const c_char) -> c_int {
1514    // Convert action_t enum to corresponding action string.
1515    let action = match Action::try_from(action) {
1516        Ok(action) => action,
1517        Err(_) => return -EINVAL,
1518    };
1519
1520    // Call magic function with del operator.
1521    esyd(&format!("{action}/read"), glob, b'-')
1522}
1523
1524/// Removes all matching patterns from the given actionlist of read sandboxing.
1525///
1526/// Returns 0 on success, negated errno on failure.
1527#[no_mangle]
1528pub extern "C" fn syd_read_rem(action: action_t, glob: *const c_char) -> c_int {
1529    // Convert action_t enum to corresponding action string.
1530    let action = match Action::try_from(action) {
1531        Ok(action) => action,
1532        Err(_) => return -EINVAL,
1533    };
1534
1535    // Call magic function with rem operator.
1536    esyd(&format!("{action}/read"), glob, b'^')
1537}
1538
1539/// Adds to the given actionlist of write sandboxing.
1540///
1541/// Returns 0 on success, negated errno on failure.
1542#[no_mangle]
1543pub extern "C" fn syd_write_add(action: action_t, glob: *const c_char) -> c_int {
1544    // Convert action_t enum to corresponding action string.
1545    let action = match Action::try_from(action) {
1546        Ok(action) => action,
1547        Err(_) => return -EINVAL,
1548    };
1549
1550    // Call magic function with add operator.
1551    esyd(&format!("{action}/write"), glob, b'+')
1552}
1553
1554/// Removes the first instance from the end of the given actionlist of
1555/// write sandboxing.
1556///
1557/// Returns 0 on success, negated errno on failure.
1558#[no_mangle]
1559pub extern "C" fn syd_write_del(action: action_t, glob: *const c_char) -> c_int {
1560    // Convert action_t enum to corresponding action string.
1561    let action = match Action::try_from(action) {
1562        Ok(action) => action,
1563        Err(_) => return -EINVAL,
1564    };
1565
1566    // Call magic function with del operator.
1567    esyd(&format!("{action}/write"), glob, b'-')
1568}
1569
1570/// Removes all matching patterns from the given actionlist of write sandboxing.
1571///
1572/// Returns 0 on success, negated errno on failure.
1573#[no_mangle]
1574pub extern "C" fn syd_write_rem(action: action_t, glob: *const c_char) -> c_int {
1575    // Convert action_t enum to corresponding action string.
1576    let action = match Action::try_from(action) {
1577        Ok(action) => action,
1578        Err(_) => return -EINVAL,
1579    };
1580
1581    // Call magic function with rem operator.
1582    esyd(&format!("{action}/write"), glob, b'^')
1583}
1584
1585/// Adds to the given actionlist of exec sandboxing.
1586///
1587/// Returns 0 on success, negated errno on failure.
1588#[no_mangle]
1589pub extern "C" fn syd_exec_add(action: action_t, glob: *const c_char) -> c_int {
1590    // Convert action_t enum to corresponding action string.
1591    let action = match Action::try_from(action) {
1592        Ok(action) => action,
1593        Err(_) => return -EINVAL,
1594    };
1595
1596    // Call magic function with add operator.
1597    esyd(&format!("{action}/exec"), glob, b'+')
1598}
1599
1600/// Removes the first instance from the end of the given actionlist of
1601/// exec sandboxing.
1602///
1603/// Returns 0 on success, negated errno on failure.
1604#[no_mangle]
1605pub extern "C" fn syd_exec_del(action: action_t, glob: *const c_char) -> c_int {
1606    // Convert action_t enum to corresponding action string.
1607    let action = match Action::try_from(action) {
1608        Ok(action) => action,
1609        Err(_) => return -EINVAL,
1610    };
1611
1612    // Call magic function with del operator.
1613    esyd(&format!("{action}/exec"), glob, b'-')
1614}
1615
1616/// Removes all matching patterns from the given actionlist of exec sandboxing.
1617///
1618/// Returns 0 on success, negated errno on failure.
1619#[no_mangle]
1620pub extern "C" fn syd_exec_rem(action: action_t, glob: *const c_char) -> c_int {
1621    // Convert action_t enum to corresponding action string.
1622    let action = match Action::try_from(action) {
1623        Ok(action) => action,
1624        Err(_) => return -EINVAL,
1625    };
1626
1627    // Call magic function with rem operator.
1628    esyd(&format!("{action}/exec"), glob, b'^')
1629}
1630
1631/// Adds to the given actionlist of ioctl sandboxing.
1632///
1633/// Returns 0 on success, negated errno on failure.
1634#[no_mangle]
1635pub extern "C" fn syd_ioctl_add(action: action_t, glob: *const c_char) -> c_int {
1636    // Convert action_t enum to corresponding action string.
1637    let action = match Action::try_from(action) {
1638        Ok(action) => action,
1639        Err(_) => return -EINVAL,
1640    };
1641
1642    // Call magic function with add operator.
1643    esyd(&format!("{action}/ioctl"), glob, b'+')
1644}
1645
1646/// Removes the first instance from the end of the given actionlist of
1647/// ioctl sandboxing.
1648///
1649/// Returns 0 on success, negated errno on failure.
1650#[no_mangle]
1651pub extern "C" fn syd_ioctl_del(action: action_t, glob: *const c_char) -> c_int {
1652    // Convert action_t enum to corresponding action string.
1653    let action = match Action::try_from(action) {
1654        Ok(action) => action,
1655        Err(_) => return -EINVAL,
1656    };
1657
1658    // Call magic function with del operator.
1659    esyd(&format!("{action}/ioctl"), glob, b'-')
1660}
1661
1662/// Removes all matching patterns from the given actionlist of ioctl sandboxing.
1663///
1664/// Returns 0 on success, negated errno on failure.
1665#[no_mangle]
1666pub extern "C" fn syd_ioctl_rem(action: action_t, glob: *const c_char) -> c_int {
1667    // Convert action_t enum to corresponding action string.
1668    let action = match Action::try_from(action) {
1669        Ok(action) => action,
1670        Err(_) => return -EINVAL,
1671    };
1672
1673    // Call magic function with rem operator.
1674    esyd(&format!("{action}/ioctl"), glob, b'^')
1675}
1676
1677/// Adds to the given actionlist of create sandboxing.
1678///
1679/// Returns 0 on success, negated errno on failure.
1680#[no_mangle]
1681pub extern "C" fn syd_create_add(action: action_t, glob: *const c_char) -> c_int {
1682    // Convert action_t enum to corresponding action string.
1683    let action = match Action::try_from(action) {
1684        Ok(action) => action,
1685        Err(_) => return -EINVAL,
1686    };
1687
1688    // Call magic function with add operator.
1689    esyd(&format!("{action}/create"), glob, b'+')
1690}
1691
1692/// Removes the first instance from the end of the given actionlist of
1693/// create sandboxing.
1694///
1695/// Returns 0 on success, negated errno on failure.
1696#[no_mangle]
1697pub extern "C" fn syd_create_del(action: action_t, glob: *const c_char) -> c_int {
1698    // Convert action_t enum to corresponding action string.
1699    let action = match Action::try_from(action) {
1700        Ok(action) => action,
1701        Err(_) => return -EINVAL,
1702    };
1703
1704    // Call magic function with del operator.
1705    esyd(&format!("{action}/create"), glob, b'-')
1706}
1707
1708/// Removes all matching patterns from the given actionlist of create sandboxing.
1709///
1710/// Returns 0 on success, negated errno on failure.
1711#[no_mangle]
1712pub extern "C" fn syd_create_rem(action: action_t, glob: *const c_char) -> c_int {
1713    // Convert action_t enum to corresponding action string.
1714    let action = match Action::try_from(action) {
1715        Ok(action) => action,
1716        Err(_) => return -EINVAL,
1717    };
1718
1719    // Call magic function with rem operator.
1720    esyd(&format!("{action}/create"), glob, b'^')
1721}
1722
1723/// Adds to the given actionlist of delete sandboxing.
1724///
1725/// Returns 0 on success, negated errno on failure.
1726#[no_mangle]
1727pub extern "C" fn syd_delete_add(action: action_t, glob: *const c_char) -> c_int {
1728    // Convert action_t enum to corresponding action string.
1729    let action = match Action::try_from(action) {
1730        Ok(action) => action,
1731        Err(_) => return -EINVAL,
1732    };
1733
1734    // Call magic function with add operator.
1735    esyd(&format!("{action}/delete"), glob, b'+')
1736}
1737
1738/// Removes the first instance from the end of the given actionlist of
1739/// delete sandboxing.
1740///
1741/// Returns 0 on success, negated errno on failure.
1742#[no_mangle]
1743pub extern "C" fn syd_delete_del(action: action_t, glob: *const c_char) -> c_int {
1744    // Convert action_t enum to corresponding action string.
1745    let action = match Action::try_from(action) {
1746        Ok(action) => action,
1747        Err(_) => return -EINVAL,
1748    };
1749
1750    // Call magic function with del operator.
1751    esyd(&format!("{action}/delete"), glob, b'-')
1752}
1753
1754/// Removes all matching patterns from the given actionlist of delete sandboxing.
1755///
1756/// Returns 0 on success, negated errno on failure.
1757#[no_mangle]
1758pub extern "C" fn syd_delete_rem(action: action_t, glob: *const c_char) -> c_int {
1759    // Convert action_t enum to corresponding action string.
1760    let action = match Action::try_from(action) {
1761        Ok(action) => action,
1762        Err(_) => return -EINVAL,
1763    };
1764
1765    // Call magic function with rem operator.
1766    esyd(&format!("{action}/delete"), glob, b'^')
1767}
1768
1769/// Adds to the given actionlist of rename sandboxing.
1770///
1771/// Returns 0 on success, negated errno on failure.
1772#[no_mangle]
1773pub extern "C" fn syd_rename_add(action: action_t, glob: *const c_char) -> c_int {
1774    // Convert action_t enum to corresponding action string.
1775    let action = match Action::try_from(action) {
1776        Ok(action) => action,
1777        Err(_) => return -EINVAL,
1778    };
1779
1780    // Call magic function with add operator.
1781    esyd(&format!("{action}/rename"), glob, b'+')
1782}
1783
1784/// Removes the first instance from the end of the given actionlist of
1785/// rename sandboxing.
1786///
1787/// Returns 0 on success, negated errno on failure.
1788#[no_mangle]
1789pub extern "C" fn syd_rename_del(action: action_t, glob: *const c_char) -> c_int {
1790    // Convert action_t enum to corresponding action string.
1791    let action = match Action::try_from(action) {
1792        Ok(action) => action,
1793        Err(_) => return -EINVAL,
1794    };
1795
1796    // Call magic function with del operator.
1797    esyd(&format!("{action}/rename"), glob, b'-')
1798}
1799
1800/// Removes all matching patterns from the given actionlist of rename sandboxing.
1801///
1802/// Returns 0 on success, negated errno on failure.
1803#[no_mangle]
1804pub extern "C" fn syd_rename_rem(action: action_t, glob: *const c_char) -> c_int {
1805    // Convert action_t enum to corresponding action string.
1806    let action = match Action::try_from(action) {
1807        Ok(action) => action,
1808        Err(_) => return -EINVAL,
1809    };
1810
1811    // Call magic function with rem operator.
1812    esyd(&format!("{action}/rename"), glob, b'^')
1813}
1814
1815/// Adds to the given actionlist of symlink sandboxing.
1816///
1817/// Returns 0 on success, negated errno on failure.
1818#[no_mangle]
1819pub extern "C" fn syd_symlink_add(action: action_t, glob: *const c_char) -> c_int {
1820    // Convert action_t enum to corresponding action string.
1821    let action = match Action::try_from(action) {
1822        Ok(action) => action,
1823        Err(_) => return -EINVAL,
1824    };
1825
1826    // Call magic function with add operator.
1827    esyd(&format!("{action}/symlink"), glob, b'+')
1828}
1829
1830/// Removes the first instance from the end of the given actionlist of
1831/// symlink sandboxing.
1832///
1833/// Returns 0 on success, negated errno on failure.
1834#[no_mangle]
1835pub extern "C" fn syd_symlink_del(action: action_t, glob: *const c_char) -> c_int {
1836    // Convert action_t enum to corresponding action string.
1837    let action = match Action::try_from(action) {
1838        Ok(action) => action,
1839        Err(_) => return -EINVAL,
1840    };
1841
1842    // Call magic function with del operator.
1843    esyd(&format!("{action}/symlink"), glob, b'-')
1844}
1845
1846/// Removes all matching patterns from the given actionlist of symlink sandboxing.
1847///
1848/// Returns 0 on success, negated errno on failure.
1849#[no_mangle]
1850pub extern "C" fn syd_symlink_rem(action: action_t, glob: *const c_char) -> c_int {
1851    // Convert action_t enum to corresponding action string.
1852    let action = match Action::try_from(action) {
1853        Ok(action) => action,
1854        Err(_) => return -EINVAL,
1855    };
1856
1857    // Call magic function with rem operator.
1858    esyd(&format!("{action}/symlink"), glob, b'^')
1859}
1860
1861/// Adds to the given actionlist of truncate sandboxing.
1862///
1863/// Returns 0 on success, negated errno on failure.
1864#[no_mangle]
1865pub extern "C" fn syd_truncate_add(action: action_t, glob: *const c_char) -> c_int {
1866    // Convert action_t enum to corresponding action string.
1867    let action = match Action::try_from(action) {
1868        Ok(action) => action,
1869        Err(_) => return -EINVAL,
1870    };
1871
1872    // Call magic function with add operator.
1873    esyd(&format!("{action}/truncate"), glob, b'+')
1874}
1875
1876/// Removes the first instance from the end of the given actionlist of
1877/// truncate sandboxing.
1878///
1879/// Returns 0 on success, negated errno on failure.
1880#[no_mangle]
1881pub extern "C" fn syd_truncate_del(action: action_t, glob: *const c_char) -> c_int {
1882    // Convert action_t enum to corresponding action string.
1883    let action = match Action::try_from(action) {
1884        Ok(action) => action,
1885        Err(_) => return -EINVAL,
1886    };
1887
1888    // Call magic function with del operator.
1889    esyd(&format!("{action}/truncate"), glob, b'-')
1890}
1891
1892/// Removes all matching patterns from the given actionlist of truncate sandboxing.
1893///
1894/// Returns 0 on success, negated errno on failure.
1895#[no_mangle]
1896pub extern "C" fn syd_truncate_rem(action: action_t, glob: *const c_char) -> c_int {
1897    // Convert action_t enum to corresponding action string.
1898    let action = match Action::try_from(action) {
1899        Ok(action) => action,
1900        Err(_) => return -EINVAL,
1901    };
1902
1903    // Call magic function with rem operator.
1904    esyd(&format!("{action}/truncate"), glob, b'^')
1905}
1906
1907/// Adds to the given actionlist of chdir sandboxing.
1908///
1909/// Returns 0 on success, negated errno on failure.
1910#[no_mangle]
1911pub extern "C" fn syd_chdir_add(action: action_t, glob: *const c_char) -> c_int {
1912    // Convert action_t enum to corresponding action string.
1913    let action = match Action::try_from(action) {
1914        Ok(action) => action,
1915        Err(_) => return -EINVAL,
1916    };
1917
1918    // Call magic function with add operator.
1919    esyd(&format!("{action}/chdir"), glob, b'+')
1920}
1921
1922/// Removes the first instance from the end of the given actionlist of
1923/// chdir sandboxing.
1924///
1925/// Returns 0 on success, negated errno on failure.
1926#[no_mangle]
1927pub extern "C" fn syd_chdir_del(action: action_t, glob: *const c_char) -> c_int {
1928    // Convert action_t enum to corresponding action string.
1929    let action = match Action::try_from(action) {
1930        Ok(action) => action,
1931        Err(_) => return -EINVAL,
1932    };
1933
1934    // Call magic function with del operator.
1935    esyd(&format!("{action}/chdir"), glob, b'-')
1936}
1937
1938/// Removes all matching patterns from the given actionlist of chdir sandboxing.
1939///
1940/// Returns 0 on success, negated errno on failure.
1941#[no_mangle]
1942pub extern "C" fn syd_chdir_rem(action: action_t, glob: *const c_char) -> c_int {
1943    // Convert action_t enum to corresponding action string.
1944    let action = match Action::try_from(action) {
1945        Ok(action) => action,
1946        Err(_) => return -EINVAL,
1947    };
1948
1949    // Call magic function with rem operator.
1950    esyd(&format!("{action}/chdir"), glob, b'^')
1951}
1952
1953/// Adds to the given actionlist of readdir sandboxing.
1954///
1955/// Returns 0 on success, negated errno on failure.
1956#[no_mangle]
1957pub extern "C" fn syd_readdir_add(action: action_t, glob: *const c_char) -> c_int {
1958    // Convert action_t enum to corresponding action string.
1959    let action = match Action::try_from(action) {
1960        Ok(action) => action,
1961        Err(_) => return -EINVAL,
1962    };
1963
1964    // Call magic function with add operator.
1965    esyd(&format!("{action}/readdir"), glob, b'+')
1966}
1967
1968/// Removes the first instance from the end of the given actionlist of
1969/// readdir sandboxing.
1970///
1971/// Returns 0 on success, negated errno on failure.
1972#[no_mangle]
1973pub extern "C" fn syd_readdir_del(action: action_t, glob: *const c_char) -> c_int {
1974    // Convert action_t enum to corresponding action string.
1975    let action = match Action::try_from(action) {
1976        Ok(action) => action,
1977        Err(_) => return -EINVAL,
1978    };
1979
1980    // Call magic function with del operator.
1981    esyd(&format!("{action}/readdir"), glob, b'-')
1982}
1983
1984/// Removes all matching patterns from the given actionlist of readdir sandboxing.
1985///
1986/// Returns 0 on success, negated errno on failure.
1987#[no_mangle]
1988pub extern "C" fn syd_readdir_rem(action: action_t, glob: *const c_char) -> c_int {
1989    // Convert action_t enum to corresponding action string.
1990    let action = match Action::try_from(action) {
1991        Ok(action) => action,
1992        Err(_) => return -EINVAL,
1993    };
1994
1995    // Call magic function with del operator.
1996    esyd(&format!("{action}/readdir"), glob, b'^')
1997}
1998
1999/// Adds to the given actionlist of mkdir sandboxing.
2000///
2001/// Returns 0 on success, negated errno on failure.
2002#[no_mangle]
2003pub extern "C" fn syd_mkdir_add(action: action_t, glob: *const c_char) -> c_int {
2004    // Convert action_t enum to corresponding action string.
2005    let action = match Action::try_from(action) {
2006        Ok(action) => action,
2007        Err(_) => return -EINVAL,
2008    };
2009
2010    // Call magic function with add operator.
2011    esyd(&format!("{action}/mkdir"), glob, b'+')
2012}
2013
2014/// Removes the first instance from the end of the given actionlist of
2015/// mkdir sandboxing.
2016///
2017/// Returns 0 on success, negated errno on failure.
2018#[no_mangle]
2019pub extern "C" fn syd_mkdir_del(action: action_t, glob: *const c_char) -> c_int {
2020    // Convert action_t enum to corresponding action string.
2021    let action = match Action::try_from(action) {
2022        Ok(action) => action,
2023        Err(_) => return -EINVAL,
2024    };
2025
2026    // Call magic function with del operator.
2027    esyd(&format!("{action}/mkdir"), glob, b'-')
2028}
2029
2030/// Removes all matching patterns from the given actionlist of mkdir sandboxing.
2031///
2032/// Returns 0 on success, negated errno on failure.
2033#[no_mangle]
2034pub extern "C" fn syd_mkdir_rem(action: action_t, glob: *const c_char) -> c_int {
2035    // Convert action_t enum to corresponding action string.
2036    let action = match Action::try_from(action) {
2037        Ok(action) => action,
2038        Err(_) => return -EINVAL,
2039    };
2040
2041    // Call magic function with del operator.
2042    esyd(&format!("{action}/mkdir"), glob, b'^')
2043}
2044
2045/// Adds to the given actionlist of rmdir sandboxing.
2046///
2047/// Returns 0 on success, negated errno on failure.
2048#[no_mangle]
2049pub extern "C" fn syd_rmdir_add(action: action_t, glob: *const c_char) -> c_int {
2050    // Convert action_t enum to corresponding action string.
2051    let action = match Action::try_from(action) {
2052        Ok(action) => action,
2053        Err(_) => return -EINVAL,
2054    };
2055
2056    // Call magic function with add operator.
2057    esyd(&format!("{action}/rmdir"), glob, b'+')
2058}
2059
2060/// Removes the first instance from the end of the given actionlist of
2061/// rmdir sandboxing.
2062///
2063/// Returns 0 on success, negated errno on failure.
2064#[no_mangle]
2065pub extern "C" fn syd_rmdir_del(action: action_t, glob: *const c_char) -> c_int {
2066    // Convert action_t enum to corresponding action string.
2067    let action = match Action::try_from(action) {
2068        Ok(action) => action,
2069        Err(_) => return -EINVAL,
2070    };
2071
2072    // Call magic function with del operator.
2073    esyd(&format!("{action}/rmdir"), glob, b'-')
2074}
2075
2076/// Removes all matching patterns from the given actionlist of rmdir sandboxing.
2077///
2078/// Returns 0 on success, negated errno on failure.
2079#[no_mangle]
2080pub extern "C" fn syd_rmdir_rem(action: action_t, glob: *const c_char) -> c_int {
2081    // Convert action_t enum to corresponding action string.
2082    let action = match Action::try_from(action) {
2083        Ok(action) => action,
2084        Err(_) => return -EINVAL,
2085    };
2086
2087    // Call magic function with del operator.
2088    esyd(&format!("{action}/rmdir"), glob, b'^')
2089}
2090
2091/// Adds to the given actionlist of chown sandboxing.
2092///
2093/// Returns 0 on success, negated errno on failure.
2094#[no_mangle]
2095pub extern "C" fn syd_chown_add(action: action_t, glob: *const c_char) -> c_int {
2096    // Convert action_t enum to corresponding action string.
2097    let action = match Action::try_from(action) {
2098        Ok(action) => action,
2099        Err(_) => return -EINVAL,
2100    };
2101
2102    // Call magic function with add operator.
2103    esyd(&format!("{action}/chown"), glob, b'+')
2104}
2105
2106/// Removes the first instance from the end of the given actionlist of
2107/// chown sandboxing.
2108///
2109/// Returns 0 on success, negated errno on failure.
2110#[no_mangle]
2111pub extern "C" fn syd_chown_del(action: action_t, glob: *const c_char) -> c_int {
2112    // Convert action_t enum to corresponding action string.
2113    let action = match Action::try_from(action) {
2114        Ok(action) => action,
2115        Err(_) => return -EINVAL,
2116    };
2117
2118    // Call magic function with del operator.
2119    esyd(&format!("{action}/chown"), glob, b'-')
2120}
2121
2122/// Removes all matching patterns from the given actionlist of chown sandboxing.
2123///
2124/// Returns 0 on success, negated errno on failure.
2125#[no_mangle]
2126pub extern "C" fn syd_chown_rem(action: action_t, glob: *const c_char) -> c_int {
2127    // Convert action_t enum to corresponding action string.
2128    let action = match Action::try_from(action) {
2129        Ok(action) => action,
2130        Err(_) => return -EINVAL,
2131    };
2132
2133    // Call magic function with rem operator.
2134    esyd(&format!("{action}/chown"), glob, b'^')
2135}
2136
2137/// Adds to the given actionlist of chgrp sandboxing.
2138///
2139/// Returns 0 on success, negated errno on failure.
2140#[no_mangle]
2141pub extern "C" fn syd_chgrp_add(action: action_t, glob: *const c_char) -> c_int {
2142    // Convert action_t enum to corresponding action string.
2143    let action = match Action::try_from(action) {
2144        Ok(action) => action,
2145        Err(_) => return -EINVAL,
2146    };
2147
2148    // Call magic function with add operator.
2149    esyd(&format!("{action}/chgrp"), glob, b'+')
2150}
2151
2152/// Removes the first instance from the end of the given actionlist of
2153/// chgrp sandboxing.
2154///
2155/// Returns 0 on success, negated errno on failure.
2156#[no_mangle]
2157pub extern "C" fn syd_chgrp_del(action: action_t, glob: *const c_char) -> c_int {
2158    // Convert action_t enum to corresponding action string.
2159    let action = match Action::try_from(action) {
2160        Ok(action) => action,
2161        Err(_) => return -EINVAL,
2162    };
2163
2164    // Call magic function with del operator.
2165    esyd(&format!("{action}/chgrp"), glob, b'-')
2166}
2167
2168/// Removes all matching patterns from the given actionlist of chgrp sandboxing.
2169///
2170/// Returns 0 on success, negated errno on failure.
2171#[no_mangle]
2172pub extern "C" fn syd_chgrp_rem(action: action_t, glob: *const c_char) -> c_int {
2173    // Convert action_t enum to corresponding action string.
2174    let action = match Action::try_from(action) {
2175        Ok(action) => action,
2176        Err(_) => return -EINVAL,
2177    };
2178
2179    // Call magic function with rem operator.
2180    esyd(&format!("{action}/chgrp"), glob, b'^')
2181}
2182
2183/// Adds to the given actionlist of chmod sandboxing.
2184///
2185/// Returns 0 on success, negated errno on failure.
2186#[no_mangle]
2187pub extern "C" fn syd_chmod_add(action: action_t, glob: *const c_char) -> c_int {
2188    // Convert action_t enum to corresponding action string.
2189    let action = match Action::try_from(action) {
2190        Ok(action) => action,
2191        Err(_) => return -EINVAL,
2192    };
2193
2194    // Call magic function with add operator.
2195    esyd(&format!("{action}/chmod"), glob, b'+')
2196}
2197
2198/// Removes the first instance from the end of the given actionlist of
2199/// chmod sandboxing.
2200///
2201/// Returns 0 on success, negated errno on failure.
2202#[no_mangle]
2203pub extern "C" fn syd_chmod_del(action: action_t, glob: *const c_char) -> c_int {
2204    // Convert action_t enum to corresponding action string.
2205    let action = match Action::try_from(action) {
2206        Ok(action) => action,
2207        Err(_) => return -EINVAL,
2208    };
2209
2210    // Call magic function with del operator.
2211    esyd(&format!("{action}/chmod"), glob, b'-')
2212}
2213
2214/// Removes all matching patterns from the given actionlist of chmod sandboxing.
2215///
2216/// Returns 0 on success, negated errno on failure.
2217#[no_mangle]
2218pub extern "C" fn syd_chmod_rem(action: action_t, glob: *const c_char) -> c_int {
2219    // Convert action_t enum to corresponding action string.
2220    let action = match Action::try_from(action) {
2221        Ok(action) => action,
2222        Err(_) => return -EINVAL,
2223    };
2224
2225    // Call magic function with rem operator.
2226    esyd(&format!("{action}/chmod"), glob, b'^')
2227}
2228
2229/// Adds to the given actionlist of chattr sandboxing.
2230///
2231/// Returns 0 on success, negated errno on failure.
2232#[no_mangle]
2233pub extern "C" fn syd_chattr_add(action: action_t, glob: *const c_char) -> c_int {
2234    // Convert action_t enum to corresponding action string.
2235    let action = match Action::try_from(action) {
2236        Ok(action) => action,
2237        Err(_) => return -EINVAL,
2238    };
2239
2240    // Call magic function with add operator.
2241    esyd(&format!("{action}/chattr"), glob, b'+')
2242}
2243
2244/// Removes the first instance from the end of the given actionlist of
2245/// chattr sandboxing.
2246///
2247/// Returns 0 on success, negated errno on failure.
2248#[no_mangle]
2249pub extern "C" fn syd_chattr_del(action: action_t, glob: *const c_char) -> c_int {
2250    // Convert action_t enum to corresponding action string.
2251    let action = match Action::try_from(action) {
2252        Ok(action) => action,
2253        Err(_) => return -EINVAL,
2254    };
2255
2256    // Call magic function with del operator.
2257    esyd(&format!("{action}/chattr"), glob, b'-')
2258}
2259
2260/// Removes all matching patterns from the given actionlist of chattr sandboxing.
2261///
2262/// Returns 0 on success, negated errno on failure.
2263#[no_mangle]
2264pub extern "C" fn syd_chattr_rem(action: action_t, glob: *const c_char) -> c_int {
2265    // Convert action_t enum to corresponding action string.
2266    let action = match Action::try_from(action) {
2267        Ok(action) => action,
2268        Err(_) => return -EINVAL,
2269    };
2270
2271    // Call magic function with rem operator.
2272    esyd(&format!("{action}/chattr"), glob, b'^')
2273}
2274
2275/// Adds to the given actionlist of chroot sandboxing.
2276///
2277/// Returns 0 on success, negated errno on failure.
2278#[no_mangle]
2279pub extern "C" fn syd_chroot_add(action: action_t, glob: *const c_char) -> c_int {
2280    // Convert action_t enum to corresponding action string.
2281    let action = match Action::try_from(action) {
2282        Ok(action) => action,
2283        Err(_) => return -EINVAL,
2284    };
2285
2286    // Call magic function with add operator.
2287    esyd(&format!("{action}/chroot"), glob, b'+')
2288}
2289
2290/// Removes the first instance from the end of the given actionlist of
2291/// chroot sandboxing.
2292///
2293/// Returns 0 on success, negated errno on failure.
2294#[no_mangle]
2295pub extern "C" fn syd_chroot_del(action: action_t, glob: *const c_char) -> c_int {
2296    // Convert action_t enum to corresponding action string.
2297    let action = match Action::try_from(action) {
2298        Ok(action) => action,
2299        Err(_) => return -EINVAL,
2300    };
2301
2302    // Call magic function with del operator.
2303    esyd(&format!("{action}/chroot"), glob, b'-')
2304}
2305
2306/// Removes all matching patterns from the given actionlist of chroot sandboxing.
2307///
2308/// Returns 0 on success, negated errno on failure.
2309#[no_mangle]
2310pub extern "C" fn syd_chroot_rem(action: action_t, glob: *const c_char) -> c_int {
2311    // Convert action_t enum to corresponding action string.
2312    let action = match Action::try_from(action) {
2313        Ok(action) => action,
2314        Err(_) => return -EINVAL,
2315    };
2316
2317    // Call magic function with rem operator.
2318    esyd(&format!("{action}/chroot"), glob, b'^')
2319}
2320
2321/// Adds to the given actionlist of utime sandboxing.
2322///
2323/// Returns 0 on success, negated errno on failure.
2324#[no_mangle]
2325pub extern "C" fn syd_utime_add(action: action_t, glob: *const c_char) -> c_int {
2326    // Convert action_t enum to corresponding action string.
2327    let action = match Action::try_from(action) {
2328        Ok(action) => action,
2329        Err(_) => return -EINVAL,
2330    };
2331
2332    // Call magic function with add operator.
2333    esyd(&format!("{action}/utime"), glob, b'+')
2334}
2335
2336/// Removes the first instance from the end of the given actionlist of
2337/// utime sandboxing.
2338///
2339/// Returns 0 on success, negated errno on failure.
2340#[no_mangle]
2341pub extern "C" fn syd_utime_del(action: action_t, glob: *const c_char) -> c_int {
2342    // Convert action_t enum to corresponding action string.
2343    let action = match Action::try_from(action) {
2344        Ok(action) => action,
2345        Err(_) => return -EINVAL,
2346    };
2347
2348    // Call magic function with del operator.
2349    esyd(&format!("{action}/utime"), glob, b'-')
2350}
2351
2352/// Removes all matching patterns from the given actionlist of utime sandboxing.
2353///
2354/// Returns 0 on success, negated errno on failure.
2355#[no_mangle]
2356pub extern "C" fn syd_utime_rem(action: action_t, glob: *const c_char) -> c_int {
2357    // Convert action_t enum to corresponding action string.
2358    let action = match Action::try_from(action) {
2359        Ok(action) => action,
2360        Err(_) => return -EINVAL,
2361    };
2362
2363    // Call magic function with rem operator.
2364    esyd(&format!("{action}/utime"), glob, b'^')
2365}
2366
2367/// Adds to the given actionlist of mkdev sandboxing.
2368///
2369/// Returns 0 on success, negated errno on failure.
2370#[no_mangle]
2371pub extern "C" fn syd_mkdev_add(action: action_t, glob: *const c_char) -> c_int {
2372    // Convert action_t enum to corresponding action string.
2373    let action = match Action::try_from(action) {
2374        Ok(action) => action,
2375        Err(_) => return -EINVAL,
2376    };
2377
2378    // Call magic function with add operator.
2379    esyd(&format!("{action}/mkdev"), glob, b'+')
2380}
2381
2382/// Removes the first instance from the end of the given actionlist of
2383/// mkdev sandboxing.
2384///
2385/// Returns 0 on success, negated errno on failure.
2386#[no_mangle]
2387pub extern "C" fn syd_mkdev_del(action: action_t, glob: *const c_char) -> c_int {
2388    // Convert action_t enum to corresponding action string.
2389    let action = match Action::try_from(action) {
2390        Ok(action) => action,
2391        Err(_) => return -EINVAL,
2392    };
2393
2394    // Call magic function with del operator.
2395    esyd(&format!("{action}/mkdev"), glob, b'-')
2396}
2397
2398/// Removes all matching patterns from the given actionlist of mkdev sandboxing.
2399///
2400/// Returns 0 on success, negated errno on failure.
2401#[no_mangle]
2402pub extern "C" fn syd_mkdev_rem(action: action_t, glob: *const c_char) -> c_int {
2403    // Convert action_t enum to corresponding action string.
2404    let action = match Action::try_from(action) {
2405        Ok(action) => action,
2406        Err(_) => return -EINVAL,
2407    };
2408
2409    // Call magic function with rem operator.
2410    esyd(&format!("{action}/mkdev"), glob, b'^')
2411}
2412
2413/// Adds to the given actionlist of mkfifo sandboxing.
2414///
2415/// Returns 0 on success, negated errno on failure.
2416#[no_mangle]
2417pub extern "C" fn syd_mkfifo_add(action: action_t, glob: *const c_char) -> c_int {
2418    // Convert action_t enum to corresponding action string.
2419    let action = match Action::try_from(action) {
2420        Ok(action) => action,
2421        Err(_) => return -EINVAL,
2422    };
2423
2424    // Call magic function with add operator.
2425    esyd(&format!("{action}/mkfifo"), glob, b'+')
2426}
2427
2428/// Removes the first instance from the end of the given actionlist of
2429/// mkfifo sandboxing.
2430///
2431/// Returns 0 on success, negated errno on failure.
2432#[no_mangle]
2433pub extern "C" fn syd_mkfifo_del(action: action_t, glob: *const c_char) -> c_int {
2434    // Convert action_t enum to corresponding action string.
2435    let action = match Action::try_from(action) {
2436        Ok(action) => action,
2437        Err(_) => return -EINVAL,
2438    };
2439
2440    // Call magic function with del operator.
2441    esyd(&format!("{action}/mkfifo"), glob, b'-')
2442}
2443
2444/// Removes all matching patterns from the given actionlist of mkfifo sandboxing.
2445///
2446/// Returns 0 on success, negated errno on failure.
2447#[no_mangle]
2448pub extern "C" fn syd_mkfifo_rem(action: action_t, glob: *const c_char) -> c_int {
2449    // Convert action_t enum to corresponding action string.
2450    let action = match Action::try_from(action) {
2451        Ok(action) => action,
2452        Err(_) => return -EINVAL,
2453    };
2454
2455    // Call magic function with rem operator.
2456    esyd(&format!("{action}/mkfifo"), glob, b'^')
2457}
2458
2459/// Adds to the given actionlist of mktemp sandboxing.
2460///
2461/// Returns 0 on success, negated errno on failure.
2462#[no_mangle]
2463pub extern "C" fn syd_mktemp_add(action: action_t, glob: *const c_char) -> c_int {
2464    // Convert action_t enum to corresponding action string.
2465    let action = match Action::try_from(action) {
2466        Ok(action) => action,
2467        Err(_) => return -EINVAL,
2468    };
2469
2470    // Call magic function with add operator.
2471    esyd(&format!("{action}/mktemp"), glob, b'+')
2472}
2473
2474/// Removes the first instance from the end of the given actionlist of
2475/// mktemp sandboxing.
2476///
2477/// Returns 0 on success, negated errno on failure.
2478#[no_mangle]
2479pub extern "C" fn syd_mktemp_del(action: action_t, glob: *const c_char) -> c_int {
2480    // Convert action_t enum to corresponding action string.
2481    let action = match Action::try_from(action) {
2482        Ok(action) => action,
2483        Err(_) => return -EINVAL,
2484    };
2485
2486    // Call magic function with del operator.
2487    esyd(&format!("{action}/mktemp"), glob, b'-')
2488}
2489
2490/// Removes all matching patterns from the given actionlist of mktemp sandboxing.
2491///
2492/// Returns 0 on success, negated errno on failure.
2493#[no_mangle]
2494pub extern "C" fn syd_mktemp_rem(action: action_t, glob: *const c_char) -> c_int {
2495    // Convert action_t enum to corresponding action string.
2496    let action = match Action::try_from(action) {
2497        Ok(action) => action,
2498        Err(_) => return -EINVAL,
2499    };
2500
2501    // Call magic function with rem operator.
2502    esyd(&format!("{action}/mktemp"), glob, b'^')
2503}
2504
2505/// Adds to the given actionlist of net/bind sandboxing.
2506///
2507/// Returns 0 on success, negated errno on failure.
2508#[no_mangle]
2509pub extern "C" fn syd_net_bind_add(action: action_t, glob: *const c_char) -> c_int {
2510    // Convert action_t enum to corresponding action string.
2511    let action = match Action::try_from(action) {
2512        Ok(action) => action,
2513        Err(_) => return -EINVAL,
2514    };
2515
2516    // Call magic function with add operator.
2517    esyd(&format!("{action}/net/bind"), glob, b'+')
2518}
2519
2520/// Removes the first instance from the end of the given actionlist of
2521/// net/bind sandboxing.
2522///
2523/// Returns 0 on success, negated errno on failure.
2524#[no_mangle]
2525pub extern "C" fn syd_net_bind_del(action: action_t, glob: *const c_char) -> c_int {
2526    // Convert action_t enum to corresponding action string.
2527    let action = match Action::try_from(action) {
2528        Ok(action) => action,
2529        Err(_) => return -EINVAL,
2530    };
2531
2532    // Call magic function with del operator.
2533    esyd(&format!("{action}/net/bind"), glob, b'-')
2534}
2535
2536/// Removes all matching patterns from the given actionlist of net/bind sandboxing.
2537///
2538/// Returns 0 on success, negated errno on failure.
2539#[no_mangle]
2540pub extern "C" fn syd_net_bind_rem(action: action_t, glob: *const c_char) -> c_int {
2541    // Convert action_t enum to corresponding action string.
2542    let action = match Action::try_from(action) {
2543        Ok(action) => action,
2544        Err(_) => return -EINVAL,
2545    };
2546
2547    // Call magic function with rem operator.
2548    esyd(&format!("{action}/net/bind"), glob, b'^')
2549}
2550
2551/// Adds to the given actionlist of net/connect sandboxing.
2552///
2553/// Returns 0 on success, negated errno on failure.
2554#[no_mangle]
2555pub extern "C" fn syd_net_connect_add(action: action_t, glob: *const c_char) -> c_int {
2556    // Convert action_t enum to corresponding action string.
2557    let action = match Action::try_from(action) {
2558        Ok(action) => action,
2559        Err(_) => return -EINVAL,
2560    };
2561
2562    // Call magic function with add operator.
2563    esyd(&format!("{action}/net/connect"), glob, b'+')
2564}
2565
2566/// Removes the first instance from the end of the given actionlist of
2567/// net/connect sandboxing.
2568///
2569/// Returns 0 on success, negated errno on failure.
2570#[no_mangle]
2571pub extern "C" fn syd_net_connect_del(action: action_t, glob: *const c_char) -> c_int {
2572    // Convert action_t enum to corresponding action string.
2573    let action = match Action::try_from(action) {
2574        Ok(action) => action,
2575        Err(_) => return -EINVAL,
2576    };
2577
2578    // Call magic function with del operator.
2579    esyd(&format!("{action}/net/connect"), glob, b'-')
2580}
2581
2582/// Removes all matching patterns from the given actionlist of net/connect sandboxing.
2583///
2584/// Returns 0 on success, negated errno on failure.
2585#[no_mangle]
2586pub extern "C" fn syd_net_connect_rem(action: action_t, glob: *const c_char) -> c_int {
2587    // Convert action_t enum to corresponding action string.
2588    let action = match Action::try_from(action) {
2589        Ok(action) => action,
2590        Err(_) => return -EINVAL,
2591    };
2592
2593    // Call magic function with rem operator.
2594    esyd(&format!("{action}/net/connect"), glob, b'^')
2595}
2596
2597/// Adds to the given actionlist of net/sendfd sandboxing.
2598///
2599/// Returns 0 on success, negated errno on failure.
2600#[no_mangle]
2601pub extern "C" fn syd_net_sendfd_add(action: action_t, glob: *const c_char) -> c_int {
2602    // Convert action_t enum to corresponding action string.
2603    let action = match Action::try_from(action) {
2604        Ok(action) => action,
2605        Err(_) => return -EINVAL,
2606    };
2607
2608    // Call magic function with add operator.
2609    esyd(&format!("{action}/net/sendfd"), glob, b'+')
2610}
2611
2612/// Removes the first instance from the end of the given actionlist of
2613/// net/sendfd sandboxing.
2614///
2615/// Returns 0 on success, negated errno on failure.
2616#[no_mangle]
2617pub extern "C" fn syd_net_sendfd_del(action: action_t, glob: *const c_char) -> c_int {
2618    // Convert action_t enum to corresponding action string.
2619    let action = match Action::try_from(action) {
2620        Ok(action) => action,
2621        Err(_) => return -EINVAL,
2622    };
2623
2624    // Call magic function with del operator.
2625    esyd(&format!("{action}/net/sendfd"), glob, b'-')
2626}
2627
2628/// Removes all matching patterns from the given actionlist of net/sendfd sandboxing.
2629///
2630/// Returns 0 on success, negated errno on failure.
2631#[no_mangle]
2632pub extern "C" fn syd_net_sendfd_rem(action: action_t, glob: *const c_char) -> c_int {
2633    // Convert action_t enum to corresponding action string.
2634    let action = match Action::try_from(action) {
2635        Ok(action) => action,
2636        Err(_) => return -EINVAL,
2637    };
2638
2639    // Call magic function with rem operator.
2640    esyd(&format!("{action}/net/sendfd"), glob, b'^')
2641}
2642
2643/// Adds to the given actionlist of net/link sandboxing.
2644///
2645/// Returns 0 on success, negated errno on failure.
2646#[no_mangle]
2647pub extern "C" fn syd_net_link_add(action: action_t, family: *const c_char) -> c_int {
2648    // Convert action_t enum to corresponding action string.
2649    let action = match Action::try_from(action) {
2650        Ok(action) => action,
2651        Err(_) => return -EINVAL,
2652    };
2653
2654    // Call magic function with add operator.
2655    esyd(&format!("{action}/net/link"), family, b'+')
2656}
2657
2658/// Removes the first instance from the end of the given actionlist of
2659/// net/link sandboxing.
2660///
2661/// Returns 0 on success, negated errno on failure.
2662#[no_mangle]
2663pub extern "C" fn syd_net_link_del(action: action_t, family: *const c_char) -> c_int {
2664    // Convert action_t enum to corresponding action string.
2665    let action = match Action::try_from(action) {
2666        Ok(action) => action,
2667        Err(_) => return -EINVAL,
2668    };
2669
2670    // Call magic function with del operator.
2671    esyd(&format!("{action}/net/link"), family, b'-')
2672}
2673
2674/// Removes all matching patterns from the given actionlist of net/link sandboxing.
2675///
2676/// Returns 0 on success, negated errno on failure.
2677#[no_mangle]
2678pub extern "C" fn syd_net_link_rem(action: action_t, family: *const c_char) -> c_int {
2679    // Convert action_t enum to corresponding action string.
2680    let action = match Action::try_from(action) {
2681        Ok(action) => action,
2682        Err(_) => return -EINVAL,
2683    };
2684
2685    // Call magic function with rem operator.
2686    esyd(&format!("{action}/net/link"), family, b'^')
2687}
2688
2689/// Set syd maximum per-process memory usage limit for memory sandboxing.
2690///
2691/// parse-size crate is used to parse the value so formatted strings are OK.
2692///
2693/// Returns 0 on success, negated errno on failure.
2694#[no_mangle]
2695pub extern "C" fn syd_mem_max(size: *const c_char) -> c_int {
2696    esyd("mem/max", size, b':')
2697}
2698
2699/// Set syd maximum per-process virtual memory usage limit for memory sandboxing.
2700///
2701/// parse-size crate is used to parse the value so formatted strings are OK.
2702///
2703/// Returns 0 on success, negated errno on failure.
2704#[no_mangle]
2705pub extern "C" fn syd_mem_vm_max(size: *const c_char) -> c_int {
2706    esyd("mem/vm_max", size, b':')
2707}
2708
2709/// Set syd maximum process id limit for PID sandboxing
2710///
2711/// Returns 0 on success, negated errno on failure.
2712#[no_mangle]
2713pub extern "C" fn syd_pid_max(size: usize) -> c_int {
2714    stat(&format!("/dev/syd/pid/max:{size}"))
2715}
2716
2717/// Specify SegvGuard entry expiry timeout in seconds.
2718/// Setting this timeout to 0 effectively disables SegvGuard.
2719///
2720/// Returns 0 on success, negated errno on failure.
2721#[no_mangle]
2722pub extern "C" fn syd_segvguard_expiry(timeout: u64) -> c_int {
2723    stat(&format!("/dev/syd/segvguard/expiry:{timeout}"))
2724}
2725
2726/// Specify SegvGuard entry suspension timeout in seconds.
2727///
2728/// Returns 0 on success, negated errno on failure.
2729#[no_mangle]
2730pub extern "C" fn syd_segvguard_suspension(timeout: u64) -> c_int {
2731    stat(&format!("/dev/syd/segvguard/suspension:{timeout}"))
2732}
2733
2734/// Specify SegvGuard max number of crashes before suspension.
2735///
2736/// Returns 0 on success, negated errno on failure.
2737#[no_mangle]
2738pub extern "C" fn syd_segvguard_maxcrashes(max: u8) -> c_int {
2739    stat(&format!("/dev/syd/segvguard/maxcrashes:{max}"))
2740}
2741
2742/// Execute a command outside the sandbox without sandboxing
2743///
2744/// # Safety
2745///
2746/// This function is marked `unsafe` because it dereferences raw
2747/// pointers, which is inherently unsafe in Rust.
2748///
2749/// The caller must ensure the following conditions are met to safely
2750/// use this function:
2751///
2752/// 1. The `file` pointer must point to a valid, null-terminated C-style
2753///    string.
2754///
2755/// 2. The `argv` pointer must point to an array of pointers, where each
2756///    pointer refers to a valid, null-terminated C-style string. The
2757///    last pointer in the array must be null, indicating the end of the
2758///    array.
2759///
2760/// 3. The memory pointed to by `file` and `argv` must remain valid for
2761///    the duration of the call.
2762///
2763/// Failing to uphold these guarantees can lead to undefined behavior,
2764/// including memory corruption and data races.
2765///
2766/// Returns 0 on success, negated errno on failure.
2767#[no_mangle]
2768pub unsafe extern "C" fn syd_exec(file: *const c_char, argv: *const *const c_char) -> c_int {
2769    if file.is_null() || argv.is_null() {
2770        return -EFAULT;
2771    }
2772
2773    // SAFETY: Trust that `file` is a null-terminated string.
2774    let file = CStr::from_ptr(file);
2775    let file = OsStr::from_bytes(file.to_bytes());
2776
2777    let mut path = OsString::from("/dev/syd/cmd/exec!");
2778    path.push(file);
2779
2780    let mut idx: isize = 0;
2781    while !(*argv.offset(idx)).is_null() {
2782        // SAFETY: Trust that each `argv` element is a null-terminated string.
2783        let arg = CStr::from_ptr(*argv.offset(idx));
2784        let arg = OsStr::from_bytes(arg.to_bytes());
2785
2786        path.push(OsStr::from_bytes(&[b'\x1F'])); // ASCII Unit Separator
2787        path.push(arg);
2788
2789        idx = idx.saturating_add(1);
2790    }
2791
2792    let path = PathBuf::from(path);
2793    stat(path)
2794}