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 chown sandboxing is enabled.
647///
648/// Returns true if chown sandboxing is enabled, false otherwise.
649#[no_mangle]
650pub extern "C" fn syd_enabled_chown() -> bool {
651    stat("/dev/syd/sandbox/chown?") == 0
652}
653
654/// Enable chown sandboxing.
655///
656/// Returns 0 on success, negated errno on failure.
657#[no_mangle]
658pub extern "C" fn syd_enable_chown() -> c_int {
659    stat("/dev/syd/sandbox/chown:on")
660}
661
662/// Disable chown sandboxing.
663///
664/// Returns 0 on success, negated errno on failure.
665#[no_mangle]
666pub extern "C" fn syd_disable_chown() -> c_int {
667    stat("/dev/syd/sandbox/chown:off")
668}
669
670/// Checks if chgrp sandboxing is enabled.
671///
672/// Returns true if chgrp sandboxing is enabled, false otherwise.
673#[no_mangle]
674pub extern "C" fn syd_enabled_chgrp() -> bool {
675    stat("/dev/syd/sandbox/chgrp?") == 0
676}
677
678/// Enable chgrp sandboxing.
679///
680/// Returns 0 on success, negated errno on failure.
681#[no_mangle]
682pub extern "C" fn syd_enable_chgrp() -> c_int {
683    stat("/dev/syd/sandbox/chgrp:on")
684}
685
686/// Disable chgrp sandboxing.
687///
688/// Returns 0 on success, negated errno on failure.
689#[no_mangle]
690pub extern "C" fn syd_disable_chgrp() -> c_int {
691    stat("/dev/syd/sandbox/chgrp:off")
692}
693
694/// Checks if chmod sandboxing is enabled.
695///
696/// Returns true if chmod sandboxing is enabled, false otherwise.
697#[no_mangle]
698pub extern "C" fn syd_enabled_chmod() -> bool {
699    stat("/dev/syd/sandbox/chmod?") == 0
700}
701
702/// Enable chmod sandboxing.
703///
704/// Returns 0 on success, negated errno on failure.
705#[no_mangle]
706pub extern "C" fn syd_enable_chmod() -> c_int {
707    stat("/dev/syd/sandbox/chmod:on")
708}
709
710/// Disable chmod sandboxing.
711///
712/// Returns 0 on success, negated errno on failure.
713#[no_mangle]
714pub extern "C" fn syd_disable_chmod() -> c_int {
715    stat("/dev/syd/sandbox/chmod:off")
716}
717
718/// Checks if chattr sandboxing is enabled.
719///
720/// Returns true if chattr sandboxing is enabled, false otherwise.
721#[no_mangle]
722pub extern "C" fn syd_enabled_chattr() -> bool {
723    stat("/dev/syd/sandbox/chattr?") == 0
724}
725
726/// Enable chattr sandboxing.
727///
728/// Returns 0 on success, negated errno on failure.
729#[no_mangle]
730pub extern "C" fn syd_enable_chattr() -> c_int {
731    stat("/dev/syd/sandbox/chattr:on")
732}
733
734/// Disable chattr sandboxing.
735///
736/// Returns 0 on success, negated errno on failure.
737#[no_mangle]
738pub extern "C" fn syd_disable_chattr() -> c_int {
739    stat("/dev/syd/sandbox/chattr:off")
740}
741
742/// Checks if chroot sandboxing is enabled.
743///
744/// Returns true if chroot sandboxing is enabled, false otherwise.
745#[no_mangle]
746pub extern "C" fn syd_enabled_chroot() -> bool {
747    stat("/dev/syd/sandbox/chroot?") == 0
748}
749
750/// Enable chroot sandboxing.
751///
752/// Returns 0 on success, negated errno on failure.
753#[no_mangle]
754pub extern "C" fn syd_enable_chroot() -> c_int {
755    stat("/dev/syd/sandbox/chroot:on")
756}
757
758/// Disable chroot sandboxing.
759///
760/// Returns 0 on success, negated errno on failure.
761#[no_mangle]
762pub extern "C" fn syd_disable_chroot() -> c_int {
763    stat("/dev/syd/sandbox/chroot:off")
764}
765
766/// Checks if utime sandboxing is enabled.
767///
768/// Returns true if utime sandboxing is enabled, false otherwise.
769#[no_mangle]
770pub extern "C" fn syd_enabled_utime() -> bool {
771    stat("/dev/syd/sandbox/utime?") == 0
772}
773
774/// Enable utime sandboxing.
775///
776/// Returns 0 on success, negated errno on failure.
777#[no_mangle]
778pub extern "C" fn syd_enable_utime() -> c_int {
779    stat("/dev/syd/sandbox/utime:on")
780}
781
782/// Disable utime sandboxing.
783///
784/// Returns 0 on success, negated errno on failure.
785#[no_mangle]
786pub extern "C" fn syd_disable_utime() -> c_int {
787    stat("/dev/syd/sandbox/utime:off")
788}
789
790/// Checks if mkdev sandboxing is enabled.
791///
792/// Returns true if mkdev sandboxing is enabled, false otherwise.
793#[no_mangle]
794pub extern "C" fn syd_enabled_mkdev() -> bool {
795    stat("/dev/syd/sandbox/mkdev?") == 0
796}
797
798/// Enable mkdev sandboxing.
799///
800/// Returns 0 on success, negated errno on failure.
801#[no_mangle]
802pub extern "C" fn syd_enable_mkdev() -> c_int {
803    stat("/dev/syd/sandbox/mkdev:on")
804}
805
806/// Disable mkdev sandboxing.
807///
808/// Returns 0 on success, negated errno on failure.
809#[no_mangle]
810pub extern "C" fn syd_disable_mkdev() -> c_int {
811    stat("/dev/syd/sandbox/mkdev:off")
812}
813
814/// Checks if mkfifo sandboxing is enabled.
815///
816/// Returns true if mkfifo sandboxing is enabled, false otherwise.
817#[no_mangle]
818pub extern "C" fn syd_enabled_mkfifo() -> bool {
819    stat("/dev/syd/sandbox/mkfifo?") == 0
820}
821
822/// Enable mkfifo sandboxing.
823///
824/// Returns 0 on success, negated errno on failure.
825#[no_mangle]
826pub extern "C" fn syd_enable_mkfifo() -> c_int {
827    stat("/dev/syd/sandbox/mkfifo:on")
828}
829
830/// Disable mkfifo sandboxing.
831///
832/// Returns 0 on success, negated errno on failure.
833#[no_mangle]
834pub extern "C" fn syd_disable_mkfifo() -> c_int {
835    stat("/dev/syd/sandbox/mkfifo:off")
836}
837
838/// Checks if mktemp sandboxing is enabled.
839///
840/// Returns true if mktemp sandboxing is enabled, false otherwise.
841#[no_mangle]
842pub extern "C" fn syd_enabled_mktemp() -> bool {
843    stat("/dev/syd/sandbox/mktemp?") == 0
844}
845
846/// Enable mktemp sandboxing.
847///
848/// Returns 0 on success, negated errno on failure.
849#[no_mangle]
850pub extern "C" fn syd_enable_mktemp() -> c_int {
851    stat("/dev/syd/sandbox/mktemp:on")
852}
853
854/// Disable mktemp sandboxing.
855///
856/// Returns 0 on success, negated errno on failure.
857#[no_mangle]
858pub extern "C" fn syd_disable_mktemp() -> c_int {
859    stat("/dev/syd/sandbox/mktemp:off")
860}
861
862/// Checks if net sandboxing is enabled.
863///
864/// Returns true if net sandboxing is enabled, false otherwise.
865#[no_mangle]
866pub extern "C" fn syd_enabled_net() -> bool {
867    stat("/dev/syd/sandbox/net?") == 0
868}
869
870/// Enable net sandboxing.
871///
872/// Returns 0 on success, negated errno on failure.
873#[no_mangle]
874pub extern "C" fn syd_enable_net() -> c_int {
875    stat("/dev/syd/sandbox/net:on")
876}
877
878/// Disable net sandboxing.
879///
880/// Returns 0 on success, negated errno on failure.
881#[no_mangle]
882pub extern "C" fn syd_disable_net() -> c_int {
883    stat("/dev/syd/sandbox/net:off")
884}
885
886/// Checks if memory sandboxing is enabled.
887///
888/// Returns true if memory sandboxing is enabled, false otherwise.
889#[no_mangle]
890pub extern "C" fn syd_enabled_mem() -> bool {
891    stat("/dev/syd/sandbox/mem?") == 0
892}
893
894/// Enable memory sandboxing.
895///
896/// Returns 0 on success, negated errno on failure.
897#[no_mangle]
898pub extern "C" fn syd_enable_mem() -> c_int {
899    stat("/dev/syd/sandbox/mem:on")
900}
901
902/// Disable memory sandboxing.
903///
904/// Returns 0 on success, negated errno on failure.
905#[no_mangle]
906pub extern "C" fn syd_disable_mem() -> c_int {
907    stat("/dev/syd/sandbox/mem:off")
908}
909
910/// Checks if PID sandboxing is enabled.
911///
912/// Returns true if PID sandboxing is enabled, false otherwise.
913#[no_mangle]
914pub extern "C" fn syd_enabled_pid() -> bool {
915    stat("/dev/syd/sandbox/pid?") == 0
916}
917
918/// Enable PID sandboxing.
919///
920/// Returns 0 on success, negated errno on failure.
921#[no_mangle]
922pub extern "C" fn syd_enable_pid() -> c_int {
923    stat("/dev/syd/sandbox/pid:on")
924}
925
926/// Disable PID sandboxing.
927///
928/// Returns 0 on success, negated errno on failure.
929#[no_mangle]
930pub extern "C" fn syd_disable_pid() -> c_int {
931    stat("/dev/syd/sandbox/pid:off")
932}
933
934/// Checks if lock sandboxing is enabled.
935///
936/// Returns true if lock sandboxing is enabled, false otherwise.
937#[no_mangle]
938pub extern "C" fn syd_enabled_lock() -> bool {
939    stat("/dev/syd/sandbox/lock?") == 0
940}
941
942/// Checks if crypt sandboxing is enabled.
943///
944/// Returns true if crypt sandboxing is enabled, false otherwise.
945#[no_mangle]
946pub extern "C" fn syd_enabled_crypt() -> bool {
947    stat("/dev/syd/sandbox/crypt?") == 0
948}
949
950/// Checks if proxy sandboxing is enabled.
951///
952/// Returns true if proxy sandboxing is enabled, false otherwise.
953#[no_mangle]
954pub extern "C" fn syd_enabled_proxy() -> bool {
955    stat("/dev/syd/sandbox/proxy?") == 0
956}
957
958/// Checks if force sandboxing is enabled.
959///
960/// Returns true if force sandboxing is enabled, false otherwise.
961#[no_mangle]
962pub extern "C" fn syd_enabled_force() -> bool {
963    stat("/dev/syd/sandbox/force?") == 0
964}
965
966/// Enable force sandboxing.
967///
968/// Returns 0 on success, negated errno on failure.
969#[no_mangle]
970pub extern "C" fn syd_enable_force() -> c_int {
971    stat("/dev/syd/sandbox/force:on")
972}
973
974/// Disable force sandboxing.
975///
976/// Returns 0 on success, negated errno on failure.
977#[no_mangle]
978pub extern "C" fn syd_disable_force() -> c_int {
979    stat("/dev/syd/sandbox/force:off")
980}
981
982/// Checks if TPE sandboxing is enabled.
983///
984/// Returns true if TPE sandboxing is enabled, false otherwise.
985#[no_mangle]
986pub extern "C" fn syd_enabled_tpe() -> bool {
987    stat("/dev/syd/sandbox/tpe?") == 0
988}
989
990/// Enable TPE sandboxing.
991///
992/// Returns 0 on success, negated errno on failure.
993#[no_mangle]
994pub extern "C" fn syd_enable_tpe() -> c_int {
995    stat("/dev/syd/sandbox/tpe:on")
996}
997
998/// Disable TPE sandboxing.
999///
1000/// Returns 0 on success, negated errno on failure.
1001#[no_mangle]
1002pub extern "C" fn syd_disable_tpe() -> c_int {
1003    stat("/dev/syd/sandbox/tpe:off")
1004}
1005
1006/// Set the default action for Stat Sandboxing.
1007#[no_mangle]
1008pub extern "C" fn syd_default_stat(action: action_t) -> c_int {
1009    // Convert action_t enum to corresponding action string.
1010    let action = match Action::try_from(action) {
1011        Ok(action) => action,
1012        Err(_) => return -EINVAL,
1013    };
1014    stat(&format!("/dev/syd/default/stat:{action}"))
1015}
1016
1017/// Set the default action for Read Sandboxing.
1018#[no_mangle]
1019pub extern "C" fn syd_default_read(action: action_t) -> c_int {
1020    // Convert action_t enum to corresponding action string.
1021    let action = match Action::try_from(action) {
1022        Ok(action) => action,
1023        Err(_) => return -EINVAL,
1024    };
1025    stat(&format!("/dev/syd/default/read:{action}"))
1026}
1027
1028/// Set the default action for Write Sandboxing.
1029#[no_mangle]
1030pub extern "C" fn syd_default_write(action: action_t) -> c_int {
1031    // Convert action_t enum to corresponding action string.
1032    let action = match Action::try_from(action) {
1033        Ok(action) => action,
1034        Err(_) => return -EINVAL,
1035    };
1036    stat(&format!("/dev/syd/default/write:{action}"))
1037}
1038
1039/// Set the default action for Exec Sandboxing.
1040#[no_mangle]
1041pub extern "C" fn syd_default_exec(action: action_t) -> c_int {
1042    // Convert action_t enum to corresponding action string.
1043    let action = match Action::try_from(action) {
1044        Ok(action) => action,
1045        Err(_) => return -EINVAL,
1046    };
1047    stat(&format!("/dev/syd/default/exec:{action}"))
1048}
1049
1050/// Set the default action for Ioctl Sandboxing.
1051#[no_mangle]
1052pub extern "C" fn syd_default_ioctl(action: action_t) -> c_int {
1053    // Convert action_t enum to corresponding action string.
1054    let action = match Action::try_from(action) {
1055        Ok(action) => action,
1056        Err(_) => return -EINVAL,
1057    };
1058    stat(&format!("/dev/syd/default/ioctl:{action}"))
1059}
1060
1061/// Set the default action for Create Sandboxing.
1062#[no_mangle]
1063pub extern "C" fn syd_default_create(action: action_t) -> c_int {
1064    // Convert action_t enum to corresponding action string.
1065    let action = match Action::try_from(action) {
1066        Ok(action) => action,
1067        Err(_) => return -EINVAL,
1068    };
1069    stat(&format!("/dev/syd/default/create:{action}"))
1070}
1071
1072/// Set the default action for Delete Sandboxing.
1073#[no_mangle]
1074pub extern "C" fn syd_default_delete(action: action_t) -> c_int {
1075    // Convert action_t enum to corresponding action string.
1076    let action = match Action::try_from(action) {
1077        Ok(action) => action,
1078        Err(_) => return -EINVAL,
1079    };
1080    stat(&format!("/dev/syd/default/delete:{action}"))
1081}
1082
1083/// Set the default action for Rename Sandboxing.
1084#[no_mangle]
1085pub extern "C" fn syd_default_rename(action: action_t) -> c_int {
1086    // Convert action_t enum to corresponding action string.
1087    let action = match Action::try_from(action) {
1088        Ok(action) => action,
1089        Err(_) => return -EINVAL,
1090    };
1091    stat(&format!("/dev/syd/default/rename:{action}"))
1092}
1093
1094/// Set the default action for Symlink Sandboxing.
1095#[no_mangle]
1096pub extern "C" fn syd_default_symlink(action: action_t) -> c_int {
1097    // Convert action_t enum to corresponding action string.
1098    let action = match Action::try_from(action) {
1099        Ok(action) => action,
1100        Err(_) => return -EINVAL,
1101    };
1102    stat(&format!("/dev/syd/default/symlink:{action}"))
1103}
1104
1105/// Set the default action for Truncate Sandboxing.
1106#[no_mangle]
1107pub extern "C" fn syd_default_truncate(action: action_t) -> c_int {
1108    // Convert action_t enum to corresponding action string.
1109    let action = match Action::try_from(action) {
1110        Ok(action) => action,
1111        Err(_) => return -EINVAL,
1112    };
1113    stat(&format!("/dev/syd/default/truncate:{action}"))
1114}
1115
1116/// Set the default action for Chdir Sandboxing.
1117#[no_mangle]
1118pub extern "C" fn syd_default_chdir(action: action_t) -> c_int {
1119    // Convert action_t enum to corresponding action string.
1120    let action = match Action::try_from(action) {
1121        Ok(action) => action,
1122        Err(_) => return -EINVAL,
1123    };
1124    stat(&format!("/dev/syd/default/chdir:{action}"))
1125}
1126
1127/// Set the default action for Readdir Sandboxing.
1128#[no_mangle]
1129pub extern "C" fn syd_default_readdir(action: action_t) -> c_int {
1130    // Convert action_t enum to corresponding action string.
1131    let action = match Action::try_from(action) {
1132        Ok(action) => action,
1133        Err(_) => return -EINVAL,
1134    };
1135    stat(&format!("/dev/syd/default/readdir:{action}"))
1136}
1137
1138/// Set the default action for Mkdir Sandboxing.
1139#[no_mangle]
1140pub extern "C" fn syd_default_mkdir(action: action_t) -> c_int {
1141    // Convert action_t enum to corresponding action string.
1142    let action = match Action::try_from(action) {
1143        Ok(action) => action,
1144        Err(_) => return -EINVAL,
1145    };
1146    stat(&format!("/dev/syd/default/mkdir:{action}"))
1147}
1148
1149/// Set the default action for Chown Sandboxing.
1150#[no_mangle]
1151pub extern "C" fn syd_default_chown(action: action_t) -> c_int {
1152    // Convert action_t enum to corresponding action string.
1153    let action = match Action::try_from(action) {
1154        Ok(action) => action,
1155        Err(_) => return -EINVAL,
1156    };
1157    stat(&format!("/dev/syd/default/chown:{action}"))
1158}
1159
1160/// Set the default action for Chgrp Sandboxing.
1161#[no_mangle]
1162pub extern "C" fn syd_default_chgrp(action: action_t) -> c_int {
1163    // Convert action_t enum to corresponding action string.
1164    let action = match Action::try_from(action) {
1165        Ok(action) => action,
1166        Err(_) => return -EINVAL,
1167    };
1168    stat(&format!("/dev/syd/default/chgrp:{action}"))
1169}
1170
1171/// Set the default action for Chmod Sandboxing.
1172#[no_mangle]
1173pub extern "C" fn syd_default_chmod(action: action_t) -> c_int {
1174    // Convert action_t enum to corresponding action string.
1175    let action = match Action::try_from(action) {
1176        Ok(action) => action,
1177        Err(_) => return -EINVAL,
1178    };
1179    stat(&format!("/dev/syd/default/chmod:{action}"))
1180}
1181
1182/// Set the default action for Chattr Sandboxing.
1183#[no_mangle]
1184pub extern "C" fn syd_default_chattr(action: action_t) -> c_int {
1185    // Convert action_t enum to corresponding action string.
1186    let action = match Action::try_from(action) {
1187        Ok(action) => action,
1188        Err(_) => return -EINVAL,
1189    };
1190    stat(&format!("/dev/syd/default/chattr:{action}"))
1191}
1192
1193/// Set the default action for Chroot Sandboxing.
1194#[no_mangle]
1195pub extern "C" fn syd_default_chroot(action: action_t) -> c_int {
1196    // Convert action_t enum to corresponding action string.
1197    let action = match Action::try_from(action) {
1198        Ok(action) => action,
1199        Err(_) => return -EINVAL,
1200    };
1201    stat(&format!("/dev/syd/default/chroot:{action}"))
1202}
1203
1204/// Set the default action for Utime Sandboxing.
1205#[no_mangle]
1206pub extern "C" fn syd_default_utime(action: action_t) -> c_int {
1207    // Convert action_t enum to corresponding action string.
1208    let action = match Action::try_from(action) {
1209        Ok(action) => action,
1210        Err(_) => return -EINVAL,
1211    };
1212    stat(&format!("/dev/syd/default/utime:{action}"))
1213}
1214
1215/// Set the default action for Mkdev Sandboxing.
1216#[no_mangle]
1217pub extern "C" fn syd_default_mkdev(action: action_t) -> c_int {
1218    // Convert action_t enum to corresponding action string.
1219    let action = match Action::try_from(action) {
1220        Ok(action) => action,
1221        Err(_) => return -EINVAL,
1222    };
1223    stat(&format!("/dev/syd/default/mkdev:{action}"))
1224}
1225
1226/// Set the default action for Mkfifo Sandboxing.
1227#[no_mangle]
1228pub extern "C" fn syd_default_mkfifo(action: action_t) -> c_int {
1229    // Convert action_t enum to corresponding action string.
1230    let action = match Action::try_from(action) {
1231        Ok(action) => action,
1232        Err(_) => return -EINVAL,
1233    };
1234    stat(&format!("/dev/syd/default/mkfifo:{action}"))
1235}
1236
1237/// Set the default action for Mktemp Sandboxing.
1238#[no_mangle]
1239pub extern "C" fn syd_default_mktemp(action: action_t) -> c_int {
1240    // Convert action_t enum to corresponding action string.
1241    let action = match Action::try_from(action) {
1242        Ok(action) => action,
1243        Err(_) => return -EINVAL,
1244    };
1245    stat(&format!("/dev/syd/default/mktemp:{action}"))
1246}
1247
1248/// Set the default action for Network Sandboxing.
1249#[no_mangle]
1250pub extern "C" fn syd_default_net(action: action_t) -> c_int {
1251    // Convert action_t enum to corresponding action string.
1252    let action = match Action::try_from(action) {
1253        Ok(action) => action,
1254        Err(_) => return -EINVAL,
1255    };
1256    stat(&format!("/dev/syd/default/net:{action}"))
1257}
1258
1259/// Set the default action for IP blocklist violations.
1260#[no_mangle]
1261pub extern "C" fn syd_default_block(action: action_t) -> c_int {
1262    // Convert action_t enum to corresponding action string.
1263    let action = match Action::try_from(action) {
1264        Ok(action) => action,
1265        Err(_) => return -EINVAL,
1266    };
1267    stat(&format!("/dev/syd/default/block:{action}"))
1268}
1269
1270/// Set the default action for Memory Sandboxing.
1271#[no_mangle]
1272pub extern "C" fn syd_default_mem(action: action_t) -> c_int {
1273    // Convert action_t enum to corresponding action string.
1274    let action = match Action::try_from(action) {
1275        Ok(action) => action,
1276        Err(_) => return -EINVAL,
1277    };
1278    stat(&format!("/dev/syd/default/mem:{action}"))
1279}
1280
1281/// Set the default action for PID Sandboxing.
1282#[no_mangle]
1283pub extern "C" fn syd_default_pid(action: action_t) -> c_int {
1284    // Convert action_t enum to corresponding action string.
1285    let action = match Action::try_from(action) {
1286        Ok(action) => action,
1287        Err(_) => return -EINVAL,
1288    };
1289    stat(&format!("/dev/syd/default/pid:{action}"))
1290}
1291
1292/// Set the default action for Force Sandboxing.
1293#[no_mangle]
1294pub extern "C" fn syd_default_force(action: action_t) -> c_int {
1295    // Convert action_t enum to corresponding action string.
1296    let action = match Action::try_from(action) {
1297        Ok(action) => action,
1298        Err(_) => return -EINVAL,
1299    };
1300    stat(&format!("/dev/syd/default/force:{action}"))
1301}
1302
1303/// Set the default action for SegvGuard
1304#[no_mangle]
1305pub extern "C" fn syd_default_segvguard(action: action_t) -> c_int {
1306    // Convert action_t enum to corresponding action string.
1307    let action = match Action::try_from(action) {
1308        Ok(action) => action,
1309        Err(_) => return -EINVAL,
1310    };
1311    stat(&format!("/dev/syd/default/segvguard:{action}"))
1312}
1313
1314/// Set the default action for TPE Sandboxing.
1315#[no_mangle]
1316pub extern "C" fn syd_default_tpe(action: action_t) -> c_int {
1317    // Convert action_t enum to corresponding action string.
1318    let action = match Action::try_from(action) {
1319        Ok(action) => action,
1320        Err(_) => return -EINVAL,
1321    };
1322    stat(&format!("/dev/syd/default/tpe:{action}"))
1323}
1324
1325/// Adds a request to the _ioctl_(2) denylist.
1326#[no_mangle]
1327pub extern "C" fn syd_ioctl_deny(request: u64) -> c_int {
1328    stat(&format!("/dev/syd/ioctl/deny+{request}"))
1329}
1330
1331/// Adds an entry to the Integrity Force map for Force Sandboxing.
1332///
1333/// # Safety
1334///
1335/// This function is marked `unsafe` because it dereferences raw
1336/// pointers, which is inherently unsafe in Rust.
1337///
1338/// The caller must ensure the following conditions are met to safely
1339/// use this function:
1340///
1341/// 1. The `path` pointer must point to a valid, null-terminated C-style
1342///    string.
1343/// 2. The `hash` pointer must point to a valid, null-terminated C-style
1344///    string.
1345#[no_mangle]
1346pub unsafe extern "C" fn syd_force_add(
1347    path: *const c_char,
1348    hash: *const c_char,
1349    action: action_t,
1350) -> c_int {
1351    // Convert action_t enum to corresponding action string.
1352    let action = match Action::try_from(action) {
1353        Ok(action) => action,
1354        Err(_) => return -EINVAL,
1355    };
1356
1357    if path.is_null() || hash.is_null() {
1358        return -EFAULT;
1359    }
1360
1361    // SAFETY: Trust that `path` and `hash` are a null-terminated strings.
1362    let path = unsafe { CStr::from_ptr(path) };
1363    // SAFETY: ditto
1364    let hash = unsafe { CStr::from_ptr(hash) };
1365    let path = match path.to_str() {
1366        Ok(s) => s,
1367        Err(_) => return -EINVAL,
1368    };
1369    let hash = match hash.to_str() {
1370        Ok(s) => s,
1371        Err(_) => return -EINVAL,
1372    };
1373
1374    // Call the stat function with the formatted string.
1375    stat(format!("/dev/syd/force+{path}:{hash}:{action}"))
1376}
1377
1378/// Removes an entry from the Integrity Force map for Force Sandboxing.
1379/// # Safety
1380///
1381/// This function is marked `unsafe` because it dereferences raw
1382/// pointers, which is inherently unsafe in Rust.
1383///
1384/// The caller must ensure the following conditions are met to safely
1385/// use this function:
1386///
1387/// 1. The `path` pointer must point to a valid, null-terminated C-style
1388///    string.
1389#[no_mangle]
1390pub unsafe extern "C" fn syd_force_del(path: *const c_char) -> c_int {
1391    if path.is_null() {
1392        return -EFAULT;
1393    }
1394
1395    // SAFETY: Trust that `path` is a null-terminated string.
1396    let path = unsafe { CStr::from_ptr(path) };
1397    let path = match path.to_str() {
1398        Ok(s) => s,
1399        Err(_) => return -EINVAL,
1400    };
1401
1402    // Call the stat function with the formatted string.
1403    stat(format!("/dev/syd/force-{path}"))
1404}
1405
1406/// Clears the Integrity Force map for Force Sandboxing.
1407#[no_mangle]
1408pub extern "C" fn syd_force_clr() -> c_int {
1409    stat("/dev/syd/force^")
1410}
1411
1412/// Adds to the given actionlist of stat sandboxing.
1413///
1414/// Returns 0 on success, negated errno on failure.
1415#[no_mangle]
1416pub extern "C" fn syd_stat_add(action: action_t, glob: *const c_char) -> c_int {
1417    // Convert action_t enum to corresponding action string.
1418    let action = match Action::try_from(action) {
1419        Ok(action) => action,
1420        Err(_) => return -EINVAL,
1421    };
1422
1423    // Call magic function with add operator.
1424    esyd(&format!("{action}/stat"), glob, b'+')
1425}
1426
1427/// Removes the first instance from the end of the given actionlist of
1428/// stat sandboxing.
1429///
1430/// Returns 0 on success, negated errno on failure.
1431#[no_mangle]
1432pub extern "C" fn syd_stat_del(action: action_t, glob: *const c_char) -> c_int {
1433    // Convert action_t enum to corresponding action string.
1434    let action = match Action::try_from(action) {
1435        Ok(action) => action,
1436        Err(_) => return -EINVAL,
1437    };
1438
1439    // Call magic function with del operator.
1440    esyd(&format!("{action}/stat"), glob, b'-')
1441}
1442
1443/// Removes all matching patterns from the given actionlist of stat sandboxing.
1444///
1445/// Returns 0 on success, negated errno on failure.
1446#[no_mangle]
1447pub extern "C" fn syd_stat_rem(action: action_t, glob: *const c_char) -> c_int {
1448    // Convert action_t enum to corresponding action string.
1449    let action = match Action::try_from(action) {
1450        Ok(action) => action,
1451        Err(_) => return -EINVAL,
1452    };
1453
1454    // Call magic function with rem operator.
1455    esyd(&format!("{action}/stat"), glob, b'^')
1456}
1457
1458/// Adds to the given actionlist of read sandboxing.
1459///
1460/// Returns 0 on success, negated errno on failure.
1461#[no_mangle]
1462pub extern "C" fn syd_read_add(action: action_t, glob: *const c_char) -> c_int {
1463    // Convert action_t enum to corresponding action string.
1464    let action = match Action::try_from(action) {
1465        Ok(action) => action,
1466        Err(_) => return -EINVAL,
1467    };
1468
1469    // Call magic function with add operator.
1470    esyd(&format!("{action}/read"), glob, b'+')
1471}
1472
1473/// Removes the first instance from the end of the given actionlist of
1474/// read sandboxing.
1475///
1476/// Returns 0 on success, negated errno on failure.
1477#[no_mangle]
1478pub extern "C" fn syd_read_del(action: action_t, glob: *const c_char) -> c_int {
1479    // Convert action_t enum to corresponding action string.
1480    let action = match Action::try_from(action) {
1481        Ok(action) => action,
1482        Err(_) => return -EINVAL,
1483    };
1484
1485    // Call magic function with del operator.
1486    esyd(&format!("{action}/read"), glob, b'-')
1487}
1488
1489/// Removes all matching patterns from the given actionlist of read sandboxing.
1490///
1491/// Returns 0 on success, negated errno on failure.
1492#[no_mangle]
1493pub extern "C" fn syd_read_rem(action: action_t, glob: *const c_char) -> c_int {
1494    // Convert action_t enum to corresponding action string.
1495    let action = match Action::try_from(action) {
1496        Ok(action) => action,
1497        Err(_) => return -EINVAL,
1498    };
1499
1500    // Call magic function with rem operator.
1501    esyd(&format!("{action}/read"), glob, b'^')
1502}
1503
1504/// Adds to the given actionlist of write sandboxing.
1505///
1506/// Returns 0 on success, negated errno on failure.
1507#[no_mangle]
1508pub extern "C" fn syd_write_add(action: action_t, glob: *const c_char) -> c_int {
1509    // Convert action_t enum to corresponding action string.
1510    let action = match Action::try_from(action) {
1511        Ok(action) => action,
1512        Err(_) => return -EINVAL,
1513    };
1514
1515    // Call magic function with add operator.
1516    esyd(&format!("{action}/write"), glob, b'+')
1517}
1518
1519/// Removes the first instance from the end of the given actionlist of
1520/// write sandboxing.
1521///
1522/// Returns 0 on success, negated errno on failure.
1523#[no_mangle]
1524pub extern "C" fn syd_write_del(action: action_t, glob: *const c_char) -> c_int {
1525    // Convert action_t enum to corresponding action string.
1526    let action = match Action::try_from(action) {
1527        Ok(action) => action,
1528        Err(_) => return -EINVAL,
1529    };
1530
1531    // Call magic function with del operator.
1532    esyd(&format!("{action}/write"), glob, b'-')
1533}
1534
1535/// Removes all matching patterns from the given actionlist of write sandboxing.
1536///
1537/// Returns 0 on success, negated errno on failure.
1538#[no_mangle]
1539pub extern "C" fn syd_write_rem(action: action_t, glob: *const c_char) -> c_int {
1540    // Convert action_t enum to corresponding action string.
1541    let action = match Action::try_from(action) {
1542        Ok(action) => action,
1543        Err(_) => return -EINVAL,
1544    };
1545
1546    // Call magic function with rem operator.
1547    esyd(&format!("{action}/write"), glob, b'^')
1548}
1549
1550/// Adds to the given actionlist of exec sandboxing.
1551///
1552/// Returns 0 on success, negated errno on failure.
1553#[no_mangle]
1554pub extern "C" fn syd_exec_add(action: action_t, glob: *const c_char) -> c_int {
1555    // Convert action_t enum to corresponding action string.
1556    let action = match Action::try_from(action) {
1557        Ok(action) => action,
1558        Err(_) => return -EINVAL,
1559    };
1560
1561    // Call magic function with add operator.
1562    esyd(&format!("{action}/exec"), glob, b'+')
1563}
1564
1565/// Removes the first instance from the end of the given actionlist of
1566/// exec sandboxing.
1567///
1568/// Returns 0 on success, negated errno on failure.
1569#[no_mangle]
1570pub extern "C" fn syd_exec_del(action: action_t, glob: *const c_char) -> c_int {
1571    // Convert action_t enum to corresponding action string.
1572    let action = match Action::try_from(action) {
1573        Ok(action) => action,
1574        Err(_) => return -EINVAL,
1575    };
1576
1577    // Call magic function with del operator.
1578    esyd(&format!("{action}/exec"), glob, b'-')
1579}
1580
1581/// Removes all matching patterns from the given actionlist of exec sandboxing.
1582///
1583/// Returns 0 on success, negated errno on failure.
1584#[no_mangle]
1585pub extern "C" fn syd_exec_rem(action: action_t, glob: *const c_char) -> c_int {
1586    // Convert action_t enum to corresponding action string.
1587    let action = match Action::try_from(action) {
1588        Ok(action) => action,
1589        Err(_) => return -EINVAL,
1590    };
1591
1592    // Call magic function with rem operator.
1593    esyd(&format!("{action}/exec"), glob, b'^')
1594}
1595
1596/// Adds to the given actionlist of ioctl sandboxing.
1597///
1598/// Returns 0 on success, negated errno on failure.
1599#[no_mangle]
1600pub extern "C" fn syd_ioctl_add(action: action_t, glob: *const c_char) -> c_int {
1601    // Convert action_t enum to corresponding action string.
1602    let action = match Action::try_from(action) {
1603        Ok(action) => action,
1604        Err(_) => return -EINVAL,
1605    };
1606
1607    // Call magic function with add operator.
1608    esyd(&format!("{action}/ioctl"), glob, b'+')
1609}
1610
1611/// Removes the first instance from the end of the given actionlist of
1612/// ioctl sandboxing.
1613///
1614/// Returns 0 on success, negated errno on failure.
1615#[no_mangle]
1616pub extern "C" fn syd_ioctl_del(action: action_t, glob: *const c_char) -> c_int {
1617    // Convert action_t enum to corresponding action string.
1618    let action = match Action::try_from(action) {
1619        Ok(action) => action,
1620        Err(_) => return -EINVAL,
1621    };
1622
1623    // Call magic function with del operator.
1624    esyd(&format!("{action}/ioctl"), glob, b'-')
1625}
1626
1627/// Removes all matching patterns from the given actionlist of ioctl sandboxing.
1628///
1629/// Returns 0 on success, negated errno on failure.
1630#[no_mangle]
1631pub extern "C" fn syd_ioctl_rem(action: action_t, glob: *const c_char) -> c_int {
1632    // Convert action_t enum to corresponding action string.
1633    let action = match Action::try_from(action) {
1634        Ok(action) => action,
1635        Err(_) => return -EINVAL,
1636    };
1637
1638    // Call magic function with rem operator.
1639    esyd(&format!("{action}/ioctl"), glob, b'^')
1640}
1641
1642/// Adds to the given actionlist of create sandboxing.
1643///
1644/// Returns 0 on success, negated errno on failure.
1645#[no_mangle]
1646pub extern "C" fn syd_create_add(action: action_t, glob: *const c_char) -> c_int {
1647    // Convert action_t enum to corresponding action string.
1648    let action = match Action::try_from(action) {
1649        Ok(action) => action,
1650        Err(_) => return -EINVAL,
1651    };
1652
1653    // Call magic function with add operator.
1654    esyd(&format!("{action}/create"), glob, b'+')
1655}
1656
1657/// Removes the first instance from the end of the given actionlist of
1658/// create sandboxing.
1659///
1660/// Returns 0 on success, negated errno on failure.
1661#[no_mangle]
1662pub extern "C" fn syd_create_del(action: action_t, glob: *const c_char) -> c_int {
1663    // Convert action_t enum to corresponding action string.
1664    let action = match Action::try_from(action) {
1665        Ok(action) => action,
1666        Err(_) => return -EINVAL,
1667    };
1668
1669    // Call magic function with del operator.
1670    esyd(&format!("{action}/create"), glob, b'-')
1671}
1672
1673/// Removes all matching patterns from the given actionlist of create sandboxing.
1674///
1675/// Returns 0 on success, negated errno on failure.
1676#[no_mangle]
1677pub extern "C" fn syd_create_rem(action: action_t, glob: *const c_char) -> c_int {
1678    // Convert action_t enum to corresponding action string.
1679    let action = match Action::try_from(action) {
1680        Ok(action) => action,
1681        Err(_) => return -EINVAL,
1682    };
1683
1684    // Call magic function with rem operator.
1685    esyd(&format!("{action}/create"), glob, b'^')
1686}
1687
1688/// Adds to the given actionlist of delete sandboxing.
1689///
1690/// Returns 0 on success, negated errno on failure.
1691#[no_mangle]
1692pub extern "C" fn syd_delete_add(action: action_t, glob: *const c_char) -> c_int {
1693    // Convert action_t enum to corresponding action string.
1694    let action = match Action::try_from(action) {
1695        Ok(action) => action,
1696        Err(_) => return -EINVAL,
1697    };
1698
1699    // Call magic function with add operator.
1700    esyd(&format!("{action}/delete"), glob, b'+')
1701}
1702
1703/// Removes the first instance from the end of the given actionlist of
1704/// delete sandboxing.
1705///
1706/// Returns 0 on success, negated errno on failure.
1707#[no_mangle]
1708pub extern "C" fn syd_delete_del(action: action_t, glob: *const c_char) -> c_int {
1709    // Convert action_t enum to corresponding action string.
1710    let action = match Action::try_from(action) {
1711        Ok(action) => action,
1712        Err(_) => return -EINVAL,
1713    };
1714
1715    // Call magic function with del operator.
1716    esyd(&format!("{action}/delete"), glob, b'-')
1717}
1718
1719/// Removes all matching patterns from the given actionlist of delete sandboxing.
1720///
1721/// Returns 0 on success, negated errno on failure.
1722#[no_mangle]
1723pub extern "C" fn syd_delete_rem(action: action_t, glob: *const c_char) -> c_int {
1724    // Convert action_t enum to corresponding action string.
1725    let action = match Action::try_from(action) {
1726        Ok(action) => action,
1727        Err(_) => return -EINVAL,
1728    };
1729
1730    // Call magic function with rem operator.
1731    esyd(&format!("{action}/delete"), glob, b'^')
1732}
1733
1734/// Adds to the given actionlist of rename sandboxing.
1735///
1736/// Returns 0 on success, negated errno on failure.
1737#[no_mangle]
1738pub extern "C" fn syd_rename_add(action: action_t, glob: *const c_char) -> c_int {
1739    // Convert action_t enum to corresponding action string.
1740    let action = match Action::try_from(action) {
1741        Ok(action) => action,
1742        Err(_) => return -EINVAL,
1743    };
1744
1745    // Call magic function with add operator.
1746    esyd(&format!("{action}/rename"), glob, b'+')
1747}
1748
1749/// Removes the first instance from the end of the given actionlist of
1750/// rename sandboxing.
1751///
1752/// Returns 0 on success, negated errno on failure.
1753#[no_mangle]
1754pub extern "C" fn syd_rename_del(action: action_t, glob: *const c_char) -> c_int {
1755    // Convert action_t enum to corresponding action string.
1756    let action = match Action::try_from(action) {
1757        Ok(action) => action,
1758        Err(_) => return -EINVAL,
1759    };
1760
1761    // Call magic function with del operator.
1762    esyd(&format!("{action}/rename"), glob, b'-')
1763}
1764
1765/// Removes all matching patterns from the given actionlist of rename sandboxing.
1766///
1767/// Returns 0 on success, negated errno on failure.
1768#[no_mangle]
1769pub extern "C" fn syd_rename_rem(action: action_t, glob: *const c_char) -> c_int {
1770    // Convert action_t enum to corresponding action string.
1771    let action = match Action::try_from(action) {
1772        Ok(action) => action,
1773        Err(_) => return -EINVAL,
1774    };
1775
1776    // Call magic function with rem operator.
1777    esyd(&format!("{action}/rename"), glob, b'^')
1778}
1779
1780/// Adds to the given actionlist of symlink sandboxing.
1781///
1782/// Returns 0 on success, negated errno on failure.
1783#[no_mangle]
1784pub extern "C" fn syd_symlink_add(action: action_t, glob: *const c_char) -> c_int {
1785    // Convert action_t enum to corresponding action string.
1786    let action = match Action::try_from(action) {
1787        Ok(action) => action,
1788        Err(_) => return -EINVAL,
1789    };
1790
1791    // Call magic function with add operator.
1792    esyd(&format!("{action}/symlink"), glob, b'+')
1793}
1794
1795/// Removes the first instance from the end of the given actionlist of
1796/// symlink sandboxing.
1797///
1798/// Returns 0 on success, negated errno on failure.
1799#[no_mangle]
1800pub extern "C" fn syd_symlink_del(action: action_t, glob: *const c_char) -> c_int {
1801    // Convert action_t enum to corresponding action string.
1802    let action = match Action::try_from(action) {
1803        Ok(action) => action,
1804        Err(_) => return -EINVAL,
1805    };
1806
1807    // Call magic function with del operator.
1808    esyd(&format!("{action}/symlink"), glob, b'-')
1809}
1810
1811/// Removes all matching patterns from the given actionlist of symlink sandboxing.
1812///
1813/// Returns 0 on success, negated errno on failure.
1814#[no_mangle]
1815pub extern "C" fn syd_symlink_rem(action: action_t, glob: *const c_char) -> c_int {
1816    // Convert action_t enum to corresponding action string.
1817    let action = match Action::try_from(action) {
1818        Ok(action) => action,
1819        Err(_) => return -EINVAL,
1820    };
1821
1822    // Call magic function with rem operator.
1823    esyd(&format!("{action}/symlink"), glob, b'^')
1824}
1825
1826/// Adds to the given actionlist of truncate sandboxing.
1827///
1828/// Returns 0 on success, negated errno on failure.
1829#[no_mangle]
1830pub extern "C" fn syd_truncate_add(action: action_t, glob: *const c_char) -> c_int {
1831    // Convert action_t enum to corresponding action string.
1832    let action = match Action::try_from(action) {
1833        Ok(action) => action,
1834        Err(_) => return -EINVAL,
1835    };
1836
1837    // Call magic function with add operator.
1838    esyd(&format!("{action}/truncate"), glob, b'+')
1839}
1840
1841/// Removes the first instance from the end of the given actionlist of
1842/// truncate sandboxing.
1843///
1844/// Returns 0 on success, negated errno on failure.
1845#[no_mangle]
1846pub extern "C" fn syd_truncate_del(action: action_t, glob: *const c_char) -> c_int {
1847    // Convert action_t enum to corresponding action string.
1848    let action = match Action::try_from(action) {
1849        Ok(action) => action,
1850        Err(_) => return -EINVAL,
1851    };
1852
1853    // Call magic function with del operator.
1854    esyd(&format!("{action}/truncate"), glob, b'-')
1855}
1856
1857/// Removes all matching patterns from the given actionlist of truncate sandboxing.
1858///
1859/// Returns 0 on success, negated errno on failure.
1860#[no_mangle]
1861pub extern "C" fn syd_truncate_rem(action: action_t, glob: *const c_char) -> c_int {
1862    // Convert action_t enum to corresponding action string.
1863    let action = match Action::try_from(action) {
1864        Ok(action) => action,
1865        Err(_) => return -EINVAL,
1866    };
1867
1868    // Call magic function with rem operator.
1869    esyd(&format!("{action}/truncate"), glob, b'^')
1870}
1871
1872/// Adds to the given actionlist of chdir sandboxing.
1873///
1874/// Returns 0 on success, negated errno on failure.
1875#[no_mangle]
1876pub extern "C" fn syd_chdir_add(action: action_t, glob: *const c_char) -> c_int {
1877    // Convert action_t enum to corresponding action string.
1878    let action = match Action::try_from(action) {
1879        Ok(action) => action,
1880        Err(_) => return -EINVAL,
1881    };
1882
1883    // Call magic function with add operator.
1884    esyd(&format!("{action}/chdir"), glob, b'+')
1885}
1886
1887/// Removes the first instance from the end of the given actionlist of
1888/// chdir sandboxing.
1889///
1890/// Returns 0 on success, negated errno on failure.
1891#[no_mangle]
1892pub extern "C" fn syd_chdir_del(action: action_t, glob: *const c_char) -> c_int {
1893    // Convert action_t enum to corresponding action string.
1894    let action = match Action::try_from(action) {
1895        Ok(action) => action,
1896        Err(_) => return -EINVAL,
1897    };
1898
1899    // Call magic function with del operator.
1900    esyd(&format!("{action}/chdir"), glob, b'-')
1901}
1902
1903/// Removes all matching patterns from the given actionlist of chdir sandboxing.
1904///
1905/// Returns 0 on success, negated errno on failure.
1906#[no_mangle]
1907pub extern "C" fn syd_chdir_rem(action: action_t, glob: *const c_char) -> c_int {
1908    // Convert action_t enum to corresponding action string.
1909    let action = match Action::try_from(action) {
1910        Ok(action) => action,
1911        Err(_) => return -EINVAL,
1912    };
1913
1914    // Call magic function with rem operator.
1915    esyd(&format!("{action}/chdir"), glob, b'^')
1916}
1917
1918/// Adds to the given actionlist of readdir sandboxing.
1919///
1920/// Returns 0 on success, negated errno on failure.
1921#[no_mangle]
1922pub extern "C" fn syd_readdir_add(action: action_t, glob: *const c_char) -> c_int {
1923    // Convert action_t enum to corresponding action string.
1924    let action = match Action::try_from(action) {
1925        Ok(action) => action,
1926        Err(_) => return -EINVAL,
1927    };
1928
1929    // Call magic function with add operator.
1930    esyd(&format!("{action}/readdir"), glob, b'+')
1931}
1932
1933/// Removes the first instance from the end of the given actionlist of
1934/// readdir sandboxing.
1935///
1936/// Returns 0 on success, negated errno on failure.
1937#[no_mangle]
1938pub extern "C" fn syd_readdir_del(action: action_t, glob: *const c_char) -> c_int {
1939    // Convert action_t enum to corresponding action string.
1940    let action = match Action::try_from(action) {
1941        Ok(action) => action,
1942        Err(_) => return -EINVAL,
1943    };
1944
1945    // Call magic function with del operator.
1946    esyd(&format!("{action}/readdir"), glob, b'-')
1947}
1948
1949/// Removes all matching patterns from the given actionlist of readdir sandboxing.
1950///
1951/// Returns 0 on success, negated errno on failure.
1952#[no_mangle]
1953pub extern "C" fn syd_readdir_rem(action: action_t, glob: *const c_char) -> c_int {
1954    // Convert action_t enum to corresponding action string.
1955    let action = match Action::try_from(action) {
1956        Ok(action) => action,
1957        Err(_) => return -EINVAL,
1958    };
1959
1960    // Call magic function with del operator.
1961    esyd(&format!("{action}/readdir"), glob, b'^')
1962}
1963
1964/// Adds to the given actionlist of mkdir sandboxing.
1965///
1966/// Returns 0 on success, negated errno on failure.
1967#[no_mangle]
1968pub extern "C" fn syd_mkdir_add(action: action_t, glob: *const c_char) -> c_int {
1969    // Convert action_t enum to corresponding action string.
1970    let action = match Action::try_from(action) {
1971        Ok(action) => action,
1972        Err(_) => return -EINVAL,
1973    };
1974
1975    // Call magic function with add operator.
1976    esyd(&format!("{action}/mkdir"), glob, b'+')
1977}
1978
1979/// Removes the first instance from the end of the given actionlist of
1980/// mkdir sandboxing.
1981///
1982/// Returns 0 on success, negated errno on failure.
1983#[no_mangle]
1984pub extern "C" fn syd_mkdir_del(action: action_t, glob: *const c_char) -> c_int {
1985    // Convert action_t enum to corresponding action string.
1986    let action = match Action::try_from(action) {
1987        Ok(action) => action,
1988        Err(_) => return -EINVAL,
1989    };
1990
1991    // Call magic function with del operator.
1992    esyd(&format!("{action}/mkdir"), glob, b'-')
1993}
1994
1995/// Removes all matching patterns from the given actionlist of mkdir sandboxing.
1996///
1997/// Returns 0 on success, negated errno on failure.
1998#[no_mangle]
1999pub extern "C" fn syd_mkdir_rem(action: action_t, glob: *const c_char) -> c_int {
2000    // Convert action_t enum to corresponding action string.
2001    let action = match Action::try_from(action) {
2002        Ok(action) => action,
2003        Err(_) => return -EINVAL,
2004    };
2005
2006    // Call magic function with del operator.
2007    esyd(&format!("{action}/mkdir"), glob, b'^')
2008}
2009
2010/// Adds to the given actionlist of chown sandboxing.
2011///
2012/// Returns 0 on success, negated errno on failure.
2013#[no_mangle]
2014pub extern "C" fn syd_chown_add(action: action_t, glob: *const c_char) -> c_int {
2015    // Convert action_t enum to corresponding action string.
2016    let action = match Action::try_from(action) {
2017        Ok(action) => action,
2018        Err(_) => return -EINVAL,
2019    };
2020
2021    // Call magic function with add operator.
2022    esyd(&format!("{action}/chown"), glob, b'+')
2023}
2024
2025/// Removes the first instance from the end of the given actionlist of
2026/// chown sandboxing.
2027///
2028/// Returns 0 on success, negated errno on failure.
2029#[no_mangle]
2030pub extern "C" fn syd_chown_del(action: action_t, glob: *const c_char) -> c_int {
2031    // Convert action_t enum to corresponding action string.
2032    let action = match Action::try_from(action) {
2033        Ok(action) => action,
2034        Err(_) => return -EINVAL,
2035    };
2036
2037    // Call magic function with del operator.
2038    esyd(&format!("{action}/chown"), glob, b'-')
2039}
2040
2041/// Removes all matching patterns from the given actionlist of chown sandboxing.
2042///
2043/// Returns 0 on success, negated errno on failure.
2044#[no_mangle]
2045pub extern "C" fn syd_chown_rem(action: action_t, glob: *const c_char) -> c_int {
2046    // Convert action_t enum to corresponding action string.
2047    let action = match Action::try_from(action) {
2048        Ok(action) => action,
2049        Err(_) => return -EINVAL,
2050    };
2051
2052    // Call magic function with rem operator.
2053    esyd(&format!("{action}/chown"), glob, b'^')
2054}
2055
2056/// Adds to the given actionlist of chgrp sandboxing.
2057///
2058/// Returns 0 on success, negated errno on failure.
2059#[no_mangle]
2060pub extern "C" fn syd_chgrp_add(action: action_t, glob: *const c_char) -> c_int {
2061    // Convert action_t enum to corresponding action string.
2062    let action = match Action::try_from(action) {
2063        Ok(action) => action,
2064        Err(_) => return -EINVAL,
2065    };
2066
2067    // Call magic function with add operator.
2068    esyd(&format!("{action}/chgrp"), glob, b'+')
2069}
2070
2071/// Removes the first instance from the end of the given actionlist of
2072/// chgrp sandboxing.
2073///
2074/// Returns 0 on success, negated errno on failure.
2075#[no_mangle]
2076pub extern "C" fn syd_chgrp_del(action: action_t, glob: *const c_char) -> c_int {
2077    // Convert action_t enum to corresponding action string.
2078    let action = match Action::try_from(action) {
2079        Ok(action) => action,
2080        Err(_) => return -EINVAL,
2081    };
2082
2083    // Call magic function with del operator.
2084    esyd(&format!("{action}/chgrp"), glob, b'-')
2085}
2086
2087/// Removes all matching patterns from the given actionlist of chgrp sandboxing.
2088///
2089/// Returns 0 on success, negated errno on failure.
2090#[no_mangle]
2091pub extern "C" fn syd_chgrp_rem(action: action_t, glob: *const c_char) -> c_int {
2092    // Convert action_t enum to corresponding action string.
2093    let action = match Action::try_from(action) {
2094        Ok(action) => action,
2095        Err(_) => return -EINVAL,
2096    };
2097
2098    // Call magic function with rem operator.
2099    esyd(&format!("{action}/chgrp"), glob, b'^')
2100}
2101
2102/// Adds to the given actionlist of chmod sandboxing.
2103///
2104/// Returns 0 on success, negated errno on failure.
2105#[no_mangle]
2106pub extern "C" fn syd_chmod_add(action: action_t, glob: *const c_char) -> c_int {
2107    // Convert action_t enum to corresponding action string.
2108    let action = match Action::try_from(action) {
2109        Ok(action) => action,
2110        Err(_) => return -EINVAL,
2111    };
2112
2113    // Call magic function with add operator.
2114    esyd(&format!("{action}/chmod"), glob, b'+')
2115}
2116
2117/// Removes the first instance from the end of the given actionlist of
2118/// chmod sandboxing.
2119///
2120/// Returns 0 on success, negated errno on failure.
2121#[no_mangle]
2122pub extern "C" fn syd_chmod_del(action: action_t, glob: *const c_char) -> c_int {
2123    // Convert action_t enum to corresponding action string.
2124    let action = match Action::try_from(action) {
2125        Ok(action) => action,
2126        Err(_) => return -EINVAL,
2127    };
2128
2129    // Call magic function with del operator.
2130    esyd(&format!("{action}/chmod"), glob, b'-')
2131}
2132
2133/// Removes all matching patterns from the given actionlist of chmod sandboxing.
2134///
2135/// Returns 0 on success, negated errno on failure.
2136#[no_mangle]
2137pub extern "C" fn syd_chmod_rem(action: action_t, glob: *const c_char) -> c_int {
2138    // Convert action_t enum to corresponding action string.
2139    let action = match Action::try_from(action) {
2140        Ok(action) => action,
2141        Err(_) => return -EINVAL,
2142    };
2143
2144    // Call magic function with rem operator.
2145    esyd(&format!("{action}/chmod"), glob, b'^')
2146}
2147
2148/// Adds to the given actionlist of chattr sandboxing.
2149///
2150/// Returns 0 on success, negated errno on failure.
2151#[no_mangle]
2152pub extern "C" fn syd_chattr_add(action: action_t, glob: *const c_char) -> c_int {
2153    // Convert action_t enum to corresponding action string.
2154    let action = match Action::try_from(action) {
2155        Ok(action) => action,
2156        Err(_) => return -EINVAL,
2157    };
2158
2159    // Call magic function with add operator.
2160    esyd(&format!("{action}/chattr"), glob, b'+')
2161}
2162
2163/// Removes the first instance from the end of the given actionlist of
2164/// chattr sandboxing.
2165///
2166/// Returns 0 on success, negated errno on failure.
2167#[no_mangle]
2168pub extern "C" fn syd_chattr_del(action: action_t, glob: *const c_char) -> c_int {
2169    // Convert action_t enum to corresponding action string.
2170    let action = match Action::try_from(action) {
2171        Ok(action) => action,
2172        Err(_) => return -EINVAL,
2173    };
2174
2175    // Call magic function with del operator.
2176    esyd(&format!("{action}/chattr"), glob, b'-')
2177}
2178
2179/// Removes all matching patterns from the given actionlist of chattr sandboxing.
2180///
2181/// Returns 0 on success, negated errno on failure.
2182#[no_mangle]
2183pub extern "C" fn syd_chattr_rem(action: action_t, glob: *const c_char) -> c_int {
2184    // Convert action_t enum to corresponding action string.
2185    let action = match Action::try_from(action) {
2186        Ok(action) => action,
2187        Err(_) => return -EINVAL,
2188    };
2189
2190    // Call magic function with rem operator.
2191    esyd(&format!("{action}/chattr"), glob, b'^')
2192}
2193
2194/// Adds to the given actionlist of chroot sandboxing.
2195///
2196/// Returns 0 on success, negated errno on failure.
2197#[no_mangle]
2198pub extern "C" fn syd_chroot_add(action: action_t, glob: *const c_char) -> c_int {
2199    // Convert action_t enum to corresponding action string.
2200    let action = match Action::try_from(action) {
2201        Ok(action) => action,
2202        Err(_) => return -EINVAL,
2203    };
2204
2205    // Call magic function with add operator.
2206    esyd(&format!("{action}/chroot"), glob, b'+')
2207}
2208
2209/// Removes the first instance from the end of the given actionlist of
2210/// chroot sandboxing.
2211///
2212/// Returns 0 on success, negated errno on failure.
2213#[no_mangle]
2214pub extern "C" fn syd_chroot_del(action: action_t, glob: *const c_char) -> c_int {
2215    // Convert action_t enum to corresponding action string.
2216    let action = match Action::try_from(action) {
2217        Ok(action) => action,
2218        Err(_) => return -EINVAL,
2219    };
2220
2221    // Call magic function with del operator.
2222    esyd(&format!("{action}/chroot"), glob, b'-')
2223}
2224
2225/// Removes all matching patterns from the given actionlist of chroot sandboxing.
2226///
2227/// Returns 0 on success, negated errno on failure.
2228#[no_mangle]
2229pub extern "C" fn syd_chroot_rem(action: action_t, glob: *const c_char) -> c_int {
2230    // Convert action_t enum to corresponding action string.
2231    let action = match Action::try_from(action) {
2232        Ok(action) => action,
2233        Err(_) => return -EINVAL,
2234    };
2235
2236    // Call magic function with rem operator.
2237    esyd(&format!("{action}/chroot"), glob, b'^')
2238}
2239
2240/// Adds to the given actionlist of utime sandboxing.
2241///
2242/// Returns 0 on success, negated errno on failure.
2243#[no_mangle]
2244pub extern "C" fn syd_utime_add(action: action_t, glob: *const c_char) -> c_int {
2245    // Convert action_t enum to corresponding action string.
2246    let action = match Action::try_from(action) {
2247        Ok(action) => action,
2248        Err(_) => return -EINVAL,
2249    };
2250
2251    // Call magic function with add operator.
2252    esyd(&format!("{action}/utime"), glob, b'+')
2253}
2254
2255/// Removes the first instance from the end of the given actionlist of
2256/// utime sandboxing.
2257///
2258/// Returns 0 on success, negated errno on failure.
2259#[no_mangle]
2260pub extern "C" fn syd_utime_del(action: action_t, glob: *const c_char) -> c_int {
2261    // Convert action_t enum to corresponding action string.
2262    let action = match Action::try_from(action) {
2263        Ok(action) => action,
2264        Err(_) => return -EINVAL,
2265    };
2266
2267    // Call magic function with del operator.
2268    esyd(&format!("{action}/utime"), glob, b'-')
2269}
2270
2271/// Removes all matching patterns from the given actionlist of utime sandboxing.
2272///
2273/// Returns 0 on success, negated errno on failure.
2274#[no_mangle]
2275pub extern "C" fn syd_utime_rem(action: action_t, glob: *const c_char) -> c_int {
2276    // Convert action_t enum to corresponding action string.
2277    let action = match Action::try_from(action) {
2278        Ok(action) => action,
2279        Err(_) => return -EINVAL,
2280    };
2281
2282    // Call magic function with rem operator.
2283    esyd(&format!("{action}/utime"), glob, b'^')
2284}
2285
2286/// Adds to the given actionlist of mkdev sandboxing.
2287///
2288/// Returns 0 on success, negated errno on failure.
2289#[no_mangle]
2290pub extern "C" fn syd_mkdev_add(action: action_t, glob: *const c_char) -> c_int {
2291    // Convert action_t enum to corresponding action string.
2292    let action = match Action::try_from(action) {
2293        Ok(action) => action,
2294        Err(_) => return -EINVAL,
2295    };
2296
2297    // Call magic function with add operator.
2298    esyd(&format!("{action}/mkdev"), glob, b'+')
2299}
2300
2301/// Removes the first instance from the end of the given actionlist of
2302/// mkdev sandboxing.
2303///
2304/// Returns 0 on success, negated errno on failure.
2305#[no_mangle]
2306pub extern "C" fn syd_mkdev_del(action: action_t, glob: *const c_char) -> c_int {
2307    // Convert action_t enum to corresponding action string.
2308    let action = match Action::try_from(action) {
2309        Ok(action) => action,
2310        Err(_) => return -EINVAL,
2311    };
2312
2313    // Call magic function with del operator.
2314    esyd(&format!("{action}/mkdev"), glob, b'-')
2315}
2316
2317/// Removes all matching patterns from the given actionlist of mkdev sandboxing.
2318///
2319/// Returns 0 on success, negated errno on failure.
2320#[no_mangle]
2321pub extern "C" fn syd_mkdev_rem(action: action_t, glob: *const c_char) -> c_int {
2322    // Convert action_t enum to corresponding action string.
2323    let action = match Action::try_from(action) {
2324        Ok(action) => action,
2325        Err(_) => return -EINVAL,
2326    };
2327
2328    // Call magic function with rem operator.
2329    esyd(&format!("{action}/mkdev"), glob, b'^')
2330}
2331
2332/// Adds to the given actionlist of mkfifo sandboxing.
2333///
2334/// Returns 0 on success, negated errno on failure.
2335#[no_mangle]
2336pub extern "C" fn syd_mkfifo_add(action: action_t, glob: *const c_char) -> c_int {
2337    // Convert action_t enum to corresponding action string.
2338    let action = match Action::try_from(action) {
2339        Ok(action) => action,
2340        Err(_) => return -EINVAL,
2341    };
2342
2343    // Call magic function with add operator.
2344    esyd(&format!("{action}/mkfifo"), glob, b'+')
2345}
2346
2347/// Removes the first instance from the end of the given actionlist of
2348/// mkfifo sandboxing.
2349///
2350/// Returns 0 on success, negated errno on failure.
2351#[no_mangle]
2352pub extern "C" fn syd_mkfifo_del(action: action_t, glob: *const c_char) -> c_int {
2353    // Convert action_t enum to corresponding action string.
2354    let action = match Action::try_from(action) {
2355        Ok(action) => action,
2356        Err(_) => return -EINVAL,
2357    };
2358
2359    // Call magic function with del operator.
2360    esyd(&format!("{action}/mkfifo"), glob, b'-')
2361}
2362
2363/// Removes all matching patterns from the given actionlist of mkfifo sandboxing.
2364///
2365/// Returns 0 on success, negated errno on failure.
2366#[no_mangle]
2367pub extern "C" fn syd_mkfifo_rem(action: action_t, glob: *const c_char) -> c_int {
2368    // Convert action_t enum to corresponding action string.
2369    let action = match Action::try_from(action) {
2370        Ok(action) => action,
2371        Err(_) => return -EINVAL,
2372    };
2373
2374    // Call magic function with rem operator.
2375    esyd(&format!("{action}/mkfifo"), glob, b'^')
2376}
2377
2378/// Adds to the given actionlist of mktemp sandboxing.
2379///
2380/// Returns 0 on success, negated errno on failure.
2381#[no_mangle]
2382pub extern "C" fn syd_mktemp_add(action: action_t, glob: *const c_char) -> c_int {
2383    // Convert action_t enum to corresponding action string.
2384    let action = match Action::try_from(action) {
2385        Ok(action) => action,
2386        Err(_) => return -EINVAL,
2387    };
2388
2389    // Call magic function with add operator.
2390    esyd(&format!("{action}/mktemp"), glob, b'+')
2391}
2392
2393/// Removes the first instance from the end of the given actionlist of
2394/// mktemp sandboxing.
2395///
2396/// Returns 0 on success, negated errno on failure.
2397#[no_mangle]
2398pub extern "C" fn syd_mktemp_del(action: action_t, glob: *const c_char) -> c_int {
2399    // Convert action_t enum to corresponding action string.
2400    let action = match Action::try_from(action) {
2401        Ok(action) => action,
2402        Err(_) => return -EINVAL,
2403    };
2404
2405    // Call magic function with del operator.
2406    esyd(&format!("{action}/mktemp"), glob, b'-')
2407}
2408
2409/// Removes all matching patterns from the given actionlist of mktemp sandboxing.
2410///
2411/// Returns 0 on success, negated errno on failure.
2412#[no_mangle]
2413pub extern "C" fn syd_mktemp_rem(action: action_t, glob: *const c_char) -> c_int {
2414    // Convert action_t enum to corresponding action string.
2415    let action = match Action::try_from(action) {
2416        Ok(action) => action,
2417        Err(_) => return -EINVAL,
2418    };
2419
2420    // Call magic function with rem operator.
2421    esyd(&format!("{action}/mktemp"), glob, b'^')
2422}
2423
2424/// Adds to the given actionlist of net/bind sandboxing.
2425///
2426/// Returns 0 on success, negated errno on failure.
2427#[no_mangle]
2428pub extern "C" fn syd_net_bind_add(action: action_t, glob: *const c_char) -> c_int {
2429    // Convert action_t enum to corresponding action string.
2430    let action = match Action::try_from(action) {
2431        Ok(action) => action,
2432        Err(_) => return -EINVAL,
2433    };
2434
2435    // Call magic function with add operator.
2436    esyd(&format!("{action}/net/bind"), glob, b'+')
2437}
2438
2439/// Removes the first instance from the end of the given actionlist of
2440/// net/bind sandboxing.
2441///
2442/// Returns 0 on success, negated errno on failure.
2443#[no_mangle]
2444pub extern "C" fn syd_net_bind_del(action: action_t, glob: *const c_char) -> c_int {
2445    // Convert action_t enum to corresponding action string.
2446    let action = match Action::try_from(action) {
2447        Ok(action) => action,
2448        Err(_) => return -EINVAL,
2449    };
2450
2451    // Call magic function with del operator.
2452    esyd(&format!("{action}/net/bind"), glob, b'-')
2453}
2454
2455/// Removes all matching patterns from the given actionlist of net/bind sandboxing.
2456///
2457/// Returns 0 on success, negated errno on failure.
2458#[no_mangle]
2459pub extern "C" fn syd_net_bind_rem(action: action_t, glob: *const c_char) -> c_int {
2460    // Convert action_t enum to corresponding action string.
2461    let action = match Action::try_from(action) {
2462        Ok(action) => action,
2463        Err(_) => return -EINVAL,
2464    };
2465
2466    // Call magic function with rem operator.
2467    esyd(&format!("{action}/net/bind"), glob, b'^')
2468}
2469
2470/// Adds to the given actionlist of net/connect sandboxing.
2471///
2472/// Returns 0 on success, negated errno on failure.
2473#[no_mangle]
2474pub extern "C" fn syd_net_connect_add(action: action_t, glob: *const c_char) -> c_int {
2475    // Convert action_t enum to corresponding action string.
2476    let action = match Action::try_from(action) {
2477        Ok(action) => action,
2478        Err(_) => return -EINVAL,
2479    };
2480
2481    // Call magic function with add operator.
2482    esyd(&format!("{action}/net/connect"), glob, b'+')
2483}
2484
2485/// Removes the first instance from the end of the given actionlist of
2486/// net/connect sandboxing.
2487///
2488/// Returns 0 on success, negated errno on failure.
2489#[no_mangle]
2490pub extern "C" fn syd_net_connect_del(action: action_t, glob: *const c_char) -> c_int {
2491    // Convert action_t enum to corresponding action string.
2492    let action = match Action::try_from(action) {
2493        Ok(action) => action,
2494        Err(_) => return -EINVAL,
2495    };
2496
2497    // Call magic function with del operator.
2498    esyd(&format!("{action}/net/connect"), glob, b'-')
2499}
2500
2501/// Removes all matching patterns from the given actionlist of net/connect sandboxing.
2502///
2503/// Returns 0 on success, negated errno on failure.
2504#[no_mangle]
2505pub extern "C" fn syd_net_connect_rem(action: action_t, glob: *const c_char) -> c_int {
2506    // Convert action_t enum to corresponding action string.
2507    let action = match Action::try_from(action) {
2508        Ok(action) => action,
2509        Err(_) => return -EINVAL,
2510    };
2511
2512    // Call magic function with rem operator.
2513    esyd(&format!("{action}/net/connect"), glob, b'^')
2514}
2515
2516/// Adds to the given actionlist of net/sendfd sandboxing.
2517///
2518/// Returns 0 on success, negated errno on failure.
2519#[no_mangle]
2520pub extern "C" fn syd_net_sendfd_add(action: action_t, glob: *const c_char) -> c_int {
2521    // Convert action_t enum to corresponding action string.
2522    let action = match Action::try_from(action) {
2523        Ok(action) => action,
2524        Err(_) => return -EINVAL,
2525    };
2526
2527    // Call magic function with add operator.
2528    esyd(&format!("{action}/net/sendfd"), glob, b'+')
2529}
2530
2531/// Removes the first instance from the end of the given actionlist of
2532/// net/sendfd sandboxing.
2533///
2534/// Returns 0 on success, negated errno on failure.
2535#[no_mangle]
2536pub extern "C" fn syd_net_sendfd_del(action: action_t, glob: *const c_char) -> c_int {
2537    // Convert action_t enum to corresponding action string.
2538    let action = match Action::try_from(action) {
2539        Ok(action) => action,
2540        Err(_) => return -EINVAL,
2541    };
2542
2543    // Call magic function with del operator.
2544    esyd(&format!("{action}/net/sendfd"), glob, b'-')
2545}
2546
2547/// Removes all matching patterns from the given actionlist of net/sendfd sandboxing.
2548///
2549/// Returns 0 on success, negated errno on failure.
2550#[no_mangle]
2551pub extern "C" fn syd_net_sendfd_rem(action: action_t, glob: *const c_char) -> c_int {
2552    // Convert action_t enum to corresponding action string.
2553    let action = match Action::try_from(action) {
2554        Ok(action) => action,
2555        Err(_) => return -EINVAL,
2556    };
2557
2558    // Call magic function with rem operator.
2559    esyd(&format!("{action}/net/sendfd"), glob, b'^')
2560}
2561
2562/// Adds to the given actionlist of net/link sandboxing.
2563///
2564/// Returns 0 on success, negated errno on failure.
2565#[no_mangle]
2566pub extern "C" fn syd_net_link_add(action: action_t, family: *const c_char) -> c_int {
2567    // Convert action_t enum to corresponding action string.
2568    let action = match Action::try_from(action) {
2569        Ok(action) => action,
2570        Err(_) => return -EINVAL,
2571    };
2572
2573    // Call magic function with add operator.
2574    esyd(&format!("{action}/net/link"), family, b'+')
2575}
2576
2577/// Removes the first instance from the end of the given actionlist of
2578/// net/link sandboxing.
2579///
2580/// Returns 0 on success, negated errno on failure.
2581#[no_mangle]
2582pub extern "C" fn syd_net_link_del(action: action_t, family: *const c_char) -> c_int {
2583    // Convert action_t enum to corresponding action string.
2584    let action = match Action::try_from(action) {
2585        Ok(action) => action,
2586        Err(_) => return -EINVAL,
2587    };
2588
2589    // Call magic function with del operator.
2590    esyd(&format!("{action}/net/link"), family, b'-')
2591}
2592
2593/// Removes all matching patterns from the given actionlist of net/link sandboxing.
2594///
2595/// Returns 0 on success, negated errno on failure.
2596#[no_mangle]
2597pub extern "C" fn syd_net_link_rem(action: action_t, family: *const c_char) -> c_int {
2598    // Convert action_t enum to corresponding action string.
2599    let action = match Action::try_from(action) {
2600        Ok(action) => action,
2601        Err(_) => return -EINVAL,
2602    };
2603
2604    // Call magic function with rem operator.
2605    esyd(&format!("{action}/net/link"), family, b'^')
2606}
2607
2608/// Set syd maximum per-process memory usage limit for memory sandboxing.
2609///
2610/// parse-size crate is used to parse the value so formatted strings are OK.
2611///
2612/// Returns 0 on success, negated errno on failure.
2613#[no_mangle]
2614pub extern "C" fn syd_mem_max(size: *const c_char) -> c_int {
2615    esyd("mem/max", size, b':')
2616}
2617
2618/// Set syd maximum per-process virtual memory usage limit for memory sandboxing.
2619///
2620/// parse-size crate is used to parse the value so formatted strings are OK.
2621///
2622/// Returns 0 on success, negated errno on failure.
2623#[no_mangle]
2624pub extern "C" fn syd_mem_vm_max(size: *const c_char) -> c_int {
2625    esyd("mem/vm_max", size, b':')
2626}
2627
2628/// Set syd maximum process id limit for PID sandboxing
2629///
2630/// Returns 0 on success, negated errno on failure.
2631#[no_mangle]
2632pub extern "C" fn syd_pid_max(size: usize) -> c_int {
2633    stat(&format!("/dev/syd/pid/max:{size}"))
2634}
2635
2636/// Specify SegvGuard entry expiry timeout in seconds.
2637/// Setting this timeout to 0 effectively disables SegvGuard.
2638///
2639/// Returns 0 on success, negated errno on failure.
2640#[no_mangle]
2641pub extern "C" fn syd_segvguard_expiry(timeout: u64) -> c_int {
2642    stat(&format!("/dev/syd/segvguard/expiry:{timeout}"))
2643}
2644
2645/// Specify SegvGuard entry suspension timeout in seconds.
2646///
2647/// Returns 0 on success, negated errno on failure.
2648#[no_mangle]
2649pub extern "C" fn syd_segvguard_suspension(timeout: u64) -> c_int {
2650    stat(&format!("/dev/syd/segvguard/suspension:{timeout}"))
2651}
2652
2653/// Specify SegvGuard max number of crashes before suspension.
2654///
2655/// Returns 0 on success, negated errno on failure.
2656#[no_mangle]
2657pub extern "C" fn syd_segvguard_maxcrashes(max: u8) -> c_int {
2658    stat(&format!("/dev/syd/segvguard/maxcrashes:{max}"))
2659}
2660
2661/// Execute a command outside the sandbox without sandboxing
2662///
2663/// # Safety
2664///
2665/// This function is marked `unsafe` because it dereferences raw
2666/// pointers, which is inherently unsafe in Rust.
2667///
2668/// The caller must ensure the following conditions are met to safely
2669/// use this function:
2670///
2671/// 1. The `file` pointer must point to a valid, null-terminated C-style
2672///    string.
2673///
2674/// 2. The `argv` pointer must point to an array of pointers, where each
2675///    pointer refers to a valid, null-terminated C-style string. The
2676///    last pointer in the array must be null, indicating the end of the
2677///    array.
2678///
2679/// 3. The memory pointed to by `file` and `argv` must remain valid for
2680///    the duration of the call.
2681///
2682/// Failing to uphold these guarantees can lead to undefined behavior,
2683/// including memory corruption and data races.
2684///
2685/// Returns 0 on success, negated errno on failure.
2686#[no_mangle]
2687pub unsafe extern "C" fn syd_exec(file: *const c_char, argv: *const *const c_char) -> c_int {
2688    if file.is_null() || argv.is_null() {
2689        return -EFAULT;
2690    }
2691
2692    // SAFETY: Trust that `file` is a null-terminated string.
2693    let file = CStr::from_ptr(file);
2694    let file = OsStr::from_bytes(file.to_bytes());
2695
2696    let mut path = OsString::from("/dev/syd/cmd/exec!");
2697    path.push(file);
2698
2699    let mut idx: isize = 0;
2700    while !(*argv.offset(idx)).is_null() {
2701        // SAFETY: Trust that each `argv` element is a null-terminated string.
2702        let arg = CStr::from_ptr(*argv.offset(idx));
2703        let arg = OsStr::from_bytes(arg.to_bytes());
2704
2705        path.push(OsStr::from_bytes(&[b'\x1F'])); // ASCII Unit Separator
2706        path.push(arg);
2707
2708        idx = idx.saturating_add(1);
2709    }
2710
2711    let path = PathBuf::from(path);
2712    stat(path)
2713}