From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from atuin.qyliss.net (localhost [IPv6:::1]) by atuin.qyliss.net (Postfix) with ESMTP id F24D7ADC5; Sat, 20 Jun 2026 17:32:56 +0000 (UTC) Received: by atuin.qyliss.net (Postfix, from userid 993) id 3CC35AFD1; Sat, 20 Jun 2026 17:32:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on atuin.qyliss.net X-Spam-Level: X-Spam-Status: No, score=-0.1 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DMARC_PASS,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=4.0.1 Received: from mail-yw1-x112e.google.com (mail-yw1-x112e.google.com [IPv6:2607:f8b0:4864:20::112e]) by atuin.qyliss.net (Postfix) with ESMTPS id D5551ADBA for ; Sat, 20 Jun 2026 17:32:51 +0000 (UTC) Received: by mail-yw1-x112e.google.com with SMTP id 00721157ae682-7e8833c99fcso31784717b3.3 for ; Sat, 20 Jun 2026 10:32:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1781976770; x=1782581570; darn=spectrum-os.org; h=cc:to:references:in-reply-to:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=AY8lxDGyZLN7ASBmCsVrom6hYBWOGawrB4TJ/Ol2AWI=; b=G8Ru1dE+9UkLHoRIat9hSQtrIEPURZmtH8EICcz6gaczKgslEDo5EkZT8BlSIwbAnt VyKeHq5NlSm3DMsk0j2H0WB47qMO/pWbgXvfGBEyAKUp915bzV1/XWsRtCUk7QTA7qn5 Ma9Ua61ACW8VrzukSe9wpKNfoR2kLbAtYyQcHYJe3m1Pa5o8cP5t0wihIqdGNx6t2HWc eL9cMMyACNuJpMxPt7Jlgp0s4vCx1Jp20jGTELimZK/Lnow+Uyf8c/Z41y5+S3gTglgx ER1UctVwl+ScD1WDtSpA9aBzzBd5E16VQJ/HgKYpQ3itNTBzRoh9t+qNaBTisH1xTEJE Ubdg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781976770; x=1782581570; h=cc:to:references:in-reply-to:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=AY8lxDGyZLN7ASBmCsVrom6hYBWOGawrB4TJ/Ol2AWI=; b=kMDepDViL5oVRsWNZpd8YIqvVp8ZPpCgaRu6WlG1Bt8VQ821QN85kc/JW9uRD3Snvx iYDOm5cbrIVs4uIhRzRG91oSisQWSrExc10uCZqRWFWE1kpvnbQbLH0OK0589nytLlT2 tDRanrcOxeEHniHS0nZs2NdPP6VNmT3gEt4t8HVb6gxIGAe2zB6Dx2bKfvSl4qhayw8o 4wkfRJXzQUdI3nQn+VyTjgtAnqaB0Z6Kmv8POhmoX5Xj2w8ddZNDMurM2rPWP5+JKcig FTpnB4Z7jlCEmDG0+HX0kZLPmzXrQdiy2/Lci9AK306FKpOiihamUXz2hcZZizFknffC xTUQ== X-Gm-Message-State: AOJu0YzdIFP1ccdm4scH39/p3/1Xc7Y6sSaDqrR9C5QgEUHzy/DUGgkc MogFkJrVX21jC4Z4LrZbJrk9aa7Mn9zF51gfmxSm/Ygf0TA1j5SFRgOR5f/fcQ== X-Gm-Gg: AfdE7cmqe+AFnKHFhFW9HAzVQxdskfhLKjOBQdZlzXrODSvRoAdcCHF9S9YBSYjjakp WRu7mrYd7LknOs3GZ9nz/5JI9QHZqNfBXuaJMTMQIrO91FTtsShV//OL1LhoG+x3J8Zb6x1g69W SjN1HADfLBOC9P7bL01Fq38iJkGK0slrz48qcz3QbDLCw3sjT0klgKdNMP4ljfTuCNMUUDpa2HN xDYkR+h+wyTe4ZNSJ1umWlXQKCXgthTcmJR1yZ8BlEuOTGBxjL+cc40Gt+aulJ80dsgDR5vJiBa J978/qpCLcTD3fU4k9Fj8XRUXdwC08NAG5V6f9iCIwBKJPSAF0ZXXTuRizCPjGKb+qUvzr1SXV5 q8KIGdTdKgz5502Kf4BQlwuQVC58vDPvMhFGrvgg9bHKGOKebMjEUfHbJ3BURJf+3cDZiTJZjQI Ozz1DCrUT2lqHsKJqV6DgHGawVLcbkx3Md86ZBVsTuo60PaOlSLYvogKzfxwD67li0iVKuUf94s 5lIUe6KILSW7rthRlh1ilVTmWL9ormORMm0 X-Received: by 2002:a05:690c:c454:b0:7fd:fccf:bb7c with SMTP id 00721157ae682-80176bb4012mr71535427b3.21.1781976769243; Sat, 20 Jun 2026 10:32:49 -0700 (PDT) Received: from localhost.localdomain (h69-131-147-66.cncrtn.broadband.dynamic.tds.net. [69.131.147.66]) by smtp.gmail.com with UTF8SMTPSA id 00721157ae682-8025f8dde30sm12370537b3.27.2026.06.20.10.32.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 20 Jun 2026 10:32:48 -0700 (PDT) From: Demi Marie Obenour Date: Sat, 20 Jun 2026 13:27:32 -0400 Subject: [PATCH v2] Set up control groups for most services MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260620-cgroups-v2-1-ccae224b6c85@gmail.com> X-B4-Tracking: v=1; b=H4sIAAAAAAAC/z2NQQ6CMBBFr0Jmbc202iqsvIdhAWWAMUJJC0RDu LsFEpcvef/9BQJ5pgBZsoCnmQO7PoI6JWDbom9IcBUZFCqDWt2FbbybhiAqgympG5K5phDtwVP Nn730zA8OU/kiO27zzWg5jM5/96tZbt5RNQr/1VkKKZB0UdYXLVGWj6Yr+H22roN8XdcfBd9E7 7AAAAA= X-Change-ID: 20260528-cgroups-d609e270e649 In-Reply-To: <20260620-cgroups-v1-1-0e5abf35101b@gmail.com> References: <20260620-cgroups-v1-1-0e5abf35101b@gmail.com> To: Spectrum OS Development X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1781976451; l=47651; i=demiobenour@gmail.com; s=20250729; h=from:subject:message-id; bh=N0Ck5PwxI3UbEsJHuUQ1+vqFm+XI7iqkGLIopJDQNkY=; b=3odx+NesQlH79pu+wzk0AxVRddi15KpoSXreEjG5A9ZzaRKT5pgj9HRzMNh7RGNfIQBxJknkl xrlY6xHGeD/BhhkY44xx16X3emc1MDlJQBYb+jZnMyU6Zx/tLU3K924 X-Developer-Key: i=demiobenour@gmail.com; a=ed25519; pk=X57Q4/YQDj9t4SBeKaDwvXYKB6quZJVx/DE2Ly2out0= Message-ID-Hash: M5GZM5OIRATAW2YT5NPJN3VAIFJWXSFW X-Message-ID-Hash: M5GZM5OIRATAW2YT5NPJN3VAIFJWXSFW X-MailFrom: demiobenour@gmail.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.spectrum-os.org-0; header-match-devel.spectrum-os.org-1; header-match-devel.spectrum-os.org-2; header-match-devel.spectrum-os.org-3; header-match-devel.spectrum-os.org-4; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Alyssa Ross , Demi Marie Obenour X-Mailman-Version: 3.3.10 Precedence: list List-Id: Patches and low-level development discussion Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The cgroups are handled by a Rust tool. The name of the cgroup is autogenerated from the service name. Using cgroups for process control is not implemented yet. Signed-off-by: Demi Marie Obenour --- Changes in v2: - Omit resource control support. It was completely broken, and the way Spectrum run scripts work means that it is better to setup resource controls just before the execve() into the final service process. This will be done by a separate tool. - Link to v1: https://spectrum-os.org/lists/archives/spectrum-devel/20260620-cgroups-v1-1-0e5abf35101b@gmail.com --- .codespellrc | 2 +- host/rootfs/default.nix | 6 +- host/rootfs/file-list.mk | 12 ++ host/rootfs/image/etc/fstab | 1 + .../s6-linux-init/run-image/service/getty-tty2/run | 1 + .../s6-linux-init/run-image/service/getty-tty3/run | 1 + .../s6-linux-init/run-image/service/getty-tty4/run | 1 + .../run-image/service/root-terminal/run | 1 + .../run-image/service/s6-linux-init-shutdownd/run | 1 + .../run-image/service/s6-svscan-log/run | 1 + .../service/serial-getty-generator/finish | 5 + .../run-image/service/serial-getty-generator/run | 3 +- .../run-image/service/serial-getty/finish | 5 + .../run-image/service/serial-getty/run | 3 +- .../run-image/service/serial-getty/template/run | 1 + .../run-image/service/vm-services/finish | 5 + .../run-image/service/vm-services/run | 3 +- .../vm-services/template/data/service/dbus/finish | 5 + .../vm-services/template/data/service/dbus/run | 3 +- .../template/data/service/spectrum-router/finish | 5 + .../template/data/service/spectrum-router/run | 3 +- .../template/data/service/vhost-user-fs/finish | 5 + .../template/data/service/vhost-user-fs/run | 1 + .../template/data/service/vhost-user-gpu/finish | 5 + .../template/data/service/vhost-user-gpu/run | 4 +- .../xdg-desktop-portal-spectrum-host/finish | 5 + .../service/xdg-desktop-portal-spectrum-host/run | 2 + .../run-image/service/vm-services/template/finish | 5 + .../run-image/service/vm-services/template/run | 1 + .../etc/s6-linux-init/run-image/service/vmm/finish | 5 + .../etc/s6-linux-init/run-image/service/vmm/run | 3 +- host/rootfs/image/etc/s6-rc/systemd-udevd/finish | 5 + host/rootfs/image/etc/s6-rc/systemd-udevd/run | 5 +- host/rootfs/image/etc/s6-rc/weston/finish | 5 + host/rootfs/image/etc/s6-rc/weston/run | 3 +- pkgs/default.nix | 1 + tools/cgroup-setup/Cargo.lock | 67 +++++++ tools/cgroup-setup/Cargo.lock.license | 2 + tools/cgroup-setup/Cargo.toml | 17 ++ tools/cgroup-setup/default.nix | 18 ++ tools/cgroup-setup/src/cgroup.rs | 181 +++++++++++++++++++ tools/cgroup-setup/src/main.rs | 196 +++++++++++++++++++++ 42 files changed, 590 insertions(+), 14 deletions(-) diff --git a/.codespellrc b/.codespellrc index d8023afc64ec44e98a88c5e397c8d5c681dde063..ae20da8309530759ac729689825a4afc683afa09 100644 --- a/.codespellrc +++ b/.codespellrc @@ -2,4 +2,4 @@ # SPDX-License-Identifier: CC0-1.0 [codespell] -ignore-words-list = crate,passt,rouge,ser +ignore-words-list = crate,passt,rouge,ser,WRONLY diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index 6bfeefbe0a5f76c1538ccb40e5eb8f291f5d3592..ccf626e2ec0f4bf96573dc5edf058c9375bb65f6 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -8,7 +8,7 @@ import ../../lib/call-package.nix ( }: pkgsMusl.callPackage ( -{ spectrum-host-tools, spectrum-router +{ spectrum-host-tools, spectrum-router, spectrum-cgroup-setup , lib, stdenvNoCC, nixos, runCommand, writeClosure, erofs-utils, s6-rc , btrfs-progs, bubblewrap, busybox, cloud-hypervisor, cosmic-files , crosvm, cryptsetup, dejavu_fonts, dbus, execline, foot, fuse3 @@ -27,8 +27,8 @@ let packages = [ btrfs-progs bubblewrap cloud-hypervisor cosmic-files crosvm cryptsetup dbus execline fuse3 inotify-tools iproute2 jq kmod mdevd mount-flatpak s6 - s6-linux-init s6-rc shadow socat spectrum-host-tools spectrum-router - virtiofsd xdg-desktop-portal-spectrum-host + s6-linux-init s6-rc shadow socat spectrum-cgroup-setup spectrum-host-tools + spectrum-router virtiofsd xdg-desktop-portal-spectrum-host (foot.override { allowPgo = false; }) diff --git a/host/rootfs/file-list.mk b/host/rootfs/file-list.mk index 3899d620717fc97f42e669e5313c4100dcf5b1cd..acf5534e7b966811c545daf2d3aa4f26ca59e15e 100644 --- a/host/rootfs/file-list.mk +++ b/host/rootfs/file-list.mk @@ -21,25 +21,35 @@ FILES = \ image/etc/s6-linux-init/run-image/service/s6-linux-init-shutdownd/run \ image/etc/s6-linux-init/run-image/service/s6-svscan-log/notification-fd \ image/etc/s6-linux-init/run-image/service/s6-svscan-log/run \ + image/etc/s6-linux-init/run-image/service/serial-getty-generator/finish \ image/etc/s6-linux-init/run-image/service/serial-getty-generator/run \ + image/etc/s6-linux-init/run-image/service/serial-getty/finish \ image/etc/s6-linux-init/run-image/service/serial-getty/notification-fd \ image/etc/s6-linux-init/run-image/service/serial-getty/run \ image/etc/s6-linux-init/run-image/service/serial-getty/template/run \ + image/etc/s6-linux-init/run-image/service/vm-services/finish \ image/etc/s6-linux-init/run-image/service/vm-services/notification-fd \ image/etc/s6-linux-init/run-image/service/vm-services/run \ + image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/finish \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/down \ + image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/finish \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run \ + image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/finish \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/notification-fd \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run \ + image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/finish \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/notification-fd \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/run \ + image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/finish \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/notification-fd \ image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run \ + image/etc/s6-linux-init/run-image/service/vm-services/template/finish \ image/etc/s6-linux-init/run-image/service/vm-services/template/notification-fd \ image/etc/s6-linux-init/run-image/service/vm-services/template/run \ + image/etc/s6-linux-init/run-image/service/vmm/finish \ image/etc/s6-linux-init/run-image/service/vmm/notification-fd \ image/etc/s6-linux-init/run-image/service/vmm/run \ image/etc/s6-linux-init/run-image/service/vmm/template/notification-fd \ @@ -96,6 +106,7 @@ S6_RC_FILES = \ image/etc/s6-rc/systemd-udevd-coldplug/dependencies.d/systemd-udevd \ image/etc/s6-rc/systemd-udevd-coldplug/type \ image/etc/s6-rc/systemd-udevd-coldplug/up \ + image/etc/s6-rc/systemd-udevd/finish \ image/etc/s6-rc/systemd-udevd/notification-fd \ image/etc/s6-rc/systemd-udevd/run \ image/etc/s6-rc/systemd-udevd/type \ @@ -108,6 +119,7 @@ S6_RC_FILES = \ image/etc/s6-rc/vmm-env/contents.d/systemd-udevd-coldplug \ image/etc/s6-rc/vmm-env/type \ image/etc/s6-rc/weston/dependencies.d/systemd-udevd-coldplug \ + image/etc/s6-rc/weston/finish \ image/etc/s6-rc/weston/notification-fd \ image/etc/s6-rc/weston/run \ image/etc/s6-rc/weston/type diff --git a/host/rootfs/image/etc/fstab b/host/rootfs/image/etc/fstab index 18bb5e45abafeaf43871306ce8233239e5c07f76..d92364d83f4d26f766fcd5b494614c06a630d2fe 100644 --- a/host/rootfs/image/etc/fstab +++ b/host/rootfs/image/etc/fstab @@ -6,3 +6,4 @@ tmpfs /dev/shm tmpfs nosuid,nodev 0 0 tmpfs /media tmpfs nosuid,nodev,noexec,nosymfollow,mode=755 0 0 sysfs /sys sysfs nosuid,nodev,noexec 0 0 tmpfs /tmp tmpfs nosuid,nodev 0 0 +cgroup2 /sys/fs/cgroup cgroup2 nosuid,nodev,noexec,nosymfollow 0 0 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty2/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty2/run index 4d2cd7172e887e90d9ce87489cdacf41e51f77e8..5b2421a3dedf7c282ea818f4064535d0fc29d511 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty2/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty2/run @@ -2,4 +2,5 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2020-2021 Alyssa Ross +# no cgroups so that nohup works getty -i -n -l /etc/login 0 tty2 linux diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty3/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty3/run index 06abf5422365ff4edc9379e5cbcab716e6830399..3ca382f76368174ee1f99ea880827958c57b602c 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty3/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty3/run @@ -2,4 +2,5 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2020-2021 Alyssa Ross +# no cgroups so that nohup works getty -i -n -l /etc/login 0 tty3 linux diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty4/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty4/run index 3dd235fc93d403fc8971e923ec62cb025684b67a..983bd82927e468bab6ae20f61411680d173e4924 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty4/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/getty-tty4/run @@ -2,4 +2,5 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2020-2021 Alyssa Ross +# no cgroups so that nohup works getty -i -n -l /etc/login 0 tty4 linux diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/root-terminal/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/root-terminal/run index 86b9a1ef70300de52f33a84cbfac22a77e00df36..fb55327dff5f189f543fb3629702caad9ff247e2 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/root-terminal/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/root-terminal/run @@ -2,6 +2,7 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2025 Alyssa Ross +# cgroups make no sense here s6-ipcserver-socketbinder -a 0700 /run/root-terminal if { chown wayland /run/root-terminal } diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/s6-linux-init-shutdownd/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/s6-linux-init-shutdownd/run index 327f4ccc5056e7ef87c089e666090307845cae3a..a6733604e91692f8440fd68efeb1a6b7378be167 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/s6-linux-init-shutdownd/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/s6-linux-init-shutdownd/run @@ -2,4 +2,5 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2023 Alyssa Ross +# cgroups make no sense for shutdownd s6-linux-init-shutdownd -Bc /etc/s6-linux-init diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/s6-svscan-log/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/s6-svscan-log/run index 8f7bd889e50d76a49b98d8ba9e2c6172f287277c..cf3f5c7b499d997fd426062651eca64b3accc146 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/s6-svscan-log/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/s6-svscan-log/run @@ -2,5 +2,6 @@ # SPDX-License-Identifier: ISC # SPDX-FileCopyrightText: Copyright (c) 2015-2024 Laurent Bercot +# cgroups make no sense for a logger redirfd -rnb 0 fifo s6-log -bpd3 -- T /run/log diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty-generator/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty-generator/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty-generator/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty-generator/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty-generator/run index bf66ab0878fc6d8e77ca71a4a89e50c139a6bb11..5c9988c994ed9b942329055673b332d0aa918957 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty-generator/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty-generator/run @@ -1,7 +1,8 @@ -#!/bin/execlineb -WP +#!/bin/execlineb -WS1 # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2024-2025 Alyssa Ross +cgroup-setup -- $1 piperw 3 4 background { fdclose 3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/run index 78f794202bf174f3c036f3e20755ac087a988277..ed0808b9e45b077023f237a0f9c0e5c830015ac2 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/run @@ -1,5 +1,6 @@ -#!/bin/execlineb -WP +#!/bin/execlineb -WS1 # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2023 Alyssa Ross +cgroup-setup -- $1 s6-svscan -d3 instance diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/template/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/template/run index f3ed9a7f08e60206afd222f4fc02c5fb19527561..775b828c72b9d73bef8a3355fb3ae0536975f474 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/template/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/serial-getty/template/run @@ -2,4 +2,5 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2020-2021, 2024 Alyssa Ross +# Don't put this in a cgroup. We want nohup to work. getty -i -n -l /etc/login 0,115200,57600,38400,9600 $1 dumb diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/run index 78f794202bf174f3c036f3e20755ac087a988277..ed0808b9e45b077023f237a0f9c0e5c830015ac2 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/run @@ -1,5 +1,6 @@ -#!/bin/execlineb -WP +#!/bin/execlineb -WS1 # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2023 Alyssa Ross +cgroup-setup -- $1 s6-svscan -d3 instance diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run index f0507dc92aadf25c092f0719eb767542ac0c4451..89676ac91d3e22db7726fc869a065137b031d0be 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run @@ -1,7 +1,8 @@ -#!/bin/execlineb -WP +#!/bin/execlineb -WS1 # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2024-2025 Alyssa Ross +cgroup-setup -- $1 importas -i VM VM if { diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run index 3de58c27facc78c48176d8f9a6dd1827ac926f1a..21e37ab8a3dad1ab701a0989fb408fed100657cf 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run @@ -1,8 +1,9 @@ -#!/bin/execlineb -WP +#!/bin/execlineb -WS1 # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2025 Yureka Lilian # SPDX-FileCopyrightText: 2025 Alyssa Ross +cgroup-setup -- $1 importas -i VM VM s6-ipcserver-socketbinder -a 0770 /run/vm/by-id/${VM}/router-driver.sock diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run index cb059aebc8dfe2c8a5b059d5bfea884de53bf922..d4321263269ae46dd6a1b72e39c57c1c07cb06ba 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run @@ -2,6 +2,7 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2021-2025 Alyssa Ross +cgroup-setup -- $1 s6-ipcserver-socketbinder -a 0700 -B env/virtiofsd.sock importas -i VM VM diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/run index c3bfafe02ec6d2ee418fe56b033bbc4c7a73b186..ad705da8460a86667b47d40e61fee167d240a9c6 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-gpu/run @@ -1,8 +1,10 @@ -#!/bin/execlineb -WP +#!/bin/execlineb -WS1 # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2025 Alyssa Ross # SPDX-FileCopyrightText: 2025 Demi Marie Obenour +cgroup-setup -- $1 + s6-ipcserver-socketbinder -a 0700 -b 1 env/crosvm.sock multisubstitute { diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run index 909957b817136149dd01c3b98847238ecda8032d..54860d67f284e7cabbfc955f44ef819ff3f593bc 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/xdg-desktop-portal-spectrum-host/run @@ -2,6 +2,8 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2024-2025 Alyssa Ross +cgroup-setup -- $1 + importas -i VM VM export DBUS_SESSION_BUS_ADDRESS unix:path=/run/portal-bus/${VM} diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/run index bf90e99eef4106a9ad17dfba310b6edb3eaa64a3..13f2cec03a087be4602c14ed78749cce1f6a26a1 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/run @@ -2,6 +2,7 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2025 Alyssa Ross +cgroup-setup -- $1 export VM $1 s6-svscan -d3 data/service diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vmm/finish b/host/rootfs/image/etc/s6-linux-init/run-image/service/vmm/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vmm/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vmm/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vmm/run index 78f794202bf174f3c036f3e20755ac087a988277..ed0808b9e45b077023f237a0f9c0e5c830015ac2 100755 --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vmm/run +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vmm/run @@ -1,5 +1,6 @@ -#!/bin/execlineb -WP +#!/bin/execlineb -WS1 # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2023 Alyssa Ross +cgroup-setup -- $1 s6-svscan -d3 instance diff --git a/host/rootfs/image/etc/s6-rc/systemd-udevd/finish b/host/rootfs/image/etc/s6-rc/systemd-udevd/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-rc/systemd-udevd/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-rc/systemd-udevd/run b/host/rootfs/image/etc/s6-rc/systemd-udevd/run old mode 100644 new mode 100755 index aec6444e951503eae988e666b77fda8f2ae33d72..c37909af23fa611a75442108100b4fd9db1e22f8 --- a/host/rootfs/image/etc/s6-rc/systemd-udevd/run +++ b/host/rootfs/image/etc/s6-rc/systemd-udevd/run @@ -1,7 +1,8 @@ -#!/bin/execlineb -WP +#!/bin/execlineb -WS1 # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2025 Demi Marie Obenour -s6-setlock /run/sd-notify-wrapper/systemd-udevd.lock + +cgroup-setup -- $1 s6-ipcserver-socketbinder -b0 -m -a 0600 /run/sd-notify-wrapper/systemd-udevd.sock background -d { fdmove 1 3 diff --git a/host/rootfs/image/etc/s6-rc/weston/finish b/host/rootfs/image/etc/s6-rc/weston/finish new file mode 100755 index 0000000000000000000000000000000000000000..0c16cc8060762eac3a91a49b54048407dfbe25c5 --- /dev/null +++ b/host/rootfs/image/etc/s6-rc/weston/finish @@ -0,0 +1,5 @@ +#!/bin/execlineb -WS3 +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +cgroup-setup -- $3 diff --git a/host/rootfs/image/etc/s6-rc/weston/run b/host/rootfs/image/etc/s6-rc/weston/run old mode 100644 new mode 100755 index fd59586c719391deb546c29578341e16a61ed4ce..6794a3ed729c9b99336cb64df95bbb3eba644582 --- a/host/rootfs/image/etc/s6-rc/weston/run +++ b/host/rootfs/image/etc/s6-rc/weston/run @@ -1,7 +1,8 @@ -#!/bin/execlineb -WP +#!/bin/execlineb -WS1 # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2021, 2025 Alyssa Ross +cgroup-setup -- $1 importas -Siu WAYLAND_DISPLAY piperw 4 3 diff --git a/pkgs/default.nix b/pkgs/default.nix index 4dbdfee8ba330f5ba5c9fedee2d1bb8a44af5722..22c0d782bf4b5467fe77d5a2d71fb8df3af3e756 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -51,6 +51,7 @@ let driverSupport = true; }; spectrum-router = self.callSpectrumPackage ../tools/router {}; + spectrum-cgroup-setup = self.callSpectrumPackage ../tools/cgroup-setup {}; xdg-desktop-portal-spectrum-host = self.callSpectrumPackage ../tools/xdg-desktop-portal-spectrum-host {}; diff --git a/tools/cgroup-setup/Cargo.lock b/tools/cgroup-setup/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..fe967b3aa02c296c87b6b36ac59253dbe0a32de9 --- /dev/null +++ b/tools/cgroup-setup/Cargo.lock @@ -0,0 +1,67 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "cgroup-setup" +version = "0.0.0" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/tools/cgroup-setup/Cargo.lock.license b/tools/cgroup-setup/Cargo.lock.license new file mode 100644 index 0000000000000000000000000000000000000000..aa108acd23886d8302eaf7babff90d1b08ae19fb --- /dev/null +++ b/tools/cgroup-setup/Cargo.lock.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: EUPL-1.2+ +SPDX-FileCopyrightText: 2026 Demi Marie Obenour diff --git a/tools/cgroup-setup/Cargo.toml b/tools/cgroup-setup/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..9cce0be706151dfd5264a81afb3ee9a6c851367c --- /dev/null +++ b/tools/cgroup-setup/Cargo.toml @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: CC0-1.0 +# SPDX-FileCopyrightText: 2025 Alyssa Ross +# SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +[package] +name = "cgroup-setup" +edition = "2024" + +[dependencies] +libc = "0.2.177" +rustix = { version = "1.1.2", features = ["fs"] } + +[profile.release] +split-debuginfo = "symbols" +strip = "symbols" +lto = true +panic = "abort" diff --git a/tools/cgroup-setup/default.nix b/tools/cgroup-setup/default.nix new file mode 100644 index 0000000000000000000000000000000000000000..9e716b8f270828b733f39961e5ca37a290a872b4 --- /dev/null +++ b/tools/cgroup-setup/default.nix @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2024 Alyssa Ross +# SPDX-FileCopyrightText: 2025 Yureka Lilian +# SPDX-License-Identifier: MIT + +import ../../lib/call-package.nix ( +{ src, lib, rustPlatform }: + +rustPlatform.buildRustPackage { + name = "spectrum-cgroup-setup"; + + src = lib.fileset.toSource { + root = ../..; + fileset = lib.fileset.intersection src ./.; + }; + sourceRoot = "source/tools/cgroup-setup"; + + cargoLock.lockFile = ./Cargo.lock; +}) (_: {}) diff --git a/tools/cgroup-setup/src/cgroup.rs b/tools/cgroup-setup/src/cgroup.rs new file mode 100644 index 0000000000000000000000000000000000000000..cd77becc0b40bfdcd983e53b63b7c21e4308d5fc --- /dev/null +++ b/tools/cgroup-setup/src/cgroup.rs @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: EUPL-1.2+ +// SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +use std::fs::File; +use std::io::{Read, Seek}; +use std::os::fd::{AsFd, OwnedFd}; +use std::os::fd::{AsRawFd, BorrowedFd}; + +use std::path::{Path, PathBuf}; + +use rustix::fs::AtFlags; +use rustix::path::Arg; +use rustix::{ + fs::{Mode, OFlags, ResolveFlags}, + io::Errno, +}; + +pub(crate) struct LeafCgroup { + path: PathBuf, + fd: OwnedFd, +} + +enum Access { + Read, + Write, +} + +impl LeafCgroup { + fn open_subtree(&self, path: &std::path::Path, access: Access) -> Result { + rustix::fs::openat2( + self.fd.as_fd(), + path, + OFlags::NOATIME + | OFlags::CLOEXEC + | OFlags::NOFOLLOW + | match access { + Access::Write => OFlags::WRONLY, + Access::Read => OFlags::RDONLY, + }, + Mode::empty(), + ResolveFlags::NO_SYMLINKS | ResolveFlags::BENEATH | ResolveFlags::NO_XDEV, + ) + } + + pub fn kill_processes(&self) -> std::io::Result<()> { + let kill_fd = self.open_subtree(std::path::Path::new("cgroup.kill"), Access::Write)?; + let wait_file = self.open_subtree(std::path::Path::new("cgroup.events"), Access::Read)?; + let poll_fd = wait_file.as_raw_fd(); + let mut wait_fd = File::from(wait_file); + assert_eq!(rustix::io::write(kill_fd.as_fd(), b"1")?, 1, "kernel bug"); + let mut fds = libc::pollfd { + fd: poll_fd, + events: libc::POLLIN | libc::POLLPRI | libc::POLLRDHUP, + revents: 0, + }; + // SAFETY: FFI call, valid arguments, fds contains 1 element + let mut v = vec![]; + 'a: loop { + v.clear(); + if unsafe { libc::poll(&raw mut fds, 1, -1) } != 1 { + panic!("poll failed"); + } + wait_fd + .seek(std::io::SeekFrom::Start(0)) + .expect("Seek on control group file should succeed"); + wait_fd + .read_to_end(&mut v) + .expect("reading from control group should work"); + for substr in v.split(|&c| c == b'\n') { + if substr == b"populated 0" { + break 'a; + } + } + } + Ok(()) + } +} + +impl AsFd for LeafCgroup { + fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> { + self.fd.as_fd() + } +} + +impl LeafCgroup { + pub(crate) fn open_cgroup_at(&self, p: &Path) -> Result { + let fd = rustix::fs::openat2( + self.fd.as_fd(), + p, + OFlags::NOATIME + | OFlags::CLOEXEC + | OFlags::NOFOLLOW + | OFlags::RDONLY + | OFlags::DIRECTORY, + Mode::empty(), + ResolveFlags::NO_SYMLINKS | ResolveFlags::BENEATH | ResolveFlags::NO_XDEV, + )?; + Ok(Self { + fd, + path: self.path.join(p), + }) + } + pub(crate) fn open_cgroup(fd: BorrowedFd, p: &Path) -> Result { + let fd = rustix::fs::openat2( + fd, + p, + OFlags::NOATIME + | OFlags::CLOEXEC + | OFlags::NOFOLLOW + | OFlags::RDONLY + | OFlags::DIRECTORY, + Mode::empty(), + //ResolveFlags::NO_SYMLINKS | ResolveFlags::BENEATH | ResolveFlags::NO_XDEV, + ResolveFlags::NO_SYMLINKS, + )?; + Ok(Self { + fd, + path: p.to_owned(), + }) + } + pub(crate) fn make_child(&self, p: &Path) -> Result<(), Errno> { + rustix::fs::mkdirat( + self.fd.as_fd(), + p, + Mode::RUSR + | Mode::WUSR + | Mode::XUSR + | Mode::RGRP + | Mode::XGRP + | Mode::ROTH + | Mode::XOTH, + ) + } + + pub(crate) fn delete_child(&self, path: &Path) -> Result<(), Errno> { + remove_all(100, self.as_fd(), &path.as_cow_c_str().unwrap()) + } +} + +fn remove_recursively(fd: OwnedFd, remaining_depth: usize) -> Result<(), Errno> { + if remaining_depth < 1 { + panic!("control groups too deeply nested"); + } + let mut d = rustix::fs::Dir::new(fd).expect("cannot start iterating"); + while let Some(element) = d.next() { + let element = element.expect("Iterating through a cgroup directory failed?"); + if element.file_type() != rustix::fs::FileType::Directory { + continue; + } + + let remaining_depth = remaining_depth - 1; + let d: &rustix::fs::Dir = &d; + let dirfd = d.fd().unwrap(); + let path = element.file_name(); + remove_all(remaining_depth, dirfd, path)?; + } + Ok(()) +} + +fn remove_all( + remaining_depth: usize, + dirfd: BorrowedFd<'_>, + path: &std::ffi::CStr, +) -> Result<(), Errno> { + if path == c"." || path == c".." { + return Ok(()); + } + if rustix::fs::unlinkat(dirfd, path, AtFlags::REMOVEDIR).is_ok() { + return Ok(()); + } + let fd = rustix::fs::openat2( + dirfd, + path, + OFlags::NOATIME | OFlags::CLOEXEC | OFlags::NOFOLLOW | OFlags::RDONLY | OFlags::DIRECTORY, + Mode::empty(), + ResolveFlags::NO_SYMLINKS | ResolveFlags::BENEATH | ResolveFlags::NO_XDEV, + )?; + remove_recursively(fd, remaining_depth)?; + rustix::fs::unlinkat(dirfd, path, AtFlags::REMOVEDIR)?; + Ok(()) +} diff --git a/tools/cgroup-setup/src/main.rs b/tools/cgroup-setup/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..358703a73fcbdc38794312fe3987e733f37c2df0 --- /dev/null +++ b/tools/cgroup-setup/src/main.rs @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: EUPL-1.2+ +// SPDX-FileCopyrightText: 2026 Demi Marie Obenour + +use std::{ + ffi::{OsStr, OsString}, + fs::File, + io::Write as _, + os::unix::prelude::*, + path::{Component, Path, PathBuf}, +}; + +use rustix::{ + fs::{FlockOperation, Mode, OFlags, ResolveFlags}, + io::Errno, +}; + +mod cgroup; + +macro_rules! fail { + ($($arg:tt)*) => {{ + eprintln!($($arg)*); + std::process::exit(1)} + }; +} + +fn main() { + let mut args = std::env::args_os(); + let Some(prog_name) = args.next() else { + fail!("No command line arguments (argv[0] is NULL)"); + }; + let mut cgroup_relative_path = args.next(); + if cgroup_relative_path.as_deref() == Some(OsStr::from_bytes(b"--")) { + cgroup_relative_path = args.next(); + } + + let Some(cgroup_relative_path) = cgroup_relative_path else { + fail!("{prog_name:?}: Have no positional arguments, expect at least 1") + }; + let mut cgroup_relative_path = cgroup_relative_path.into_vec(); + + // slow but we do not care + if cgroup_relative_path.len() > 247 { + fail!("{prog_name:?}: Cgroup name {cgroup_relative_path:?} too long"); + } + if cgroup_relative_path.is_empty() { + fail!("{prog_name:?}: Cgroup name {cgroup_relative_path:?} empty"); + } + if cgroup_relative_path[0] == b'-' { + fail!("{prog_name:?}: Cgroup name {cgroup_relative_path:?} starts with '-'"); + } + for &i in &cgroup_relative_path { + match i { + b'/' => fail!( + "{prog_name:?}: Cgroup name {cgroup_relative_path:?} \ +contains /" + ), + b'$' => fail!( + "{prog_name:?}: Cgroup name {cgroup_relative_path:?} \ +contains $: did you forget an execline substitution?" + ), + b'!'..=b'~' => {} + _ => fail!( + "{prog_name:?}: Cgroup name {cgroup_relative_path:?} \ +contains space, non-ASCII character, or control character (byte {i})" + ), + } + } + cgroup_relative_path.extend_from_slice(b".service"); + let cgroup_relative_path = Path::new(OsStr::from_bytes(&cgroup_relative_path)); + + let local_cgroup = std::fs::read("/proc/thread-self/cgroup") + .unwrap_or_else(|e| fail!("{prog_name:?}: cannot read /proc/thread-self/cgroup: {e}")); + + if !local_cgroup.starts_with(b"0::/") + || !local_cgroup.ends_with(b"\n") + || local_cgroup.contains(&b'\0') + { + fail!("{prog_name:?}: Kernel bug: Bad contents of /proc/thread-self/cgroup"); + } + + let mut local_cgroup = PathBuf::from(::from_vec( + local_cgroup[4..local_cgroup.len() - 1].to_owned(), + )); + + match local_cgroup.components().next_back() { + Some(Component::Prefix(_)) => unreachable!("does not occur on Linux"), + Some(Component::RootDir) | None => {} + Some(Component::CurDir) => unreachable!("not produced by kernel"), + Some(Component::ParentDir) => unreachable!("not produced by kernel"), + Some(Component::Normal(os_str)) => { + if os_str.as_bytes() == b"@inner.service" { + let _ = local_cgroup.pop(); + } + } + } + + if local_cgroup.as_os_str().is_empty() { + local_cgroup = PathBuf::from("."); + } + + let cgroup_root = rustix::fs::openat2( + rustix::fs::CWD, + Path::new("/sys/fs/cgroup"), + OFlags::DIRECTORY | OFlags::RDONLY | OFlags::CLOEXEC | OFlags::NOFOLLOW, + Mode::empty(), + ResolveFlags::NO_MAGICLINKS | ResolveFlags::NO_SYMLINKS, + ) + .unwrap_or_else(|e| fail!("{prog_name:?}: cannot open /sys/fs/cgroup: {e}")); + + let cgroup = match cgroup::LeafCgroup::open_cgroup(cgroup_root.as_fd(), &local_cgroup) { + Ok(e) => e, + Err(e) => fail!( + "{prog_name:?}: Failed to open {}: {e:?}", + local_cgroup.display() + ), + }; + + match rustix::fs::flock(cgroup.as_fd(), FlockOperation::LockExclusive) { + Ok(()) => {} + Err(e) => fail!("{prog_name:?}: cannot lock cgroup: {e}"), + } + purge_cgroup(&prog_name, &cgroup, cgroup_relative_path); + let Some(program_name) = args.next() else { + return; + }; + if let Err(e) = cgroup.make_child(cgroup_relative_path) { + fail!("{prog_name:?}: cannot create child cgroup: {e}") + } + let child = cgroup + .open_cgroup_at(cgroup_relative_path) + .unwrap_or_else(|e| { + fail!("{prog_name:?}: cannot create child cgroup {cgroup_relative_path:?}: {e}") + }); + child + .make_child(Path::new("@inner.service")) + .unwrap_or_else(|e| { + fail!("{prog_name:?}: cannot create child cgroup {cgroup_relative_path:?}/@inner.service: {e}") + }); + let child = child + .open_cgroup_at(Path::new("@inner.service")) + .unwrap_or_else(|e| { + fail!("{prog_name:?}: cannot open child cgroup {cgroup_relative_path:?}/@inner.service: {e}") + }); + + // SAFETY: safe FFI call + let pid = unsafe { libc::getpid() }; + write_cgroup_value(&prog_name, &child, "cgroup.procs", &pid.to_string()); + + let e = std::process::Command::new(&program_name).args(args).exec(); + fail!( + "{prog_name:?}: cannot spawn child {:?}: {}", + program_name, + e + ); +} + +fn write_cgroup_value(prog_name: &OsStr, child: &cgroup::LeafCgroup, name: &str, value: &str) { + let path = Path::new(name); + let fd = rustix::fs::openat2( + child.as_fd(), + path, + OFlags::NOATIME | OFlags::CLOEXEC | OFlags::NOFOLLOW | OFlags::WRONLY, + Mode::empty(), + ResolveFlags::NO_SYMLINKS | ResolveFlags::BENEATH | ResolveFlags::NO_XDEV, + ) + .unwrap_or_else(|e| fail!("{prog_name:?}: cannot open {:?}: {}", path, e)); + let () = File::from(fd) + .write_all(value.as_bytes()) + .unwrap_or_else(|e| { + fail!( + "{prog_name:?}: Cannot write {:?} to {:?}: {}", + name, + path, + e + ) + }); +} + +fn purge_cgroup(prog_name: &OsStr, cgroup: &cgroup::LeafCgroup, cgroup_relative_path: &Path) { + let child = match cgroup.open_cgroup_at(cgroup_relative_path) { + Ok(child_cgroup) => child_cgroup, + Err(Errno::NOENT) => return, + Err(other) => { + fail!("{prog_name:?}: cannot open child cgroup {cgroup_relative_path:?}: {other}") + } + }; + child.kill_processes().unwrap_or_else(|e| { + fail!("{prog_name:?}: cannot kill programs in {cgroup_relative_path:?}: {e}") + }); + + cgroup + .delete_child(cgroup_relative_path) + .unwrap_or_else(|e| { + fail!("{prog_name:?}: delete child cgroup {cgroup_relative_path:?}: {e}") + }); +} --- base-commit: 36ea9d85403a29f1e700f534020cc4592d78ee50 change-id: 20260528-cgroups-d609e270e649 -- Sincerely, Demi Marie Obenour (she/her/hers)