An error returned by a Linx.User operation.
Built from a failed File.read/1 / File.write/2 against one of
the user-namespace procfs files (/proc/<pid>/uid_map,
/proc/<pid>/gid_map, /proc/<pid>/setgroups). The shape:
:path— the procfs path the operation targeted.:operation— what we were trying to do, as an atom (:set_uid_map,:set_gid_map,:deny_setgroups,:read_uid_map,:read_gid_map).:errno— the POSIX errno as an atom (:enoent,:eperm,:einval, …).:code— the matching positive errno integer, ornilif we don't have a mapping for this atom. Included for symmetry withLinx.Mount.Error/Linx.Cgroup.Error.
Pattern-match on :errno and :operation to handle specific
failures:
case Linx.User.set_uid_map(pid, [{0, 1000, 1}]) do
:ok ->
:mapped
{:error, %Linx.User.Error{errno: :eperm}} ->
# No CAP_SETUID in the parent user ns; the map is too
# broad for an unprivileged caller, or the map was
# already written (write-once).
:no_perm
{:error, %Linx.User.Error{errno: :enoent}} ->
# The target pid is gone.
:pid_dead
endImplements Exception, so an error can be raised or rendered
with Exception.message/1.
Caller-side input mistakes (e.g. a non-list mappings,
negative ids, zero-length entries) surface as
{:error, {:bad_map, reason}} instead — distinct from kernel
rejections, mirroring Linx.Mount's :bad_flag / %Error{}
split.
Summary
Functions
Builds a %Linx.User.Error{} from a posix-atom errno, the
procfs path that failed, and the operation we attempted.
Types
@type operation() ::
:set_uid_map | :set_gid_map | :deny_setgroups | :read_uid_map | :read_gid_map
@type t() :: %Linx.User.Error{ __exception__: true, code: pos_integer() | nil, errno: atom(), operation: operation(), path: Path.t() }