Files
Christian Brauner 626261b486 rust: add the systemd_shared crate
This adds the crate programs are written against. It's the idiomatic
layer on top of systemd_shared_sys and only contains what a first
program needs. Nothing is added speculatively. This is the core of it,
the remaining modules follow one by one.

There's no std and, like in the kernel's Rust code, no alloc crate
either. Its collections abort the program when memory runs out but an
allocation failure has to be handled like it is in C. So the crate
fills the gaps std and alloc would fill otherwise:

- Box and Vec work like the kernel's. Everything that allocates
  returns AllocError on failure, which converts into -ENOMEM, and
  there are no infallible variants. Memory comes from malloc() and
  posix_memalign() so Rust and C allocations share one heap. There's
  no global allocator, so a program that uses the alloc crate
  regardless doesn't link.

- The panic handler logs the location at LOG_CRIT and aborts like a
  failed assert().

- print!() and println!() write to C's stdout so their output stays in
  order with the output of the C code a program calls.

- The prelude brings in Box and Vec.

The precompiled core crate is built for unwinding and refers to
rust_eh_personality. With panic=abort nothing unwinds so that's an
abort() stub. A program that pulls in std doesn't link as std brings
a second panic handler.

The modules are:

- errno: Errno is a positive errno value that is never zero so
  Result<(), Errno> is a machine word. Every errno has an associated
  constant such as Errno::ENOENT. The symbolic name comes from
  errno_name_no_fallback() and the message from strerror_or_eof().
  check() handles the negative errno convention and from_result() the
  int an extern "C" callback returns. Conversions from TryFromIntError,
  Utf8Error and AllocError make ? just work.

- log: The log_*! macros mirror their C counterparts. log_*_errno!
  evaluates to the Errno just like the C version returns it. Passing
  SYNTHETIC_ERRNO(EINVAL) as the error leaves out ERRNO= like
  SYNTHETIC_ERRNO() does in C. Messages are formatted into a LINE_MAX
  buffer on the stack and handed to log_dispatch_internal(). That's the
  path log_internalv() takes after vsnprintf(). So there's no
  allocation and truncation works like in C. file!() is the remapped
  path so CODE_FILE= matches the C programs.

- cstr: OwnedCStr is for strings C allocated. It can also be created
  via strdup(), memdup_suffix0() and formatting and reports -ENOMEM
  instead of aborting when memory runs out. Formatting measures the
  output first and then formats into one allocation of exactly that
  size, like the kernel's CString::try_from_fmt(). display() shows a C
  string in a log message without allocating and strip_prefix() is
  startswith().

- prelude: use systemd_shared::prelude::* brings in everything a
  program needs.

Names mirror the C names with Rust casing and without repeating the
namespace. Every unsafe block carries a SAFETY comment and every unsafe
fn a Safety section. The build enforces both. .clippy.toml refuses
abort(). panic!() logs why first so use that instead.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-10-23 16:34:46 +02:00

9 lines
228 B
TOML

# SPDX-License-Identifier: LGPL-2.1-or-later
msrv = "1.85"
check-private-items = true
[[disallowed-methods]]
path = "systemd_shared_sys::abort"
reason = "panic!() instead, the panic handler logs where and why before aborting"