feat: build system transition to release fork + archive hardening

Release fork infrastructure:
- REDBEAR_RELEASE=0.1.1 with offline enforcement (fetch/distclean/unfetch blocked)
- 195 BLAKE3-verified source archives in standard format
- Atomic provisioning via provision-release.sh (staging + .complete sentry)
- 5-phase improvement plan: restore format auto-detection, source tree
  validation (validate-source-trees.py), archive-map.json, REPO_BINARY fallback

Archive normalization:
- Removed 87 duplicate/unversioned archives from shared pool
- Regenerated all archives in consistent format with source/ + recipe.toml
- BLAKE3SUMS and manifest.json generated from stable tarball set

Patch management:
- verify-patches.sh: pre-sync dry-run report (OK/REVERSED/CONFLICT)
- 121 upstream-absorbed patches moved to absorbed/ directories
- 43 active patches verified clean against rebased sources
- Stress test: base updated to upstream HEAD, relibc reset and patched

Compilation fixes:
- relibc: Vec imports in redox-rt (proc.rs, lib.rs, sys.rs)
- relibc: unsafe from_raw_parts in mod.rs (2024 edition)
- fetch.rs: rev comparison handles short/full hash prefixes
- kibi recipe: corrected rev mismatch

New scripts: restore-sources.sh, provision-release.sh, verify-sources-archived.sh,
check-upstream-releases.sh, validate-source-trees.py, verify-patches.sh,
repair-archive-format.sh, generate-manifest.py

Documentation: AGENTS.md, README.md, local/AGENTS.md updated for release fork model
This commit is contained in:
2026-05-02 01:41:17 +01:00
parent f55acba68c
commit 5851974b20
242 changed files with 29015 additions and 1818 deletions
+216
View File
@@ -0,0 +1,216 @@
a31ebd5556523f41a65224633177608303909d2ee332a67d2dfa39868915606a archives-zstd.tar.gz
ea059a7222b0b79f1d4224fe844940e2bd5362247df94854f57bcf64b7fd3eb5 archives-zstd-v1.5.7-patched.tar.gz
3ee6d3d961b7671a3a7978222fd2d124934a2047797bbb3341438b2251d50ef0 branding-redbear-release-vunknown-patched.tar.gz
61983d26e05966da0a5e0abb0d68f719521aa416fd3aeadd8b93a8304fc84a60 core-base-initfs.tar.gz
3674a72d65977c03422127fee2b961ff1997f0854ad44f1651410840d37152ab core-base-initfs-v463f76b9-patched.tar.gz
61983d26e05966da0a5e0abb0d68f719521aa416fd3aeadd8b93a8304fc84a60 core-base.tar.gz
1415356f8557f1f3b5568eff10fcb99f87c754fcad254cde72caf003282270e7 core-base-v463f76b9-patched.tar.gz
aca55a89de555eb722bd002ab3f707e964001b9e2b62ca32168feda3ab94672f core-base-v463f76b-patched.tar.gz
76695e0ee48f379ff4301769e1587a5239c60b7796760c1d24b3925198a31dea core-bootloader.tar.gz
5af476ccd1bc93c89d0c650a57a17fd98b4bb2a4d2ad4af8b50b3f24523ed87b core-bootloader-vb22a35c-patched.tar.gz
e5652eaf14965efeaebd0aba5d6ddd205ba3308567693ddc93592ab9c32e4620 core-coreutils.tar.gz
ce33a62697205ee82ca1d7c4ce07fe5031307f8034d20851f4ee2ea49887e4ce core-coreutils-v5559e20-patched.tar.gz
19be72b52f4595797ecc72337dfad208a21e0765feff8768e653748de6033ae4 core-ext4d.tar.gz
f2906b6101db9842c6618978d97026ae6dbc9791c7410a98db84500787ded5b2 core-ext4d-vunknown-patched.tar.gz
9bc43eb5601d4f7d7a4bfed5b2743f2c48b9fb60ad2b1ebf41aec32ad7c0d8b1 core-extrautils.tar.gz
4346bdabe83b31fe4adf7cbddfa6674ec7b31f20bc25c7d8c6c5aebdd8e5b571 core-extrautils-vfb66941-patched.tar.gz
ec501aa5fd302e853befd2119a44f4040d3dda09c0e704949c39d507d52354e9 core-fatd.tar.gz
cf45041abc4d198467091cdc16d5d8375b2545521dc986130f01abd46f8e0c6d core-fatd-vunknown-patched.tar.gz
cc4e08580e1d2ea4f4d98fd17f17c03894984ca166b6cb6ab6c38946c2301a07 core-findutils.tar.gz
fedfb7851f7bfcbf75e4980b04ed59d4ac524f9d9a3b73786b6e5469c876962b core-findutils-v116c044-patched.tar.gz
c59f3bec37b179df5e895de1fa726a0b27c7979f6c9d023e1167db1443bad9b7 core-grub-v2.12-patched.tar.gz
844ddbc8c107f2d7626f14303092aa40468c439e23c1a2aeaca77e520cbd51cb core-installer.tar.gz
a791231835630e84da0f4fd45f4d39d7e1ae92a877baa3756ca4d4bddca98273 core-installer-v948bfdc-patched.tar.gz
54c14322d0aa2dba5077fcfbb35b83f3b818411e2b65f38857fc4c8cf040b8b3 core-ion.tar.gz
dfc55adc306c136ddc4d754256e2d2f1474c4c44e5e40da1ae03faa32f4684fb core-ion-v1440704f-patched.tar.gz
b65b124363fda03508fa2aebb0b0bc1351a3cea0af6cb53c123487c6e5688e36 core-kernel-v866dfad-patched.tar.gz
c5f66c8e0c47bde679b2d2e3f6d4f4d9b7072925dd3923664f9b057743bd54e4 core-netdb.tar.gz
cf4dc0636fe527815efe23a7c4004728d43d56ca07fab785170dca39b2ca700d core-netdb-v2c15606-patched.tar.gz
e036b781f0e5570d2c9ed99a0bf38468fd4322409bc6f2bbc8e1108debd915cc core-netutils.tar.gz
0724f5e41c8c5cdeaae8e1c23eef2832f05ae2b94e7ef96bfff8d2178bcc174c core-netutils-v40a573b-patched.tar.gz
5a7f70553dd588fa65332e12cc21ce59de3dc05dbac73064dad70d29e0e26511 core-pkgutils.tar.gz
787557d5430033d0eed827e029a23f56439c4c76bc12f639c32245fccaec3f9b core-pkgutils-v70c5067-patched.tar.gz
889dd144e5d6c8a90da00d83545686ae3ac0a1258f5e092bcd1c3e0cd26c4371 core-redoxfs.tar.gz
a9886db5a6b2ff5ce2fd1ad3167b1a6c1fdf509c819ccaf9d59e439370621ece core-redoxfs-vb596776-patched.tar.gz
67d6cfb8eb3f7164212858cd27f49e950e1b7fc00ac03bd7a6af738a735af0c2 core-relibc-v861bbb0-patched.tar.gz
7203243b8bf1eb0d2f24dce55e31e16229a817ef14c372a1b9b88653d3896d91 core-userutils.tar.gz
14e7288f3cc7ae01c60c2a3ceef634dcc1c7dda87f5d88fec1624bb122138cef core-userutils-v0c5274f-patched.tar.gz
87f09948dde5800459bd92b242391dcfc0684d91a6590318a06be354d8e7c3c2 core-uutils.tar.gz
501572a66e107bc4ae07d0336d09d59da475bcc36c688487fac2d06c384ffeb7 core-uutils-v1f7c81f-patched.tar.gz
3bb4b54cc021f5b4633d8d36d16c808911d7de2590172b3768fe9d0c7eecbd39 dev-cmake-v4.0.3-patched.tar.gz
ee26032e11572ddfc35010b6bc2fc26a069ceda6ec01293be103fa7006d7c1e7 dev-gcc13-v8e365ce7e5-patched.tar.gz
59ed3971c39dee06327da06a92545e4f70eddbbdc4ebf73fc7e075e1ee046dd4 dev-git.tar.gz
230a1a25c1b3d3782ac61eedd900052b075b055a944ce4cdec356ffb779410d5 dev-git-v2.13.1-patched.tar.gz
0cb8eaec77c01c7668f8ac13656a252cdee92f97ff24f9cfd9cb39125e8e2b5a dev-llvm21.tar.gz
a508f9987095a8a45428763a6b7d74ad8852a89d46c4696fec7bb671ba02d846 dev-llvm21-v250d0b022e-patched.tar.gz
e046d500a60a3266dd04b63b92b85cbba3ddfc76c1d163e7f63e015e4162badc dev-pciids.tar.gz
7c65ff91a06b0c30759ca657f6652b4c4a0e6cc4da7ff939715359eb1af49549 dev-pciids-vfae84a8-patched.tar.gz
1af52b8b8bcd2f04626db16a491f5285ac8b9a2354c6e7c28ad57cf46fb82a26 download-curl-vf50c28394-patched.tar.gz
02b7f74d6149e3eea2e1e069f61595ae0943328cd5906f1dd84b407f26ab41d1 drivers-linux-kpi.tar.gz
c1dad118b2fa2d477b4a6540225ca4278a869667aeca8fb05cbf1887987709b0 drivers-linux-kpi-vunknown-patched.tar.gz
9a00ac5a5576b2699d5b0613010853614aafdc9fc2e6ce6e0ba72c4164624c7f drivers-redbear-btusb.tar.gz
ae5ea46a07572ca35f2df89650fd15f6637e7a5893ea20300ebae967b4b9b275 drivers-redbear-btusb-vunknown-patched.tar.gz
b1fc69a7fdf3b0556165207531429adc47eff7aac9cc80d2ec87777d1ab71104 drivers-redbear-iwlwifi.tar.gz
0bfbc2d093b829d1f2ba2e1eefa55a88198525d08daa91bcdf475c306bbbc6bd drivers-redbear-iwlwifi-vunknown-patched.tar.gz
95899472009b85ba2b29fdc77e7ebdad926f81c86d071ca1c4f56b3e4617501c drivers-redox-driver-sys.tar.gz
bddd6f7c4f48ecfcc0f91644da1a4f3e796225fcb2595b6fee44006c0ff4afa9 drivers-redox-driver-sys-vunknown-patched.tar.gz
7c51a7d0bbe6871c0199bde1527d455662b6c8430c061470a4962084b373ad26 files-mc-v4.8.33-patched.tar.gz
1372f921f5d095953d20e253662881cc2ba51ee8eda9c7ebcc24388ffc30c527 fonts-dejavu-v2.37-patched.tar.gz
031881eb827deb0c545bef5d8ebc7f1c4c2989dc0ab67972ac33d288821acdaa fonts-freefont-vunknown-patched.tar.gz
5d31b6dbcf47f2c8626c9d6efbbcfd3246a2589e36f92c54dbd62cf5c83b148d fuse-e2fsprogs-v1.47.1-patched.tar.gz
97313c39dac45eca01dd46c96813473e426a99fe91d5971ad56b9bab53106063 gpu-amdgpu-vunknown-patched.tar.gz
dd64e143ca81e3d8a8935f9a8421c66f2dfe4e774ef0d57a8799f670dc20cf55 gpu-redox-drm.tar.gz
aaec2ebff059ed9a23a11d9b333c130b5bbfaaeb68b14d270a6279120de86c2a gpu-redox-drm-vunknown-patched.tar.gz
d4f6e46eb431869b728a0d9ae8e9a9690bb635755a5b0ff6a7c34bdc08a54429 icons-hicolor-icon-theme.tar.gz
adcc4573c1ef28ec48b497d59b7d92865c7086a1269c6082038356e3fb8cf10a icons-hicolor-icon-theme-v8d22bbf-patched.tar.gz
6a7c47b0f20e3d391aead41bc5a097aaf4bb95c3e74e2f32be3f8439bc71a5a7 icons-pop-icon-theme.tar.gz
1d1b966a61a02458662d8ae7ad40fc662d80e3ac2c91f8e01d4f7b2d31e2022d icons-pop-icon-theme-v1a575a8-patched.tar.gz
894cccef17471956656757a8e6eec4b6b85d1b66568f08b61b95cbb3b375b92e kde-kdecoration-v6.3.4-patched.tar.gz
ee62bf2441e9763e4cde26c0dbf980425e595663fc412da56c7f338d89020cf1 kde-kf6-attica-v6.10.0-patched.tar.gz
1b4667ac737250698eb5406d0b06476b048821e0f9aced7fa2a7f6f3ab69fb6f kde-kf6-extra-cmake-modules-v6.10.0-patched.tar.gz
9e109258bec7005d63ef4f547957105e989848f7d66d559af24645460e096aff kde-kf6-karchive-v6.10.0-patched.tar.gz
00e72e346159e3ca9a236b6fa13b840f347e2997e11d83f762ca4c7fa789745c kde-kf6-kauth-v6.10.0-patched.tar.gz
37be8a15b00a623d546e14ae4f34d8c8a6a8f4941edc81ce7d04fa06b601b78d kde-kf6-kbookmarks-v6.10.0-patched.tar.gz
682291f3bdc84c9c78b8f20546d681773766381934f3db58e353bf7320801402 kde-kf6-kcmutils-v6.10.0-patched.tar.gz
a20c7cc62c5e80206625feecf7719a90884a5cb5a97b00e08751f5588362643b kde-kf6-kcodecs-v6.10.0-patched.tar.gz
ea9bf7bfcabf062b16be1b7d29571762591cb785bdc6b247e84497c9cc46bd13 kde-kf6-kcolorscheme-v6.10.0-patched.tar.gz
ae69e3d4f04760acc209deef12d27acb729fb11c1e3a070d3ddd036f073c8878 kde-kf6-kcompletion-v6.10.0-patched.tar.gz
8c2a7e62c5170ceca56fff639aeaa404aa73f4916c64cd8a54081fcc1318ce8b kde-kf6-kconfig-v6.10.0-patched.tar.gz
e726a54383744a6e90f4de558a8b7962c1f6d658a8848df18e49da0748342b81 kde-kf6-kconfigwidgets-v6.10.0-patched.tar.gz
f31f1a855b7c8952f3afc067f6fbc968e8d6ddb8bf8997830d72d937aa738603 kde-kf6-kcoreaddons-v6.10.0-patched.tar.gz
9fec6ce5988b055c530b1f5a2bcea096dcacd85c56781c51086a93213965a0e0 kde-kf6-kcrash-v6.10.0-patched.tar.gz
6ca5d940920a86c79ac96d09d42bf1245bd99301fb50deca65f6dd509f312f01 kde-kf6-kdbusaddons-v6.10.0-patched.tar.gz
217fa5a3088fe2974f0b69db48adde58fe85234a2275510ce09aea028dc59360 kde-kf6-kdeclarative-v6.10.0-patched.tar.gz
8aa9c0df4e7383af69da6a0adc670728365270074c9b838f46760a31f6ab1ac9 kde-kf6-kded6-v6.10.0-patched.tar.gz
21c2f0e2282e499e0915023b19c9d7be74bd80c2450de2157667c17832107200 kde-kf6-kglobalaccel-v6.10.0-patched.tar.gz
955c1a31361812c65cadcf903d631335413073ac1bc52317c996cf808e5b992f kde-kf6-kguiaddons-v6.10.0-patched.tar.gz
b123dcdd8aa0a4cf66aaef6dc12d3ac1f4e77d5139f1d07fe76b89ae0400eb3a kde-kf6-ki18n-v6.10.0-patched.tar.gz
d81ec6333c08ebd850843888942aaea884bbe6cff682b974004195781762db03 kde-kf6-kiconthemes-v6.10.0-patched.tar.gz
3aff2490c3d354f052ad1d536ac1e05d0c78a710946c652f568ea2287d91651c kde-kf6-kidletime-v6.10.0-patched.tar.gz
ee1281eaaafc1e3966387292a9cfb36930c5c610a98cee8dddec0a7a1674b218 kde-kf6-kio-v6.10.0-patched.tar.gz
05a9d9f1b3469cd369a5f5d9c336232338529c4161298cb64dbc5fab253ad4e5 kde-kf6-kitemmodels-v6.10.0-patched.tar.gz
ab0623ff7695e1f99367f592f59d81d856164d3f4727a0473ab761a36c4e2737 kde-kf6-kitemviews-v6.10.0-patched.tar.gz
4cf81e73c14f24ee4adc8c909d4475e9f43e7f1d7e6b0d91ab23ce2c55514248 kde-kf6-kjobwidgets-v6.10.0-patched.tar.gz
94d02004033a2f718abefb164d7126b48cd7795ff523318372568f7608d706fe kde-kf6-knewstuff-v6.10.0-patched.tar.gz
d4783658caa5141b25aced8b5211c343bffb50a9425d50c8abc5193365976892 kde-kf6-knotifications-v6.10.0-patched.tar.gz
3d84d8a9a3248ffc0d28d014912db2570ac582c0792a09585c1b1dc4319a1978 kde-kf6-kpackage-v6.10.0-patched.tar.gz
7284d9158a17718239687ec032b21bee57cbd0ac6d446b9e5d35181bf2f28e1a kde-kf6-kservice-v6.10.0-patched.tar.gz
06da94541e03d74c187788ff79e7669b4e2f743fb320b677891bef77c852f69a kde-kf6-ktextwidgets-v6.10.0-patched.tar.gz
d837dd42e5c873860b8e8d1c6ca8a5147bc86bf4fc420cd2ea60e8e2c43209f1 kde-kf6-kwallet-v6.10.0-patched.tar.gz
b2154c5c74f140816cbdafb19111b787ede155da3c78b6fbf52c7bc45cab1409 kde-kf6-kwayland-v6.3.4-patched.tar.gz
b36ec1f1cd4959b2d8e4543a595a6a9de526143b5147ded18c78e3300ec3bd8a kde-kf6-kwidgetsaddons-v6.10.0-patched.tar.gz
23e2bdab499dc5898df859dc0e3690b27f88b1e22db829798e8b6d60252267e2 kde-kf6-kwindowsystem-v6.10.0-patched.tar.gz
7d73a7dd6a72c7f03644a4afa5ee2c57a3f4d04aad1725977ebb16325f39c47c kde-kf6-kxmlgui-v6.10.0-patched.tar.gz
bd6ea6cc02c6e4020e80f307cd5d6adabd70b05d228bdb4f584a5ddc7284ffce kde-kf6-solid-v6.10.0-patched.tar.gz
a577a8e3b70252156a8c622c71417e726606de37ed8a9c043d2e2359fc3b60b5 kde-kf6-sonnet-v6.10.0-patched.tar.gz
95419c92002d893914fd31ffb48f71a0f34f07dc7bdce7427f0a0fd8493601ed kde-kglobalacceld-v6.0.0-patched.tar.gz
4443841da66842d557cbdbbf7971d56554548ae98a44f023507542176e683117 kde-kirigami-v6.10.0-patched.tar.gz
be98158da9f17efcc18c56f9cd132e68b300fcbb594ebe860a8b5357f18c8bd0 kde-kwin-v6.3.4-patched.tar.gz
c1010706dfb8e00d349b24a2b3a525aedcc1d2e41227ee1673dd071cef8359ef kde-plasma-wayland-protocols-v1.16.0-patched.tar.gz
1c8b0f5038240f01f1aac9f5cdf5f963ad355bca87118239aafa20b2a1b51fd2 libs-expat-v2.5.0-patched.tar.gz
4953f6e273501761d0e6c2460b09b50922ebd53c2ad499c6aabce71c21708af9 libs-glib-v2.87-patched.tar.gz
0e73529eac6877af802a680ea66291a7222327bdb313b7b44364cb2297d231c5 libs-lcms2-stub-vunknown-patched.tar.gz
9b2f35c1fafb93de041105dd421b687fe05e7e6d6a8d1a5a5727c4992d6d39b5 libs-libdisplay-info-stub-vunknown-patched.tar.gz
a0a37aaa219a1ab096ad294df04029a16b7bd2313b8002ebbdaf959fd6583225 libs-libepoxy-stub-vunknown-patched.tar.gz
31828be1d165a7902487333e997cdab5d1b9429a12b5171d447afb92d424cbf7 libs-libevdev-vunknown-patched.tar.gz
288d95219a2c0e4bd56fcdaea926ce9a04582bb80272dda4199a1c907c0f649b libs-libffi-v3.4.5-patched.tar.gz
da3aca123e4668eabed1423698db6d4f39b27992743f72b89015ed962489b209 libs-libgcc-vunknown-patched.tar.gz
d142df1affbc425a9e7542b4f8c9248f1149811c3b9da740ff3c33b3b3759b50 libs-libgmp-v6.3.0-patched.tar.gz
bf9804f179eaf2548091931b91ae1fc5cd5a01b330dc85bc6bf097a9d2fbc0e9 libs-libiconv-v1.17-patched.tar.gz
d9a76013904ac6497d4bef0305ac17efa1bdd1a3adebc1bfa437b6e3948ed358 libs-libinput-vunknown-patched.tar.gz
09f63d7254e75360f0bae505336c750778313ed05ad69c50f6b6da208d197153 libs-liborbital.tar.gz
f6714b4200ca33c9660009ec6487fbadf7afc56aa42537641ad75323d5a55af4 libs-liborbital-v9958363-patched.tar.gz
cbfd9505dce77c42ce76d97d6d0a37abc50396ca95e8c214cbd26acbbc924c48 libs-libqrencode-vunknown-patched.tar.gz
fd80625619d81631862572e466430d143e057f880f0299f20851e4e39f53265b libs-libstdcxx-v3-v8e365ce7e5-patched.tar.gz
5d0312ddf758cc34ef7ee4428e1f7f6e3d9b7d8a64ec29cca888483a2daaa58b libs-libstdcxx-vunknown-patched.tar.gz
f500f0bc22c3e586035f0a8d197f5f0b60dfcd3284f10f878470491eb6d54963 libs-libudev-stub-vunknown-patched.tar.gz
f1e5de47ba6353b671a43938ccd430ce5f7d75063ee33e6eb2bf60bf8d302ff9 libs-libxcvt-stub-vunknown-patched.tar.gz
efab18ac232c641efd116915cce08afe279e5c768f9447fedb44af349fdc809b libs-libxml2-v2.11-patched.tar.gz
ad11eb07412afcd561fb8d1a5a33cc71cc98be4af498ebb3deedfca89ad99066 libs-linux-input-headers-v1.13.2-patched.tar.gz
10733f31293e2b4edf2a48296dde7ec174b8273d86fc80294d38523554fa7132 libs-linux-input-headers-vunknown-patched.tar.gz
6be00852e063056feb93adc2befba6738de148df910a953b5f0cd4ea1f2a4c1f libs-mesa.tar.gz
7a6e727621e38ab1a376458a4693a0dabd02240f8c09eff8e94d7fb097866d30 libs-mesa-v0ecd6b66c-patched.tar.gz
17b8f98b55298356745ba2533c374671ed5971786db64919641a1c2b9e698669 libs-mesa-va86b5f3ac-patched.tar.gz
646c4e0b4100edd2dbcb43a7bea6f71e83bd15798be4a35af15a53d209a2149e libs-ncurses-v6.6-patched.tar.gz
7b7d6bd13a85825c2b2154f2a1ce5833e97cbfdda75186e36574f89c3189039e libs-ncursesw-vunknown-patched.tar.gz
8dd4168855f5022f5982aa0d556cf659e4cf0e778441d0469674f1c856f9b6aa libs-nghttp2-v1.64.0-patched.tar.gz
27236afc509099c0ff9491a81d2afa982483ffd5a7f4b373a9c6c8719965a59c libs-pcre2-v10.45-patched.tar.gz
d8fba8c19b69d3b0cb07473f0071ff077e8a0d411638b9a89858fe16e8e27217 libs-readline-v8.3-patched.tar.gz
981bd0d9bfd57f38af1fde45b3cef7300ff67b133083092e7b3f7330c50e4e2c libs-termcap-v1.3.1-patched.tar.gz
33e9d23d697c53245d54152ec9dbbe6d21543034003104d21dd8eb180936cf43 libs-zbus.tar.gz
9130fffd118e2f0ad61cf0b98b26c1dcf0caee5aac456b04cd536c15e1abe3a1 libs-zbus-vunknown-patched.tar.gz
93a7d8d5f25ff9f9a143d649161ebb857054bf133ca5a2246e66455dcd4f4c6e libs-zlib-v1.3-patched.tar.gz
02b7f74d6149e3eea2e1e069f61595ae0943328cd5906f1dd84b407f26ab41d1 local-recipes-drivers-linux-kpi.tar.gz
95899472009b85ba2b29fdc77e7ebdad926f81c86d071ca1c4f56b3e4617501c local-recipes-drivers-redox-driver-sys.tar.gz
2c40bc71a01e4a35786644052999c2a1a5207d2100592cbd5e2002418409ec12 local-recipes-gpu-redox-drm.tar.gz
413a49795400c91e2bb29eb6a7269567b4cd261fbc46bbaf466f91023d31108a monitors-bottom-v7cf3105d-patched.tar.gz
e0a529cda4be63780a00f842194bf3e8293855c3533cc7802bee400712a8f1cd monitors-htop-vc9444cd3-patched.tar.gz
841a848f29847679e9f2f1f70cbe7f2cd6b2a1ee3023872272dc77f24f1a11b4 other-ca-certificates-v8139d99-patched.tar.gz
3ae5efcd34b7460b83173168b779d1a6c2a04554623d468fdf62cccd27b61d4c other-libevdev-v1.13.2-patched.tar.gz
2fe33d35f4599d0ddf6972afeec393c4d761d9886e61f4af14a06225363b56b1 other-libinput-v1.30.2-patched.tar.gz
26db541bf0c6f29b03e38f4c419f1e5aa933280e6ba666de63b64613bfcc316f other-libxkbcommon-v1.7.0-patched.tar.gz
4295d94e0c4cf13d2563246928e4bd27a38dabef39cbb62cd9652ae3aac4f72a other-shared-mime-info-v2.4-patched.tar.gz
9c93841855c95f98eb1be3972f0b63dbb62eef004577c19fd87e783f849075f9 other-terminfo-vdc5712b-patched.tar.gz
33a00587669db9e3170ebc56d30cf9d24caa19b2b1a0d445c62eef535df900a8 qt-qt6-sensors-v6.11.0-patched.tar.gz
6e569d30e590028b100bb6a8a19e9845a4f4d2054e83171b7ccd938c43700197 qt-qtbase-v6.11-patched.tar.gz
1537c65840f5f739be7e111946981ce65cd22c256cdd1fa4b4db8919f661ea67 qt-qtdeclarative-v6.11-patched.tar.gz
8c76cd8bd68377ba046e7c1ba9355ca9205706dadec963a90ba004cad729b453 qt-qtshadertools-v6.11-patched.tar.gz
d92e719a14e7ab3f18ed8a6878c6ac6a5dd16e9b36afc470b18b0970204c4f9a qt-qtsvg-v6.11-patched.tar.gz
5d59ddd50ebd5a6addcbad446405561db9583c129c1d2c7e203dbb8ffd5e47be qt-qtwayland-v6.11-patched.tar.gz
369ad527a41701a8e99b5fe515c77b525812f5c8d2bce11d9961840ea7277b8d recipes-core-base.tar.gz
1eec412c012d34a2fc24ba3e414e9e043ef0321c71138f7b2a0e7a136c834ef1 recipes-core-kernel.tar.gz
93e05db4d8876d004be593fde5ce8e32da68f32b548aaa30a38db28c8357d57c recipes-core-relibc.tar.gz
c2449ef6c4bb04b1fb11998b89bcbf53176637bac2d60c5c9d35e667eca47550 redbear-full-patches.tar.gz
0836215d5f5a04b6fc846f8f98b4dd5dfd98c1f4ca7fbeca47b5cd01b2bc5c56 redbear-full-recipes.tar.gz
6ee867a2defcd6a013ff2622913ba6de4425728ba2ba6b8544828d89563f4765 services-dbus-v1.16.2-patched.tar.gz
2ce71338a83c0b17c257b3057d2c9988ff8bf958043d2a4d76d2fe60e383a815 services-seatd-v3f1eb28-patched.tar.gz
8d576fd91b66cea8842f878a382c141261b390210e0e011390968b670359b272 shells-bash-v5.2.15-patched.tar.gz
38628def4aad9fa4aef950da9e2de420973f9adf5d7cc606c5fa19ac799e8801 shells-zsh-v5.9-patched.tar.gz
85a683e768c3d36d9234b2a7ad1a8c4e4c124c75921c1dafddd82d3c42351014 system-cub-vunknown-patched.tar.gz
4916b35d619780fbf8a574c277a97c05d283b838743aa5eda8503b79452f1b06 system-evdevd-vunknown-patched.tar.gz
9fc9633a945c4d365b0e1eb34f8d18a5c417ba11979ff79ba3687eb28b9fd5c1 system-firmware-loader-vunknown-patched.tar.gz
d4cb8ed32b54271ffaf55019e27b8ecc065f0a2d40c93e40b64cab8e0dfc459b system-iommu-vunknown-patched.tar.gz
694a9dbe3a8e78469078ca77868eb4e197041c19e70d3fec774ccd248b5f565a system-redbear-authd-vunknown-patched.tar.gz
acaffb939037d7f47e59d529989fa1d07a730f8b110d0543359c890f43473e77 system-redbear-btctl-vunknown-patched.tar.gz
933e4150fe644908ed14215ce65adfa7c4109045a439cf6d4b6915918886bb42 system-redbear-dbus-services-vunknown-patched.tar.gz
2093c20a3c7469d8ccb745ddf89166f20b18897ebad93a51deb52e5b1754a565 system-redbear-firmware-vunknown-patched.tar.gz
d800b22a152be6644b49b6e94a62aaa3d79fcae7b123f38b307e06a93abf63ff system-redbear-greeter-vunknown-patched.tar.gz
d16af63308960d92ab53cc36ec42d8881f498e6df76f622887eb347a533fc4d4 system-redbear-hwutils-vunknown-patched.tar.gz
5e9a0d4515ae3723ffa3d168587622b17aadc3dce3de6cb3517d6bb2ead8bc58 system-redbear-info-vunknown-patched.tar.gz
6b373aa9efa9cc443546424ead7e059292b9fc18a7d30e61ee78bf45fce4eda8 system-redbear-login-protocol-vunknown-patched.tar.gz
899d7f873581329c105a34d6ed250c7d480a846c7ec1d2517bf40f701650b6bf system-redbear-meta-vunknown-patched.tar.gz
60d83c89ff4616dfb897aa1407cb4d50df9eea90fef0d0af4b0052208b87f7a8 system-redbear-mtr-vunknown-patched.tar.gz
431d8f00a1e69abaab7efd569d901f143aa1ab025447ccc1ec4a54f9fb01eb52 system-redbear-netctl-console-vunknown-patched.tar.gz
03be200f30feed1df7ffd4c398927227d3bedb5c98914a8b8182885f70955171 system-redbear-netctl-vunknown-patched.tar.gz
02e497ed346e3be6ba2fb0696bbcfb3677405a7a7b3041686d74b9b3ea74e60e system-redbear-netstat-vunknown-patched.tar.gz
4614f0094a0e3a4fbd9020bbf97af30614ae774c5bd5b6b768b73befe0ae52f4 system-redbear-nmap-vunknown-patched.tar.gz
e28d97371b53a94e38d85d27dcacd0c20702df07a0f43a672dcea91026086197 system-redbear-notifications-vunknown-patched.tar.gz
5a00ee80093d75b49fb261ee975337159de5678e805ce4f45e0172bbcd5154b2 system-redbear-passwd-vunknown-patched.tar.gz
f278f8b45413a7dc0794e4e20d0e85c4f9ab10c053c87aa2ab64168b8ce9dccf system-redbear-polkit-vunknown-patched.tar.gz
b73f27fa09f69b35119714156c0c1d51ed606a426ab1c075961433a13712c0ed system-redbear-quirks-vunknown-patched.tar.gz
3212767ffb06b426fb6183e20efe240bc6625d6bc4570fdc52d4c145f8aefc75 system-redbear-sessiond-vunknown-patched.tar.gz
6a56c56497e460a16011265f59ff79b3ec09f49268865aef194dfdb86baa4381 system-redbear-session-launch-vunknown-patched.tar.gz
a945b57d5db1573bb372a9c990ee603688371e3dcfbcc6f8658e4899e63b31ab system-redbear-statusnotifierwatcher-vunknown-patched.tar.gz
39a66dc9db654771752019e7880a537b64a197d50da4b3de218bfe8b97cc7679 system-redbear-traceroute-vunknown-patched.tar.gz
d1554c1ac0a2bd1d8517d077748a8f6df202a3df19a5f641afe1048fb710e718 system-redbear-udisks-vunknown-patched.tar.gz
78f7cba0fd6615e636f3de67cd5071116f7207d4295ba6053a3b03d3cef7c63b system-redbear-upower-vunknown-patched.tar.gz
3a5df1ea45ae41391999c2368a5ddb68111bd6d507fd475077df26ab1162be21 system-redbear-wifictl-vunknown-patched.tar.gz
7ebecf99b79e3c778ab754afc8cc37b19e7bafc7cc253f77ac300bb8f3c38453 system-udev-shim-vunknown-patched.tar.gz
368eac6b32215479386cbc890fa3ed3664c8b2f93057d46c440533e9fa916860 tests-redox-drm-prime-test-vunknown-patched.tar.gz
a6c6bdea2db16ea80746b0694fd0139f91b45d8884d3902eda3d12225a806366 tests-relibc-phase1-tests-vunknown-patched.tar.gz
59d31683475d60881c265dcd90940117e8989af494d114865cbe2045f731e446 tests-relibc-tests-bins-v861bbb0-patched.tar.gz
cd5cbb14c0fd791324b9a9092204e6506df3ef329384d4b673ae773e15d7bb3b tests-relibc-tests-v861bbb0-patched.tar.gz
abacbb13c8cd322b6354195073955413aaf47f33b0068f574a7be856632b9d5f text-kibi-v274b371-patched.tar.gz
872bbd46650c1d95bec31ae41583c93c10c57354cea98237ff7ac4ddd8e6ff4d tls-openssl3-v3.5.3-patched.tar.gz
ed67149137d05652604a7b413b1e8e01d35f43220a28b79ca6e2b3ea2d51caa4 tools-bzip2-v1.0.8-patched.tar.gz
e641a5081e426ebb6e040faa341317bb86fd517102517912edd34fbe300a5357 tools-diffutils-v3.6-patched.tar.gz
a44c1070830b55046eadff1c00b2cda203aae2b5455def1c31b271437bfeab61 tools-gettext-v0.22.5-patched.tar.gz
9142b86c6540364d521f4d6377f37d6fa3ee91f9b83287de321d1e35aa26a485 tools-patchelf-v0.18.0-patched.tar.gz
baae7c04d9d3d19ec03eeb352f0958c4fd3f1194911803a88485d92b484b6a28 tools-xz-v5.2.13-patched.tar.gz
cd580d47ad6392da89101229af43a875ce0d84378abf5a666dd65c83bdbb3d5f tui-mc-v4.8.33-patched.tar.gz
9ca92b1564dcdbcaf7a9acb7489f4f8e8ab998d6f714139e9072d24cce4d354f wayland-libwayland-v1.24.0-patched.tar.gz
e08c34a729eb71f93e194b801dcd219c958e9a3a999e3c90b18e901e748530ed wayland-qt6-wayland-smoke-vunknown-patched.tar.gz
3fe4ebda86ca28acaede4f1379fba0eceb18a65e3cbc6cd6a372e741cc317149 wayland-redbear-compositor-vunknown-patched.tar.gz
a517ec643eb7b373b7bf9748e353c688a7ea0f7ef070f66e92b9d8f879fbfa25 wayland-wayland-protocols-v1.38-patched.tar.gz
09ed779f68238b71d1b68d9d8c6248e2e6598cb28b0c20f0348b723f3b6d5577 x11-libdrm-v2.4.125-patched.tar.gz
c455fe44cde03931c96f8c183776e83b34f4e08a0e64fdd87aa3f74b8c846729 x11-mesa-x11-va86b5f3ac-patched.tar.gz
+1
View File
@@ -0,0 +1 @@
PODMAN_BUILD?=0
+320
View File
@@ -0,0 +1,320 @@
# Base configuration: This configuration is meant to be included by
# other configurations rather than use directly. It is the greatest
# common divisor of all other configurations and misses several
# parts necessary to create a bootable system.
# General settings
[general]
# Do not prompt if settings are not defined
prompt = false
[packages]
base = {}
base-initfs = {}
bootloader = {}
kernel = {}
libgcc = {}
libstdcxx = {}
netdb = {}
netutils = {}
relibc = {}
userutils = {}
uutils = {}
## Configuration files
[[files]]
path = "/usr/lib/init.d/00_base.service"
data = """
[unit]
description = "Base environment setup (tmpdir)"
[service]
cmd = "ion"
args = ["-c", "rm -rf /tmp; mkdir -m a=rwxt /tmp"]
type = "oneshot"
"""
[[files]]
path = "/usr/lib/init.d/00_sudo.service"
data = """
[unit]
description = "Sudo privilege daemon"
[service]
cmd = "sudo"
args = ["--daemon"]
type = "oneshot_async"
"""
[[files]]
path = "/etc/login_schemes.toml"
data = """
[user_schemes.root]
schemes = ["*"]
[user_schemes.user]
schemes = [
# Kernel schemes
"debug",
"event",
"memory",
"pipe",
"serio",
"irq",
"time",
"sys",
# Base schemes
"rand",
"null",
"zero",
"log",
# Network schemes
"ip",
"icmp",
"tcp",
"udp",
# IPC schemes
"shm",
"chan",
"uds_stream",
"uds_dgram",
# File schemes
"file",
# Display schemes
"display.vesa",
"display*",
# Other schemes
"pty",
"sudo",
"audio",
]
"""
[[files]]
path = "/etc/hostname"
data = "redbear"
## Default net configuration (optimized for QEMU)
[[files]]
path = "/etc/net/dns"
data = """
9.9.9.9
"""
[[files]]
path = "/etc/net/ip"
data = """
10.0.2.15
"""
[[files]]
path = "/etc/net/ip_router"
data = """
10.0.2.2
"""
[[files]]
path = "/etc/net/ip_subnet"
data = """
255.255.255.0
"""
# https://www.freedesktop.org/software/systemd/man/latest/os-release.html
[[files]]
path = "/usr/lib/os-release"
data = """
PRETTY_NAME="Red Bear OS 0.1.0"
NAME="Red Bear OS"
VERSION_ID="0.1.0"
VERSION="0.1.0"
ID="redbear-os"
ID_LIKE="redox-os"
HOME_URL="https://github.com/vasilito/Red-Bear-OS-3"
DOCUMENTATION_URL="https://doc.redox-os.org/"
SUPPORT_URL="https://github.com/vasilito/Red-Bear-OS-3/issues"
"""
# FIXME maybe add VARIANT= and VARIANT_ID= keys depending on the chosen configuration?
[[files]]
path = "/etc/os-release"
data = "../usr/lib/os-release"
symlink = true
[[files]]
path = "/etc/pkg.d/50_redox"
data = "https://static.redox-os.org/pkg"
## /usr and symlinks for usrmerge
[[files]]
path = "/usr"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/usr/bin"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/bin"
data = "usr/bin"
symlink = true
[[files]]
path = "/usr/include"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/include"
data = "usr/include"
symlink = true
[[files]]
path = "/usr/lib"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/lib"
data = "usr/lib"
symlink = true
[[files]]
path = "/usr/libexec"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/usr/share"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/share"
data = "usr/share"
symlink = true
[[files]]
path = "/ui"
data = "usr/share/ui"
symlink = true
## legacy display font directory
[[files]]
path = "/usr/share/ui/fonts"
data = "/usr/share/fonts"
symlink = true
## legacy display icon directory
[[files]]
path = "/usr/share/ui/icons"
data = "/usr/share/icons"
symlink = true
## /var
[[files]]
path = "/var"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/var/cache"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/var/lib"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/var/lock"
data = ""
directory = true
mode = 0o1777
[[files]]
path = "/var/log"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/var/run"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/var/tmp"
data = ""
directory = true
mode = 0o1777
## Device file symlinks
[[files]]
path = "/dev/null"
data = "/scheme/null"
symlink = true
[[files]]
path = "/dev/random"
data = "/scheme/rand"
symlink = true
[[files]]
path = "/dev/urandom"
data = "/scheme/rand"
symlink = true
[[files]]
path = "/dev/zero"
data = "/scheme/zero"
symlink = true
[[files]]
path = "/dev/tty"
data = "libc:tty"
symlink = true
[[files]]
path = "/dev/stdin"
data = "libc:stdin"
symlink = true
[[files]]
path = "/dev/stdout"
data = "libc:stdout"
symlink = true
[[files]]
path = "/dev/stderr"
data = "libc:stderr"
symlink = true
# User settings
[users.root]
password = "password"
uid = 0
gid = 0
shell = "/usr/bin/ion"
[users.user]
# Password is unset
password = ""
shell = "/usr/bin/ion"
# Group settings
[groups.sudo]
gid = 1
members = ["user"]
@@ -0,0 +1,56 @@
# Minimal configuration
include = ["base.toml"]
# General settings
[general]
# Filesystem size in MiB
filesystem_size = 196
# Package settings
[packages]
ca-certificates = {}
coreutils = {}
extrautils = {}
ion = {}
pkgutils = {}
kibi = {}
[[files]]
path = "/usr/lib/init.d/29_activate_console.service"
data = """
[unit]
description = "Activate console VT"
requires_weak = ["00_base.target"]
[service]
cmd = "inputd"
args = ["-A", "2"]
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/30_console.service"
data = """
[unit]
description = "Console terminals"
requires_weak = ["29_activate_console.service"]
[service]
cmd = "getty"
args = ["2"]
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/31_debug_console.service"
data = """
[unit]
description = "Debug console"
requires_weak = ["29_activate_console.service"]
[service]
cmd = "getty"
args = ["/scheme/debug/no-preserve", "-J"]
type = "oneshot_async"
"""
@@ -0,0 +1,17 @@
# Red Bear OS Bluetooth Experimental Profile
#
# Standalone build target for the first bounded Bluetooth slice.
#
# This profile extends the existing minimal Red Bear baseline but keeps Bluetooth wiring isolated to
# this profile instead of leaking it into the shared device-service fragments used by all images.
# The current slice is explicit-startup, USB-attached, BLE-first, and intentionally not wired to
# USB-class autospawn yet.
include = ["redbear-minimal.toml", "redbear-bluetooth-services.toml"]
[general]
filesystem_size = 2048
[packages]
redbear-btusb = {}
redbear-btctl = {}
@@ -0,0 +1,17 @@
# Red Bear OS Bluetooth experimental service wiring
#
# Kept in a dedicated included fragment so the Bluetooth profile can inject
# bounded runtime files and service units without relying on profile-local
# [[files]] behavior.
[[files]]
path = "/var/lib/bluetooth"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/var/run/redbear-btusb"
data = ""
directory = true
mode = 0o755
@@ -0,0 +1,829 @@
# Red Bear OS shared device-service wiring
#
# Shared by profiles that ship the firmware/input/Wi-Fi control compatibility stack.
[packages]
redbear-quirks = {}
pciids = {}
fatd = {}
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/usr/lib/init.d/12_boot-late.target"
data = """
[unit]
description = "Late boot services target"
requires_weak = [
"00_base.target",
]
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/lib/drivers.d"
data = ""
directory = true
mode = 0o755
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/lib/drivers.d/00-storage.toml"
data = """
[[driver]]
name = "nvmed"
description = "NVMe storage driver"
priority = 100
command = ["/usr/lib/drivers/nvmed"]
[[driver.match]]
class = 1
subclass = 8
[[driver]]
name = "ahcid"
description = "AHCI SATA driver"
priority = 100
command = ["/usr/lib/drivers/ahcid"]
[[driver.match]]
class = 1
subclass = 6
[[driver]]
name = "ided"
description = "PATA IDE driver"
priority = 100
command = ["/usr/lib/drivers/ided"]
[[driver.match]]
class = 1
subclass = 1
[[driver]]
name = "virtio-blkd"
description = "VirtIO block device driver"
priority = 100
command = ["/usr/lib/drivers/virtio-blkd"]
[[driver.match]]
vendor = 0x1AF4
device = 0x1001
class = 1
subclass = 0
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/lib/drivers.d/10-network.toml"
data = """
[[driver]]
name = "e1000d"
description = "Intel Gigabit Ethernet"
priority = 50
command = ["/usr/lib/drivers/e1000d"]
[[driver.match]]
vendor = 0x8086
class = 2
[[driver]]
name = "rtl8168d"
description = "Realtek 8168/8125 Ethernet"
priority = 50
command = ["/usr/lib/drivers/rtl8168d"]
[[driver.match]]
vendor = 0x10EC
class = 2
[[driver]]
name = "rtl8139d"
description = "Realtek 8139 Ethernet"
priority = 50
command = ["/usr/lib/drivers/rtl8139d"]
[[driver.match]]
vendor = 0x10EC
device = 0x8139
[[driver]]
name = "ixgbed"
description = "Intel 10 Gigabit Ethernet"
priority = 50
command = ["/usr/lib/drivers/ixgbed"]
[[driver.match]]
vendor = 0x8086
class = 2
subclass = 0
[[driver]]
name = "virtio-netd"
description = "VirtIO network driver"
priority = 50
command = ["/usr/lib/drivers/virtio-netd"]
[[driver.match]]
vendor = 0x1AF4
class = 2
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/lib/drivers.d/20-usb.toml"
data = """
[[driver]]
name = "xhcid"
description = "xHCI USB host controller"
priority = 80
command = ["/usr/lib/drivers/xhcid"]
[[driver.match]]
class = 0x0C
subclass = 0x03
prog_if = 0x30
[[driver]]
name = "ehcid"
description = "EHCI USB 2.0 host controller"
priority = 80
command = ["/usr/lib/drivers/ehcid"]
# EHCI now owns a simple /scheme/usb controller surface for per-port status and
# control-transfer pass-through while the wider USB stack continues converging.
[[driver.match]]
class = 0x0C
subclass = 0x03
prog_if = 0x20
[[driver]]
name = "ohcid"
description = "OHCI USB 1.1 host controller"
priority = 80
command = ["/usr/lib/drivers/ohcid"]
[[driver.match]]
class = 0x0C
subclass = 0x03
prog_if = 0x10
[[driver]]
name = "uhcid"
description = "UHCI USB 1.1 host controller (Intel)"
priority = 80
command = ["/usr/lib/drivers/uhcid"]
[[driver.match]]
class = 0x0C
subclass = 0x03
prog_if = 0x00
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/lib/drivers.d/30-graphics.toml"
data = """
[[driver]]
name = "vesad"
description = "VESA BIOS display driver"
priority = 60
command = ["/usr/lib/drivers/vesad"]
[[driver.match]]
class = 0x03
[[driver]]
name = "redox-drm"
description = "DRM/KMS display driver (AMD + Intel)"
priority = 60
command = ["/usr/bin/redox-drm"]
[[driver.match]]
class = 0x03
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/lib/drivers.d/40-input.toml"
data = """
[[driver]]
name = "ps2d"
description = "PS/2 keyboard and mouse driver"
priority = 90
command = ["/usr/lib/drivers/ps2d"]
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/lib/drivers.d/50-audio.toml"
data = """
[[driver]]
name = "ihdad"
description = "Intel HD Audio driver"
priority = 40
command = ["/usr/lib/drivers/ihdad"]
[[driver.match]]
vendor = 0x8086
class = 0x04
[[driver]]
name = "ac97d"
description = "AC'97 audio codec driver"
priority = 40
command = ["/usr/lib/drivers/ac97d"]
[[driver.match]]
class = 0x04
subclass = 0x01
"""
[[files]]
path = "/lib/drivers.d/70-usb-class.toml"
data = """
[[driver]]
name = "redbear-acmd"
description = "USB CDC ACM serial driver"
priority = 70
command = ["/usr/bin/redbear-acmd"]
[[driver]]
name = "redbear-ecmd"
description = "USB CDC ECM/NCM ethernet driver"
priority = 70
command = ["/usr/bin/redbear-ecmd"]
[[driver]]
name = "redbear-usbaudiod"
description = "USB Audio Class driver"
priority = 70
command = ["/usr/bin/redbear-usbaudiod"]
"""
# Profiles that include this fragment should start `driver-manager` instead of
# `pcid-spawner`; the manager performs the PCI bind/channel handoff itself.
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/usr/lib/init.d/00_driver-manager.service"
data = """
[unit]
description = "PCI driver spawner"
requires_weak = [
"00_base.target",
]
[service]
cmd = "pcid-spawner"
type = "oneshot"
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/lib/drivers.d"
data = ""
directory = true
mode = 0o755
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/usr/lib/init.d/10_evdevd.service"
data = """
[unit]
description = "Evdev input daemon"
requires_weak = [
"12_boot-late.target",
"00_pcid-spawner.service",
]
[service]
cmd = "evdevd"
type = "oneshot_async"
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d"
data = ""
directory = true
mode = 0o755
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/usr/lib/init.d/15_cpufreqd.service"
data = """
[unit]
description = "CPU frequency scaling daemon"
requires_weak = ["12_boot-late.target"]
[service]
cmd = "/usr/bin/cpufreqd"
type = "oneshot_async"
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/usr/lib/init.d/15_thermald.service"
data = """
[unit]
description = "Thermal management daemon"
requires_weak = ["12_boot-late.target"]
[service]
cmd = "/usr/bin/thermald"
type = "oneshot_async"
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/usr/lib/init.d/15_hwrngd.service"
data = """
[unit]
description = "Hardware RNG entropy daemon"
requires_weak = ["00_base.target"]
[service]
cmd = "/usr/bin/hwrngd"
type = "oneshot_async"
"""
# Firmware fallback chain configs
[[files]]
path = "/etc/firmware-fallbacks.d/00-amdgpu.toml"
data = """
[[fallback]]
pattern = "amdgpu/dmcub_dcn31.bin"
chain = ["amdgpu/dmcub_dcn30.bin", "amdgpu/dmcub_dcn20.bin"]
[[fallback]]
pattern = "amdgpu/dmcub_dcn30.bin"
chain = ["amdgpu/dmcub_dcn20.bin"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/10-iwlwifi.toml"
data = """
[[fallback]]
pattern = "iwlwifi-bz-b0-gf-a0-92.ucode"
chain = ["iwlwifi-bz-b0-gf-a0-83.ucode", "iwlwifi-bz-b0-gf-a0-77.ucode"]
"""
[[files]]
path = "/etc/firmware-fallbacks.d/20-intel-dmc.toml"
data = """
[[fallback]]
pattern = "i915/adlp_dmc_ver2_16.bin"
chain = ["i915/adlp_dmc_ver2_14.bin", "i915/adlp_dmc_ver2_12.bin"]
"""
[[files]]
path = "/usr/lib/init.d/13_driver-params.service"
data = """
[unit]
description = "Driver parameter scheme"
requires_weak = ["00_driver-manager.service"]
[service]
cmd = "/usr/bin/driver-params"
type = { scheme = "driver-params" }
"""
[[files]]
path = "/usr/lib/init.d/16_redbear-acmd.service"
data = """
[unit]
description = "USB CDC ACM serial daemon"
requires_weak = ["12_boot-late.target"]
[service]
cmd = "/usr/bin/redbear-acmd"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/16_redbear-ecmd.service"
data = """
[unit]
description = "USB CDC ECM/NCM ethernet daemon"
requires_weak = ["12_boot-late.target"]
[service]
cmd = "/usr/bin/redbear-ecmd"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/16_redbear-usbaudiod.service"
data = """
[unit]
description = "USB Audio Class daemon"
requires_weak = ["12_boot-late.target"]
[service]
cmd = "/usr/bin/redbear-usbaudiod"
type = "oneshot_async"
"""
@@ -0,0 +1,408 @@
# Red Bear OS Full Configuration
# Desktop/graphics ISO for bare metal and QEMU.
#
# Build: make live CONFIG_NAME=redbear-full
# QEMU: make all CONFIG_NAME=redbear-full && make qemu
#
# Extends redbear-mini with the full desktop/graphics stack:
# Wayland, Qt6, KF6, KWin, Mesa, DRM drivers, firmware, greeter.
include = ["redbear-mini.toml"]
[general]
filesystem_size = 4096
efi_partition_size = 16
[users.messagebus]
uid = 100
gid = 100
name = "messagebus"
home = "/nonexistent"
shell = "/usr/bin/ion"
[users.root]
shell = "/usr/bin/zsh"
[packages]
# Runtime driver parameter control surface.
driver-params = {}
# Firmware loading
redbear-firmware = {}
firmware-loader = {}
# NUMA topology discovery (userspace daemon)
numad = {}
# GPU/graphics stack
redox-drm = {}
mesa = {}
libdrm = {}
libwayland = {}
wayland-protocols = {}
# redbear-compositor = {}
# Keyboard/input
# libxkbcommon = {} # build needed
# xkeyboard-config = {} # build needed
libevdev = {}
# libinput = {} # WIP: missing libepoll-shim recipe dependency
# Qt6 stack
qtbase = {}
qtdeclarative = {}
qtsvg = {}
qtwayland = {}
qt6-wayland-smoke = {}
qt6-sensors = {}
# KF6 Frameworks — explicit real-build surface in alphabetical order
# kirigami: blocked (QML gate — QQuickWindow/QQmlEngine headers don't exist on Redox)
kf6-kio = {}
# kde-cli-tools = {} # blocked: direct repo cook fails
kdecoration = {}
kf6-attica = {}
kf6-karchive = {}
kf6-kauth = {}
kf6-kbookmarks = {}
kf6-kcmutils = {}
kf6-kcodecs = {}
kf6-kcolorscheme = {}
kf6-kcompletion = {}
kf6-kconfig = {}
kf6-kconfigwidgets = {}
kf6-kcoreaddons = {}
kf6-kcrash = {}
kf6-kdbusaddons = {}
kf6-kdeclarative = {}
kf6-kded6 = {}
kf6-kguiaddons = {}
kf6-ki18n = {}
kf6-kiconthemes = {}
kf6-kidletime = {}
kf6-kitemmodels = {}
kf6-kitemviews = {}
kf6-kjobwidgets = {}
kf6-knotifications = {}
kf6-kpackage = {}
kf6-kservice = {}
kf6-ktextwidgets = {}
kf6-kwayland = {}
kf6-kwidgetsaddons = {}
kf6-kxmlgui = {}
kf6-prison = {}
kf6-solid = {}
kf6-sonnet = {}
kf6-knewstuff = {}
kf6-kwallet = {}
kglobalacceld = {}
# kwin = {} # Blocked: Qt6 Wayland plugin import error (QML gate)
# Plasma + app packages — blocked on kirigami (QML gate)
# plasma-framework = {}
# plasma-workspace = {}
# plasma-desktop = {}
redbear-authd = {}
redbear-session-launch = {}
seatd = {}
redbear-greeter = {}
amdgpu = {}
# Core Red Bear umbrella package
redbear-meta = {}
# Phase 1 runtime validation tests (POSIX: signalfd, timerfd, eventfd, shm_open, sem_open, waitid)
relibc-phase1-tests = {}
# Desktop fonts and icons
dejavu = {}
freefont = {}
hicolor-icon-theme = {}
pop-icon-theme = {}
# Suppress legacy desktop packages
orbdata = "ignore"
orbital = "ignore"
orbterm = "ignore"
orbutils = "ignore"
cosmic-edit = "ignore"
cosmic-files = "ignore"
cosmic-icons = "ignore"
cosmic-term = "ignore"
curl = "ignore"
git = "ignore"
mc = "ignore"
#curl = "ignore" # suppressed: cascade rebuild
#git = "ignore" # suppressed: cascade rebuild
#konsole = {} # WIP: recipe exists, not yet built — blocked by libiconv fetch
#kf6-pty = {} # WIP: recipe exists, not yet built
[[files]]
path = "/lib/firmware/amdgpu"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/usr/lib/fonts"
data = "/usr/share/fonts"
symlink = true
[[files]]
path = "/usr/lib/init.d/05_boot-essential.target"
data = """
[unit]
description = "Boot essential services target"
requires_weak = [
"00_base.target",
]
"""
[[files]]
path = "/usr/lib/init.d/13_iommu.service"
data = """
[unit]
description = "IOMMU DMA remapping daemon"
requires_weak = [
"12_boot-late.target",
"00_pcid-spawner.service",
]
[service]
cmd = "/usr/bin/iommu"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/12_dbus.service"
data = """
[unit]
description = "D-Bus system bus"
requires_weak = [
"12_boot-late.target",
]
[service]
cmd = "dbus-daemon"
args = ["--system", "--nopidfile"]
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/13_redbear-sessiond.service"
data = """
[unit]
description = "Red Bear session broker (org.freedesktop.login1)"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-sessiond"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/13_seatd.service"
data = """
[unit]
description = "seatd seat management daemon"
requires_weak = [
"12_dbus.service",
"13_redbear-sessiond.service",
]
[service]
cmd = "/usr/bin/seatd"
args = ["-l", "info"]
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/14_redbear-upower.service"
data = """
[unit]
description = "UPower D-Bus service (org.freedesktop.UPower)"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-upower"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/14_redbear-udisks.service"
data = """
[unit]
description = "UDisks2 D-Bus service (org.freedesktop.UDisks2)"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-udisks"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/14_redbear-polkit.service"
data = """
[unit]
description = "PolicyKit1 D-Bus service (org.freedesktop.PolicyKit1)"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-polkit"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/19_redbear-authd.service"
data = """
[unit]
description = "Red Bear authentication daemon"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "/usr/bin/redbear-authd"
envs = { QT_PLUGIN_PATH = "/usr/plugins", QT_QPA_PLATFORM_PLUGIN_PATH = "/usr/plugins/platforms", QML2_IMPORT_PATH = "/usr/qml", XCURSOR_THEME = "Pop", XKB_CONFIG_ROOT = "/usr/share/X11/xkb", KWIN_DRM_DEVICES = "/scheme/drm/card0" }
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/20_display.service"
data = """
[unit]
description = "KDE session assembly helper"
requires_weak = [
"12_dbus.service",
"13_redbear-sessiond.service",
"13_seatd.service",
"19_redbear-authd.service",
]
[service]
cmd = "/usr/bin/redbear-session-launch"
args = ["--username", "root", "--mode", "session", "--session", "kde-wayland", "--vt", "4", "--runtime-dir", "/tmp/run/redbear-display-session", "--wayland-display", "wayland-display"]
envs = { QT_PLUGIN_PATH = "/usr/plugins", QT_QPA_PLATFORM_PLUGIN_PATH = "/usr/plugins/platforms", QML2_IMPORT_PATH = "/usr/qml", XCURSOR_THEME = "Pop", XKB_CONFIG_ROOT = "/usr/share/X11/xkb", REDBEAR_KDE_SESSION_BACKEND = "virtual", REDBEAR_KDE_SESSION_STATE_DIR = "/run/redbear-display-session" }
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/20_greeter.service"
data = """
[unit]
description = "Red Bear greeter service"
requires_weak = [
"00_pcid-spawner.service",
"12_dbus.service",
"13_redbear-sessiond.service",
"13_seatd.service",
"19_redbear-authd.service",
]
[service]
cmd = "/usr/bin/redbear-greeterd"
envs = { VT = "3", REDBEAR_GREETER_USER = "greeter", KWIN_DRM_DEVICES = "/scheme/drm/card0", REDBEAR_DRM_WAIT_SECONDS = "10" }
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/29_activate_console.service"
data = """
[unit]
description = "Activate fallback console VT"
requires_weak = [
"05_boot-essential.target",
]
[service]
cmd = "inputd"
args = ["-A", "2"]
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/30_console.service"
data = """
[unit]
description = "Console terminals"
requires_weak = [
"29_activate_console.service",
]
[service]
cmd = "getty"
args = ["2"]
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/31_debug_console.service"
data = """
[unit]
description = "Debug console"
requires_weak = [
"29_activate_console.service",
]
[service]
cmd = "getty"
args = ["/scheme/debug/no-preserve", "-J"]
type = "oneshot_async"
"""
[users.greeter]
password = ""
uid = 101
gid = 101
name = "greeter"
home = "/nonexistent"
shell = "/usr/bin/ion"
[groups.greeter]
gid = 101
members = ["greeter"]
[groups.messagebus]
gid = 100
members = ["messagebus"]
[[files]]
path = "/etc/pcid.d/ihdgd.toml"
data = """
[[drivers]]
name = "Intel GPU (VGA compatible)"
class = 0x03
vendor = 0x8086
subclass = 0x00
command = ["redox-drm"]
[[drivers]]
name = "Intel GPU (3D controller)"
class = 0x03
vendor = 0x8086
subclass = 0x02
command = ["redox-drm"]
"""
[[files]]
path = "/etc/pcid.d/virtio-gpud.toml"
data = """
[[drivers]]
name = "VirtIO GPU"
class = 0x03
vendor = 0x1af4
subclass = 0x00
command = ["redox-drm"]
"""
@@ -0,0 +1,127 @@
# Red Bear greeter/login service wiring
#
# This fragment is intended to be included by the active desktop/graphics target.
[[files]]
path = "/usr/lib/init.d/05_boot-essential.target"
data = """
[unit]
description = "Boot essential services target"
requires_weak = [
"00_base.target",
]
"""
[users.greeter]
password = ""
uid = 101
gid = 101
name = "greeter"
home = "/nonexistent"
shell = "/usr/bin/ion"
[groups.greeter]
gid = 101
members = ["greeter"]
[packages]
redbear-authd = {}
redbear-session-launch = {}
redbear-greeter = {}
[[files]]
path = "/usr/lib/init.d/19_redbear-authd.service"
data = """
[unit]
description = "Red Bear authentication daemon"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-authd"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/20_display.service"
data = """
[unit]
description = "Compositor proof (Phase 2: KWin virtual + Qt6 smoke + 60s survival)"
requires_weak = [
"12_dbus.service",
"13_redbear-sessiond.service",
"13_seatd.service",
]
[service]
cmd = "redbear-validation-session"
envs = { VT = "3" }
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/20_greeter.service"
data = """
[unit]
description = "Red Bear greeter service (experimental Phase 3 user session bring-up)"
requires_weak = [
"00_pcid-spawner.service",
"12_dbus.service",
"13_redbear-sessiond.service",
"13_seatd.service",
"19_redbear-authd.service",
]
[service]
cmd = "/usr/bin/redbear-greeterd"
envs = { VT = "3", REDBEAR_GREETER_USER = "greeter", KWIN_DRM_DEVICES = "/scheme/drm/card0", REDBEAR_DRM_WAIT_SECONDS = "10" }
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/30_console.service"
data = """
[unit]
description = "Console terminals"
requires_weak = [
"29_activate_console.service",
]
[service]
cmd = "getty"
args = ["2"]
type = "oneshot_async"
respawn = true
"""
[[files]]
path = "/usr/lib/init.d/29_activate_console.service"
data = """
[unit]
description = "Activate fallback console VT"
requires_weak = [
"05_boot-essential.target",
]
[service]
cmd = "inputd"
args = ["-A", "2"]
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/31_debug_console.service"
data = """
[unit]
description = "Debug console"
requires_weak = [
"29_activate_console.service",
]
[service]
cmd = "getty"
args = ["/scheme/debug/no-preserve", "-J"]
type = "oneshot_async"
respawn = true
"""
@@ -0,0 +1,9 @@
# Red Bear OS shared GRUB policy fragment
# Use with any redbear-* profile to make GRUB first-class in installer flows.
[general]
bootloader = "grub"
efi_partition_size = 16
[packages]
grub = {}
@@ -0,0 +1,16 @@
# Red Bear OS GRUB Configuration
# Text-only ISO with GRUB boot manager for bare metal.
#
# Build: make live CONFIG_NAME=redbear-grub
#
# Identical to redbear-mini but uses GNU GRUB as the boot manager
# instead of the Redox EFI bootloader.
include = ["redbear-mini.toml", "redbear-grub-policy.toml"]
[general]
bootloader = "grub"
efi_partition_size = 16
[packages]
grub = {}
@@ -0,0 +1,51 @@
# Red Bear OS overrides for base init services.
#
# 00_base.service: stripped base setup (tmpdir only, no sudo — sudo runs from
# base.toml's 00_sudo.service). ipcd and ptyd are started by
# 00_ipcd.service and 00_ptyd.service from the base recipe.
# 00_drivers / 10_net: no longer overridden — the legacy scripts were removed
# from base.toml. The retained 00_pcid-spawner.service unit name now
# launches driver-manager so existing init ordering remains stable.
# 00_pcid-spawner.service: compatibility wrapper for driver-manager. The base
# recipe uses type="oneshot" which blocks init until pcid-spawner exits.
# Running driver-manager here with oneshot_async keeps the historic unit
# name for downstream `requires_weak` consumers while moving PCI driver
# spawning to the manager that performs bind/channel handoff.
[packages]
zsh = {}
[[files]]
path = "/usr/lib/init.d/00_base.service"
data = """
[unit]
description = "Base environment setup (tmpdir)"
[service]
cmd = "ion"
args = ["-c", "rm -rf /tmp; mkdir -m a=rwxt /tmp"]
type = "oneshot"
"""
[[files]]
path = "/etc/init.d/20_audiod.service"
data = """
[unit]
description = "Audio multiplexer"
default_dependencies = false
[service]
cmd = "audiod"
type = "oneshot_async"
"""
[[files]]
path = "/etc/init.d/00_pcid-spawner.service"
data = """
[unit]
description = "PCI driver spawner"
[service]
cmd = "pcid-spawner"
type = "oneshot"
"""
@@ -0,0 +1,20 @@
# Red Bear OS overrides for legacy desktop init services.
# Blank the display and console services inherited from desktop-minimal.toml.
# These intentional empty overrides prevent the inherited services from launching;
# the active redbear-full config provides its own display/console/greeter services.
[[files]]
path = "/usr/lib/init.d/20_display.service"
data = ""
[[files]]
path = "/usr/lib/init.d/29_activate_console.service"
data = ""
[[files]]
path = "/usr/lib/init.d/30_console.service"
data = ""
[[files]]
path = "/usr/lib/init.d/31_debug_console.service"
data = ""
@@ -0,0 +1,467 @@
# Red Bear OS Mini Configuration
# Text-only ISO for console/recovery/install on bare metal.
#
# Build: make live CONFIG_NAME=redbear-mini
#
# Target contract:
# - text-login live/recovery/install surface
# - boot framebuffer for VT text consoles via vesad + fbcond
# - all non-graphics, non-firmware packages from the full profile
# - no linux-firmware payload, no firmware-loader, no GPU/display drivers
include = ["minimal.toml", "redbear-legacy-base.toml", "redbear-netctl.toml", "redbear-device-services.toml"]
[general]
filesystem_size = 1536
[users.messagebus]
uid = 100
gid = 100
name = "messagebus"
home = "/nonexistent"
shell = "/usr/bin/ion"
[packages]
# Red Bear OS branding and host utilities.
redbear-release = {}
redbear-hwutils = {}
redbear-quirks = {}
# Device driver infrastructure (pcid-spawner is built by the base recipe;
# driver-manager requires driver config migration and is not yet ready)
ehcid = {}
ohcid = {}
uhcid = {}
# Redox-native netctl tooling.
redbear-netctl = {}
redbear-netctl-console = {}
redbear-netstat = {}
redbear-traceroute = {}
redbear-mtr = {}
redbear-nmap = {}
# Wi-Fi control daemon (firmware-loader excluded — no firmware blobs in mini).
redbear-wifictl = {}
# Diagnostics and shell-side utilities.
mc = "ignore"
redbear-info = {}
# Keep package builder utility in live environment.
cub = {}
cpufreqd = {}
thermald = {}
hwrngd = {}
redbear-acmd = {}
redbear-ecmd = {}
redbear-usbaudiod = {}
driver-params = {}
# ── PCI device database (critical for PCI driver matching) ──
pciids = {}
# ── Filesystem support ──
ext4d = {}
fatd = {}
redoxfs = {}
# ── System installer ──
installer = {}
# ── Input / device management ──
evdevd = {}
udev-shim = {}
# ── D-Bus IPC and session services ──
dbus = {}
redbear-sessiond = {}
redbear-dbus-services = {}
redbear-notifications = {}
redbear-upower = {}
redbear-udisks = {}
redbear-polkit = {}
# ── IOMMU DMA remapping ──
iommu = {}
# ── Standard CLI tools (from server profile) ──
bash = {}
bottom = {}
#curl = {} # suppressed: nghttp2 dependency chain fails; curl not needed for boot/recovery
diffutils = {}
findutils = {}
#git = {} # suppressed: cascading rebuild; git not needed for boot/recovery
htop = {}
#mc = {} # suppressed: C99 format warning errors in compilation
# ── Build / packaging utilities ──
# patchelf = {} # requires strtold which is missing in relibc
shared-mime-info = {}
# VT/getty/login chain: initfs starts inputd + vesad + fbcond in phase 1,
# then minimal.toml legacy 30_console runs inputd -A 2 + getty 2 + getty debug.
[[files]]
path = "/etc/netctl/active"
data = "wired-dhcp\n"
[[files]]
path = "/etc/init.d/10_smolnetd.service"
data = """
[unit]
description = "Network stack (non-blocking on live-mini)"
requires_weak = [
"00_pcid-spawner.service",
]
[service]
cmd = "netstack"
type = "oneshot_async"
"""
[[files]]
path = "/etc/init.d/10_dhcpd.service"
data = """
[unit]
description = "DHCP client daemon (non-blocking on live-mini)"
requires_weak = [
"10_smolnetd.service",
]
[service]
cmd = "dhcpd"
args = ["-f"]
type = "oneshot_async"
"""
[[files]]
path = "/etc/issue"
data = """
########## Red Bear OS #########
# Login with the following: #
# `user` #
# `root`:`password` #
################################
"""
[[files]]
path = "/etc/motd"
data = """
_ _
| | (_)
| | ___ _ ___ _ __ _ _ ___
| |/ / || |/ _ \\ | '_ \\| | | / __|
| < | || | (_) || |_) | |_| \\__ \\
|_|\\_\\|_|/ |\\___/ | .__/ \\__,_|___/
|__/ | |
|_|
Red Bear OS v0.2.0 "Liliya" — Built on Redox OS
Type 'help' for available commands.
"""
[[files]]
path = "/etc/init.d/20_audiod.service"
data = """
[unit]
description = "Audio multiplexer (non-blocking on live-mini)"
requires_weak = [
"00_base.target",
]
[service]
cmd = "audiod"
type = "oneshot_async"
"""
[[files]]
path = "/etc/init.d/02_serial_probe.service"
data = """
[unit]
description = "Serial boot probe marker"
requires_weak = [
"00_base.target",
]
[service]
cmd = "echo"
args = ["RB_SERIAL_PROBE_OK"]
type = "oneshot"
"""
[[files]]
path = "/etc/init.d/00_gpiod.service"
data = """
[unit]
description = "GPIO controller registry (non-blocking on live-mini)"
requires_weak = [
"00_base.target",
]
[service]
cmd = "gpiod"
type = { scheme = "gpio" }
"""
[[files]]
path = "/etc/init.d/00_i2cd.service"
data = """
[unit]
description = "I2C adapter registry (non-blocking on live-mini)"
requires_weak = [
"00_base.target",
]
[service]
cmd = "i2cd"
type = { scheme = "i2c" }
"""
[[files]]
path = "/etc/init.d/00_i2c-dw-acpi.service"
data = """
[unit]
description = "DesignWare ACPI I2C controller (non-blocking)"
requires_weak = [
"00_i2cd.service",
]
[service]
cmd = "dw-acpi-i2cd"
type = "oneshot_async"
"""
[[files]]
path = "/etc/init.d/00_intel-gpiod.service"
data = """
[unit]
description = "Intel ACPI GPIO registrar (non-blocking)"
requires_weak = [
"00_gpiod.service",
"00_i2cd.service",
]
[service]
cmd = "intel-gpiod"
type = "oneshot_async"
"""
[[files]]
path = "/etc/init.d/00_i2c-gpio-expanderd.service"
data = """
[unit]
description = "I2C GPIO expander companion bridge (non-blocking on live-mini)"
requires_weak = [
"00_i2cd.service",
"00_gpiod.service",
]
[service]
cmd = "i2c-gpio-expanderd"
type = "oneshot_async"
"""
[[files]]
path = "/etc/init.d/00_i2c-hidd.service"
data = """
[unit]
description = "ACPI I2C HID bring-up daemon (non-blocking)"
requires_weak = [
"00_i2cd.service",
"00_i2c-dw-acpi.service",
"00_intel-gpiod.service",
"00_i2c-gpio-expanderd.service",
]
[service]
cmd = "i2c-hidd"
type = "oneshot_async"
"""
[[files]]
path = "/etc/init.d/00_ucsid.service"
data = """
[unit]
description = "USB-C UCSI topology detector (non-blocking on live-mini)"
requires_weak = [
"00_base.target",
"00_i2cd.service",
]
[service]
cmd = "ucsid"
type = { scheme = "ucsi" }
"""
[[files]]
path = "/usr/lib/init.d/12_boot-late.target"
data = """
[unit]
description = "Late boot services target"
requires_weak = [
"00_base.target",
]
"""
[[files]]
path = "/usr/lib/init.d/11_udev.service"
data = """
[unit]
description = "udev compatibility shim"
requires_weak = [
"12_boot-late.target",
"00_pcid-spawner.service",
]
[service]
cmd = "udev-shim"
type = { scheme = "udev" }
"""
[[files]]
path = "/usr/lib/init.d/10_evdevd.service"
data = """
[unit]
description = "Evdev input daemon"
requires_weak = [
"12_boot-late.target",
"00_pcid-spawner.service",
]
[service]
cmd = "evdevd"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/11_wifictl.service"
data = """
[unit]
description = "Wi-Fi control daemon"
requires_weak = [
"12_boot-late.target",
"00_pcid-spawner.service",
]
[service]
cmd = "redbear-wifictl"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/12_dbus.service"
data = """
[unit]
description = "D-Bus system bus"
requires_weak = [
"12_boot-late.target",
]
[service]
cmd = "dbus-daemon"
args = ["--system"]
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/13_redbear-sessiond.service"
data = """
[unit]
description = "Red Bear session broker (org.freedesktop.login1)"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-sessiond"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/13_iommu.service"
data = """
[unit]
description = "IOMMU DMA remapping daemon"
requires_weak = [
"12_boot-late.target",
"00_pcid-spawner.service",
]
[service]
cmd = "/usr/bin/iommu"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/14_redbear-upower.service"
data = """
[unit]
description = "UPower D-Bus service (org.freedesktop.UPower)"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-upower"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/14_redbear-udisks.service"
data = """
[unit]
description = "UDisks2 D-Bus service (org.freedesktop.UDisks2)"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-udisks"
type = "oneshot_async"
"""
[[files]]
path = "/usr/lib/init.d/14_redbear-polkit.service"
data = """
[unit]
description = "PolicyKit1 D-Bus service (org.freedesktop.PolicyKit1)"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-polkit"
type = "oneshot_async"
"""
[[files]]
path = "/var/lib/dbus"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/run/dbus"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/etc/pcid.d/ihdgd.toml"
data = """
# redbear-live-mini: text-only image; override upstream ihdgd config with empty file
"""
[[files]]
path = "/etc/pcid.d/virtio-gpud.toml"
data = """
# redbear-live-mini: text-only image; override upstream virtio-gpud config with empty file
"""
[[files]]
path = "/etc/pcid.d/00_text_mode_gpu_mask.toml"
data = """
# redbear-live-mini: no display driver matched; class 0x03 devices are skipped
"""
@@ -0,0 +1,106 @@
# Red Bear OS shared network profile wiring
#
# Shared by redbear-minimal, redbear-desktop, redbear-full, and redbear-kde.
[[files]]
path = "/etc/netctl"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/etc/netctl/examples"
data = ""
directory = true
mode = 0o755
[[files]]
path = "/etc/netctl/examples/wired-dhcp"
data = """
Description='Red Bear wired DHCP profile'
Interface=eth0
Connection=ethernet
IP=dhcp
"""
[[files]]
path = "/etc/netctl/wired-dhcp"
data = """
Description='Red Bear wired DHCP profile'
Interface=eth0
Connection=ethernet
IP=dhcp
"""
[[files]]
path = "/etc/netctl/examples/wired-static"
data = """
Description='Red Bear wired static profile'
Interface=eth0
Connection=ethernet
IP=static
Address=('192.168.1.10/24')
Gateway='192.168.1.1'
DNS=('1.1.1.1')
"""
[[files]]
path = "/etc/netctl/examples/wifi-dhcp"
data = """
Description='Red Bear Wi-Fi DHCP profile'
Interface=wlan0
Connection=wifi
SSID='example-ssid'
Security=wpa2-psk
Key='example-passphrase'
IP=dhcp
"""
[[files]]
path = "/etc/netctl/examples/wifi-open"
data = """
Description='Red Bear Wi-Fi open-network profile'
Interface=wlan0
Connection=wifi
SSID='example-open-ssid'
Security=open
IP=dhcp
"""
[[files]]
path = "/etc/netctl/examples/wifi-open-bounded"
data = """
Description='Red Bear Wi-Fi bounded lifecycle profile'
Interface=wlan0
Connection=wifi
SSID='example-open-ssid'
Security=open
IP=bounded
"""
[[files]]
path = "/etc/netctl/wifi-open-bounded"
data = """
Description='Red Bear Wi-Fi bounded lifecycle profile'
Interface=wlan0
Connection=wifi
SSID='example-open-ssid'
Security=open
IP=bounded
"""
[[files]]
path = "/usr/lib/init.d/12_netctl.service"
data = """
[unit]
description = "Network profile application"
requires_weak = [
"10_smolnetd.service",
"10_dhcpd.service",
]
[service]
cmd = "redbear-netctl"
args = ["--boot"]
type = "oneshot_async"
"""
@@ -0,0 +1,20 @@
# Red Bear OS Wi-Fi Experimental Profile
#
# Standalone tracked build target for the current bounded Intel Wi-Fi slice.
#
# This profile extends the existing minimal Red Bear baseline but switches the default active profile
# to the bounded Wi-Fi path and adds the first Intel driver-side package on top of the shared
# firmware/control/profile tooling.
include = ["redbear-minimal.toml"]
[general]
filesystem_size = 2048
[packages]
# First bounded Intel driver-side package
redbear-iwlwifi = {}
[[files]]
path = "/etc/netctl/active"
data = "wifi-open-bounded\n"
+385
View File
@@ -0,0 +1,385 @@
# Red Bear OS 0.1.0 Release Manifest
# Generated: vie 01 may 2026 10:31:16 WEST
# Build system: f55acba68
# Total: 404 recipes (139 git, 165 tar)
archives/lz4 tar=https://github.com/lz4/lz4/releases/download/v1.10.0/lz4-1.10.0.tar.gz blake3=3e69fd475e7852e17594985528b5232afeba7d3d56cfebe2e89071768b2ab36a
archives/zstd tar=https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz blake3=730dca31244abd219e995f03a55d95b2cfb4b3e16cda055a79fa6f30a4f0e1db
artwork/pop-wallpapers git=https://github.com/pop-os/wallpapers rev=
artwork/ubuntu-wallpapers tar=https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/ubuntu-wallpapers/23.10.4/ubuntu-wallpapers_23.10.4.orig.tar.gz blake3=1e479d0aa48fe3f2961a2dac28c3ed397a29616cf6e7d73f5ceb6fabfd6449e1
branding/redbear-release path=source
core/base git=https://gitlab.redox-os.org/redox-os/base.git rev=463f76b9608a896e6f6c9f63457f57f6409873c7
core/base-initfs same_as=../base
core/binutils git=https://gitlab.redox-os.org/redox-os/binutils.git rev=
core/bootloader git=https://gitlab.redox-os.org/redox-os/bootloader.git rev=b22a35c
core/contain git=https://gitlab.redox-os.org/redox-os/contain.git rev=
core/coreutils git=https://gitlab.redox-os.org/redox-os/coreutils.git rev=5559e20
core/dash git=https://gitlab.redox-os.org/redox-os/dash.git rev=
core/ext4d path=source
core/extrautils git=https://gitlab.redox-os.org/redox-os/extrautils.git rev=fb66941
core/fatd path=source
core/findutils git=https://gitlab.redox-os.org/redox-os/findutils.git rev=116c044
core/grub tar=https://ftp.gnu.org/gnu/grub/grub-2.12.tar.xz blake3=13c48453f9becf4a6e49618749dc7cb83a2c4a0d7600eeeadc6c7c2772c0b877
core/installer git=https://gitlab.redox-os.org/redox-os/installer.git rev=948bfdc
core/ion git=https://gitlab.redox-os.org/redox-os/ion.git rev=1440704f
core/kernel git=https://gitlab.redox-os.org/redox-os/kernel.git rev=866dfad
core/netdb git=https://gitlab.redox-os.org/redox-os/netdb.git rev=2c15606
core/netutils git=https://gitlab.redox-os.org/redox-os/netutils.git rev=40a573b
core/pkgar git=https://gitlab.redox-os.org/redox-os/pkgar.git rev=
core/pkgutils git=https://gitlab.redox-os.org/redox-os/pkgutils.git rev=70c5067
core/profiled git=https://gitlab.redox-os.org/redox-os/profiled.git rev=
core/redoxfs git=https://gitlab.redox-os.org/redox-os/redoxfs.git rev=b596776
core/relibc git=https://gitlab.redox-os.org/redox-os/relibc.git rev=861bbb0
core/strace git=https://gitlab.redox-os.org/redox-os/strace-redox.git rev=
core/userutils git=https://gitlab.redox-os.org/redox-os/userutils.git rev=0c5274f
core/uutils git=https://github.com/uutils/coreutils rev=1f7c81f5d2d3e56c518349c0392158871a1ea9ec
demos/cmatrix git=https://github.com/abishekvashok/cmatrix rev=
demos/cpal git=https://gitlab.redox-os.org/redox-os/cpal.git rev=
demos/dynamic-example git=https://gitlab.redox-os.org/redox-os/dynamic-example.git rev=
demos/exampled git=https://gitlab.redox-os.org/redox-os/exampled.git rev=
demos/glutin git=https://gitlab.redox-os.org/redox-os/glutin.git rev=
demos/iced git=https://gitlab.redox-os.org/redox-os/iced.git rev=
demos/orbclient git=https://gitlab.redox-os.org/redox-os/orbclient.git rev=
demos/pixelcannon git=https://github.com/jackpot51/pixelcannon.git rev=
demos/winit git=https://github.com/pop-os/winit.git rev=
dev/autoconf tar=https://ftp.gnu.org/gnu/autoconf/autoconf-2.71.tar.xz blake3=da1cc8af8551c343de9f42af0ae53fd7dff3623487157623892b6cd7e3bb5692
dev/automake tar=https://ftp.gnu.org/gnu/automake/automake-1.16.5.tar.xz blake3=f42cfc333aaaa11f2bcb05b5b0273b8706c820c22f9ba4367f7eb920551695cd
dev/binutils-gdb git=https://gitlab.redox-os.org/redox-os/binutils-gdb rev=
dev/clang21 same_as=../llvm21
dev/cmake tar=https://github.com/Kitware/CMake/releases/download/v4.0.3/cmake-4.0.3.tar.gz blake3=
dev/crates-io-index git=https://github.com/rust-lang/crates.io-index.git rev=
dev/fontconfig tar=https://www.freedesktop.org/software/fontconfig/release/fontconfig-2.16.0.tar.xz blake3=5c95d48f5b9150f4a06d8acac12c25edaac956007df95a3bf527df02a5908f0e
dev/gcc13 git=https://gitlab.redox-os.org/redox-os/gcc rev=8e365ce7e5
dev/gdbserver git=https://gitlab.redox-os.org/redox-os/gdbserver.git rev=
dev/gdk-pixbuf tar=https://ftp.gnome.org/pub/gnome/sources/gdk-pixbuf/2.44/gdk-pixbuf-2.44.4.tar.xz blake3=94db7bebffbd6be84a1b58a05771e411e9f7c16b06d73fcedaf0e6c0e552be9c
dev/git tar=https://www.kernel.org/pub/software/scm/git/git-2.13.1.tar.xz blake3=bc78271bffd60c5b8b938d8c08fd74dc2de8d21fbaf8f8e0e3155436d9263f17
dev/gitoxide git=https://github.com/Byron/gitoxide.git rev=
dev/gnu-make tar=http://ftp.gnu.org/gnu/make/make-4.4.tar.gz blake3=1a0e5353205e106bd9b3c0f4a5f37ee1156a1e1c8feb771d1b4842c216612cba
dev/hello-world-examples git=https://github.com/leachim6/hello-world rev=
dev/jq tar=https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-1.8.1.tar.gz blake3=
dev/lci git=https://github.com/jD91mZM2/rust-lci rev=
dev/libtool git=https://gitlab.redox-os.org/redox-os/libtool rev=
dev/lld21 same_as=../llvm21
dev/llvm18 git=https://gitlab.redox-os.org/redox-os/llvm-project.git rev=
dev/llvm21 git=https://gitlab.redox-os.org/redox-os/llvm-project.git rev=250d0b022e
dev/lua54 tar=https://lua.org/ftp/lua-5.4.7.tar.gz blake3=e51c2f347e3185479d5ff95cae8ac77511db486853269443c56bedaa0a6ae629
dev/luajit git=https://luajit.org/git/luajit.git rev=a4f56a459a588ae768801074b46ba0adcfb49eb1
dev/luarocks git=https://github.com/luarocks/luarocks.git rev=
dev/nasm tar=https://gstreamer.freedesktop.org/src/mirror/nasm-2.14.02.tar.xz blake3=f66c0cc852c3b9e3321f57c33ef336e17a128bd3d854ee095aae7e6f64629f20
dev/patch tar=https://ftp.gnu.org/gnu/patch/patch-2.7.6.tar.xz blake3=d46d14c12aa4ea51e356bf92091c368fd871e1d770b94bc29027886737aecd5f
dev/pciids git=https://github.com/pciutils/pciids.git rev=1f4ff7c
dev/php84 tar=https://www.php.net/distributions/php-8.4.17.tar.xz blake3=a8478dddd948d4b26e51c5727ac0895440da76e8ad9be947098a4284ca0b7f2a
dev/pkg-config tar=https://pkg-config.freedesktop.org/releases/pkg-config-0.29.2.tar.gz blake3=713372b09a1fafeec130dc9bf812a3880f2a90496af5d2194e508d91ccf667d0
dev/python312 tar=https://www.python.org/ftp/python/3.12.12/Python-3.12.12.tar.xz blake3=29636fdae3e0ee8d0fe585e528c9376fe43876f5f3f0f7892140567946fd907b
dev/redoxer git=https://gitlab.redox-os.org/redox-os/redoxer rev=
dev/rust git=https://gitlab.redox-os.org/redox-os/rust.git rev=
dev/rustpython git=https://github.com/RustPython/RustPython rev=2025-10-13-main-51
doc/book git=https://gitlab.redox-os.org/redox-os/book.git rev=
drivers/ehcid path=source
drivers/linux-kpi path=source
drivers/ohcid path=source
drivers/redbear-btusb path=source
drivers/redbear-iwlwifi path=source
drivers/redox-driver-core path=source
drivers/redox-driver-pci path=source
drivers/redox-driver-sys path=source
drivers/uhcid path=source
drivers/usb-core path=source
emulators/dosbox tar=https://sourceforge.net/projects/dosbox/files/dosbox/0.74-3/dosbox-0.74-3.tar.gz/download blake3=8bc50ffdba20579fb3080a0dca32cb939c8a3c19259aed026482c6ac069b0007
emulators/flycast git=https://github.com/jackpot51/flycast.git rev=
emulators/libretro-super git=https://github.com/jackpot51/libretro-super.git rev=
emulators/mednafen tar=https://mednafen.github.io/releases/files/mednafen-1.29.0.tar.xz blake3=c75c1044cdc9328b2349915a67972d6135c77eb53eb0d995788f22b7daacf79b
emulators/mgba tar=https://github.com/mgba-emu/mgba/archive/0.10.5.tar.gz blake3=a1b9e797a5058f5264d276805aef5643b7ea460916e491a0098ba32d87f1519e
emulators/retroarch git=https://github.com/jackpot51/retroarch.git rev=
emulators/rs-nes git=https://gitlab.redox-os.org/redox-os/rs-nes.git rev=
emulators/rust64 git=https://gitlab.redox-os.org/redox-os/rust64.git rev=
emulators/rustual-boy git=https://gitlab.redox-os.org/redox-os/rustual-boy.git rev=
emulators/rvvm git=https://github.com/LekKit/RVVM.git rev=
emulators/scummvm tar=https://downloads.scummvm.org/frs/scummvm/2.0.0/scummvm-2.0.0.tar.xz blake3=02e6791fd43ad3cb4238c07d23350ca1459a0f692689e585dba1d46648f64327
files/hf git=https://github.com/sorairolake/hf rev=
fonts/dejavu tar=http://sourceforge.net/projects/dejavu/files/dejavu/2.37/dejavu-fonts-ttf-2.37.tar.bz2 blake3=b702bac8a0f8e0802758549da3b4d8041c3c83c3894e1e8a960eab53af18cce8
fonts/freefont tar=https://ftp.gnu.org/gnu/freefont/freefont-otf-20120503.tar.gz blake3=e950397741d84981106cf648fbc143c7827b61d637c86c916232d47aabdfe253
fonts/ibm-plex tar=https://github.com/IBM/plex/archive/refs/tags/v6.3.0.tar.gz blake3=6c67f5bf8069762eea1e31f5cca5b4e6f57ea1151b34b338046c7976072ccdef
fonts/intel-one-mono tar=https://github.com/intel/intel-one-mono/archive/refs/tags/V1.3.0.tar.gz blake3=9caff71b0a9fe8627253c55889964612ea4ae144584a283cd2fe88b7a14a4140
fonts/noto-color-emoji git=https://github.com/googlefonts/noto-emoji rev=e8073ab740292f8d5f19b5de144087ac58044d06
fonts/ttf-hack tar=https://github.com/source-foundry/Hack/releases/download/v3.003/Hack-v3.003-ttf.tar.xz blake3=acd40f61f6f512b0808d4bf530ab4aeb5a8ec3aa1f65bf5a1d08964d1bc3d044
games/classicube git=https://github.com/jackpot51/ClassiCube.git rev=
games/devilutionx tar=https://github.com/diasurgical/devilutionX/archive/refs/tags/1.5.4.tar.gz blake3=d4a61ff3a7c69d86a29158918aad48ab9c4866c6a22a3e8da5feadbb7d23b3ca
games/eduke32 tar=https://dukeworld.com/eduke32/synthesis/20181010-7067/eduke32_src_20181010-7067.tar.xz blake3=b0b759fe9ca51849f42669e4832ae1ae1f9ad7938529769108f7cf6a6a176558
games/freeciv tar=https://files.freeciv.org/stable/freeciv-3.1.4.tar.xz blake3=212630af5e50fb72662ca62a71cdd57318d0cf309b53e46377dd24c8199923a4
games/freedoom git=https://gitlab.redox-os.org/redox-os/freedoom.git rev=
games/game-2048 git=https://gitlab.redox-os.org/redox-os/2048-rs.git rev=
games/gigalomania git=https://gitlab.redox-os.org/redox-os/gigalomania.git rev=
games/hematite git=https://gitlab.redox-os.org/redox-os/hematite.git rev=
games/neverball tar=https://neverball.org/neverball-1.6.0.tar.gz blake3=74f3b68595f475e89fd2ca8b5fc349837ff36fbbe141f321dfc232dbf8fccf51
games/neverball-sols same_as=../neverball
games/openjazz tar=https://github.com/AlisterT/openjazz/archive/refs/tags/20240919.tar.gz blake3=c419066dd7bf50510c5ef0746fc47450ab8f5a17a0010a1bc0ad67d0e63538da
games/openjk git=https://github.com/jackpot51/OpenJK rev=
games/openttd git=https://github.com/OpenTTD/OpenTTD.git rev=231402fb4bea0a0d6a16cef90764d9e7aa699c53
games/openttd-opengfx git=https://gitlab.redox-os.org/redox-os/openttd-opengfx.git rev=
games/openttd-openmsx git=https://gitlab.redox-os.org/redox-os/openttd-openmsx.git rev=
games/openttd-opensfx git=https://gitlab.redox-os.org/redox-os/openttd-opensfx.git rev=
games/opentyrian git=https://github.com/opentyrian/opentyrian rev=
games/prboom tar=https://downloads.sourceforge.net/project/prboom/prboom%20stable/2.5.0/prboom-2.5.0.tar.gz blake3=24c1b9b5aa15fd73e59162055f2c6d8faa82759b76ddfca9828cd2a5c8dc6b2a
games/quakespasm git=https://github.com/sezero/quakespasm rev=cc32abe09ed417ce3be10af300d2dc2f686349ba
games/redox-games git=https://gitlab.redox-os.org/redox-os/games.git rev=
games/sm64ex git=https://github.com/jackpot51/sm64ex.git rev=
games/sopwith tar=https://github.com/fragglet/sdl-sopwith/releases/download/sdl-sopwith-1.8.4/sopwith-1.8.4.tar.gz blake3=44e1404a9c4bea257d7778d2a4b1512231603a74b0a7b18eac5d18f36730ed3e
games/spacecadetpinball git=https://gitlab.redox-os.org/xTibor/SpaceCadetPinball.git rev=
gpu/amdgpu path=source
gpu/redox-drm path=source
graphics/procedural-wallpapers-rs git=https://github.com/lukas-kirschner/procedural-wallpapers-rs.git rev=
gui/installer-gui git=https://gitlab.redox-os.org/redox-os/installer-gui.git rev=
gui/orbdata git=https://gitlab.redox-os.org/redox-os/orbdata.git rev=
gui/orbital git=https://gitlab.redox-os.org/redox-os/orbital.git rev=
gui/orbterm git=https://gitlab.redox-os.org/redox-os/orbterm.git rev=
gui/orbutils git=https://gitlab.redox-os.org/redox-os/orbutils.git rev=
gui/orbutils-background same_as=../orbutils
icons/cosmic-icons git=https://github.com/pop-os/cosmic-icons.git rev=f93dcdfa1060c2cf3f8cf0b56b0338292edcafa5
icons/hicolor-icon-theme git=https://gitlab.freedesktop.org/xdg/default-icon-theme.git rev=8d22bbf
icons/pop-icon-theme git=https://github.com/pop-os/icon-theme.git rev=1a575a8
kde/breeze tar=https://invent.kde.org/plasma/breeze/-/archive/v6.3.4/breeze-v6.3.4.tar.gz blake3=
kde/kde-cli-tools tar=https://invent.kde.org/plasma/kde-cli-tools/-/archive/v6.3.4/kde-cli-tools-v6.3.4.tar.gz blake3=
kde/kdecoration tar=https://invent.kde.org/plasma/kdecoration/-/archive/v6.3.4/kdecoration-v6.3.4.tar.gz blake3=
kde/kf6-attica tar=https://invent.kde.org/frameworks/attica/-/archive/v6.10.0/attica-v6.10.0.tar.gz blake3=
kde/kf6-extra-cmake-modules tar=https://invent.kde.org/frameworks/extra-cmake-modules/-/archive/v6.10.0/extra-cmake-modules-v6.10.0.tar.gz blake3=
kde/kf6-karchive tar=https://invent.kde.org/frameworks/karchive/-/archive/v6.10.0/karchive-v6.10.0.tar.gz blake3=
kde/kf6-kauth tar=https://invent.kde.org/frameworks/kauth/-/archive/v6.10.0/kauth-v6.10.0.tar.gz blake3=
kde/kf6-kbookmarks tar=https://invent.kde.org/frameworks/kbookmarks/-/archive/v6.10.0/kbookmarks-v6.10.0.tar.gz blake3=
kde/kf6-kcmutils tar=https://invent.kde.org/frameworks/kcmutils/-/archive/v6.10.0/kcmutils-v6.10.0.tar.gz blake3=
kde/kf6-kcodecs tar=https://invent.kde.org/frameworks/kcodecs/-/archive/v6.10.0/kcodecs-v6.10.0.tar.gz blake3=
kde/kf6-kcolorscheme tar=https://invent.kde.org/frameworks/kcolorscheme/-/archive/v6.10.0/kcolorscheme-v6.10.0.tar.gz blake3=
kde/kf6-kcompletion tar=https://invent.kde.org/frameworks/kcompletion/-/archive/v6.10.0/kcompletion-v6.10.0.tar.gz blake3=
kde/kf6-kconfig tar=https://invent.kde.org/frameworks/kconfig/-/archive/v6.10.0/kconfig-v6.10.0.tar.gz blake3=
kde/kf6-kconfigwidgets tar=https://invent.kde.org/frameworks/kconfigwidgets/-/archive/v6.10.0/kconfigwidgets-v6.10.0.tar.gz blake3=
kde/kf6-kcoreaddons tar=https://invent.kde.org/frameworks/kcoreaddons/-/archive/v6.10.0/kcoreaddons-v6.10.0.tar.gz blake3=
kde/kf6-kcrash tar=https://invent.kde.org/frameworks/kcrash/-/archive/v6.10.0/kcrash-v6.10.0.tar.gz blake3=
kde/kf6-kdbusaddons tar=https://invent.kde.org/frameworks/kdbusaddons/-/archive/v6.10.0/kdbusaddons-v6.10.0.tar.gz blake3=
kde/kf6-kdeclarative tar=https://invent.kde.org/frameworks/kdeclarative/-/archive/v6.10.0/kdeclarative-v6.10.0.tar.gz blake3=
kde/kf6-kded6 tar=https://invent.kde.org/frameworks/kded/-/archive/v6.10.0/kded-v6.10.0.tar.gz blake3=
kde/kf6-kglobalaccel tar=https://invent.kde.org/frameworks/kglobalaccel/-/archive/v6.10.0/kglobalaccel-v6.10.0.tar.gz blake3=
kde/kf6-kguiaddons tar=https://invent.kde.org/frameworks/kguiaddons/-/archive/v6.10.0/kguiaddons-v6.10.0.tar.gz blake3=
kde/kf6-ki18n tar=https://invent.kde.org/frameworks/ki18n/-/archive/v6.10.0/ki18n-v6.10.0.tar.gz blake3=
kde/kf6-kiconthemes tar=https://invent.kde.org/frameworks/kiconthemes/-/archive/v6.10.0/kiconthemes-v6.10.0.tar.gz blake3=
kde/kf6-kidletime tar=https://invent.kde.org/frameworks/kidletime/-/archive/v6.10.0/kidletime-v6.10.0.tar.gz blake3=
kde/kf6-kio tar=https://invent.kde.org/frameworks/kio/-/archive/v6.10.0/kio-v6.10.0.tar.gz blake3=
kde/kf6-kirigami tar=https://invent.kde.org/frameworks/kirigami/-/archive/v6.10.0/kirigami-v6.10.0.tar.gz blake3=d0964890aa6523f7067510bb7e6c784ba77611952d952bfdd6422a58a23664f6
kde/kf6-kitemmodels tar=https://invent.kde.org/frameworks/kitemmodels/-/archive/v6.10.0/kitemmodels-v6.10.0.tar.gz blake3=
kde/kf6-kitemviews tar=https://invent.kde.org/frameworks/kitemviews/-/archive/v6.10.0/kitemviews-v6.10.0.tar.gz blake3=
kde/kf6-kjobwidgets tar=https://invent.kde.org/frameworks/kjobwidgets/-/archive/v6.10.0/kjobwidgets-v6.10.0.tar.gz blake3=
kde/kf6-knotifications tar=https://invent.kde.org/frameworks/knotifications/-/archive/v6.10.0/knotifications-v6.10.0.tar.gz blake3=
kde/kf6-kpackage tar=https://invent.kde.org/frameworks/kpackage/-/archive/v6.10.0/kpackage-v6.10.0.tar.gz blake3=
kde/kf6-kservice tar=https://invent.kde.org/frameworks/kservice/-/archive/v6.10.0/kservice-v6.10.0.tar.gz blake3=
kde/kf6-ktextwidgets tar=https://invent.kde.org/frameworks/ktextwidgets/-/archive/v6.10.0/ktextwidgets-v6.10.0.tar.gz blake3=
kde/kf6-kwallet tar=https://invent.kde.org/frameworks/kwallet/-/archive/v6.10.0/kwallet-v6.10.0.tar.gz blake3=
kde/kf6-kwayland tar=https://download.kde.org/stable/plasma/6.3.4/kwayland-6.3.4.tar.xz blake3=
kde/kf6-kwidgetsaddons tar=https://invent.kde.org/frameworks/kwidgetsaddons/-/archive/v6.10.0/kwidgetsaddons-v6.10.0.tar.gz blake3=
kde/kf6-kwindowsystem tar=https://invent.kde.org/frameworks/kwindowsystem/-/archive/v6.10.0/kwindowsystem-v6.10.0.tar.gz blake3=
kde/kf6-kxmlgui tar=https://invent.kde.org/frameworks/kxmlgui/-/archive/v6.10.0/kxmlgui-v6.10.0.tar.gz blake3=
kde/kf6-prison tar=https://invent.kde.org/frameworks/prison/-/archive/v6.10.0/prison-v6.10.0.tar.gz blake3=
kde/kf6-pty tar=https://invent.kde.org/frameworks/kpty/-/archive/v6.10.0/kpty-v6.10.0.tar.gz blake3=
kde/kf6-solid tar=https://invent.kde.org/frameworks/solid/-/archive/v6.10.0/solid-v6.10.0.tar.gz blake3=
kde/kf6-sonnet tar=https://invent.kde.org/frameworks/sonnet/-/archive/v6.10.0/sonnet-v6.10.0.tar.gz blake3=
kde/kglobalacceld tar=https://invent.kde.org/plasma/kglobalacceld/-/archive/v6.0.0/kglobalacceld-v6.0.0.tar.gz blake3=
kde/kirigami tar=https://invent.kde.org/frameworks/kirigami/-/archive/v6.10.0/kirigami-v6.10.0.tar.gz blake3=d0964890aa6523f7067510bb7e6c784ba77611952d952bfdd6422a58a23664f6
kde/konsole tar=https://invent.kde.org/utilities/konsole/-/archive/v24.08.3/konsole-v24.08.3.tar.gz blake3=
kde/kwin tar=https://invent.kde.org/plasma/kwin/-/archive/v6.3.4/kwin-v6.3.4.tar.gz blake3=2aa1e234a75b0aa94f0da3a74d93e2a8e49b30a3afb12dc24b2ecd3abaa94e7f
kde/plasma-desktop tar=https://invent.kde.org/plasma/plasma-desktop/-/archive/v6.3.4/plasma-desktop-v6.3.4.tar.gz blake3=
kde/plasma-framework tar=https://invent.kde.org/frameworks/plasma-framework/-/archive/v6.10.0/plasma-framework-v6.10.0.tar.gz blake3=
kde/plasma-wayland-protocols tar=https://invent.kde.org/libraries/plasma-wayland-protocols/-/archive/v1.16.0/plasma-wayland-protocols-v1.16.0.tar.gz blake3=
kde/plasma-workspace tar=https://invent.kde.org/plasma/plasma-workspace/-/archive/v6.3.4/plasma-workspace-v6.3.4.tar.gz blake3=
libs/atk tar=https://download.gnome.org/sources/atk/2.38/atk-2.38.0.tar.xz blake3=cbc1b7ba03009ee5cc0e646d8a86117e0d65bf8d105f2e8714fbde0299a8012e
libs/cairo tar=https://www.cairographics.org/releases/cairo-1.18.4.tar.xz blake3=b9fa14e02f85ec4e72396c62236c98502d04dbbdf8daf01ab9557a1c7aa7106e
libs/duktape tar=https://duktape.org/duktape-2.7.0.tar.xz blake3=b0a17da888847bc9c73624ae3ba7f858ec327a9bbce9d287aee6a2489e518448
libs/expat tar=https://github.com/libexpat/libexpat/releases/download/R_2_5_0/expat-2.5.0.tar.xz blake3=ea89dd9a5a2e48d5e44fed38554b36a8f2e365a5091a99d08e30bfb1c15dda5e
libs/ffmpeg6 tar=https://ffmpeg.org/releases/ffmpeg-6.0.tar.xz blake3=4879074c357102f85932673044c57c144b0c188ae58edec2a115965536ee340f
libs/freetype2 tar=https://sourceforge.net/projects/freetype/files/freetype2/2.13.3/freetype-2.13.3.tar.xz/download blake3=07a01894ccdb584943ce817b57341a8595ce9a92bfaa77c602ec4757dfabd5e2
libs/fribidi tar=https://github.com/fribidi/fribidi/releases/download/v1.0.16/fribidi-1.0.16.tar.xz blake3=c16ee250f73f149d7d52dc7d285eb73ac755bad7907d237391e23f429b2b71d5
libs/glib tar=https://download.gnome.org/sources/glib/2.87/glib-2.87.0.tar.xz blake3=26b77ae24bc02f85d1c6742fe601167b056085f117cda70da7b805cefa6195e9
libs/gstreamer tar=https://gitlab.freedesktop.org/gstreamer/gstreamer/-/archive/1.24.12/gstreamer-1.24.12.tar.gz blake3=181daf73050f7472ec656e7461b7f67028d6002c1133870576033a32e43a364f
libs/harfbuzz tar=https://github.com/harfbuzz/harfbuzz/releases/download/11.0.1/harfbuzz-11.0.1.tar.xz blake3=51f0edaaf2e9b7a7176d3252f15d03d409ef7ad35f77b050c407de89f85b77c5
libs/jansson tar=https://github.com/akheron/jansson/releases/download/v2.10/jansson-2.10.tar.gz blake3=3c74f374a6c7ac5e323f72d87e49e5309ca922ca26cfe4992873b31f28776624
libs/lcms2-stub path=source
libs/libarchive tar=https://libarchive.org/downloads/libarchive-3.6.2.tar.xz blake3=f98695fe81235a74fa3fc2c3ba0f0d4f13ea15f9be3850b83e304cf5d78be710
libs/libatomic same_as=../../dev/gcc13
libs/libcosmic git=https://gitlab.redox-os.org/redox-os/libcosmic.git rev=
libs/libdisplay-info-stub path=source
libs/libepoxy-stub path=source
libs/libffi tar=https://github.com/libffi/libffi/releases/download/v3.4.5/libffi-3.4.5.tar.gz blake3=f9a2cfe1d2ac8d211c18c99f9cfafe5537925101bfb92c2d44d844680dd82264
libs/libflac tar=https://github.com/xiph/flac/releases/download/1.5.0/flac-1.5.0.tar.xz blake3=2adca3cd8da4b577ebb9c12e73c91cf6f6a7feb7485b3f003853b82710bada84
libs/libgmp tar=https://ftp.gnu.org/gnu/gmp/gmp-6.3.0.tar.xz blake3=fffe4996713928ae19331c8ef39129e46d3bf5b7182820656fd4639435cd83a4
libs/libiconv tar=https://ftp.gnu.org/gnu/libiconv/libiconv-1.17.tar.gz blake3=820b3b9fd3e2181bfb95475f01e9a3451e6d751e4f8c98ebcdcca1d8aa720f7f
libs/libjpeg tar=https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.1.0/libjpeg-turbo-3.1.0.tar.gz blake3=3efc14da55c56fc0a6a50f109d9e1ee8a91f5ae7dd17a21d3aebe04a65f3ee96
libs/libmodplug1 tar=https://pilotfiber.dl.sourceforge.net/project/modplug-xmms/libmodplug/0.8.9.0/libmodplug-0.8.9.0.tar.gz blake3=01d71f7fe4e1abeb848db02b74c70ab2fd51e824f5ea7e9e18631571a76c3592
libs/libmpfr tar=https://www.mpfr.org/mpfr-current/mpfr-4.2.2.tar.xz blake3=11d59d061ef8db588650bc7dc5172594a6e5aad013994801c6f63011a62b191d
libs/libnettle tar=https://ftp.gnu.org/gnu/nettle/nettle-3.9.1.tar.gz blake3=e4bfbda32f4fdf5ed96c152efe3a3867193b690faa5378d02a2a6fd052ee3393
libs/libogg tar=https://github.com/xiph/ogg/releases/download/v1.3.4/libogg-1.3.4.tar.xz blake3=1cffbe7c498555ddfdb1390d7a38179c4bead6129ea37b1b1d54f3a76b816304
libs/libopus tar=https://downloads.xiph.org/releases/opus/opus-1.6.1.tar.gz blake3=874bd7d28e24f10d88105c7d846a2e5bf085284af91a0ee36b05674a8f78e759
libs/liborbital git=https://gitlab.redox-os.org/redox-os/liborbital.git rev=cdb08e8
libs/libpng tar=https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.46.tar.gz blake3=36f4bbb48c70975116b00ab0cff577931b96f703b2774ac3b33131d001419435
libs/libpsl tar=https://github.com/rockdaboot/libpsl/releases/download/0.21.5/libpsl-0.21.5.tar.lz blake3=91318b7b876b12ff4649b7a0d6f6ed4ab1ab44f48a49508c8978ab7b4ccf3298
libs/libqrencode tar=https://github.com/fukuchi/libqrencode/archive/refs/tags/v4.1.1.tar.gz blake3=78bf8bbcfb037140d0e98dc355e77416c9c9b0fd3ac12fd6e767b07d68f60f8c
libs/libsodium tar=https://github.com/jedisct1/libsodium/archive/1.0.16.tar.gz blake3=2482633f872c173f9a42e6badb44c3efb042e783e664fdf8b1046babfa2405e7
libs/libssh2 tar=https://www.libssh2.org/download/libssh2-1.10.0.tar.gz blake3=2447216ce82c1d22301456bb02f60dfb6688f1461417b90f900c099a87f1292f
libs/libstdcxx-v3 same_as=../../dev/gcc13
libs/libudev-stub path=source
libs/liburcu tar=https://lttng.org/files/urcu/userspace-rcu-0.14.0.tar.bz2 blake3=
libs/libuv tar=https://dist.libuv.org/dist/v1.51.0/libuv-v1.51.0.tar.gz blake3=e8b5e68bc2d0776ac4ea67df59d694fca58d5cc570c103443a2284e723d01fc2
libs/libvorbis tar=https://github.com/xiph/vorbis/releases/download/v1.3.7/libvorbis-1.3.7.tar.xz blake3=c67f3f74ec26d93a5571c4404a64eb6e6587d7d77b46b552f7b410f5bc5b1f03
libs/libxcvt-stub path=source
libs/libxml2 tar=https://download.gnome.org/sources/libxml2/2.11/libxml2-2.11.3.tar.xz blake3=0653d3750576299c4cb88740942165671b576ff93019f3d669b3f37136225ab7
libs/lua-compat-53 git=https://github.com/lunarmodules/lua-compat-5.3.git rev=
libs/luv git=https://github.com/luvit/luv.git rev=
libs/mesa git=https://gitlab.redox-os.org/redox-os/mesa.git rev=0ecd6b66c
libs/mesa-glu tar=https://archive.mesa3d.org/glu/glu-9.0.3.tar.xz blake3=beed1665ed983540e7502289ec50c7e66d840820af3e9ef21c9c4a7e9686ab9f
libs/mpc tar=https://ftp.gnu.org/gnu/mpc/mpc-1.3.1.tar.gz blake3=
libs/ncurses tar=https://ftp.gnu.org/gnu/ncurses/ncurses-6.6.tar.gz blake3=fbec55697a01f99b9cc3f25be55e73ae7091f4c53e5d81a1ea15734c4e5b7238
libs/ncursesw same_as=../ncurses
libs/nghttp2 tar=https://github.com/nghttp2/nghttp2/releases/download/v1.64.0/nghttp2-1.64.0.tar.xz blake3=1bbc08de4816769d800c42f501a00c1ba3f5efa1b76e1f65d2e5bdf3aa30354d
libs/openssl1 git=https://gitlab.redox-os.org/redox-os/openssl.git rev=
libs/opusfile tar=https://downloads.xiph.org/releases/opus/opusfile-0.12.tar.gz blake3=1b6a5c371a0ea2ae8e37ab2e921388dfef9252dbf7f60045192dabbdd898f2bf
libs/pango tar=https://download.gnome.org/sources/pango/1.56/pango-1.56.3.tar.xz blake3=78542feaaf007c1d648b94c4e9b6655ed7515d27ce434766aea99bef886c21ac
libs/pcre tar=https://mirrors.gigenet.com/OSDN//sfnet/p/pc/pcre/pcre/8.42/pcre-8.42.tar.gz blake3=12d515ba12a816994def6b1e7196b5783fd2cfe495733a9167fa4d71dbe10248
libs/pcre2 tar=https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.45/pcre2-10.45.tar.bz2 blake3=aea544846f9a03c1ec62c9f8d1c9a4187cc3cce557e53e6876eb6a58c7cdd9fe
libs/pixman tar=https://www.cairographics.org/releases/pixman-0.46.0.tar.xz blake3=379369245a0bbd13784bf550c87622964a6aba87edf598ffa137dc10201746e0
libs/readline tar=https://ftp.gnu.org/gnu/readline/readline-8.3.tar.gz blake3=7109f094062bda387a0c16b4875375b96e36437bebbbd8d8f91bb27ba01d687f
libs/redox-fatfs git=https://gitlab.redox-os.org/redox-os/redox-fatfs.git rev=
libs/sdl-gfx tar=https://sourceforge.net/projects/sdlgfx/files/SDL_gfx-2.0.25.tar.gz blake3=e6f571a38e51d369b010f4b10eb35b95e3d2edae2edd796241c47ea8376581e6
libs/sdl1 git=https://gitlab.redox-os.org/redox-os/sdl1.2.git rev=
libs/sdl1-image tar=https://www.libsdl.org/projects/SDL_image/release/SDL_image-1.2.12.tar.gz blake3=731a6f8cad9fff22c82394bd1c0c34ce4aa60fa8923f3755a3e3239f1e269389
libs/sdl1-mixer tar=https://www.libsdl.org/projects/SDL_mixer/release/SDL_mixer-1.2.12.tar.gz blake3=ef23bab2d42250dfdc51ce6939ee7b393973ff11a0dd3481f32180b489d2661c
libs/sdl1-ttf tar=https://www.libsdl.org/projects/SDL_ttf/release/SDL_ttf-2.0.11.tar.gz blake3=a684e57553e43b55ab28b064d1d5d44b8749299f259da31a62d671fc1d5505ee
libs/sdl2 git=https://gitlab.redox-os.org/redox-os/sdl2.git rev=
libs/sdl2-gfx tar=http://www.ferzkopp.net/Software/SDL2_gfx/SDL2_gfx-1.0.4.tar.gz blake3=2e9bd2dc0f004349b51418f33219ebf5cd69f25ed0ba660373652a662cbb857c
libs/sdl2-image tar=https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.4.tar.gz blake3=
libs/sdl2-mixer tar=https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.8.1.tar.gz blake3=fa0798ce7ffdb5f89545311292374e5b7af479df8bc99a4aacfb40d2ab2f8384
libs/sdl2-ttf tar=https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.15.tar.gz blake3=9814a07f33a3501b414f0fc7fa962e7d7ffc56748406f3798b7698b8d7e7fe12
libs/termcap tar=https://ftp.gnu.org/gnu/termcap/termcap-1.3.1.tar.gz blake3=57c095e0bb6e60e7b4a0597f51f7ac15b501ca0f95d37424d8d13978d28b8da3
libs/unibilium tar=https://github.com/neovim/unibilium/archive/refs/tags/v2.1.2.tar.gz blake3=856a7593a412942f4716bb55bfdd225f3ce92cb013b9d4a44693255f0570b1c7
libs/utf8proc tar=https://github.com/JuliaStrings/utf8proc/archive/refs/tags/v2.10.0.tar.gz blake3=6f675db5d1ae55ad0825351ba9c58a5b5c24c862f559cc7bfed1cb63c1185594
libs/zbus path=source
libs/zlib tar=https://www.zlib.net/fossils/zlib-1.3.tar.gz blake3=ec1abc6f672a7a6ee6f49ba544cc9529f73121b478310473be44fee22a140ebf
math/orbcalculator git=https://gitlab.redox-os.org/redox-os/orbcalculator.git rev=
net/nginx tar=https://nginx.org/download/nginx-1.28.0.tar.gz blake3=
net/openssh tar=https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.8p1.tar.gz blake3=
net/redox-ssh git=https://gitlab.redox-os.org/redox-os/redox-ssh.git rev=
net/rsync tar=https://download.samba.org/pub/rsync/src/rsync-3.4.1.tar.gz blake3=
other/ca-certificates git=https://gitlab.redox-os.org/redox-os/ca-certificates.git rev=8139d99
other/cookbook git=https://gitlab.redox-os.org/redox-os/redox.git rev=
other/generaluser-gs git=https://gitlab.redox-os.org/redox-os/generaluser-gs.git rev=
other/jeremy git=https://gitlab.redox-os.org/jackpot51/jeremy.git rev=
other/rustconf2025 git=https://github.com/jackpot51/rustconf2025.git rev=
other/shared-mime-info tar=https://gitlab.freedesktop.org/xdg/shared-mime-info/-/archive/2.4/shared-mime-info-2.4.tar.gz blake3=ad130f2f923ab3d5455c643e6257abf3598339fdd134ad0fac4e5dbbbf070eb9
other/terminfo git=https://github.com/sajattack/terminfo rev=dc5712b
qt/qt6-sensors tar=https://download.qt.io/official_releases/qt/6.11/6.11.0/submodules/qtsensors-everywhere-src-6.11.0.tar.xz blake3=
shells/bash tar=https://ftp.gnu.org/gnu/bash/bash-5.2.15.tar.gz blake3=c1548e3f2a9b6de5296e18c28b3d2007985e647273e03f039efd3e489edaa41f
shells/nushell git=https://github.com/nushell/nushell rev=172a070a4bbeff15a289813bc73d4628a3032210
shells/zsh tar=https://github.com/zsh-users/zsh/archive/refs/tags/zsh-5.9.tar.gz blake3=a15b94fae03e87aba6fc6a27df3c98e610b85b0c7c0fc90248f07fdcb8816860
sound/freepats git=https://gitlab.redox-os.org/redox-os/freepats.git rev=
sound/rodioplay git=https://gitlab.redox-os.org/redox-os/rodioplay.git rev=
sound/timidity git=https://gitlab.redox-os.org/redox-os/timidity.git rev=
system/cpufreqd path=source
system/cub path=source
system/driver-manager path=source
system/driver-params path=source
system/evdevd path=source
system/firmware-loader path=source
system/hwrngd path=source
system/iommu path=source
system/numad path=source
system/redbear-acmd path=source
system/redbear-authd path=source
system/redbear-btctl path=source
system/redbear-dbus-services path=files
system/redbear-ecmd path=source
system/redbear-firmware path=source
system/redbear-greeter path=source
system/redbear-hwutils path=source
system/redbear-info path=source
system/redbear-login-protocol path=source
system/redbear-meta path=source
system/redbear-mtr path=source
system/redbear-netctl path=source
system/redbear-netctl-console path=source
system/redbear-netstat path=source
system/redbear-nmap path=source
system/redbear-notifications path=source
system/redbear-polkit path=source
system/redbear-quirks path=source
system/redbear-session-launch path=source
system/redbear-sessiond path=source
system/redbear-traceroute path=source
system/redbear-udisks path=source
system/redbear-upower path=source
system/redbear-usbaudiod path=source
system/redbear-wifictl path=source
system/thermald path=source
system/udev-shim path=source
terminal/bash-completion tar=https://github.com/scop/bash-completion/releases/download/2.17.0/bash-completion-2.17.0.tar.xz blake3=
terminal/pls git=https://github.com/pls-rs/pls rev=
terminal/zoxide git=https://github.com/ajeetdsouza/zoxide rev=
tests/acid git=https://gitlab.redox-os.org/redox-os/acid.git rev=
tests/acid-bins same_as=../acid
tests/benchmarks git=https://gitlab.redox-os.org/redox-os/benchmarks rev=
tests/iperf3 tar=https://downloads.es.net/pub/iperf/iperf-3.20.tar.gz blake3=
tests/openposixtestsuite git=https://gitlab.redox-os.org/redox-os/openposixtestsuite.git rev=
tests/os-test git=https://gitlab.com/sortix/os-test rev=
tests/os-test-bins same_as=../os-test
tests/os-test-result same_as=../os-test
tests/redox-drm-prime-test path=source
tests/redox-posix-tests git=https://gitlab.redox-os.org/redox-os/redox-posix-tests.git rev=
tests/relibc-phase1-tests path=source
tests/relibc-tests same_as=../../core/relibc
tests/relibc-tests-bins same_as=../../core/relibc
tests/schedrs git=https://gitlab.redox-os.org/akshitgaur2005/schedrs.git rev=
tests/sysbench git=https://github.com/akopytov/sysbench.git rev=
tests/vttest tar=https://invisible-island.net/archives/vttest/vttest-20140305.tgz blake3=b515b9a5e1f1498ed99e1a1c172fbcfdf2b7a214e185bd2005cc994407ded89e
tools/bzip2 tar=https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz blake3=97af3f520629c65fe41292f77e6ca798fe594d7987bfb2aebe7c6fcdc7ab5ed2
tools/cleye git=https://gitlab.redox-os.org/redox-os/cleye.git rev=
tools/cosmic-edit git=https://github.com/pop-os/cosmic-edit.git rev=epoch-1.0.8
tools/cosmic-files git=https://github.com/pop-os/cosmic-files.git rev=epoch-1.0.8
tools/cosmic-reader git=https://github.com/pop-os/cosmic-reader.git rev=epoch-1.0.8
tools/cosmic-settings git=https://github.com/pop-os/cosmic-settings.git rev=
tools/cosmic-store git=https://github.com/pop-os/cosmic-store.git rev=epoch-1.0.8
tools/cosmic-term git=https://github.com/pop-os/cosmic-term.git rev=epoch-1.0.8
tools/cosmic-text git=https://github.com/pop-os/cosmic-text.git rev=
tools/diffutils tar=https://ftp.gnu.org/gnu/diffutils/diffutils-3.6.tar.xz blake3=086a95093c15edcdb826e75ff4de6c2213de6fbd2eb13538d07bdc3286dfb4a4
tools/fd git=https://github.com/sharkdp/fd.git rev=840a565d3aadbeb303b10a01c0aa3561924dfc46
tools/file tar=https://astron.com/pub/file/file-5.46.tar.gz blake3=
tools/friar git=https://github.com/jackpot51/friar.git rev=
tools/gettext tar=https://ftp.gnu.org/gnu/gettext/gettext-0.22.5.tar.gz blake3=cb3f3a34da7ce1a92746df81f5b78c5d53841973a24eb80ab76537263d380ec0
tools/gnu-binutils tar=https://ftp.gnu.org/gnu/binutils/binutils-2.43.1.tar.xz blake3=f074c81313b70eabc58ce9a9411cd771c5fa2433792d0ad8abcc45f603f58ed6
tools/gnu-grep tar=https://ftp.gnu.org/gnu/grep/grep-3.1.tar.xz blake3=46b6e24dfa1b0f309f4eae3c450d612396c8faa6510b53a55f629e4f4c70b4a3
tools/helix git=https://github.com/greyshaman/helix.git rev=
tools/libc-bench tar=https://www.etalabs.net/releases/libc-bench-20110206.tar.gz blake3=64093102f29faa76da455f55a7b4be25b6d74d5c3d6fe88dbbc38aaae185182f
tools/lsd git=https://github.com/lsd-rs/lsd rev=
tools/nano tar=https://www.nano-editor.org/dist/v7/nano-7.2.tar.xz blake3=
tools/onefetch git=https://github.com/o2sh/onefetch rev=
tools/patchelf tar=https://github.com/NixOS/patchelf/releases/download/0.18.0/patchelf-0.18.0.tar.bz2 blake3=f843b32bdf3ee8a1f465e92d3fef34f30c48ccef9c112fdb793e2e7f2ae7283a
tools/pathfinder git=https://gitlab.redox-os.org/redox-os/pathfinder.git rev=
tools/perg git=https://github.com/guerinoni/perg.git rev=e206fab6bbd9c363c686fa7503d318304e48ddbe
tools/periodictable git=https://gitlab.redox-os.org/redox-os/periodictable.git rev=
tools/powerline git=https://github.com/jD91mZM2/powerline-rs rev=
tools/ripgrep git=https://github.com/jackpot51/ripgrep.git rev=
tools/schismtracker tar=https://github.com/schismtracker/schismtracker/archive/20181223.tar.gz blake3=057e973f4f84cf898e2240d67c0e92f25086d8b9ffdc7e0c7ef81dd8dc81bc70
tools/sed tar=https://ftp.gnu.org/gnu/sed/sed-4.4.tar.xz blake3=a88c12b2b4304e53e3c7ae2eb0499d02e28873c1b9e1a6871e5347c6886a1ecd
tools/shellharden git=https://github.com/anordal/shellharden.git rev=bd24c99d5d1e76452b6d0749404837c1c95d923c
tools/shellstorm git=https://gitlab.redox-os.org/redox-os/shellstorm.git rev=
tools/smith git=https://gitlab.redox-os.org/redox-os/Smith.git rev=
tools/sodium git=https://gitlab.redox-os.org/redox-os/sodium.git rev=
tools/tokei git=https://github.com/XAMPPRocky/tokei.git rev=
tools/twin-commander git=https://github.com/kivimango/twin-commander.git rev=
tools/vim tar=https://github.com/vim/vim/archive/refs/tags/v9.1.0821.tar.gz blake3=d1f5802ceb047b09143f1764bf4016f084cf7e6c026c7047919264c9f262a5dd
tools/xz tar=https://github.com/tukaani-project/xz/releases/download/v5.2.13/xz-5.2.13.tar.gz blake3=edc6350542e8cb7188a878135e5b9bd592d687e5b47451ca1c89d51cc4bc6b53
tui/goaccess tar=https://tar.goaccess.io/goaccess-1.9.4.tar.gz blake3=a7a7641c98956e8941191956129141e071321851d004269c7d21bce536d9224a
tui/mc tar=https://ftp.osuosl.org/pub/midnightcommander/mc-4.8.33.tar.xz blake3=cad9c1587f2976b9e42016191a72c4f23a07222c96ec7a9454a1a66ce639ac63
tui/mdp git=https://github.com/visit1985/mdp.git rev=
tui/ncdu tar=https://dev.yorhel.nl/download/ncdu-1.22.tar.gz blake3=b7838c03ded7207a328a26c840ec3d62d3be6bbf7269a70ea3430c6cbf065960
video/sdl-player git=https://gitlab.redox-os.org/redox-os/sdl-player.git rev=
wayland/qt6-wayland-smoke path=source
wayland/redbear-compositor path=source
wayland/seatd-redox tar=https://git.sr.ht/~kennylevinsen/seatd/archive/0.9.1.tar.gz blake3=
wayland/smallvil git=https://github.com/jackpot51/smithay rev=
web/netsurf tar=https://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-all-3.11.tar.gz blake3=cd406668a9ed5712efac1a8685125b83626690b73bbc6cb5de82ef00e3f65087
web/website git=https://gitlab.redox-os.org/redox-os/website rev=
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,913 @@
diff --git a/src/context/file.rs b/src/context/file.rs
index 2d3790f..150f483 100644
--- a/src/context/file.rs
+++ b/src/context/file.rs
@@ -4,7 +4,7 @@ use crate::{
event,
scheme::{self, SchemeId},
sync::{CleanLockToken, RwLock, L6},
- syscall::error::Result,
+ syscall::error::{Error, Result, ESTALE},
};
use alloc::sync::Arc;
use syscall::{schemev2::NewFdFlags, RwFlags, O_APPEND, O_NONBLOCK};
@@ -18,6 +18,7 @@ pub struct FileDescription {
pub offset: u64,
/// The scheme that this file refers to
pub scheme: SchemeId,
+ pub scheme_generation: Option<u64>,
/// The number the scheme uses to refer to this file
pub number: usize,
/// The flags passed to open or fcntl(SETFL)
@@ -32,6 +33,52 @@ bitflags! {
}
}
impl FileDescription {
+ pub fn with_generation(
+ scheme: SchemeId,
+ scheme_generation: Option<u64>,
+ number: usize,
+ offset: u64,
+ flags: u32,
+ internal_flags: InternalFlags,
+ ) -> Self {
+ Self {
+ offset,
+ scheme,
+ scheme_generation,
+ number,
+ flags,
+ internal_flags,
+ }
+ }
+
+ pub fn new(
+ scheme: SchemeId,
+ number: usize,
+ offset: u64,
+ flags: u32,
+ internal_flags: InternalFlags,
+ token: &mut CleanLockToken,
+ ) -> Self {
+ Self::with_generation(
+ scheme,
+ Some(scheme::current_scheme_generation(token.token(), scheme)),
+ number,
+ offset,
+ flags,
+ internal_flags,
+ )
+ }
+
+ pub fn get_scheme(&self, token: &mut CleanLockToken) -> Result<scheme::KernelSchemes> {
+ if let Some(expected_generation) = self.scheme_generation
+ && expected_generation != scheme::current_scheme_generation(token.token(), self.scheme)
+ {
+ return Err(Error::new(ESTALE));
+ }
+
+ scheme::get_scheme(token.token(), self.scheme)
+ }
+
pub fn rw_flags(&self, rw: RwFlags) -> u32 {
let mut ret = self.flags & !(O_NONBLOCK | O_APPEND) as u32;
if rw.contains(RwFlags::APPEND) {
@@ -76,7 +123,7 @@ impl FileDescription {
pub fn try_close(self, token: &mut CleanLockToken) -> Result<()> {
event::unregister_file(self.scheme, self.number, token);
- let scheme = scheme::get_scheme(token.token(), self.scheme)?;
+ let scheme = self.get_scheme(token)?;
scheme.close(self.number, token)
}
@@ -85,12 +132,12 @@ impl FileDescription {
impl FileDescriptor {
pub fn close(self, token: &mut CleanLockToken) -> Result<()> {
{
- let (scheme_id, number, internal_flags) = {
+ let (desc, number, internal_flags) = {
let desc = self.description.read(token.token());
- (desc.scheme, desc.number, desc.internal_flags)
+ (*desc, desc.number, desc.internal_flags)
};
if internal_flags.contains(InternalFlags::NOTIFY_ON_NEXT_DETACH) {
- let scheme = scheme::get_scheme(token.token(), scheme_id)?;
+ let scheme = desc.get_scheme(token)?;
scheme.detach(number, token)?;
}
}
diff --git a/src/context/memory.rs b/src/context/memory.rs
index 93446ba..a862b35 100644
--- a/src/context/memory.rs
+++ b/src/context/memory.rs
@@ -64,14 +64,13 @@ impl UnmapResult {
return Ok(());
};
- let (scheme_id, number) = {
- let desc = description.write(token.token());
- (desc.scheme, desc.number)
+ let (scheme, number) = {
+ let desc = *description.read(token.token());
+ (desc.get_scheme(token)?, desc.number)
};
- let scheme_opt = scheme::get_scheme(token.token(), scheme_id);
- let funmap_result = scheme_opt
- .and_then(|scheme| scheme.kfunmap(number, base_offset, self.size, self.flags, token));
+ let funmap_result = scheme
+ .kfunmap(number, base_offset, self.size, self.flags, token);
if let Ok(fd) = Arc::try_unwrap(description) {
fd.into_inner().try_close(token)?;
@@ -2687,20 +2686,13 @@ fn correct_inner<'l>(
// XXX: This is cheating, but guaranteed we won't deadlock because we've dropped addr_space_guard
let mut token = unsafe { CleanLockToken::new() };
- let (scheme_id, scheme_number) = {
- let desc = &file_ref.description.read(token.token());
- (desc.scheme, desc.number)
+ let desc = *file_ref.description.read(token.token());
+ let scheme = desc.get_scheme(&mut token).map_err(|_| PfError::Segv)?;
+ let scheme_number = desc.number;
+ let user_inner = match scheme {
+ KernelSchemes::User(user) => user.inner,
+ _ => return Err(PfError::Segv),
};
- let user_inner = scheme::get_scheme(token.token(), scheme_id)
- .ok()
- .and_then(|s| {
- if let KernelSchemes::User(user) = s {
- Some(user.inner)
- } else {
- None
- }
- })
- .ok_or(PfError::Segv)?;
let offset = file_ref.base_offset as u64 + (pages_from_grant_start * PAGE_SIZE) as u64;
user_inner
diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs
index d30272c..765e547 100644
--- a/src/scheme/mod.rs
+++ b/src/scheme/mod.rs
@@ -14,7 +14,7 @@ use alloc::{
};
use core::{
str,
- sync::atomic::{AtomicUsize, Ordering},
+ sync::atomic::{AtomicU64, AtomicUsize, Ordering},
};
use hashbrown::hash_map::{self, DefaultHashBuilder, HashMap};
use spin::Once;
@@ -169,6 +169,7 @@ enum Handle {
/// Schemes list
static HANDLES: Once<RwLock<L1, HashMap<SchemeId, Handle>>> = Once::new();
+static SCHEME_GENERATIONS: Once<RwLock<L1, HashMap<SchemeId, AtomicU64>>> = Once::new();
static SCHEME_LIST_NEXT_ID: AtomicUsize = AtomicUsize::new(MAX_GLOBAL_SCHEMES);
static SCHEME_LIST_ID: AtomicUsize = AtomicUsize::new(0);
@@ -204,6 +205,10 @@ fn init_schemes() -> RwLock<L1, HashMap<SchemeId, Handle>> {
RwLock::new(handles)
}
+fn init_scheme_generations() -> RwLock<L1, HashMap<SchemeId, AtomicU64>> {
+ RwLock::new(HashMap::new())
+}
+
/// Get a handle to a scheme.
pub fn get_scheme(token: LockToken<'_, L0>, scheme_id: SchemeId) -> Result<KernelSchemes> {
match handles().read(token).get(&scheme_id) {
@@ -212,10 +217,33 @@ pub fn get_scheme(token: LockToken<'_, L0>, scheme_id: SchemeId) -> Result<Kerne
}
}
+pub fn current_scheme_generation(token: LockToken<'_, L0>, scheme_id: SchemeId) -> u64 {
+ scheme_generations()
+ .read(token)
+ .get(&scheme_id)
+ .map(|generation| generation.load(Ordering::Acquire))
+ .unwrap_or(0)
+}
+
fn handles<'a>() -> &'a RwLock<L1, HashMap<SchemeId, Handle>> {
HANDLES.call_once(init_schemes)
}
+fn scheme_generations<'a>() -> &'a RwLock<L1, HashMap<SchemeId, AtomicU64>> {
+ SCHEME_GENERATIONS.call_once(init_scheme_generations)
+}
+
+fn increment_scheme_generation(scheme_id: SchemeId, token: &mut CleanLockToken) {
+ match scheme_generations().write(token.token()).entry(scheme_id) {
+ hash_map::Entry::Occupied(entry) => {
+ entry.get().fetch_add(1, Ordering::AcqRel);
+ }
+ hash_map::Entry::Vacant(entry) => {
+ entry.insert(AtomicU64::new(1));
+ }
+ }
+}
+
/// Scheme list type
pub struct SchemeList;
@@ -260,9 +288,14 @@ impl SchemeList {
/// Remove a scheme
fn remove(&self, id: usize, token: &mut CleanLockToken) {
- let scheme = handles().write(token.token()).remove(&SchemeId(id));
+ let scheme_id = SchemeId(id);
+ let scheme = handles().write(token.token()).remove(&scheme_id);
assert!(scheme.is_some());
+ if let Some(Handle::Scheme(KernelSchemes::User(user))) = scheme.as_ref() {
+ user.inner.fail_pending_calls(token);
+ }
+ increment_scheme_generation(scheme_id, token);
if let Some(Handle::Scheme(KernelSchemes::User(user))) = scheme
&& let Some(user) = Arc::into_inner(user.inner)
{
@@ -287,32 +320,32 @@ impl KernelScheme for SchemeList {
token: &mut CleanLockToken,
) -> Result<OpenResult> {
let scheme_id = SchemeId(scheme_id);
- match handles()
- .read(token.token())
- .get(&scheme_id)
- .ok_or(Error::new(EBADF))?
- {
- Handle::Scheme(KernelSchemes::User(UserScheme { inner })) => {
- let inner = inner.clone();
- assert!(scheme_id == inner.scheme_id);
- let scheme = scheme_id;
- let params = unsafe { user_buf.read_exact::<NewFdParams>()? };
-
- return Ok(OpenResult::External(Arc::new(RwLock::new(
- FileDescription {
- scheme,
- number: params.number,
- offset: params.offset,
- flags: params.flags as u32,
- internal_flags: InternalFlags::from_extra0(params.internal_flags)
- .ok_or(Error::new(EINVAL))?,
- },
- ))));
+ let maybe_inner = {
+ let handles = handles().read(token.token());
+ match handles.get(&scheme_id).ok_or(Error::new(EBADF))? {
+ Handle::Scheme(KernelSchemes::User(UserScheme { inner })) => Some(inner.clone()),
+ Handle::SchemeCreationCapability => None,
+ _ => return Err(Error::new(EBADF)),
}
- Handle::SchemeCreationCapability => (),
- _ => return Err(Error::new(EBADF)),
};
+ if let Some(inner) = maybe_inner {
+ assert!(scheme_id == inner.scheme_id);
+ let params = unsafe { user_buf.read_exact::<NewFdParams>()? };
+
+ return Ok(OpenResult::External(Arc::new(RwLock::new(
+ FileDescription::new(
+ scheme_id,
+ params.number,
+ params.offset,
+ params.flags as u32,
+ InternalFlags::from_extra0(params.internal_flags)
+ .ok_or(Error::new(EINVAL))?,
+ token,
+ ),
+ ))));
+ }
+
const EXPECTED: &[u8] = b"create-scheme";
let mut buf = [0u8; EXPECTED.len()];
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
index 47588e1..1bdd6cc 100644
--- a/src/scheme/proc.rs
+++ b/src/scheme/proc.rs
@@ -849,17 +873,17 @@ impl KernelScheme for ProcScheme {
}
}
fn extract_scheme_number(fd: usize, token: &mut CleanLockToken) -> Result<(KernelSchemes, usize)> {
- let (scheme_id, number) = {
+ let desc = {
let current_lock = context::current();
let mut current = current_lock.read(token.token());
- let (context, mut token) = current.token_split();
+ let (context, mut context_token) = current.token_split();
let file_descriptor = context
- .get_file(FileHandle::from(fd), &mut token)
+ .get_file(FileHandle::from(fd), &mut context_token)
.ok_or(Error::new(EBADF))?;
- let desc = file_descriptor.description.read(token.token());
- (desc.scheme, desc.number)
+ *file_descriptor.description.read(context_token.token())
};
- let scheme = scheme::get_scheme(token.token(), scheme_id)?;
+ let scheme = desc.get_scheme(token)?;
+ let number = desc.number;
Ok((scheme, number))
}
diff --git a/src/scheme/user.rs b/src/scheme/user.rs
index b901302..dfbf66b 100644
--- a/src/scheme/user.rs
+++ b/src/scheme/user.rs
@@ -80,6 +80,7 @@ const ONE: NonZeroUsize = match NonZeroUsize::new(1) {
Some(one) => one,
None => unreachable!(),
};
+const MAX_SPURIOUS_WAKEUPS: usize = 100;
enum ParsedCqe {
TriggerFevent {
@@ -209,6 +210,8 @@ impl UserInner {
caller_responsible: &mut PageSpan,
token: &mut CleanLockToken,
) -> Result<Response> {
+ let mut remaining_spurious_wakeups = MAX_SPURIOUS_WAKEUPS;
+
{
// Disable preemption to avoid context switches between setting the
// process state and sending the scheme request. The process is made
@@ -261,7 +264,10 @@ impl UserInner {
};
let states = self.states.lock(token.token());
- let (mut states, mut token) = states.into_split();
+ let (mut states, mut state_token) = states.into_split();
+ let mut timed_out_descriptions = None;
+ let mut remove_state = false;
+ let mut timed_out = false;
match states.get_mut(sqe.tag as usize) {
// invalid state
None => return Err(Error::new(EBADFD)),
@@ -274,24 +280,35 @@ impl UserInner {
fds,
} => {
let maybe_eintr =
- eintr_if_sigkill(&mut callee_responsible, &mut token.token());
- *o = State::Waiting {
- canceling: true,
- callee_responsible,
- context,
- fds,
- };
+ eintr_if_sigkill(&mut callee_responsible, &mut state_token.token());
- maybe_eintr?;
+ if maybe_eintr.is_ok() {
+ remaining_spurious_wakeups =
+ remaining_spurious_wakeups.saturating_sub(1);
+ }
+
+ if maybe_eintr.is_ok() && remaining_spurious_wakeups == 0 {
+ timed_out_descriptions = Some(Self::collect_descriptions_to_close(fds));
+ remove_state = true;
+ } else {
+ *o = State::Waiting {
+ canceling: true,
+ callee_responsible,
+ context,
+ fds,
+ };
+ }
- context::current()
- .write(token.token())
- .block("UserInner::call (woken up after cancelation request)");
+ maybe_eintr?;
- // We do not want to drop the lock before blocking
- // as if we get preempted in between we might miss a
- // wakeup.
- drop(states);
+ if remove_state {
+ states.remove(sqe.tag as usize);
+ timed_out = true;
+ } else {
+ context::current()
+ .write(state_token.token())
+ .block("UserInner::call (woken up after cancelation request)");
+ }
}
// spurious wakeup
State::Waiting {
@@ -300,60 +317,76 @@ impl UserInner {
context,
mut callee_responsible,
} => {
- let maybe_eintr = eintr_if_sigkill(&mut callee_responsible, &mut token);
let current_context = context::current();
+ let maybe_eintr =
+ eintr_if_sigkill(&mut callee_responsible, &mut state_token);
+
+ if maybe_eintr.is_ok() {
+ remaining_spurious_wakeups =
+ remaining_spurious_wakeups.saturating_sub(1);
+ }
- *o = State::Waiting {
- // Currently we treat all spurious wakeups to have the same behavior
- // as signals (i.e., we send a cancellation request). It is not something
- // that should happen, but it certainly can happen, for example if a context
- // is awoken through its thread handle without setting any sig bits, or if the
- // caller clears its own sig bits. If it actually is a signal, then it is the
- // intended behavior.
- canceling: true,
- fds,
- context,
- callee_responsible,
- };
+ if maybe_eintr.is_ok() && remaining_spurious_wakeups == 0 {
+ timed_out_descriptions = Some(Self::collect_descriptions_to_close(fds));
+ remove_state = true;
+ } else {
+ *o = State::Waiting {
+ // Currently we treat all spurious wakeups to have the same behavior
+ // as signals (i.e., we send a cancellation request). It is not something
+ // that should happen, but it certainly can happen, for example if a context
+ // is awoken through its thread handle without setting any sig bits, or if the
+ // caller clears its own sig bits. If it actually is a signal, then it is the
+ // intended behavior.
+ canceling: true,
+ fds,
+ context,
+ callee_responsible,
+ };
+ }
maybe_eintr?;
- // We do not want to preempt between sending the
- // cancellation and blocking again where we might
- // miss a wakeup.
- let mut preempt = PreemptGuardL1::new(&current_context, &mut token);
- let token = preempt.token();
-
- self.todo.send_locked(
- Sqe {
- opcode: Opcode::Cancel as u8,
- sqe_flags: SqeFlags::ONEWAY,
- tag: sqe.tag,
- ..Default::default()
- },
- token.token(),
- );
- event::trigger_locked(
- self.root_id,
- self.scheme_id.get(),
- EVENT_READ,
- token.token(),
- );
-
- // 1. If cancellation was requested and arrived
- // before the scheme processed the request, an
- // acknowledgement will be sent back after the
- // cancellation is processed and we will be woken up
- // again. State will be State::Responded then.
- //
- // 2. If cancellation was requested but the scheme
- // already processed the request, we will receive
- // the actual response next and woken up again.
- // State will be State::Responded then.
- context::current()
- .write(token.token())
- .block("UserInner::call (spurious wakeup)");
- drop(states);
+ if remove_state {
+ states.remove(sqe.tag as usize);
+ timed_out = true;
+ } else {
+ // We do not want to preempt between sending the
+ // cancellation and blocking again where we might
+ // miss a wakeup.
+ let mut preempt =
+ PreemptGuardL1::new(&current_context, &mut state_token);
+ let token = preempt.token();
+
+ self.todo.send_locked(
+ Sqe {
+ opcode: Opcode::Cancel as u8,
+ sqe_flags: SqeFlags::ONEWAY,
+ tag: sqe.tag,
+ ..Default::default()
+ },
+ token.token(),
+ );
+ event::trigger_locked(
+ self.root_id,
+ self.scheme_id.get(),
+ EVENT_READ,
+ token.token(),
+ );
+
+ // 1. If cancellation was requested and arrived
+ // before the scheme processed the request, an
+ // acknowledgement will be sent back after the
+ // cancellation is processed and we will be woken up
+ // again. State will be State::Responded then.
+ //
+ // 2. If cancellation was requested but the scheme
+ // already processed the request, we will receive
+ // the actual response next and woken up again.
+ // State will be State::Responded then.
+ context::current()
+ .write(token.token())
+ .block("UserInner::call (spurious wakeup)");
+ }
}
// invalid state
@@ -368,6 +401,68 @@ impl UserInner {
}
},
}
+
+ if let Some(descriptions) = timed_out_descriptions {
+ drop(states);
+ for desc in descriptions {
+ let _ = desc.try_close(token);
+ }
+ }
+
+ if timed_out {
+ return Err(Error::new(ETIMEDOUT));
+ }
+ }
+ }
+ }
+
+ fn collect_descriptions_to_close(
+ fds: Vec<Arc<LockedFileDescription>>,
+ ) -> Vec<FileDescription> {
+ fds.into_iter()
+ .filter_map(|fd| Arc::try_unwrap(fd).ok())
+ .map(RwLock::into_inner)
+ .collect()
+ }
+
+ pub fn fail_pending_calls(&self, token: &mut CleanLockToken) {
+ let descriptions_to_close = {
+ let mut states_lock = self.states.lock(token.token());
+ let (states, mut lock_token) = states_lock.token_split();
+ let mut descriptions_to_close = Vec::new();
+ let mut states_to_remove = Vec::new();
+
+ for (id, state) in states.iter_mut() {
+ match mem::replace(state, State::Placeholder) {
+ State::Waiting { context, fds, .. } => {
+ descriptions_to_close.extend(Self::collect_descriptions_to_close(fds));
+
+ match context.upgrade() {
+ Some(context) => {
+ *state = State::Responded(Response::Regular(
+ Err(Error::new(ENODEV)),
+ 0,
+ false,
+ ));
+ context.write(lock_token.token()).unblock();
+ }
+ None => states_to_remove.push(id),
+ }
+ }
+ old_state => *state = old_state,
+ }
+ }
+
+ for id in states_to_remove {
+ states.remove(id);
+ }
+
+ descriptions_to_close
+ };
+
+ for desc in descriptions_to_close {
+ let _ = desc.try_close(token);
+ }
}
}
}
@@ -1283,6 +1376,7 @@ impl UserInner {
}
pub fn into_drop(self, token: &mut CleanLockToken) {
+ self.fail_pending_calls(token);
self.todo.condition.into_drop(token);
}
}
diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs
index bf98464..10c6a92 100644
--- a/src/syscall/fs.rs
+++ b/src/syscall/fs.rs
@@ -12,7 +12,7 @@ use crate::{
memory::{AddrSpace, GenericFlusher, Grant, PageSpan, TlbShootdownActions},
},
memory::{Page, VirtualAddress, PAGE_SIZE},
- scheme::{self, FileHandle, KernelScheme, OpenResult, StrOrBytes},
+ scheme::{FileHandle, KernelScheme, OpenResult, StrOrBytes},
sync::{CleanLockToken, RwLock},
syscall::{data::Stat, error::*, flag::*},
};
@@ -45,7 +45,7 @@ pub fn file_op_generic_ext<T>(
(file, desc)
};
- let scheme = scheme::get_scheme(token.token(), desc.scheme)?;
+ let scheme = desc.get_scheme(token)?;
op(&*scheme, file.description, desc, token)
}
@@ -73,14 +73,18 @@ pub fn openat(
) -> Result<FileHandle> {
let path_buf = copy_path_to_buf(raw_path, PATH_MAX)?;
- let (scheme_id, number) = {
+ let desc = {
let current_lock = context::current();
let mut current = current_lock.read(token.token());
- let (context, mut token) = current.token_split();
- let pipe = context.get_file(fh, &mut token).ok_or(Error::new(EBADF))?;
- let desc = pipe.description.read(token.token());
- (desc.scheme, desc.number)
+ let (context, mut context_token) = current.token_split();
+ let pipe = context
+ .get_file(fh, &mut context_token)
+ .ok_or(Error::new(EBADF))?;
+ *pipe.description.read(context_token.token())
};
+ let scheme = desc.get_scheme(token)?;
+ let number = desc.number;
+ let scheme_id = desc.scheme;
let caller_ctx = context::current()
.read(token.token())
@@ -88,8 +92,6 @@ pub fn openat(
.filter_uid_gid(euid, egid);
let new_description = {
- let scheme = scheme::get_scheme(token.token(), scheme_id)?;
-
let res = scheme.kopenat(
number,
StrOrBytes::from_str(&path_buf),
@@ -101,13 +103,14 @@ pub fn openat(
match res? {
OpenResult::SchemeLocal(number, internal_flags) => {
- Arc::new(RwLock::new(FileDescription {
- offset: 0,
- internal_flags,
- scheme: scheme_id,
+ Arc::new(RwLock::new(FileDescription::new(
+ scheme_id,
number,
- flags: (flags & !O_CLOEXEC) as u32,
- }))
+ 0,
+ (flags & !O_CLOEXEC) as u32,
+ internal_flags,
+ token,
+ )))
}
OpenResult::External(desc) => desc,
}
@@ -137,16 +140,17 @@ pub fn unlinkat(
) -> Result<()> {
let path_buf = copy_path_to_buf(raw_path, PATH_MAX)?;
- let (number, scheme_id) = {
+ let desc = {
let current_lock = context::current();
let mut current = current_lock.read(token.token());
- let (context, mut token) = current.token_split();
- let pipe = context.get_file(fh, &mut token).ok_or(Error::new(EBADF))?;
- let desc = pipe.description.read(token.token());
- (desc.number, desc.scheme)
+ let (context, mut context_token) = current.token_split();
+ let pipe = context
+ .get_file(fh, &mut context_token)
+ .ok_or(Error::new(EBADF))?;
+ *pipe.description.read(context_token.token())
};
-
- let scheme = scheme::get_scheme(token.token(), scheme_id)?;
+ let number = desc.number;
+ let scheme = desc.get_scheme(token)?;
let caller_ctx = context::current()
.read(token.token())
@@ -199,17 +203,18 @@ fn duplicate_file(
let description = { *file.description.read(token.token()) };
let new_description = {
- let scheme = scheme::get_scheme(token.token(), description.scheme)?;
+ let scheme = description.get_scheme(token)?;
match scheme.kdup(description.number, user_buf, caller_ctx, token)? {
OpenResult::SchemeLocal(number, internal_flags) => {
- Arc::new(RwLock::new(FileDescription {
- offset: 0,
- internal_flags,
- scheme: description.scheme,
+ Arc::new(RwLock::new(FileDescription::new(
+ description.scheme,
number,
- flags: description.flags,
- }))
+ 0,
+ description.flags,
+ internal_flags,
+ token,
+ )))
}
OpenResult::External(desc) => desc,
}
@@ -296,11 +301,10 @@ fn call_normal(
}
.ok_or(Error::new(EBADF))?;
- let (scheme_id, number) = {
- let desc = file.description.read(token.token());
- (desc.scheme, desc.number)
+ let (scheme, number) = {
+ let desc = *file.description.read(token.token());
+ (desc.get_scheme(token)?, desc.number)
};
- let scheme = scheme::get_scheme(token.token(), scheme_id)?;
if flags.contains(CallFlags::STD_FS) {
scheme.translate_std_fs_call(number, file.description, payload, flags, metadata, token)
@@ -341,28 +345,28 @@ fn fdwrite_inner(
) -> Result<usize> {
// TODO: Ensure deadlocks can't happen
let (scheme, number, descs_to_send) = {
- let (scheme, number) = {
+ let desc = {
let current_lock = context::current();
let mut current = current_lock.read(token.token());
- let (context, mut token) = current.token_split();
+ let (context, mut context_token) = current.token_split();
let file_descriptor = context
- .get_file(socket, &mut token)
+ .get_file(socket, &mut context_token)
.ok_or(Error::new(EBADF))?;
- let desc = &file_descriptor.description.read(token.token());
- (desc.scheme, desc.number)
+ *file_descriptor.description.read(context_token.token())
};
- let scheme = scheme::get_scheme(token.token(), scheme)?;
+ let scheme = desc.get_scheme(token)?;
+ let number = desc.number;
let current_lock = context::current();
let mut current = current_lock.read(token.token());
- let (context, mut token) = current.token_split();
+ let (context, mut context_token) = current.token_split();
(
scheme,
number,
if flags.contains(CallFlags::FD_CLONE) {
- context.bulk_get_files(&target_fds, &mut token)
+ context.bulk_get_files(&target_fds, &mut context_token)
} else {
- context.bulk_remove_files(&target_fds, &mut token)
+ context.bulk_remove_files(&target_fds, &mut context_token)
}?
.into_iter()
.map(|f| f.description)
@@ -395,18 +399,22 @@ fn call_fdread(
metadata: &[u64],
token: &mut CleanLockToken,
) -> Result<usize> {
+ let desc = {
+ let current_lock = context::current();
+ let mut current = current_lock.read(token.token());
+ let (context, mut context_token) = current.token_split();
+ let file_descriptor = context
+ .get_file(fd, &mut context_token)
+ .ok_or(Error::new(EBADF))?;
+ *file_descriptor.description.read(context_token.token())
+ };
let (scheme, number) = {
- let (scheme, number) = {
- let current_lock = context::current();
- let mut current = current_lock.read(token.token());
- let (context, mut token) = current.token_split();
- let file_descriptor = context.get_file(fd, &mut token).ok_or(Error::new(EBADF))?;
- let desc = file_descriptor.description.read(token.token());
- (desc.scheme, desc.number)
- };
- let scheme = scheme::get_scheme(token.token(), scheme)?;
-
- (scheme, number)
+ let scheme = desc.get_scheme(token)?;
+ let number = desc.number;
+ (
+ scheme,
+ number,
+ )
};
scheme.kfdread(number, payload, flags, metadata, token)
@@ -440,9 +448,9 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize, token: &mut CleanLockToken)
}
.ok_or(Error::new(EBADF))?;
- let (scheme_id, number, flags) = {
- let desc = file.description.write(token.token());
- (desc.scheme, desc.number, desc.flags)
+ let (number, flags, desc) = {
+ let desc = *file.description.read(token.token());
+ (desc.number, desc.flags, desc)
};
if cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC {
@@ -460,7 +468,7 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize, token: &mut CleanLockToken)
// Communicate fcntl with scheme
if cmd != F_GETFD && cmd != F_SETFD {
- let scheme = scheme::get_scheme(token.token(), scheme_id)?;
+ let scheme = desc.get_scheme(token)?;
scheme.fcntl(number, cmd, arg, token)?;
};
@@ -518,13 +526,11 @@ pub fn flink(fd: FileHandle, raw_path: UserSliceRo, token: &mut CleanLockToken)
let path = RedoxPath::from_absolute(&path_buf).ok_or(Error::new(EINVAL))?;
let (_, reference) = path.as_parts().ok_or(Error::new(EINVAL))?;
- let (number, scheme_id) = {
- let desc = file.description.read(token.token());
- (desc.number, desc.scheme)
+ let (number, scheme) = {
+ let desc = *file.description.read(token.token());
+ (desc.number, desc.get_scheme(token)?)
};
- let scheme = scheme::get_scheme(token.token(), scheme_id)?;
-
// TODO: Check EXDEV.
/*
if scheme_id != description.scheme {
@@ -554,13 +560,11 @@ pub fn frename(fd: FileHandle, raw_path: UserSliceRo, token: &mut CleanLockToken
let path = RedoxPath::from_absolute(&path_buf).ok_or(Error::new(EINVAL))?;
let (_, reference) = path.as_parts().ok_or(Error::new(EINVAL))?;
- let (number, scheme_id) = {
- let desc = file.description.read(token.token());
- (desc.number, desc.scheme)
+ let (number, scheme) = {
+ let desc = *file.description.read(token.token());
+ (desc.number, desc.get_scheme(token)?)
};
- let scheme = scheme::get_scheme(token.token(), scheme_id)?;
-
// TODO: Check EXDEV.
/*
if scheme_id != description.scheme {
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index e83da42..78eed9d 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -271,23 +274,26 @@ unsafe fn bootstrap_mem(bootstrap: &crate::startup::Bootstrap) -> &'static [u8]
}
fn insert_fd(scheme: SchemeId, number: usize, cloexec: bool, token: &mut CleanLockToken) -> usize {
+ let description = Arc::new(RwLock::new(FileDescription::new(
+ scheme,
+ number,
+ 0,
+ (O_CREAT | O_RDWR) as u32,
+ InternalFlags::empty(),
+ token,
+ )));
+
let current_lock = context::current();
let mut current = current_lock.read(token.token());
- let (context, mut token) = current.token_split();
+ let (context, mut context_token) = current.token_split();
context
.add_file_min(
FileDescriptor {
- description: Arc::new(RwLock::new(FileDescription {
- scheme,
- number,
- offset: 0,
- flags: (O_CREAT | O_RDWR) as u32,
- internal_flags: InternalFlags::empty(),
- })),
+ description,
cloexec,
},
syscall::flag::UPPER_FDTBL_TAG + scheme.get(),
- &mut token,
+ &mut context_token,
)
.expect("failed to insert fd to current context")
.get()
@@ -0,0 +1,137 @@
diff --git a/src/context/context.rs b/src/context/context.rs
index c97c516..6d723f4 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -148,6 +148,8 @@ pub struct Context {
pub euid: u32,
pub egid: u32,
pub pid: usize,
+ /// Supplementary group IDs for access control decisions.
+ pub groups: Vec<u32>,
// See [`PreemptGuard`]
//
@@ -204,6 +206,7 @@ impl Context {
euid: 0,
egid: 0,
pid: 0,
+ groups: Vec::new(),
#[cfg(feature = "syscall_debug")]
syscall_debug_info: crate::syscall::debug::SyscallDebugInfo::default(),
@@ -479,6 +482,7 @@ impl Context {
uid: self.euid,
gid: self.egid,
pid: self.pid,
+ groups: self.groups.clone(),
}
}
}
diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs
index d30272c..9da2b28 100644
--- a/src/scheme/mod.rs
+++ b/src/scheme/mod.rs
@@ -777,6 +777,7 @@ pub struct CallerCtx {
pub pid: usize,
pub uid: u32,
pub gid: u32,
+ pub groups: alloc::vec::Vec<u32>,
}
impl CallerCtx {
pub fn filter_uid_gid(self, euid: u32, egid: u32) -> Self {
@@ -785,6 +786,7 @@ impl CallerCtx {
pid: self.pid,
uid: euid,
gid: egid,
+ groups: self.groups,
}
} else {
self
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
index 47588e1..6ffb256 100644
--- a/src/scheme/proc.rs
+++ b/src/scheme/proc.rs
@@ -105,6 +105,7 @@ enum ContextHandle {
// Attr handles, to set ens/euid/egid/pid.
Authority,
Attr,
+ Groups,
Status {
privileged: bool,
@@ -261,6 +262,7 @@ impl ProcScheme {
let handle = match actual_name {
"attrs" => ContextHandle::Attr,
"status" => ContextHandle::Status { privileged: true },
+ "groups" => ContextHandle::Groups,
_ => return Err(Error::new(ENOENT)),
};
@@ -306,6 +308,11 @@ impl ProcScheme {
let id = NonZeroUsize::new(NEXT_ID.fetch_add(1, Ordering::Relaxed))
.ok_or(Error::new(EMFILE))?;
let context = context::spawn(true, Some(id), ret, token)?;
+ {
+ let parent_groups =
+ context::current().read(token.token()).groups.clone();
+ context.write(token.token()).groups = parent_groups;
+ }
HANDLES.write(token.token()).insert(
id.get(),
Handle {
@@ -1271,6 +1278,39 @@ impl ContextHandle {
guard.prio = (info.prio as usize).min(39);
Ok(size_of::<ProcSchemeAttrs>())
}
+ Self::Groups => {
+ const NGROUPS_MAX: usize = 65536;
+ if buf.len() % size_of::<u32>() != 0 {
+ return Err(Error::new(EINVAL));
+ }
+ let count = buf.len() / size_of::<u32>();
+ if count > NGROUPS_MAX {
+ return Err(Error::new(EINVAL));
+ }
+ let mut groups = Vec::with_capacity(count);
+ for chunk in buf.in_exact_chunks(size_of::<u32>()).take(count) {
+ groups.push(chunk.read_u32()?);
+ }
+ let proc_id = {
+ let guard = context.read(token.token());
+ guard.owner_proc_id
+ };
+ {
+ let mut guard = context.write(token.token());
+ guard.groups = groups.clone();
+ }
+ if let Some(pid) = proc_id {
+ let mut contexts = context::contexts(token.downgrade());
+ let (contexts, mut t) = contexts.token_split();
+ for context_ref in contexts.iter() {
+ let mut ctx = context_ref.write(t.token());
+ if ctx.owner_proc_id == Some(pid) {
+ ctx.groups = groups.clone();
+ }
+ }
+ }
+ Ok(count * size_of::<u32>())
+ }
ContextHandle::OpenViaDup => {
let mut args = buf.usizes();
@@ -1475,6 +1515,15 @@ impl ContextHandle {
debug_name,
})
}
+ Self::Groups => {
+ let c = &context.read(token.token());
+ let max = buf.len() / size_of::<u32>();
+ let count = c.groups.len().min(max);
+ for (chunk, gid) in buf.in_exact_chunks(size_of::<u32>()).zip(&c.groups).take(count) {
+ chunk.copy_from_slice(&gid.to_ne_bytes())?;
+ }
+ Ok(count * size_of::<u32>())
+ }
ContextHandle::Sighandler => {
let data = match context.read(token.token()).sig {
Some(ref sig) => SetSighandlerData {
@@ -0,0 +1,422 @@
diff --git a/src/acpi/madt/arch/x86.rs b/src/acpi/madt/arch/x86.rs
index 4dc2388..f472c08 100644
--- a/src/acpi/madt/arch/x86.rs
+++ b/src/acpi/madt/arch/x86.rs
@@ -18,6 +18,7 @@ use crate::{
use super::{Madt, MadtEntry};
+const AP_SPIN_LIMIT: u32 = 1_000_000;
const TRAMPOLINE: usize = 0x8000;
static TRAMPOLINE_DATA: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/trampoline"));
@@ -42,13 +43,17 @@ pub(super) fn init(madt: Madt) {
//TODO: do not have writable and executable!
let mut mapper = KernelMapper::lock_rw();
- let result = mapper
- .map_phys(
- trampoline_page.start_address(),
- trampoline_frame.base(),
- PageFlags::new().execute(true).write(true),
- )
- .expect("failed to map trampoline");
+ let result = match mapper.map_phys(
+ trampoline_page.start_address(),
+ trampoline_frame.base(),
+ PageFlags::new().execute(true).write(true),
+ ) {
+ Some(result) => result,
+ None => {
+ println!("KERNEL AP: failed to map trampoline page, AP bring-up disabled");
+ return;
+ }
+ };
(result, mapper.table().phys().data())
};
@@ -72,17 +77,27 @@ pub(super) fn init(madt: Madt) {
if u32::from(ap_local_apic.id) == me.get() {
debug!(" This is my local APIC");
} else if ap_local_apic.flags & 1 == 1 {
- let cpu_id = LogicalCpuId::next();
-
// Allocate a stack
- let stack_start = RmmA::phys_to_virt(
- allocate_p2frame(4)
- .expect("no more frames in acpi stack_start")
- .base(),
- )
- .data();
+ let alloc = match allocate_p2frame(4) {
+ Some(frame) => frame,
+ None => {
+ println!("KERNEL AP: CPU {} no memory for stack, skipping", ap_local_apic.id);
+ continue;
+ }
+ };
+ let stack_start = RmmA::phys_to_virt(alloc.base()).data();
let stack_end = stack_start + (PAGE_SIZE << 4);
+ let next_cpu = crate::CPU_COUNT.load(Ordering::Relaxed);
+ if next_cpu >= crate::cpu_set::MAX_CPU_COUNT {
+ println!(
+ "KERNEL AP: CPU {} exceeds logical CPU limit, skipping",
+ ap_local_apic.id
+ );
+ continue;
+ }
+ let cpu_id = LogicalCpuId::new(next_cpu);
+
let pcr_ptr = crate::arch::gdt::allocate_and_init_pcr(cpu_id, stack_end);
let idt_ptr = crate::arch::idt::allocate_and_init_idt(cpu_id);
@@ -137,13 +152,34 @@ pub(super) fn init(madt: Madt) {
local_apic.set_icr(icr);
}
- // Wait for trampoline ready
- while unsafe { (*ap_ready.cast::<AtomicU8>()).load(Ordering::SeqCst) } == 0 {
+ // Wait for trampoline ready with timeout
+ let mut trampoline_ready = false;
+ for _ in 0..AP_SPIN_LIMIT {
+ if unsafe { (*ap_ready.cast::<AtomicU8>()).load(Ordering::SeqCst) } != 0 {
+ trampoline_ready = true;
+ break;
+ }
hint::spin_loop();
}
- while !AP_READY.load(Ordering::SeqCst) {
+ if !trampoline_ready {
+ println!("KERNEL AP: CPU {} trampoline timeout, skipping", ap_local_apic.id);
+ continue;
+ }
+
+ let mut kernel_ready = false;
+ for _ in 0..AP_SPIN_LIMIT {
+ if AP_READY.load(Ordering::SeqCst) {
+ kernel_ready = true;
+ break;
+ }
hint::spin_loop();
}
+ if !kernel_ready {
+ println!("KERNEL AP: CPU {} AP_READY timeout, skipping", ap_local_apic.id);
+ continue;
+ }
+
+ crate::CPU_COUNT.fetch_add(1, Ordering::Relaxed);
RmmA::invalidate_all();
}
@@ -151,10 +187,12 @@ pub(super) fn init(madt: Madt) {
}
// Unmap trampoline
- let (_frame, _, flush) = unsafe {
+ if let Some((_frame, _, flush)) = unsafe {
KernelMapper::lock_rw()
.unmap_phys(trampoline_page.start_address())
- .expect("failed to unmap trampoline page")
- };
- flush.flush();
+ } {
+ flush.flush();
+ } else {
+ println!("KERNEL AP: failed to unmap trampoline page (non-fatal)");
+ }
}
diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs
index 4fdb0ba..aaa7196 100644
--- a/src/allocator/mod.rs
+++ b/src/allocator/mod.rs
@@ -7,26 +7,40 @@ mod linked_list;
/// Size of kernel heap
const KERNEL_HEAP_SIZE: usize = ::rmm::MEGABYTE;
+#[cold]
+fn halt_kernel_heap_init(message: &str) -> ! {
+ print!("{message}");
+ println!("Kernel heap initialization cannot continue. Halting.");
+ loop {
+ core::hint::spin_loop();
+ }
+}
+
unsafe fn map_heap(mapper: &mut KernelMapper<true>, offset: usize, size: usize) {
let mut flush_all = PageFlushAll::new();
let heap_start_page = Page::containing_address(VirtualAddress::new(offset));
let heap_end_page = Page::containing_address(VirtualAddress::new(offset + size - 1));
for page in Page::range_inclusive(heap_start_page, heap_end_page) {
- let phys = mapper
- .allocator_mut()
- .allocate_one()
- .expect("failed to allocate kernel heap");
+ let phys = match mapper.allocator_mut().allocate_one() {
+ Some(phys) => phys,
+ None => halt_kernel_heap_init(
+ "FATAL: failed to allocate physical frame for kernel heap\n",
+ ),
+ };
let flush = unsafe {
- mapper
- .map_phys(
- page.start_address(),
- phys,
- PageFlags::new()
- .write(true)
- .global(cfg!(not(feature = "pti"))),
- )
- .expect("failed to map kernel heap")
+ match mapper.map_phys(
+ page.start_address(),
+ phys,
+ PageFlags::new()
+ .write(true)
+ .global(cfg!(not(feature = "pti"))),
+ ) {
+ Some(flush) => flush,
+ None => halt_kernel_heap_init(
+ "FATAL: failed to map kernel heap virtual page\n",
+ ),
+ }
};
flush_all.consume(flush);
}
diff --git a/src/arch/x86_shared/gdt.rs b/src/arch/x86_shared/gdt.rs
index cad344f..f7acae3 100644
--- a/src/arch/x86_shared/gdt.rs
+++ b/src/arch/x86_shared/gdt.rs
@@ -192,6 +192,15 @@ impl ProcessorControlRegion {
}
}
+#[cold]
+fn halt_pcr_init() -> ! {
+ println!("FATAL: failed to allocate physical memory for Processor Control Region");
+ println!("Processor startup cannot continue. Halting.");
+ loop {
+ core::hint::spin_loop();
+ }
+}
+
pub unsafe fn pcr() -> *mut ProcessorControlRegion {
unsafe {
// Primitive benchmarking of RDFSBASE and RDGSBASE in userspace, appears to indicate that
@@ -375,7 +384,10 @@ pub fn allocate_and_init_pcr(
.next_power_of_two()
.trailing_zeros();
- let pcr_frame = crate::memory::allocate_p2frame(alloc_order).expect("failed to allocate PCR");
+ let pcr_frame = match crate::memory::allocate_p2frame(alloc_order) {
+ Some(frame) => frame,
+ None => halt_pcr_init(),
+ };
let pcr_ptr = RmmA::phys_to_virt(pcr_frame.base()).data() as *mut ProcessorControlRegion;
unsafe { core::ptr::write(pcr_ptr, ProcessorControlRegion::new_partial_init(cpu_id)) };
diff --git a/src/arch/x86_shared/idt.rs b/src/arch/x86_shared/idt.rs
index 5006458..47f692f 100644
--- a/src/arch/x86_shared/idt.rs
+++ b/src/arch/x86_shared/idt.rs
@@ -78,6 +78,15 @@ static INIT_BSP_IDT: SyncUnsafeCell<Idt> = SyncUnsafeCell::new(Idt::new());
pub(crate) static IDTS: RwLock<HashMap<LogicalCpuId, &'static mut Idt>> =
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
+#[cold]
+fn halt_idt_init() -> ! {
+ println!("FATAL: failed to allocate physical pages for backup interrupt stack");
+ println!("Interrupt setup cannot continue. Halting.");
+ loop {
+ core::hint::spin_loop();
+ }
+}
+
#[inline]
pub fn is_reserved(cpu_id: LogicalCpuId, index: u8) -> bool {
if cpu_id == LogicalCpuId::BSP {
@@ -161,8 +170,10 @@ pub fn allocate_and_init_idt(cpu_id: LogicalCpuId) -> *mut Idt {
.or_insert_with(|| Box::leak(Box::new(Idt::new())));
use crate::memory::{RmmA, RmmArch};
- let frames = crate::memory::allocate_p2frame(4)
- .expect("failed to allocate pages for backup interrupt stack");
+ let frames = match crate::memory::allocate_p2frame(4) {
+ Some(frames) => frames,
+ None => halt_idt_init(),
+ };
// Physical pages are mapped linearly. So is the linearly mapped virtual memory.
let base_address = RmmA::phys_to_virt(frames.base());
diff --git a/src/memory/mod.rs b/src/memory/mod.rs
index 393ae7e..b4a1aa3 100644
--- a/src/memory/mod.rs
+++ b/src/memory/mod.rs
@@ -754,7 +754,8 @@ pub fn init_mm(allocator: BumpAllocator<RmmA>) {
init_sections(allocator);
unsafe {
- let the_frame = allocate_frame().expect("failed to allocate static zeroed frame");
+ let the_frame = allocate_frame()
+ .expect("KERNEL MEM: failed to allocate static zeroed frame during init_mm - physical memory exhausted");
let the_info = get_page_info(the_frame).expect("static zeroed frame had no PageInfo");
the_info
.refcount
@@ -1027,9 +1028,13 @@ pub fn page_fault_handler(
let mut token = unsafe { CleanLockToken::new() };
match context::memory::try_correcting_page_tables(faulting_page, mode, &mut token) {
Ok(()) => return Ok(()),
- Err(PfError::Oom) => todo!("oom"),
+ Err(PfError::Oom) => {
+ debug!("KERNEL PF: OOM during page table correction for {:#x}", faulting_address.data());
+ }
Err(PfError::Segv | PfError::RecursionLimitExceeded) => (),
- Err(PfError::NonfatalInternalError) => todo!(),
+ Err(PfError::NonfatalInternalError) => {
+ debug!("KERNEL PF: internal error during page table correction for {:#x}", faulting_address.data());
+ }
}
}
@@ -1038,6 +1043,17 @@ pub fn page_fault_handler(
return Ok(());
}
+ debug!(
+ "KERNEL PF: addr={:#x} ip={:#x} mode={:?} kernel={} user={} write={} instr={}",
+ faulting_address.data(),
+ stack.ip(),
+ mode,
+ caused_by_kernel,
+ caused_by_user,
+ caused_by_write,
+ caused_by_instr_fetch,
+ );
+
Err(Segv)
}
static THE_ZEROED_FRAME: SyncUnsafeCell<Option<(Frame, &'static PageInfo)>> =
diff --git a/src/startup/memory.rs b/src/startup/memory.rs
index 26922dd..f271200 100644
--- a/src/startup/memory.rs
+++ b/src/startup/memory.rs
@@ -323,7 +323,16 @@ unsafe fn map_memory<A: Arch>(areas: &[MemoryArea], mut bump_allocator: &mut Bum
}
}
- let kernel_area = (*MEMORY_MAP.get()).kernel().unwrap();
+ let kernel_area = match (*MEMORY_MAP.get()).kernel() {
+ Some(area) => area,
+ None => {
+ println!("FATAL: kernel memory area not found in boot memory map");
+ println!("Cannot determine kernel base address. Halting.");
+ loop {
+ core::hint::spin_loop();
+ }
+ }
+ };
let kernel_base = kernel_area.start;
let kernel_size = kernel_area.end.saturating_sub(kernel_area.start);
// Map kernel at KERNEL_OFFSET
diff --git a/src/startup/mod.rs b/src/startup/mod.rs
index 8ad3cdf..86aabc2 100644
--- a/src/startup/mod.rs
+++ b/src/startup/mod.rs
@@ -149,6 +149,15 @@ static BOOTSTRAP: spin::Once<Bootstrap> = spin::Once::new();
pub(crate) static AP_READY: AtomicBool = AtomicBool::new(false);
static BSP_READY: AtomicBool = AtomicBool::new(false);
+#[cold]
+fn halt_boot(message: &str) -> ! {
+ print!("{message}");
+ println!("Kernel boot cannot continue. Halting.");
+ loop {
+ hint::spin_loop();
+ }
+}
+
/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
pub(crate) fn kmain(bootstrap: Bootstrap) -> ! {
let mut token = unsafe { CleanLockToken::new() };
@@ -180,9 +189,7 @@ pub(crate) fn kmain(bootstrap: Bootstrap) -> ! {
context.euid = 0;
context.egid = 0;
}
- Err(err) => {
- panic!("failed to spawn userspace_init: {:?}", err);
- }
+ Err(_err) => halt_boot("FATAL: failed to spawn first userspace process userspace_init\n"),
}
run_userspace(&mut token)
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index e83da42..084b64e 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -33,6 +33,8 @@ pub fn exit_this_context(excp: Option<syscall::Exception>, token: &mut CleanLock
let mut close_files;
let addrspace_opt;
+ super::futex::cleanup_current_robust_futexes(token);
+
let context_lock = context::current();
{
let mut context = context_lock.write(token.token());
@@ -44,6 +46,7 @@ pub fn exit_this_context(excp: Option<syscall::Exception>, token: &mut CleanLock
addrspace_opt = context
.set_addr_space(None, token.downgrade())
.and_then(|a| Arc::try_unwrap(a).ok());
+ context.robust_list_head = None;
drop(mem::replace(&mut context.syscall_head, SyscallFrame::Dummy));
drop(mem::replace(&mut context.syscall_tail, SyscallFrame::Dummy));
}
@@ -244,7 +247,11 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap, token: &mut CleanLockTok
.copy_from_slice(bootstrap_slice)
.expect("failed to copy memory to bootstrap");
- let bootstrap_entry = u64::from_le_bytes(bootstrap_slice[0x1a..0x22].try_into().unwrap());
+ let bootstrap_entry = if bootstrap_slice.len() >= 0x22 {
+ u64::from_le_bytes(bootstrap_slice[0x1a..0x22].try_into().unwrap())
+ } else {
+ panic!("KERNEL BOOT: bootstrap initfs too small ({} bytes, need at least 34) - cannot determine entry point", bootstrap_slice.len());
+ };
debug!("Bootstrap entry point: {:X}", bootstrap_entry);
assert_ne!(bootstrap_entry, 0);
@@ -271,23 +278,26 @@ unsafe fn bootstrap_mem(bootstrap: &crate::startup::Bootstrap) -> &'static [u8]
}
fn insert_fd(scheme: SchemeId, number: usize, cloexec: bool, token: &mut CleanLockToken) -> usize {
+ let description = Arc::new(RwLock::new(FileDescription::new(
+ scheme,
+ number,
+ 0,
+ (O_CREAT | O_RDWR) as u32,
+ InternalFlags::empty(),
+ token,
+ )));
+
let current_lock = context::current();
let mut current = current_lock.read(token.token());
- let (context, mut token) = current.token_split();
+ let (context, mut context_token) = current.token_split();
context
.add_file_min(
FileDescriptor {
- description: Arc::new(RwLock::new(FileDescription {
- scheme,
- number,
- offset: 0,
- flags: (O_CREAT | O_RDWR) as u32,
- internal_flags: InternalFlags::empty(),
- })),
+ description,
cloexec,
},
syscall::flag::UPPER_FDTBL_TAG + scheme.get(),
- &mut token,
+ &mut context_token,
)
.expect("failed to insert fd to current context")
.get()
@@ -0,0 +1,13 @@
diff --git a/src/context/mod.rs b/src/context/mod.rs
index 37c73f5..4f5d60f 100644
--- a/src/context/mod.rs
+++ b/src/context/mod.rs
@@ -22,7 +22,7 @@ use crate::{
use self::context::Kstack;
pub use self::{
- context::{BorrowedHtBuf, Context, Status},
+ context::{BorrowedHtBuf, Context, SchedPolicy, Status},
switch::switch,
};
@@ -0,0 +1,188 @@
diff --git a/src/lib.rs b/src/lib.rs
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -57,16 +57,151 @@ pub mod start;
pub mod sync;
-use crate::platform::{Allocator, NEWALLOCATOR};
+use crate::platform::{Allocator, NEWALLOCATOR, Pal, Sys};
#[global_allocator]
static ALLOCATOR: Allocator = NEWALLOCATOR;
+
+const MAX_FATAL_BACKTRACE_FRAMES: usize = 16;
+const MAX_FATAL_FRAME_STRIDE: usize = 1024 * 1024;
+
+#[inline(never)]
+fn write_process_thread_identity(w: &mut platform::FileWriter) {
+ use core::fmt::Write;
+
+ let pid = Sys::getpid();
+ let tid = Sys::gettid();
+
+ match crate::pthread::current_thread() {
+ Some(thread) => {
+ let _ = w.write_fmt(format_args!(
+ "RELIBC CONTEXT: pid={} tid={} pthread={:#x}\n",
+ pid,
+ tid,
+ thread as *const _ as usize,
+ ));
+ }
+ None => {
+ let _ = w.write_fmt(format_args!(
+ "RELIBC CONTEXT: pid={} tid={} pthread=<unavailable>\n",
+ pid, tid,
+ ));
+ }
+ }
+}
+
+#[cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))]
+#[inline(never)]
+fn current_frame_pointer() -> *const usize {
+ let frame: *const usize;
+
+ #[cfg(target_arch = "x86_64")]
+ unsafe {
+ core::arch::asm!("mov {}, rbp", out(reg) frame, options(nomem, nostack, preserves_flags));
+ }
+
+ #[cfg(target_arch = "x86")]
+ unsafe {
+ core::arch::asm!("mov {}, ebp", out(reg) frame, options(nomem, nostack, preserves_flags));
+ }
+
+ #[cfg(target_arch = "aarch64")]
+ unsafe {
+ core::arch::asm!("mov {}, x29", out(reg) frame, options(nomem, nostack, preserves_flags));
+ }
+
+ frame
+}
+
+#[cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))]
+fn read_backtrace_frame(frame: *const usize) -> Option<(*const usize, usize)> {
+ let align = core::mem::align_of::<usize>();
+ let frame_addr = frame as usize;
+
+ if frame.is_null() || frame_addr % align != 0 {
+ return None;
+ }
+
+ let next_frame = unsafe { frame.read() } as *const usize;
+ let return_address = unsafe { frame.add(1).read() };
+
+ if return_address == 0 {
+ return None;
+ }
+
+ Some((next_frame, return_address))
+}
+
+#[cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))]
+fn is_sane_next_backtrace_frame(current: *const usize, next: *const usize) -> bool {
+ let align = core::mem::align_of::<usize>();
+ let current_addr = current as usize;
+ let next_addr = next as usize;
+
+ !next.is_null()
+ && next_addr % align == 0
+ && next_addr > current_addr
+ && next_addr - current_addr <= MAX_FATAL_FRAME_STRIDE
+}
+
+#[inline(never)]
+fn write_best_effort_backtrace(w: &mut platform::FileWriter) {
+ use core::fmt::Write;
+
+ let _ = w.write_str("RELIBC: attempting best-effort backtrace\n");
+
+ #[cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))]
+ {
+ let mut frame = current_frame_pointer();
+ let mut wrote_frame = false;
+
+ for frame_index in 0..MAX_FATAL_BACKTRACE_FRAMES {
+ let Some((next_frame, return_address)) = read_backtrace_frame(frame) else {
+ break;
+ };
+
+ wrote_frame = true;
+ let _ = w.write_fmt(format_args!(
+ "RELIBC BACKTRACE[{frame_index:02}]: {:#x}\n",
+ return_address,
+ ));
+
+ if !is_sane_next_backtrace_frame(frame, next_frame) {
+ break;
+ }
+
+ frame = next_frame;
+ }
+
+ if !wrote_frame {
+ let _ = w.write_str("RELIBC: backtrace attempt produced no frames\n");
+ }
+ }
+
+ #[cfg(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64")))]
+ {
+ let _ = w.write_str("RELIBC: backtrace unavailable on this architecture\n");
+ }
+}
#[unsafe(no_mangle)]
pub extern "C" fn relibc_panic(pi: &::core::panic::PanicInfo) -> ! {
use core::fmt::Write;
let mut w = platform::FileWriter::new(2);
- let _ = w.write_fmt(format_args!("RELIBC PANIC: {}\n", pi));
+
+ if let Some(location) = pi.location() {
+ let _ = w.write_fmt(format_args!(
+ "RELIBC PANIC LOCATION: {}:{}:{}\n",
+ location.file(),
+ location.line(),
+ location.column(),
+ ));
+ } else {
+ let _ = w.write_str("RELIBC PANIC LOCATION: <unavailable>\n");
+ }
+
+ write_process_thread_identity(&mut w);
+ let _ = w.write_fmt(format_args!("RELIBC PANIC: {}\n", pi));
core::intrinsics::abort();
}
@@ -95,23 +235,28 @@ pub extern "C" fn rust_oom(layout: ::core::alloc::Layout) -> ! {
let mut w = platform::FileWriter::new(2);
let _ = w.write_fmt(format_args!(
- "RELIBC OOM: {} bytes aligned to {} bytes\n",
+ "RELIBC OOM: {} bytes aligned to {} bytes - process will abort\n",
layout.size(),
layout.align()
));
+ write_process_thread_identity(&mut w);
+ write_best_effort_backtrace(&mut w);
core::intrinsics::abort();
}
#[cfg(not(test))]
#[allow(non_snake_case)]
#[linkage = "weak"]
#[unsafe(no_mangle)]
pub extern "C" fn _Unwind_Resume() -> ! {
use core::fmt::Write;
let mut w = platform::FileWriter::new(2);
- let _ = w.write_str("_Unwind_Resume\n");
+ let _ = w.write_str(
+ "RELIBC: _Unwind_Resume called - exception propagation failed, aborting\n",
+ );
+ write_process_thread_identity(&mut w);
core::intrinsics::abort();
}
@@ -0,0 +1,685 @@
diff --git a/drivers/acpid/src/main.rs b/drivers/acpid/src/main.rs
index 059254b3..a3f5f996 100644
--- a/drivers/acpid/src/main.rs
+++ b/drivers/acpid/src/main.rs
@@ -3,6 +3,7 @@ use std::fs::File;
use std::mem;
use std::ops::ControlFlow;
use std::os::unix::io::AsRawFd;
+use std::process;
use std::sync::Arc;
use ::acpi::aml::op_region::{RegionHandler, RegionSpace};
@@ -17,6 +18,58 @@ mod ec;
mod scheme;
+fn parse_physaddrs(sdt: &self::acpi::Sdt) -> Vec<u64> {
+ match &sdt.signature {
+ b"RSDT" => {
+ let chunks = sdt.data().chunks_exact(mem::size_of::<u32>());
+ if !chunks.remainder().is_empty() {
+ eprintln!(
+ "acpid: malformed RSDT length {}: expected 4-byte entries",
+ sdt.data().len()
+ );
+ process::exit(1);
+ }
+
+ chunks
+ .map(|chunk| match <[u8; mem::size_of::<u32>()]>::try_from(chunk) {
+ Ok(bytes) => u32::from_le_bytes(bytes) as u64,
+ Err(_) => {
+ eprintln!("acpid: failed to decode RSDT physical address entry");
+ process::exit(1);
+ }
+ })
+ .collect()
+ }
+ b"XSDT" => {
+ let chunks = sdt.data().chunks_exact(mem::size_of::<u64>());
+ if !chunks.remainder().is_empty() {
+ eprintln!(
+ "acpid: malformed XSDT length {}: expected 8-byte entries",
+ sdt.data().len()
+ );
+ process::exit(1);
+ }
+
+ chunks
+ .map(|chunk| match <[u8; mem::size_of::<u64>()]>::try_from(chunk) {
+ Ok(bytes) => u64::from_le_bytes(bytes),
+ Err(_) => {
+ eprintln!("acpid: failed to decode XSDT physical address entry");
+ process::exit(1);
+ }
+ })
+ .collect()
+ }
+ signature => {
+ eprintln!(
+ "acpid: expected [RX]SDT from kernel, got {:?}",
+ String::from_utf8_lossy(signature)
+ );
+ process::exit(1);
+ }
+ }
+}
+
fn daemon(daemon: daemon::Daemon) -> ! {
common::setup_logging(
"misc",
@@ -29,7 +82,10 @@ fn daemon(daemon: daemon::Daemon) -> ! {
log::info!("acpid start");
let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt")
- .expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`")
+ .unwrap_or_else(|err| {
+ eprintln!("acpid: failed to read `/scheme/kernel.acpi/rxsdt`: {err}");
+ process::exit(1);
+ })
.into();
if rxsdt_raw_data.is_empty() {
@@ -38,84 +94,84 @@ fn daemon(daemon: daemon::Daemon) -> ! {
std::process::exit(0);
}
- let sdt = self::acpi::Sdt::new(rxsdt_raw_data).expect("acpid: failed to parse [RX]SDT");
-
- let mut thirty_two_bit;
- let mut sixty_four_bit;
-
- let physaddrs_iter = match &sdt.signature {
- b"RSDT" => {
- thirty_two_bit = sdt
- .data()
- .chunks(mem::size_of::<u32>())
- // TODO: With const generics, the compiler has some way of doing this for static sizes.
- .map(|chunk| <[u8; mem::size_of::<u32>()]>::try_from(chunk).unwrap())
- .map(|chunk| u32::from_le_bytes(chunk))
- .map(u64::from);
-
- &mut thirty_two_bit as &mut dyn Iterator<Item = u64>
- }
- b"XSDT" => {
- sixty_four_bit = sdt
- .data()
- .chunks(mem::size_of::<u64>())
- .map(|chunk| <[u8; mem::size_of::<u64>()]>::try_from(chunk).unwrap())
- .map(|chunk| u64::from_le_bytes(chunk));
-
- &mut sixty_four_bit as &mut dyn Iterator<Item = u64>
- }
- _ => panic!("acpid: expected [RX]SDT from kernel to be either of those"),
- };
+ let sdt = self::acpi::Sdt::new(rxsdt_raw_data).unwrap_or_else(|err| {
+ eprintln!("acpid: failed to parse [RX]SDT: {err}");
+ process::exit(1);
+ });
+ let physaddrs = parse_physaddrs(&sdt);
let region_handlers: Vec<(RegionSpace, Box<dyn RegionHandler + 'static>)> = vec![
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
(RegionSpace::EmbeddedControl, Box::new(ec::Ec::new())),
];
- let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter, region_handlers);
+ let acpi_context = self::acpi::AcpiContext::init(physaddrs.into_iter(), region_handlers);
// TODO: I/O permission bitmap?
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
- common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3");
+ common::acquire_port_io_rights().unwrap_or_else(|err| {
+ eprintln!("acpid: failed to set I/O privilege level to Ring 3: {err}");
+ process::exit(1);
+ });
let shutdown_pipe = File::open("/scheme/kernel.acpi/kstop")
- .expect("acpid: failed to open `/scheme/kernel.acpi/kstop`");
-
- let mut event_queue = RawEventQueue::new().expect("acpid: failed to create event queue");
- let socket = Socket::nonblock().expect("acpid: failed to create disk scheme");
+ .unwrap_or_else(|err| {
+ eprintln!("acpid: failed to open `/scheme/kernel.acpi/kstop`: {err}");
+ process::exit(1);
+ });
+
+ let mut event_queue = RawEventQueue::new().unwrap_or_else(|err| {
+ eprintln!("acpid: failed to create event queue: {err}");
+ process::exit(1);
+ });
+ let socket = Socket::nonblock().unwrap_or_else(|err| {
+ eprintln!("acpid: failed to create disk scheme: {err}");
+ process::exit(1);
+ });
let mut scheme = self::scheme::AcpiScheme::new(&acpi_context, &socket);
let mut handler = Blocking::new(&socket, 16);
event_queue
.subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ)
- .expect("acpid: failed to register shutdown pipe for event queue");
+ .unwrap_or_else(|err| {
+ eprintln!("acpid: failed to register shutdown pipe for event queue: {err}");
+ process::exit(1);
+ });
event_queue
.subscribe(socket.inner().raw(), 1, EventFlags::READ)
- .expect("acpid: failed to register scheme socket for event queue");
+ .unwrap_or_else(|err| {
+ eprintln!("acpid: failed to register scheme socket for event queue: {err}");
+ process::exit(1);
+ });
register_sync_scheme(&socket, "acpi", &mut scheme)
- .expect("acpid: failed to register acpi scheme to namespace");
+ .unwrap_or_else(|err| {
+ eprintln!("acpid: failed to register acpi scheme to namespace: {err}");
+ process::exit(1);
+ });
daemon.ready();
- libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace");
+ libredox::call::setrens(0, 0).unwrap_or_else(|err| {
+ eprintln!("acpid: failed to enter null namespace: {err}");
+ process::exit(1);
+ });
let mut mounted = true;
while mounted {
- let Some(event) = event_queue
- .next()
- .transpose()
- .expect("acpid: failed to read event file")
- else {
+ let Some(event) = event_queue.next().transpose().unwrap_or_else(|err| {
+ eprintln!("acpid: failed to read event file: {err}");
+ process::exit(1);
+ }) else {
break;
};
if event.fd == socket.inner().raw() {
loop {
- match handler
- .process_requests_nonblocking(&mut scheme)
- .expect("acpid: failed to process requests")
- {
+ match handler.process_requests_nonblocking(&mut scheme).unwrap_or_else(|err| {
+ eprintln!("acpid: failed to process requests: {err}");
+ process::exit(1);
+ }) {
ControlFlow::Continue(()) => {}
ControlFlow::Break(()) => break,
}
@@ -134,7 +190,8 @@ fn daemon(daemon: daemon::Daemon) -> ! {
acpi_context.set_global_s_state(5);
- unreachable!("System should have shut down before this is entered");
+ eprintln!("acpid: system did not shut down after requesting S5");
+ process::exit(1);
}
fn main() {
diff --git a/drivers/pcid/src/main.rs b/drivers/pcid/src/main.rs
index 61cd9a78..18ee18ab 100644
--- a/drivers/pcid/src/main.rs
+++ b/drivers/pcid/src/main.rs
@@ -3,6 +3,7 @@
#![feature(non_exhaustive_omitted_patterns_lint)]
use std::collections::BTreeMap;
+use std::process;
use log::{debug, info, trace, warn};
use pci_types::capability::PciCapability;
@@ -42,7 +43,16 @@ fn handle_parsed_header(
continue;
}
match endpoint_header.bar(i, pcie) {
- Some(TyBar::Io { port }) => bars[i as usize] = PciBar::Port(port.try_into().unwrap()),
+ Some(TyBar::Io { port }) => match port.try_into() {
+ Ok(port) => bars[i as usize] = PciBar::Port(port),
+ Err(_) => {
+ warn!(
+ "pcid: skipping invalid I/O BAR port {port:#x} on {}",
+ endpoint_header.header().address()
+ );
+ bars[i as usize] = PciBar::None;
+ }
+ },
Some(TyBar::Memory32 {
address,
size,
@@ -251,7 +261,10 @@ fn daemon(daemon: daemon::Daemon) -> ! {
info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV");
let mut scheme = scheme::PciScheme::new(pcie);
- let socket = redox_scheme::Socket::create().expect("failed to open pci scheme socket");
+ let socket = redox_scheme::Socket::create().unwrap_or_else(|err| {
+ eprintln!("pcid: failed to open pci scheme socket: {err}");
+ process::exit(1);
+ });
let handler = Blocking::new(&socket, 16);
{
@@ -259,17 +272,27 @@ fn daemon(daemon: daemon::Daemon) -> ! {
Ok(register_pci) => {
let access_id = scheme.access();
- let access_fd = socket
- .create_this_scheme_fd(0, access_id, syscall::O_RDWR, 0)
- .expect("failed to issue this resource");
- let access_bytes = access_fd.to_ne_bytes();
- let _ = register_pci
- .call_wo(
- &access_bytes,
- syscall::CallFlags::WRITE | syscall::CallFlags::FD,
- &[],
- )
- .expect("failed to send pci_fd to acpid");
+ match socket.create_this_scheme_fd(0, access_id, syscall::O_RDWR, 0) {
+ Ok(access_fd) => {
+ let access_bytes = access_fd.to_ne_bytes();
+ if let Err(err) = register_pci.call_wo(
+ &access_bytes,
+ syscall::CallFlags::WRITE | syscall::CallFlags::FD,
+ &[],
+ ) {
+ warn!(
+ "pcid: failed to send pci_fd to acpid (error: {}). Running without ACPI integration.",
+ err
+ );
+ }
+ }
+ Err(err) => {
+ warn!(
+ "pcid: failed to issue acpid registration resource (error: {}). Running without ACPI integration.",
+ err
+ );
+ }
+ }
}
Err(err) => {
if err.errno() == libredox::errno::ENODEV {
@@ -305,13 +328,20 @@ fn daemon(daemon: daemon::Daemon) -> ! {
debug!("Enumeration complete, now starting pci scheme");
register_sync_scheme(&socket, "pci", &mut scheme)
- .expect("failed to register pci scheme to namespace");
+ .unwrap_or_else(|err| {
+ eprintln!("pcid: failed to register pci scheme to namespace: {err}");
+ process::exit(1);
+ });
let _ = daemon.ready();
- handler
- .process_requests_blocking(scheme)
- .expect("pcid: failed to process requests");
+ match handler.process_requests_blocking(scheme) {
+ Ok(never) => match never {},
+ Err(err) => {
+ eprintln!("pcid: failed to process requests: {err}");
+ process::exit(1);
+ }
+ }
}
fn scan_device(
@@ -323,6 +353,7 @@ fn scan_device(
) {
for func_num in 0..8 {
let header = TyPciHeader::new(PciAddress::new(0, bus_num, dev_num, func_num));
+ let header_address = header.address();
let (vendor_id, device_id) = header.id(pcie);
if vendor_id == 0xffff && device_id == 0xffff {
@@ -344,21 +375,40 @@ fn scan_device(
revision,
};
- info!("PCI {} {}", header.address(), full_device_id.display());
+ info!("PCI {} {}", header_address, full_device_id.display());
let has_multiple_functions = header.has_multiple_functions(pcie);
match header.header_type(pcie) {
HeaderType::Endpoint => {
+ let endpoint_header = match EndpointHeader::from_header(header, pcie) {
+ Some(endpoint_header) => endpoint_header,
+ None => {
+ warn!(
+ "pcid: failed to parse endpoint header for {}",
+ header_address,
+ );
+ continue;
+ }
+ };
handle_parsed_header(
pcie,
tree,
- EndpointHeader::from_header(header, pcie).unwrap(),
+ endpoint_header,
full_device_id,
);
}
HeaderType::PciPciBridge => {
- let bridge_header = PciPciBridgeHeader::from_header(header, pcie).unwrap();
+ let bridge_header = match PciPciBridgeHeader::from_header(header, pcie) {
+ Some(bridge_header) => bridge_header,
+ None => {
+ warn!(
+ "pcid: failed to parse bridge header for {}",
+ header_address,
+ );
+ continue;
+ }
+ };
bus_nums.push(bridge_header.secondary_bus_number(pcie));
}
ty => {
diff --git a/init/src/main.rs b/init/src/main.rs
index 5682cf44..cd270a6e 100644
--- a/init/src/main.rs
+++ b/init/src/main.rs
@@ -1,6 +1,7 @@
use std::collections::BTreeMap;
use std::ffi::OsString;
use std::path::Path;
+use std::time::Duration;
use std::{env, fs, io};
use libredox::flag::{O_RDONLY, O_WRONLY};
@@ -166,19 +167,36 @@ fn main() {
}
};
for entry in entries {
+ let Some(unit_name) = entry.file_name().and_then(|name| name.to_str()) else {
+ eprintln!(
+ "init: skipping config entry with invalid filename: {}",
+ entry.display()
+ );
+ continue;
+ };
scheduler.schedule_start_and_report_errors(
&mut unit_store,
- UnitId(entry.file_name().unwrap().to_str().unwrap().to_owned()),
+ UnitId(unit_name.to_owned()),
);
}
};
scheduler.step(&mut unit_store, &mut init_config);
- libredox::call::setrens(0, 0).expect("init: failed to enter null namespace");
+ if let Err(err) = libredox::call::setrens(0, 0) {
+ eprintln!("init: failed to enter null namespace: {err}");
+ std::process::exit(1);
+ }
loop {
let mut status = 0;
- libredox::call::waitpid(0, &mut status, 0).unwrap();
+ match libredox::call::waitpid(0, &mut status, 0) {
+ Ok(_) => {}
+ Err(err) if err.errno() == libredox::errno::EINTR => continue,
+ Err(err) => {
+ eprintln!("init: waitpid failed: {err}");
+ std::thread::sleep(Duration::from_millis(100));
+ }
+ }
}
}
diff --git a/init/src/scheduler.rs b/init/src/scheduler.rs
index d42a4e57..3b8d10b0 100644
--- a/init/src/scheduler.rs
+++ b/init/src/scheduler.rs
@@ -43,7 +43,10 @@ impl Scheduler {
) {
let loaded_units = unit_store.load_units(unit_id.clone(), errors);
for unit_id in loaded_units {
- if !unit_store.unit(&unit_id).conditions_met() {
+ if unit_store
+ .try_unit(&unit_id)
+ .is_ok_and(|unit| !unit.conditions_met())
+ {
continue;
}
@@ -62,7 +65,10 @@ impl Scheduler {
match job.kind {
JobKind::Start => {
- let unit = unit_store.unit_mut(&job.unit);
+ let Ok(unit) = unit_store.try_unit_mut(&job.unit) else {
+ eprintln!("init: unit {} not found in store, skipping", job.unit.0);
+ continue 'a;
+ };
for dep in &unit.info.requires_weak {
for pending_job in &self.pending {
diff --git a/init/src/service.rs b/init/src/service.rs
index ed0023e9..827ae275 100644
--- a/init/src/service.rs
+++ b/init/src/service.rs
@@ -3,13 +3,24 @@ use std::ffi::OsString;
use std::io::Read;
use std::os::fd::{AsRawFd, OwnedFd};
use std::os::unix::process::CommandExt;
-use std::process::Command;
+use std::process::{Child, Command};
use std::{env, io};
use serde::Deserialize;
use crate::script::subst_env;
+fn terminate_child(child: &mut Child, command: &str) {
+ if let Err(err) = child.kill() {
+ if err.kind() != io::ErrorKind::InvalidInput {
+ eprintln!("init: failed to terminate {command}: {err}");
+ }
+ }
+ if let Err(err) = child.wait() {
+ eprintln!("init: failed to reap {command}: {err}");
+ }
+}
+
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Service {
@@ -37,7 +48,8 @@ pub enum ServiceType {
impl Service {
pub fn spawn(&self, base_envs: &BTreeMap<String, OsString>) {
let mut command = Command::new(&self.cmd);
- command.args(self.args.iter().map(|arg| subst_env(arg)));
+ let resolved_args: Vec<String> = self.args.iter().map(|arg| subst_env(arg)).collect();
+ command.args(&resolved_args);
command.env_clear();
for env in &self.inherit_envs {
if let Some(value) = env::var_os(env) {
@@ -45,14 +57,25 @@ impl Service {
}
}
command.envs(base_envs).envs(&self.envs);
+ let command_display = if resolved_args.is_empty() {
+ self.cmd.clone()
+ } else {
+ format!("{} {}", self.cmd, resolved_args.join(" "))
+ };
- let (mut read_pipe, write_pipe) = io::pipe().unwrap();
+ let (mut read_pipe, write_pipe) = match io::pipe().map_err(|err| {
+ eprintln!("init: failed to create readiness pipe for {command_display}: {err}");
+ err
+ }) {
+ Ok(pair) => pair,
+ Err(_) => return,
+ };
unsafe { pass_fd(&mut command, "INIT_NOTIFY", write_pipe.into()) };
let mut child = match command.spawn() {
Ok(child) => child,
Err(err) => {
- eprintln!("init: failed to execute {:?}: {}", command, err);
+ eprintln!("init: failed to execute {command_display}: {err}");
return;
}
};
@@ -61,10 +84,10 @@ impl Service {
ServiceType::Notify => match read_pipe.read_exact(&mut [0]) {
Ok(()) => {}
Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
- eprintln!("init: {command:?} exited without notifying readiness");
+ eprintln!("init: {command_display} exited without notifying readiness");
}
Err(err) => {
- eprintln!("init: failed to wait for {command:?}: {err}");
+ eprintln!("init: failed to wait for {command_display}: {err}");
}
},
ServiceType::Scheme(scheme) => {
@@ -80,7 +103,7 @@ impl Service {
errno: syscall::EINTR,
}) => continue,
Ok(0) => {
- eprintln!("init: {command:?} exited without notifying readiness");
+ eprintln!("init: {command_display} exited without notifying readiness");
return;
}
Ok(1) => break,
@@ -89,26 +112,40 @@ impl Service {
return;
}
Err(err) => {
- eprintln!("init: failed to wait for {command:?}: {err}");
+ eprintln!("init: failed to wait for {command_display}: {err}");
return;
}
}
}
- let current_namespace_fd = libredox::call::getns().expect("TODO");
- libredox::call::register_scheme_to_ns(current_namespace_fd, scheme, new_fd)
- .expect("TODO");
+ let current_namespace_fd = match libredox::call::getns() {
+ Ok(fd) => fd,
+ Err(err) => {
+ eprintln!("init: failed to get current namespace for {command_display}: {err}");
+ terminate_child(&mut child, &command_display);
+ return;
+ }
+ };
+ if let Err(err) =
+ libredox::call::register_scheme_to_ns(current_namespace_fd, scheme, new_fd)
+ {
+ eprintln!(
+ "init: failed to register scheme {scheme:?} for {command_display}: {err}"
+ );
+ terminate_child(&mut child, &command_display);
+ return;
+ }
}
ServiceType::Oneshot => {
drop(read_pipe);
match child.wait() {
Ok(exit_status) => {
if !exit_status.success() {
- eprintln!("init: {command:?} failed with {exit_status}");
+ eprintln!("init: {command_display} failed with {exit_status}");
}
}
Err(err) => {
- eprintln!("init: failed to wait for {:?}: {}", command, err)
+ eprintln!("init: failed to wait for {command_display}: {err}")
}
}
}
diff --git a/init/src/unit.rs b/init/src/unit.rs
index 98053cb2..bd998394 100644
--- a/init/src/unit.rs
+++ b/init/src/unit.rs
@@ -23,8 +23,14 @@ impl UnitStore {
}
pub fn set_runtime_target(&mut self, unit_id: UnitId) {
- assert!(self.runtime_target.is_none());
- assert!(self.units.contains_key(&unit_id));
+ if self.runtime_target.is_some() {
+ eprintln!("init: runtime target already set, ignoring {}", unit_id.0);
+ return;
+ }
+ if !self.units.contains_key(&unit_id) {
+ eprintln!("init: runtime target {} not found in unit store", unit_id.0);
+ return;
+ }
self.runtime_target = Some(unit_id);
}
@@ -85,8 +91,15 @@ impl UnitStore {
let unit = self.load_single_unit(unit_id, errors);
if let Some(unit) = unit {
loaded_units.push(unit.clone());
- for dep in &self.unit(&unit).info.requires_weak {
- pending_units.push(dep.clone());
+ match self.try_unit(&unit) {
+ Ok(unit) => {
+ for dep in &unit.info.requires_weak {
+ pending_units.push(dep.clone());
+ }
+ }
+ Err(err) => {
+ errors.push(err);
+ }
}
}
}
@@ -94,12 +107,34 @@ impl UnitStore {
loaded_units
}
+ pub fn try_unit(&self, unit: &UnitId) -> Result<&Unit, String> {
+ self.units
+ .get(unit)
+ .ok_or_else(|| format!("unit {} not found in store", unit.0))
+ }
+
+ // Keep the legacy infallible accessors for compatibility while scheduler/load paths
+ // use the fallible helpers to avoid panicking on missing units.
+ #[allow(dead_code)]
pub fn unit(&self, unit: &UnitId) -> &Unit {
- self.units.get(unit).unwrap()
+ self.try_unit(unit).unwrap_or_else(|err| {
+ eprintln!("init: {err}");
+ std::process::exit(1);
+ })
+ }
+
+ pub fn try_unit_mut(&mut self, unit: &UnitId) -> Result<&mut Unit, String> {
+ self.units
+ .get_mut(unit)
+ .ok_or_else(|| format!("unit {} not found in store", unit.0))
}
+ #[allow(dead_code)]
pub fn unit_mut(&mut self, unit: &UnitId) -> &mut Unit {
- self.units.get_mut(unit).unwrap()
+ self.try_unit_mut(unit).unwrap_or_else(|err| {
+ eprintln!("init: {err}");
+ std::process::exit(1);
+ })
}
}
@@ -180,7 +215,7 @@ impl Unit {
) -> io::Result<Self> {
let config = fs::read_to_string(config_path)?;
- let Some(ext) = config_path.extension().map(|ext| ext.to_str().unwrap()) else {
+ let Some(ext) = config_path.extension().and_then(|ext| ext.to_str()) else {
let script = Script::from_str(&config, errors)?;
return Ok(Unit {
id,
@@ -0,0 +1,633 @@
diff --git a/drivers/acpid/src/acpi.rs b/drivers/acpid/src/acpi.rs
index 94a1eb17e..3521bfc7b 100644
--- a/drivers/acpid/src/acpi.rs
+++ b/drivers/acpid/src/acpi.rs
@@ -136,9 +136,10 @@ impl Sdt {
let header = match plain::from_bytes::<SdtHeader>(&slice) {
Ok(header) => header,
Err(plain::Error::TooShort) => return Err(InvalidSdtError::InvalidSize),
- Err(plain::Error::BadAlignment) => panic!(
- "plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)]!"
- ),
+ Err(plain::Error::BadAlignment) => {
+ log::error!("acpid: plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)] - internal inconsistency");
+ return Err(InvalidSdtError::InvalidSize);
+ }
};
if header.length() != slice.len() {
diff --git a/drivers/acpid/src/main.rs b/drivers/acpid/src/main.rs
index 059254b3e..8f99f2ea9 100644
--- a/drivers/acpid/src/main.rs
+++ b/drivers/acpid/src/main.rs
@@ -28,9 +28,13 @@ fn daemon(daemon: daemon::Daemon) -> ! {
log::info!("acpid start");
- let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt")
- .expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`")
- .into();
+ let rxsdt_raw_data: Arc<[u8]> = match std::fs::read("/scheme/kernel.acpi/rxsdt") {
+ Ok(data) => data.into(),
+ Err(err) => {
+ log::error!("acpid: failed to read `/scheme/kernel.acpi/rxsdt`: {}", err);
+ std::process::exit(1);
+ }
+ };
if rxsdt_raw_data.is_empty() {
log::info!("System doesn't use ACPI");
@@ -38,7 +42,13 @@ fn daemon(daemon: daemon::Daemon) -> ! {
std::process::exit(0);
}
- let sdt = self::acpi::Sdt::new(rxsdt_raw_data).expect("acpid: failed to parse [RX]SDT");
+ let sdt = match self::acpi::Sdt::new(rxsdt_raw_data) {
+ Ok(sdt) => sdt,
+ Err(err) => {
+ log::error!("acpid: failed to parse [RX]SDT: {:?}", err);
+ std::process::exit(1);
+ }
+ };
let mut thirty_two_bit;
let mut sixty_four_bit;
@@ -64,7 +74,10 @@ fn daemon(daemon: daemon::Daemon) -> ! {
&mut sixty_four_bit as &mut dyn Iterator<Item = u64>
}
- _ => panic!("acpid: expected [RX]SDT from kernel to be either of those"),
+ _ => {
+ log::error!("acpid: expected [RX]SDT from kernel to be RSDT or XSDT");
+ std::process::exit(1);
+ }
};
let region_handlers: Vec<(RegionSpace, Box<dyn RegionHandler + 'static>)> = vec![
@@ -75,49 +88,84 @@ fn daemon(daemon: daemon::Daemon) -> ! {
// TODO: I/O permission bitmap?
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
- common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3");
+ if let Err(err) = common::acquire_port_io_rights() {
+ log::error!("acpid: failed to set I/O privilege level to Ring 3: {:?}", err);
+ std::process::exit(1);
+ }
- let shutdown_pipe = File::open("/scheme/kernel.acpi/kstop")
- .expect("acpid: failed to open `/scheme/kernel.acpi/kstop`");
+ let shutdown_pipe = match File::open("/scheme/kernel.acpi/kstop") {
+ Ok(f) => f,
+ Err(err) => {
+ log::error!("acpid: failed to open `/scheme/kernel.acpi/kstop`: {}", err);
+ std::process::exit(1);
+ }
+ };
- let mut event_queue = RawEventQueue::new().expect("acpid: failed to create event queue");
- let socket = Socket::nonblock().expect("acpid: failed to create disk scheme");
+ let mut event_queue = match RawEventQueue::new() {
+ Ok(q) => q,
+ Err(err) => {
+ log::error!("acpid: failed to create event queue: {:?}", err);
+ std::process::exit(1);
+ }
+ };
+ let socket = match Socket::nonblock() {
+ Ok(s) => s,
+ Err(err) => {
+ log::error!("acpid: failed to create scheme socket: {:?}", err);
+ std::process::exit(1);
+ }
+ };
let mut scheme = self::scheme::AcpiScheme::new(&acpi_context, &socket);
let mut handler = Blocking::new(&socket, 16);
- event_queue
+ if let Err(err) = event_queue
.subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ)
- .expect("acpid: failed to register shutdown pipe for event queue");
- event_queue
+ {
+ log::error!("acpid: failed to register shutdown pipe for event queue: {:?}", err);
+ std::process::exit(1);
+ }
+ if let Err(err) = event_queue
.subscribe(socket.inner().raw(), 1, EventFlags::READ)
- .expect("acpid: failed to register scheme socket for event queue");
+ {
+ log::error!("acpid: failed to register scheme socket for event queue: {:?}", err);
+ std::process::exit(1);
+ }
- register_sync_scheme(&socket, "acpi", &mut scheme)
- .expect("acpid: failed to register acpi scheme to namespace");
+ if let Err(err) = register_sync_scheme(&socket, "acpi", &mut scheme) {
+ log::error!("acpid: failed to register acpi scheme to namespace: {:?}", err);
+ std::process::exit(1);
+ }
daemon.ready();
- libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace");
+ if let Err(err) = libredox::call::setrens(0, 0) {
+ log::error!("acpid: failed to enter null namespace: {}", err);
+ std::process::exit(1);
+ }
let mut mounted = true;
while mounted {
- let Some(event) = event_queue
- .next()
- .transpose()
- .expect("acpid: failed to read event file")
- else {
- break;
+ let event = match event_queue.next().transpose() {
+ Ok(Some(ev)) => ev,
+ Ok(None) => break,
+ Err(err) => {
+ log::error!("acpid: failed to read event file: {:?}", err);
+ break;
+ }
};
if event.fd == socket.inner().raw() {
loop {
- match handler
- .process_requests_nonblocking(&mut scheme)
- .expect("acpid: failed to process requests")
- {
- ControlFlow::Continue(()) => {}
- ControlFlow::Break(()) => break,
+ match handler.process_requests_nonblocking(&mut scheme) {
+ Ok(flow) => match flow {
+ ControlFlow::Continue(()) => {}
+ ControlFlow::Break(()) => break,
+ },
+ Err(err) => {
+ log::error!("acpid: failed to process requests: {:?}", err);
+ break;
+ }
}
}
} else if event.fd == shutdown_pipe.as_raw_fd() as usize {
diff --git a/drivers/pcid/src/main.rs b/drivers/pcid/src/main.rs
index 61cd9a787..cad33114b 100644
--- a/drivers/pcid/src/main.rs
+++ b/drivers/pcid/src/main.rs
@@ -4,7 +4,7 @@
use std::collections::BTreeMap;
-use log::{debug, info, trace, warn};
+use log::{debug, error, info, trace, warn};
use pci_types::capability::PciCapability;
use pci_types::{
Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress,
@@ -259,17 +259,25 @@ fn daemon(daemon: daemon::Daemon) -> ! {
Ok(register_pci) => {
let access_id = scheme.access();
- let access_fd = socket
+ let access_fd = match socket
.create_this_scheme_fd(0, access_id, syscall::O_RDWR, 0)
- .expect("failed to issue this resource");
- let access_bytes = access_fd.to_ne_bytes();
- let _ = register_pci
- .call_wo(
+ {
+ Ok(fd) => Some(fd),
+ Err(err) => {
+ warn!("pcid: failed to issue acpi resource fd: {:?}", err);
+ None
+ }
+ };
+ if let Some(access_fd) = access_fd {
+ let access_bytes = access_fd.to_ne_bytes();
+ if let Err(err) = register_pci.call_wo(
&access_bytes,
syscall::CallFlags::WRITE | syscall::CallFlags::FD,
&[],
- )
- .expect("failed to send pci_fd to acpid");
+ ) {
+ warn!("pcid: failed to send pci_fd to acpid: {:?}", err);
+ }
+ }
}
Err(err) => {
if err.errno() == libredox::errno::ENODEV {
@@ -304,14 +312,17 @@ fn daemon(daemon: daemon::Daemon) -> ! {
}
debug!("Enumeration complete, now starting pci scheme");
- register_sync_scheme(&socket, "pci", &mut scheme)
- .expect("failed to register pci scheme to namespace");
+ if let Err(err) = register_sync_scheme(&socket, "pci", &mut scheme) {
+ error!("pcid: failed to register pci scheme to namespace: {:?}", err);
+ std::process::exit(1);
+ }
let _ = daemon.ready();
- handler
- .process_requests_blocking(scheme)
- .expect("pcid: failed to process requests");
+ handler.process_requests_blocking(scheme).unwrap_or_else(|err| {
+ error!("pcid: failed to process requests: {:?}", err);
+ std::process::exit(1);
+ });
}
fn scan_device(
diff --git a/init/src/main.rs b/init/src/main.rs
index 5682cf445..72c97f53c 100644
--- a/init/src/main.rs
+++ b/init/src/main.rs
@@ -166,19 +166,29 @@ fn main() {
}
};
for entry in entries {
+ let Some(file_name) = entry.file_name().and_then(|n| n.to_str()) else {
+ eprintln!("init: skipping entry with invalid filename: {}", entry.display());
+ continue;
+ };
scheduler.schedule_start_and_report_errors(
&mut unit_store,
- UnitId(entry.file_name().unwrap().to_str().unwrap().to_owned()),
+ UnitId(file_name.to_owned()),
);
}
};
scheduler.step(&mut unit_store, &mut init_config);
- libredox::call::setrens(0, 0).expect("init: failed to enter null namespace");
+ if let Err(err) = libredox::call::setrens(0, 0) {
+ eprintln!("init: failed to enter null namespace: {}", err);
+ return;
+ }
loop {
let mut status = 0;
- libredox::call::waitpid(0, &mut status, 0).unwrap();
+ match libredox::call::waitpid(0, &mut status, 0) {
+ Ok(()) => {}
+ Err(err) => eprintln!("init: waitpid error: {}", err),
+ }
}
}
diff --git a/init/src/scheduler.rs b/init/src/scheduler.rs
index d42a4e570..333e0e20e 100644
--- a/init/src/scheduler.rs
+++ b/init/src/scheduler.rs
@@ -1,7 +1,16 @@
use std::collections::VecDeque;
+use std::io::Read;
+use std::os::fd::AsRawFd;
+use std::os::unix::process::CommandExt;
+use std::process::Command;
+use std::time::Duration;
+use std::{env, io};
use crate::InitConfig;
-use crate::unit::{Unit, UnitId, UnitKind, UnitStore};
+use crate::service::ServiceType;
+use crate::unit::{RestartPolicy, UnitId, UnitKind, UnitStore};
+
+const MAX_DEPENDENCY_WAIT_RETRIES: u32 = 1000;
pub struct Scheduler {
pending: VecDeque<Job>,
@@ -10,10 +19,12 @@ pub struct Scheduler {
struct Job {
unit: UnitId,
kind: JobKind,
+ dep_retries: u32,
}
enum JobKind {
Start,
+ Restart { backoff: Duration },
}
impl Scheduler {
@@ -50,37 +61,97 @@ impl Scheduler {
self.pending.push_back(Job {
unit: unit_id,
kind: JobKind::Start,
+ dep_retries: 0,
});
}
}
pub fn step(&mut self, unit_store: &mut UnitStore, init_config: &mut InitConfig) {
'a: loop {
- let Some(job) = self.pending.pop_front() else {
+ let Some(mut job) = self.pending.pop_front() else {
return;
};
match job.kind {
JobKind::Start => {
- let unit = unit_store.unit_mut(&job.unit);
+ let unit = unit_store.unit(&job.unit);
+ let timeout_secs = unit.info.dependency_timeout_secs;
+ let mut deps_pending = false;
for dep in &unit.info.requires_weak {
for pending_job in &self.pending {
if &pending_job.unit == dep {
- self.pending.push_back(job);
- continue 'a;
+ deps_pending = true;
+ break;
}
}
+ if deps_pending {
+ break;
+ }
}
- run(unit, init_config);
+ if deps_pending {
+ if timeout_secs > 0 {
+ job.dep_retries += 1;
+ let max_retries = timeout_secs * 100; // ~10ms per retry
+ if job.dep_retries > max_retries as u32 {
+ eprintln!(
+ "init: {}: dependency timeout after {}s, failing",
+ job.unit.0, timeout_secs
+ );
+ continue;
+ }
+ } else if job.dep_retries >= MAX_DEPENDENCY_WAIT_RETRIES {
+ eprintln!(
+ "init: {}: dependency wait exceeded {} retries, failing",
+ job.unit.0, MAX_DEPENDENCY_WAIT_RETRIES
+ );
+ continue;
+ }
+ job.dep_retries += 1;
+ self.pending.push_back(job);
+ continue 'a;
+ }
+
+ if let Err(restart) = run(unit_store, &job.unit, init_config) {
+ if let Some(backoff) = restart {
+ self.pending.push_back(Job {
+ unit: job.unit.clone(),
+ kind: JobKind::Restart { backoff },
+ dep_retries: 0,
+ });
+ }
+ }
+ }
+ JobKind::Restart { backoff } => {
+ std::thread::sleep(backoff);
+ let next_backoff = (backoff * 2).min(Duration::from_secs(60));
+ if let Err(restart) = run(unit_store, &job.unit, init_config) {
+ if let Some(_next) = restart {
+ self.pending.push_back(Job {
+ unit: job.unit,
+ kind: JobKind::Restart {
+ backoff: next_backoff,
+ },
+ dep_retries: 0,
+ });
+ }
+ }
}
}
}
}
}
-fn run(unit: &mut Unit, config: &mut InitConfig) {
+fn run(
+ unit_store: &UnitStore,
+ unit_id: &UnitId,
+ config: &mut InitConfig,
+) -> Result<(), Option<Duration>> {
+ let unit = unit_store.unit(unit_id);
+
+ let restart_policy = unit.info.restart;
+
match &unit.kind {
UnitKind::LegacyScript { script } => {
for cmd in script.clone() {
@@ -89,11 +160,12 @@ fn run(unit: &mut Unit, config: &mut InitConfig) {
}
cmd.run(config);
}
+ Ok(())
}
UnitKind::Service { service } => {
if config.skip_cmd.contains(&service.cmd) {
eprintln!("Skipping '{} {}'", service.cmd, service.args.join(" "));
- return;
+ return Ok(());
}
if config.log_debug {
eprintln!(
@@ -102,7 +174,44 @@ fn run(unit: &mut Unit, config: &mut InitConfig) {
service.cmd,
);
}
- service.spawn(&config.envs);
+
+ let mut command = Command::new(&service.cmd);
+ command.args(&service.args);
+ command.env_clear();
+ for env in &service.inherit_envs {
+ if let Some(value) = env::var_os(env) {
+ command.env(env, value);
+ }
+ }
+ command.envs(config.envs.iter().map(|(k, v)| (k.as_str(), v.as_os_str())));
+
+ let (read_pipe, write_pipe) = match io::pipe() {
+ Ok(p) => p,
+ Err(err) => {
+ eprintln!("init: pipe failed for {}: {}", service.cmd, err);
+ return Err(restart_signal(restart_policy));
+ }
+ };
+
+ let write_fd: std::os::fd::OwnedFd = write_pipe.into();
+ unsafe {
+ command.env("INIT_NOTIFY", format!("{}", write_fd.as_raw_fd()));
+ command.pre_exec(move || {
+ if unsafe { libc::fcntl(write_fd.as_raw_fd(), libc::F_SETFD, 0) } == -1 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(())
+ }
+ });
+ }
+
+ let status = service_spawn_status(read_pipe, command, &service.type_, &service.cmd);
+
+ match status {
+ SpawnStatus::Success => Ok(()),
+ SpawnStatus::Failed => Err(restart_signal(restart_policy)),
+ SpawnStatus::Async => Ok(()),
+ }
}
UnitKind::Target {} => {
if config.log_debug {
@@ -111,6 +220,113 @@ fn run(unit: &mut Unit, config: &mut InitConfig) {
unit.info.description.as_ref().unwrap_or(&unit.id.0),
);
}
+ Ok(())
+ }
+ }
+}
+
+enum SpawnStatus {
+ Success,
+ Failed,
+ Async,
+}
+
+fn restart_signal(policy: RestartPolicy) -> Option<Duration> {
+ match policy {
+ RestartPolicy::No => None,
+ RestartPolicy::OnFailure | RestartPolicy::Always => Some(Duration::from_secs(1)),
+ }
+}
+
+fn service_spawn_status(
+ mut read_pipe: impl Read + AsRawFd,
+ mut command: Command,
+ service_type: &ServiceType,
+ cmd: &str,
+) -> SpawnStatus {
+ let mut child = match command.spawn() {
+ Ok(child) => child,
+ Err(err) => {
+ eprintln!("init: failed to execute {}: {}", cmd, err);
+ return SpawnStatus::Failed;
+ }
+ };
+
+ match service_type {
+ ServiceType::Notify => match read_pipe.read_exact(&mut [0]) {
+ Ok(()) => SpawnStatus::Success,
+ Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
+ eprintln!("init: {cmd} exited without notifying readiness");
+ SpawnStatus::Failed
+ }
+ Err(err) => {
+ eprintln!("init: failed to wait for {cmd}: {err}");
+ SpawnStatus::Failed
+ }
+ },
+ ServiceType::Scheme(scheme) => {
+ let scheme = scheme.clone();
+ let mut new_fd = usize::MAX;
+ let res = loop {
+ match syscall::call_ro(
+ read_pipe.as_raw_fd() as usize,
+ unsafe { plain::as_mut_bytes(&mut new_fd) },
+ syscall::CallFlags::FD | syscall::CallFlags::FD_UPPER,
+ &[],
+ ) {
+ Err(syscall::Error {
+ errno: syscall::EINTR,
+ }) => continue,
+ Ok(0) => break SpawnStatus::Failed,
+ Ok(1) => break SpawnStatus::Success,
+ Ok(n) => {
+ eprintln!("init: incorrect amount of fds {n} returned from {cmd}");
+ break SpawnStatus::Failed;
+ }
+ Err(err) => {
+ eprintln!("init: failed to wait for {cmd}: {err}");
+ break SpawnStatus::Failed;
+ }
+ }
+ };
+
+ if matches!(res, SpawnStatus::Success) {
+ match libredox::call::getns() {
+ Ok(current_namespace_fd) => {
+ if let Err(err) = libredox::call::register_scheme_to_ns(
+ current_namespace_fd,
+ &scheme,
+ new_fd,
+ ) {
+ eprintln!("init: scheme registration failed for {cmd}: {err}");
+ return SpawnStatus::Failed;
+ }
+ }
+ Err(err) => {
+ eprintln!("init: getns failed for {cmd}: {err}");
+ return SpawnStatus::Failed;
+ }
+ }
+ }
+ res
+ }
+ ServiceType::Oneshot => {
+ drop(read_pipe);
+ match child.wait() {
+ Ok(exit_status) => {
+ if !exit_status.success() {
+ eprintln!("init: {cmd} failed with {exit_status}");
+ SpawnStatus::Failed
+ } else {
+ SpawnStatus::Success
+ }
+ }
+ Err(err) => {
+ eprintln!("init: failed to wait for {cmd}: {err}");
+ SpawnStatus::Failed
+ }
+ }
}
+ ServiceType::OneshotAsync => SpawnStatus::Async,
}
}
diff --git a/init/src/unit.rs b/init/src/unit.rs
index 98053cb2d..414b92d17 100644
--- a/init/src/unit.rs
+++ b/init/src/unit.rs
@@ -125,6 +125,25 @@ pub struct UnitInfo {
pub condition_architecture: Option<Vec<String>>,
// FIXME replace this with hwd reading from the devicetree
pub condition_board: Option<Vec<String>>,
+ /// Restart policy for the service (only applies to Service units)
+ #[serde(default)]
+ pub restart: RestartPolicy,
+ /// Maximum time in seconds to wait for dependencies before failing (0 = no timeout)
+ #[serde(default)]
+ pub dependency_timeout_secs: u64,
+}
+
+/// Restart policy for managed services
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Default)]
+#[serde(rename_all = "kebab-case")]
+pub enum RestartPolicy {
+ /// Never restart the service (default)
+ #[default]
+ No,
+ /// Restart on failure (non-zero exit or crash)
+ OnFailure,
+ /// Always restart (on any exit)
+ Always,
}
fn true_bool() -> bool {
@@ -190,6 +209,8 @@ impl Unit {
requires_weak: script.1,
condition_architecture: None,
condition_board: None,
+ restart: RestartPolicy::No,
+ dependency_timeout_secs: 0,
},
kind: UnitKind::LegacyScript { script: script.0 },
});
@@ -0,0 +1,152 @@
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
index 47588e1..6578761 100644
--- a/src/scheme/proc.rs
+++ b/src/scheme/proc.rs
@@ -1,7 +1,7 @@
use crate::{
context::{
self,
- context::{HardBlockedReason, LockedFdTbl, SignalState},
+ context::{HardBlockedReason, LockedFdTbl, SchedPolicy, SignalState},
file::InternalFlags,
memory::{handle_notify_files, AddrSpace, AddrSpaceWrapper, Grant, PageSpan},
Context, ContextLock, Status,
@@ -105,6 +105,7 @@ enum ContextHandle {
// Attr handles, to set ens/euid/egid/pid.
Authority,
Attr,
+ Groups,
Status {
privileged: bool,
@@ -145,6 +146,7 @@ enum ContextHandle {
// directory.
OpenViaDup,
SchedAffinity,
+ SchedPolicy,
MmapMinAddr(Arc<AddrSpaceWrapper>),
}
@@ -249,6 +251,9 @@ impl ProcScheme {
false,
),
"sched-affinity" => (ContextHandle::SchedAffinity, true),
+ // TODO: Switch this kernel-local proc handle over to a stable upstream
+ // redox_syscall ProcCall::SetSchedPolicy opcode once that lands.
+ "sched-policy" => (ContextHandle::SchedPolicy, false),
"status" => (ContextHandle::Status { privileged: false }, false),
_ if path.starts_with("auth-") => {
let nonprefix = &path["auth-".len()..];
@@ -261,6 +266,7 @@ impl ProcScheme {
let handle = match actual_name {
"attrs" => ContextHandle::Attr,
"status" => ContextHandle::Status { privileged: true },
+ "groups" => ContextHandle::Groups,
_ => return Err(Error::new(ENOENT)),
};
@@ -306,6 +312,11 @@ impl ProcScheme {
let id = NonZeroUsize::new(NEXT_ID.fetch_add(1, Ordering::Relaxed))
.ok_or(Error::new(EMFILE))?;
let context = context::spawn(true, Some(id), ret, token)?;
+ {
+ let parent_groups =
+ context::current().read(token.token()).groups.clone();
+ context.write(token.token()).groups = parent_groups;
+ }
HANDLES.write(token.token()).insert(
id.get(),
Handle {
@@ -1165,6 +1176,20 @@ impl ContextHandle {
Ok(size_of_val(&mask))
}
+ Self::SchedPolicy => {
+ if buf.len() != 2 {
+ return Err(Error::new(EINVAL));
+ }
+
+ let [policy, rt_priority] = unsafe { buf.read_exact::<[u8; 2]>()? };
+ let sched_policy = SchedPolicy::try_from_raw(policy).ok_or(Error::new(EINVAL))?;
+
+ context
+ .write(token.token())
+ .set_sched_policy(sched_policy, rt_priority);
+
+ Ok(2)
+ }
ContextHandle::Status { privileged } => {
let mut args = buf.usizes();
@@ -1268,9 +1293,42 @@ impl ContextHandle {
guard.pid = info.pid as usize;
guard.euid = info.euid;
guard.egid = info.egid;
- guard.prio = (info.prio as usize).min(39);
+ guard.set_sched_other_prio(info.prio as usize);
Ok(size_of::<ProcSchemeAttrs>())
}
+ Self::Groups => {
+ const NGROUPS_MAX: usize = 65536;
+ if buf.len() % size_of::<u32>() != 0 {
+ return Err(Error::new(EINVAL));
+ }
+ let count = buf.len() / size_of::<u32>();
+ if count > NGROUPS_MAX {
+ return Err(Error::new(EINVAL));
+ }
+ let mut groups = Vec::with_capacity(count);
+ for chunk in buf.in_exact_chunks(size_of::<u32>()).take(count) {
+ groups.push(chunk.read_u32()?);
+ }
+ let proc_id = {
+ let guard = context.read(token.token());
+ guard.owner_proc_id
+ };
+ {
+ let mut guard = context.write(token.token());
+ guard.groups = groups.clone();
+ }
+ if let Some(pid) = proc_id {
+ let mut contexts = context::contexts(token.downgrade());
+ let (contexts, mut t) = contexts.token_split();
+ for context_ref in contexts.iter() {
+ let mut ctx = context_ref.write(t.token());
+ if ctx.owner_proc_id == Some(pid) {
+ ctx.groups = groups.clone();
+ }
+ }
+ }
+ Ok(count * size_of::<u32>())
+ }
ContextHandle::OpenViaDup => {
let mut args = buf.usizes();
@@ -1427,6 +1485,11 @@ impl ContextHandle {
buf.copy_exactly(crate::cpu_set::mask_as_bytes(&mask))?;
Ok(size_of_val(&mask))
+ }
+ ContextHandle::SchedPolicy => {
+ let context = context.read(token.token());
+ let data = [context.sched_policy as u8, context.sched_rt_priority];
+ buf.copy_common_bytes_from_slice(&data)
} // TODO: Replace write() with SYS_SENDFD?
ContextHandle::Status { .. } => {
let status = {
@@ -1475,6 +1538,15 @@ impl ContextHandle {
debug_name,
})
}
+ Self::Groups => {
+ let c = &context.read(token.token());
+ let max = buf.len() / size_of::<u32>();
+ let count = c.groups.len().min(max);
+ for (chunk, gid) in buf.in_exact_chunks(size_of::<u32>()).zip(&c.groups).take(count) {
+ chunk.copy_from_slice(&gid.to_ne_bytes())?;
+ }
+ Ok(count * size_of::<u32>())
+ }
ContextHandle::Sighandler => {
let data = match context.read(token.token()).sig {
Some(ref sig) => SetSighandlerData {
@@ -0,0 +1,63 @@
diff --git a/src/header/signal/mod.rs b/src/header/signal/mod.rs
index f049573..f3d665c 100644
--- a/src/header/signal/mod.rs
+++ b/src/header/signal/mod.rs
@@ -2,7 +2,10 @@
//!
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/signal.h.html>.
-use core::{mem, ptr};
+use core::{
+ mem, ptr,
+ sync::atomic::Ordering,
+};
use cbitset::BitSet;
@@ -32,6 +35,9 @@ pub mod sys;
#[path = "redox.rs"]
pub mod sys;
+mod signalfd;
+pub use self::signalfd::*;
+
type SigSet = BitSet<[u64; 1]>;
pub(crate) const SIG_DFL: usize = 0;
@@ -154,10 +160,15 @@ pub extern "C" fn killpg(pgrp: pid_t, sig: c_int) -> c_int {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_kill.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_kill(thread: pthread_t, sig: c_int) -> c_int {
- let os_tid = {
- let pthread = unsafe { &*(thread as *const crate::pthread::Pthread) };
- unsafe { pthread.os_tid.get().read() }
- };
+ let pthread = unsafe { &*(thread as *const crate::pthread::Pthread) };
+ let os_tid = unsafe { pthread.os_tid.get().read() };
+ let flags = crate::pthread::PthreadFlags::from_bits_retain(
+ pthread.flags.load(Ordering::Acquire),
+ );
+ if flags.contains(crate::pthread::PthreadFlags::FINISHED) {
+ return errno::ESRCH;
+ }
+
crate::header::pthread::e(unsafe { Sys::rlct_kill(os_tid, sig as usize) })
}
@@ -168,12 +179,10 @@ pub unsafe extern "C" fn pthread_sigmask(
set: *const sigset_t,
oldset: *mut sigset_t,
) -> c_int {
- // On Linux and Redox, pthread_sigmask and sigprocmask are equivalent
- if unsafe { sigprocmask(how, set, oldset) } == 0 {
- 0
- } else {
- //TODO: Fix race
- platform::ERRNO.get()
+ let filtered_set = unsafe { set.as_ref().map(|&block| block & !RLCT_SIGNAL_MASK) };
+ match unsafe { Sys::sigprocmask(how, filtered_set.as_ref(), oldset.as_mut()) } {
+ Ok(()) => 0,
+ Err(errno) => errno.0,
}
}
@@ -0,0 +1,87 @@
Fix ENOTRECOVERABLE returned for non-robust mutexes and register main
thread in OS_TID_TO_PTHREAD.
The robust mutex liveness check (mutex_owner_id_is_live) was returning
ENOTRECOVERABLE for non-robust mutexes when the owner appeared dead.
Per POSIX, the behaviour of a non-robust mutex whose owner has died is
undefined; returning an error crashes every Rust std::sync::Mutex user.
For lock_inner, fall through to spin/futex-wait instead. For try_lock,
return EBUSY instead.
Additionally, pthread::init() never registered the main thread in
OS_TID_TO_PTHREAD, so any mutex owned by the main thread would always
appear to have a dead owner, making the liveness check unreliable.
diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs
index 8243a48..c455a67 100644
--- a/src/pthread/mod.rs
+++ b/src/pthread/mod.rs
@@ -43,9 +43,13 @@ pub unsafe fn init() {
thread.stack_size = STACK_SIZE;
}
- unsafe { Tcb::current() }
- .expect_notls("no TCB present for main thread")
- .pthread = thread;
+ let tcb = unsafe { Tcb::current() }
+ .expect_notls("no TCB present for main thread");
+ tcb.pthread = thread;
+
+ OS_TID_TO_PTHREAD
+ .lock()
+ .insert(Sys::current_os_tid(), ForceSendSync(tcb as *const Tcb as *mut Tcb));
}
//static NEXT_INDEX: AtomicU32 = AtomicU32::new(FIRST_THREAD_IDX + 1);
diff --git a/src/sync/pthread_mutex.rs b/src/sync/pthread_mutex.rs
index af0c429..1b2b3ca 100644
--- a/src/sync/pthread_mutex.rs
+++ b/src/sync/pthread_mutex.rs
@@ -136,11 +136,7 @@ impl RlctMutex {
Err(thread) => {
let owner = thread & INDEX_MASK;
- if !crate::pthread::mutex_owner_id_is_live(owner) {
- if !self.robust {
- return Err(Errno(ENOTRECOVERABLE));
- }
-
+ if !crate::pthread::mutex_owner_id_is_live(owner) && self.robust {
let new_value = (thread & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread;
match self.inner.compare_exchange(
thread,
@@ -152,6 +155,11 @@ impl RlctMutex {
Ok(_) => return self.finish_lock_acquire(true),
Err(_) => continue,
}
+ } else if !crate::pthread::mutex_owner_id_is_live(owner) {
+ // Non-robust mutex with apparently-dead owner: per POSIX the
+ // behaviour is undefined. We conservatively keep spinning /
+ // futex-waiting rather than returning ENOTRECOVERABLE, which
+ // would crash any Rust std::sync::Mutex user.
}
if spins_left > 0 {
@@ -241,9 +250,6 @@ impl RlctMutex {
if current & FUTEX_OWNER_DIED != 0 || (owner != 0 && !crate::pthread::mutex_owner_id_is_live(owner)) {
- if !self.robust {
- return Err(Errno(ENOTRECOVERABLE));
- }
-
+ if self.robust {
let new_value = (current & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread;
match self.inner.compare_exchange(
current,
@@ -257,6 +269,11 @@ impl RlctMutex {
Ok(_) => return self.finish_lock_acquire(true),
Err(_) => continue,
}
+ } else {
+ // Non-robust mutex: owner appears dead but POSIX behaviour is
+ // undefined; report busy rather than ENOTRECOVERABLE.
+ return Err(Errno(EBUSY));
+ }
}
return Err(Errno(EBUSY));
@@ -0,0 +1,380 @@
diff --git a/src/sync/pthread_mutex.rs b/src/sync/pthread_mutex.rs
index 29bad63..af0c429 100644
--- a/src/sync/pthread_mutex.rs
+++ b/src/sync/pthread_mutex.rs
@@ -1,3 +1,4 @@
+use alloc::boxed::Box;
use core::{
cell::Cell,
sync::atomic::{AtomicU32 as AtomicUint, Ordering},
@@ -6,10 +7,9 @@ use core::{
use crate::{
error::Errno,
header::{bits_timespec::timespec, errno::*, pthread::*},
+ platform::{Pal, Sys, types::c_int},
};
-use crate::platform::{Pal, Sys, types::c_int};
-
use super::FutexWaitResult;
pub struct RlctMutex {
@@ -21,15 +21,22 @@ pub struct RlctMutex {
robust: bool,
}
+pub struct RobustMutexNode {
+ pub next: *mut RobustMutexNode,
+ pub prev: *mut RobustMutexNode,
+ pub mutex: *const RlctMutex,
+}
+
const STATE_UNLOCKED: u32 = 0;
const WAITING_BIT: u32 = 1 << 31;
-const INDEX_MASK: u32 = !WAITING_BIT;
+const FUTEX_OWNER_DIED: u32 = 1 << 30;
+const INDEX_MASK: u32 = !(WAITING_BIT | FUTEX_OWNER_DIED);
// TODO: Lower limit is probably better.
const RECURSIVE_COUNT_MAX_INCLUSIVE: u32 = u32::MAX;
// TODO: How many spins should we do before it becomes more time-economical to enter kernel mode
// via futexes?
-const SPIN_COUNT: usize = 0;
+const SPIN_COUNT: usize = 100;
impl RlctMutex {
pub(crate) fn new(attr: &RlctMutexAttr) -> Result<Self, Errno> {
@@ -69,13 +76,25 @@ impl RlctMutex {
Ok(0)
}
pub fn make_consistent(&self) -> Result<(), Errno> {
- todo_skip!(0, "pthread robust mutexes: not implemented");
- Ok(())
+ debug_assert!(self.robust, "make_consistent called on non-robust mutex");
+
+ if !self.robust {
+ return Err(Errno(EINVAL));
+ }
+
+ let current = self.inner.load(Ordering::Relaxed);
+ let owner = current & INDEX_MASK;
+
+ if owner == os_tid_invalid_after_fork() && current & FUTEX_OWNER_DIED != 0 {
+ self.inner.store(0, Ordering::Release);
+ Ok(())
+ } else {
+ Err(Errno(EINVAL))
+ }
}
fn lock_inner(&self, deadline: Option<&timespec>) -> Result<(), Errno> {
let this_thread = os_tid_invalid_after_fork();
-
- //let mut spins_left = SPIN_COUNT;
+ let mut spins_left = SPIN_COUNT;
loop {
let result = self.inner.compare_exchange_weak(
@@ -86,45 +105,59 @@ impl RlctMutex {
);
match result {
- // CAS succeeded
- Ok(_) => {
- if self.ty == Ty::Recursive {
- self.increment_recursive_count()?;
- }
- return Ok(());
- }
- // CAS failed, but the mutex was recursive and we already own the lock.
+ Ok(_) => return self.finish_lock_acquire(false),
Err(thread) if thread & INDEX_MASK == this_thread && self.ty == Ty::Recursive => {
self.increment_recursive_count()?;
return Ok(());
}
- // CAS failed, but the mutex was error-checking and we already own the lock.
Err(thread) if thread & INDEX_MASK == this_thread && self.ty == Ty::Errck => {
- return Err(Errno(EAGAIN));
+ return Err(Errno(EDEADLK));
}
- // CAS spuriously failed, simply retry the CAS. TODO: Use core::hint::spin_loop()?
- Err(thread) if thread & INDEX_MASK == 0 => {
- continue;
+ Err(thread) if thread & FUTEX_OWNER_DIED != 0 && thread & INDEX_MASK == 0 => {
+ return Err(Errno(ENOTRECOVERABLE));
}
- // CAS failed because some other thread owned the lock. We must now wait.
+ Err(thread) if thread & FUTEX_OWNER_DIED != 0 => {
+ if !self.robust {
+ return Err(Errno(ENOTRECOVERABLE));
+ }
+
+ let new_value = (thread & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread;
+ match self.inner.compare_exchange(
+ thread,
+ new_value,
+ Ordering::Acquire,
+ Ordering::Relaxed,
+ ) {
+ Ok(_) => return self.finish_lock_acquire(true),
+ Err(_) => continue,
+ }
+ }
+ Err(thread) if thread & INDEX_MASK == 0 => continue,
Err(thread) => {
- /*if spins_left > 0 {
- // TODO: Faster to spin trying to load the flag, compared to CAS?
+ let owner = thread & INDEX_MASK;
+
+ if !crate::pthread::mutex_owner_id_is_live(owner) {
+ if !self.robust {
+ return Err(Errno(ENOTRECOVERABLE));
+ }
+
+ let new_value = (thread & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread;
+ match self.inner.compare_exchange(
+ thread,
+ new_value,
+ Ordering::Acquire,
+ Ordering::Relaxed,
+ ) {
+ Ok(_) => return self.finish_lock_acquire(true),
+ Err(_) => continue,
+ }
+ }
+
+ if spins_left > 0 {
spins_left -= 1;
core::hint::spin_loop();
continue;
}
-
- spins_left = SPIN_COUNT;
-
- let inner = self.inner.fetch_or(WAITING_BIT, Ordering::Relaxed);
-
- if inner == STATE_UNLOCKED {
- continue;
- }*/
-
- // If the mutex is not robust, simply futex_wait until unblocked.
- //crate::sync::futex_wait(&self.inner, inner | WAITING_BIT, None);
if crate::sync::futex_wait(&self.inner, thread, deadline)
== FutexWaitResult::TimedOut
{
@@ -140,6 +173,20 @@ impl RlctMutex {
pub fn lock_with_timeout(&self, deadline: &timespec) -> Result<(), Errno> {
self.lock_inner(Some(deadline))
}
+ fn finish_lock_acquire(&self, owner_dead: bool) -> Result<(), Errno> {
+ if self.ty == Ty::Recursive {
+ self.increment_recursive_count()?;
+ }
+ if self.robust {
+ add_to_robust_list(self);
+ }
+
+ if owner_dead {
+ Err(Errno(EOWNERDEAD))
+ } else {
+ Ok(())
+ }
+ }
fn increment_recursive_count(&self) -> Result<(), Errno> {
// We don't have to worry about asynchronous signals here, since pthread_mutex_trylock
// is not async-signal-safe.
@@ -161,41 +208,65 @@ impl RlctMutex {
pub fn try_lock(&self) -> Result<(), Errno> {
let this_thread = os_tid_invalid_after_fork();
- // TODO: If recursive, omitting CAS may be faster if it is already owned by this thread.
- let result = self.inner.compare_exchange(
- STATE_UNLOCKED,
- this_thread,
- Ordering::Acquire,
- Ordering::Relaxed,
- );
+ loop {
+ let current = self.inner.load(Ordering::Relaxed);
+
+ if current == STATE_UNLOCKED {
+ match self.inner.compare_exchange(
+ STATE_UNLOCKED,
+ this_thread,
+ Ordering::Acquire,
+ Ordering::Relaxed,
+ ) {
+ Ok(_) => return self.finish_lock_acquire(false),
+ Err(_) => continue,
+ }
+ }
- if self.ty == Ty::Recursive {
- match result {
- Err(index) if index & INDEX_MASK != this_thread => return Err(Errno(EBUSY)),
- _ => (),
+ let owner = current & INDEX_MASK;
+
+ if owner == this_thread && self.ty == Ty::Recursive {
+ self.increment_recursive_count()?;
+ return Ok(());
}
- self.increment_recursive_count()?;
+ if owner == this_thread && self.ty == Ty::Errck {
+ return Err(Errno(EDEADLK));
+ }
- return Ok(());
- }
+ if current & FUTEX_OWNER_DIED != 0 && owner == 0 {
+ return Err(Errno(ENOTRECOVERABLE));
+ }
- match result {
- Ok(_) => Ok(()),
- Err(index) if index & INDEX_MASK == this_thread && self.ty == Ty::Errck => {
- Err(Errno(EDEADLK))
+ if current & FUTEX_OWNER_DIED != 0 || (owner != 0 && !crate::pthread::mutex_owner_id_is_live(owner)) {
+ if !self.robust {
+ return Err(Errno(ENOTRECOVERABLE));
+ }
+
+ let new_value = (current & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread;
+ match self.inner.compare_exchange(
+ current,
+ new_value,
+ Ordering::Acquire,
+ Ordering::Relaxed,
+ ) {
+ Ok(_) => return self.finish_lock_acquire(true),
+ Err(_) => continue,
+ }
}
- Err(_) => Err(Errno(EBUSY)),
+
+ return Err(Errno(EBUSY));
}
}
// Safe because we are not protecting any data.
pub fn unlock(&self) -> Result<(), Errno> {
+ let current = self.inner.load(Ordering::Relaxed);
+
if self.robust || matches!(self.ty, Ty::Recursive | Ty::Errck) {
- if self.inner.load(Ordering::Relaxed) & INDEX_MASK != os_tid_invalid_after_fork() {
+ if current & INDEX_MASK != os_tid_invalid_after_fork() {
return Err(Errno(EPERM));
}
- // TODO: Is this fence correct?
core::sync::atomic::fence(Ordering::Acquire);
}
@@ -208,18 +279,47 @@ impl RlctMutex {
}
}
- self.inner.store(STATE_UNLOCKED, Ordering::Release);
- crate::sync::futex_wake(&self.inner, i32::MAX);
- /*let was_waiting = self.inner.swap(STATE_UNLOCKED, Ordering::Release) & WAITING_BIT != 0;
+ if self.robust {
+ remove_from_robust_list(self);
+ }
- if was_waiting {
- let _ = crate::sync::futex_wake(&self.inner, 1);
- }*/
+ let new_state = if self.robust && current & FUTEX_OWNER_DIED != 0 {
+ FUTEX_OWNER_DIED
+ } else {
+ STATE_UNLOCKED
+ };
+
+ self.inner.store(new_state, Ordering::Release);
+ crate::sync::futex_wake(&self.inner, i32::MAX);
Ok(())
}
}
+pub(crate) unsafe fn mark_robust_mutexes_dead(thread: &crate::pthread::Pthread) {
+ let head = thread.robust_list_head.get();
+ let this_thread = os_tid_invalid_after_fork();
+ let mut node = unsafe { *head };
+
+ unsafe { *head = core::ptr::null_mut() };
+
+ while !node.is_null() {
+ let next = unsafe { (*node).next };
+ let mutex = unsafe { &*(*node).mutex };
+ let current = mutex.inner.load(Ordering::Relaxed);
+
+ if current & INDEX_MASK == this_thread {
+ mutex
+ .inner
+ .store((current & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread, Ordering::Release);
+ crate::sync::futex_wake(&mutex.inner, i32::MAX);
+ }
+
+ unsafe { drop(Box::from_raw(node)) };
+ node = next;
+ }
+}
+
#[repr(u8)]
#[derive(PartialEq)]
enum Ty {
@@ -237,6 +337,54 @@ enum Ty {
#[thread_local]
static CACHED_OS_TID_INVALID_AFTER_FORK: Cell<u32> = Cell::new(0);
+fn add_to_robust_list(mutex: &RlctMutex) {
+ let thread = crate::pthread::current_thread().expect("current thread not present");
+ let node_ptr = Box::into_raw(Box::new(RobustMutexNode {
+ next: core::ptr::null_mut(),
+ prev: core::ptr::null_mut(),
+ mutex: core::ptr::from_ref(mutex),
+ }));
+
+ unsafe {
+ let head = thread.robust_list_head.get();
+ if !(*head).is_null() {
+ (**head).prev = node_ptr;
+ }
+ (*node_ptr).next = *head;
+ *head = node_ptr;
+ }
+}
+
+fn remove_from_robust_list(mutex: &RlctMutex) {
+ let thread = match crate::pthread::current_thread() {
+ Some(thread) => thread,
+ None => return,
+ };
+
+ unsafe {
+ let mut node = *thread.robust_list_head.get();
+
+ while !node.is_null() {
+ if core::ptr::eq((*node).mutex, core::ptr::from_ref(mutex)) {
+ if !(*node).prev.is_null() {
+ (*(*node).prev).next = (*node).next;
+ } else {
+ *thread.robust_list_head.get() = (*node).next;
+ }
+
+ if !(*node).next.is_null() {
+ (*(*node).next).prev = (*node).prev;
+ }
+
+ drop(Box::from_raw(node));
+ return;
+ }
+
+ node = (*node).next;
+ }
+ }
+}
+
// Assumes TIDs are unique between processes, which I only know is true for Redox.
fn os_tid_invalid_after_fork() -> u32 {
// TODO: Coordinate better if using shared == PTHREAD_PROCESS_SHARED, with up to 2^32 separate
@@ -0,0 +1,130 @@
diff --git a/src/header/sched/mod.rs b/src/header/sched/mod.rs
index bcdd346..6066550 100644
--- a/src/header/sched/mod.rs
+++ b/src/header/sched/mod.rs
@@ -27,43 +27,110 @@ pub const SCHED_RR: c_int = 1;
pub const SCHED_OTHER: c_int = 2;
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sched_get_priority_max.html>.
-// #[unsafe(no_mangle)]
+#[unsafe(no_mangle)]
pub extern "C" fn sched_get_priority_max(policy: c_int) -> c_int {
- todo!()
+ match policy {
+ SCHED_FIFO | SCHED_RR => 99,
+ SCHED_OTHER => 0,
+ _ => {
+ crate::platform::ERRNO.set(crate::header::errno::EINVAL);
+ -1
+ }
+ }
}
-/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sched_get_priority_max.html>.
-// #[unsafe(no_mangle)]
+/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sched_get_priority_min.html>.
+#[unsafe(no_mangle)]
pub extern "C" fn sched_get_priority_min(policy: c_int) -> c_int {
- todo!()
+ match policy {
+ SCHED_FIFO | SCHED_RR => 1,
+ SCHED_OTHER => 0,
+ _ => {
+ crate::platform::ERRNO.set(crate::header::errno::EINVAL);
+ -1
+ }
+ }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sched_getparam.html>.
-// #[unsafe(no_mangle)]
+#[unsafe(no_mangle)]
pub unsafe extern "C" fn sched_getparam(pid: pid_t, param: *mut sched_param) -> c_int {
- todo!()
+ if pid != 0 {
+ crate::platform::ERRNO.set(crate::header::errno::ESRCH);
+ return -1;
+ }
+ crate::platform::ERRNO.set(crate::header::errno::ENOSYS);
+ -1
+}
+
+/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sched_getscheduler.html>.
+#[unsafe(no_mangle)]
+pub extern "C" fn sched_getscheduler(pid: pid_t) -> c_int {
+ if pid != 0 {
+ crate::platform::ERRNO.set(crate::header::errno::ESRCH);
+ return -1;
+ }
+ crate::platform::ERRNO.set(crate::header::errno::ENOSYS);
+ -1
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sched_rr_get_interval.html>.
-// #[unsafe(no_mangle)]
-pub extern "C" fn sched_rr_get_interval(pid: pid_t, time: *const timespec) -> c_int {
- todo!()
+#[unsafe(no_mangle)]
+pub extern "C" fn sched_rr_get_interval(pid: pid_t, tp: *mut timespec) -> c_int {
+ if pid != 0 {
+ crate::platform::ERRNO.set(crate::header::errno::ESRCH);
+ return -1;
+ }
+ if tp.is_null() {
+ crate::platform::ERRNO.set(crate::header::errno::EINVAL);
+ return -1;
+ }
+ unsafe {
+ (*tp).tv_sec = 0;
+ (*tp).tv_nsec = 100_000_000; // 100ms default SCHED_RR quantum
+ }
+ 0
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sched_setparam.html>.
-// #[unsafe(no_mangle)]
-pub unsafe extern "C" fn sched_setparam(pid: pid_t, param: *const sched_param) -> c_int {
- todo!()
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn sched_setparam(pid: pid_t, _param: *const sched_param) -> c_int {
+ if pid != 0 {
+ crate::platform::ERRNO.set(crate::header::errno::ESRCH);
+ return -1;
+ }
+ crate::platform::ERRNO.set(crate::header::errno::ENOSYS);
+ -1
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sched_setscheduler.html>.
-// #[unsafe(no_mangle)]
+#[unsafe(no_mangle)]
pub extern "C" fn sched_setscheduler(
pid: pid_t,
policy: c_int,
param: *const sched_param,
) -> c_int {
- todo!()
+ if pid != 0 {
+ crate::platform::ERRNO.set(crate::header::errno::ESRCH);
+ return -1;
+ }
+ match policy {
+ SCHED_OTHER => {
+ if !param.is_null() && unsafe { (*param).sched_priority } != 0 {
+ crate::platform::ERRNO.set(crate::header::errno::EINVAL);
+ return -1;
+ }
+ SCHED_OTHER
+ }
+ SCHED_FIFO | SCHED_RR => {
+ crate::platform::ERRNO.set(crate::header::errno::ENOSYS);
+ -1
+ }
+ _ => {
+ crate::platform::ERRNO.set(crate::header::errno::EINVAL);
+ -1
+ }
+ }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sched_yield.html>.
@@ -0,0 +1,176 @@
diff --git a/src/context/context.rs b/src/context/context.rs
index c97c516..8a8b078 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -18,7 +18,8 @@ use crate::{
cpu_stats,
ipi::{ipi, IpiKind, IpiTarget},
memory::{
- allocate_p2frame, deallocate_p2frame, Enomem, Frame, RaiiFrame, RmmA, RmmArch, PAGE_SIZE,
+ allocate_p2frame, deallocate_p2frame, Enomem, Frame, PhysicalAddress, RaiiFrame, RmmA,
+ RmmArch, PAGE_SIZE,
},
percpu::PercpuBlock,
scheme::{CallerCtx, FileHandle, SchemeId},
@@ -62,6 +63,38 @@ impl Status {
}
}
+pub const SCHED_PRIORITY_LEVELS: usize = 40;
+pub const DEFAULT_SCHED_OTHER_PRIORITY: usize = 20;
+pub const DEFAULT_SCHED_RR_QUANTUM: u128 = 100_000_000;
+
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum SchedPolicy {
+ Fifo = 0,
+ RoundRobin = 1,
+ Other = 2,
+}
+
+impl SchedPolicy {
+ pub fn try_from_raw(raw: u8) -> Option<Self> {
+ match raw {
+ 0 => Some(Self::Fifo),
+ 1 => Some(Self::RoundRobin),
+ 2 => Some(Self::Other),
+ _ => None,
+ }
+ }
+}
+
+pub fn rt_priority_to_kernel_prio(rt_priority: u8) -> usize {
+ (SCHED_PRIORITY_LEVELS - 1)
+ .saturating_sub((usize::from(rt_priority.min(99)) * (SCHED_PRIORITY_LEVELS - 1)) / 99)
+}
+
+fn clamp_sched_other_prio(prio: usize) -> usize {
+ prio.min(SCHED_PRIORITY_LEVELS - 1)
+}
+
#[derive(Clone, Debug)]
pub enum HardBlockedReason {
/// "SIGSTOP", only procmgr is allowed to switch contexts this state
@@ -140,6 +173,17 @@ pub struct Context {
pub fmap_ret: Option<Frame>,
/// Priority
pub prio: usize,
+ pub sched_policy: SchedPolicy,
+ pub sched_rt_priority: u8,
+ pub sched_rr_ticks_consumed: u32,
+ pub sched_static_prio: usize,
+ pub sched_rr_quantum: u128,
+ #[allow(dead_code)]
+ pub futex_pi_boost: bool,
+ #[allow(dead_code)]
+ pub futex_pi_original_prio: usize,
+ #[allow(dead_code)]
+ pub futex_pi_waiters: Vec<PhysicalAddress>,
// TODO: id can reappear after wraparound?
pub owner_proc_id: Option<NonZeroUsize>,
@@ -148,6 +192,8 @@ pub struct Context {
pub euid: u32,
pub egid: u32,
pub pid: usize,
+ /// Supplementary group IDs for access control decisions.
+ pub groups: Vec<u32>,
// See [`PreemptGuard`]
//
@@ -197,13 +243,22 @@ impl Context {
files: Arc::new(RwLock::new(FdTbl::new())),
userspace: false,
fmap_ret: None,
- prio: 20,
+ prio: DEFAULT_SCHED_OTHER_PRIORITY,
+ sched_policy: SchedPolicy::Other,
+ sched_rt_priority: 0,
+ sched_rr_ticks_consumed: 0,
+ sched_static_prio: DEFAULT_SCHED_OTHER_PRIORITY,
+ sched_rr_quantum: DEFAULT_SCHED_RR_QUANTUM,
+ futex_pi_boost: false,
+ futex_pi_original_prio: DEFAULT_SCHED_OTHER_PRIORITY,
+ futex_pi_waiters: Vec::new(),
being_sigkilled: false,
owner_proc_id,
euid: 0,
egid: 0,
pid: 0,
+ groups: Vec::new(),
#[cfg(feature = "syscall_debug")]
syscall_debug_info: crate::syscall::debug::SyscallDebugInfo::default(),
@@ -218,11 +273,47 @@ impl Context {
self.preempt_locks == 0
}
+ fn base_sched_prio(&self) -> usize {
+ match self.sched_policy {
+ SchedPolicy::Other => clamp_sched_other_prio(self.sched_static_prio),
+ SchedPolicy::Fifo | SchedPolicy::RoundRobin => {
+ rt_priority_to_kernel_prio(self.sched_rt_priority)
+ }
+ }
+ }
+
+ fn apply_sched_prio(&mut self) {
+ let base_prio = self.base_sched_prio();
+ if self.futex_pi_boost {
+ self.futex_pi_original_prio = base_prio;
+ self.prio = self.prio.min(base_prio);
+ } else {
+ self.futex_pi_original_prio = base_prio;
+ self.prio = base_prio;
+ }
+ }
+
+ pub fn set_sched_other_prio(&mut self, prio: usize) {
+ self.sched_static_prio = clamp_sched_other_prio(prio);
+ self.apply_sched_prio();
+ }
+
+ pub fn set_sched_policy(&mut self, sched_policy: SchedPolicy, rt_priority: u8) {
+ self.sched_policy = sched_policy;
+ self.sched_rt_priority = match sched_policy {
+ SchedPolicy::Other => 0,
+ SchedPolicy::Fifo | SchedPolicy::RoundRobin => rt_priority.min(99),
+ };
+ self.sched_rr_ticks_consumed = 0;
+ self.apply_sched_prio();
+ }
+
/// Block the context, and return true if it was runnable before being blocked
pub fn block(&mut self, reason: &'static str) -> bool {
if self.status.is_runnable() {
self.status = Status::Blocked;
self.status_reason = reason;
+ self.sched_rr_ticks_consumed = 0;
true
} else {
false
@@ -232,6 +323,7 @@ impl Context {
pub fn hard_block(&mut self, reason: HardBlockedReason) -> bool {
if self.status.is_runnable() {
self.status = Status::HardBlocked { reason };
+ self.sched_rr_ticks_consumed = 0;
true
} else {
@@ -261,6 +353,7 @@ impl Context {
if self.status.is_soft_blocked() {
self.status = Status::Runnable;
self.status_reason = "";
+ self.sched_rr_ticks_consumed = 0;
true
} else {
@@ -479,6 +572,7 @@ impl Context {
uid: self.euid,
gid: self.egid,
pid: self.pid,
+ groups: self.groups.clone(),
}
}
}
@@ -0,0 +1,150 @@
diff --git a/src/context/switch.rs b/src/context/switch.rs
index 86684c8..aeb29c9 100644
--- a/src/context/switch.rs
+++ b/src/context/switch.rs
@@ -5,7 +5,7 @@
use crate::{
context::{
self, arch, idle_contexts, idle_contexts_try, run_contexts, ArcContextLockWriteGuard,
- Context, ContextLock, WeakContextRef,
+ Context, ContextLock, SchedPolicy, WeakContextRef,
},
cpu_set::LogicalCpuId,
cpu_stats::{self, CpuState},
@@ -33,35 +33,17 @@ const SCHED_PRIO_TO_WEIGHT: [usize; 40] = [
70, 56, 45, 36, 29, 23, 18, 15,
];
-/// Determines if a given context is eligible to be scheduled on a given CPU (in
-/// principle, the current CPU).
-///
-/// # Safety
-/// This function is unsafe because it modifies the `context`'s state directly without synchronization.
-///
-/// # Parameters
-/// - `context`: The context (process/thread) to be checked.
-/// - `cpu_id`: The logical ID of the CPU on which the context is being scheduled.
-///
-/// # Returns
-/// - `UpdateResult::CanSwitch`: If the context can be switched to.
-/// - `UpdateResult::Skip`: If the context should be skipped (e.g., it's running on another CPU).
unsafe fn update_runnable(
context: &mut Context,
cpu_id: LogicalCpuId,
switch_time: u128,
) -> UpdateResult {
- // Ignore contexts that are already running.
if context.running {
return UpdateResult::Skip;
}
-
- // Ignore contexts assigned to other CPUs.
if !context.sched_affinity.contains(cpu_id) {
return UpdateResult::Skip;
}
-
- // If context is soft-blocked and has a wake-up time, check if it should wake up.
if context.status.is_soft_blocked()
&& let Some(wake) = context.wake
&& switch_time >= wake
@@ -69,8 +51,6 @@ unsafe fn update_runnable(
context.wake = None;
context.unblock_no_ipi();
}
-
- // If the context is runnable, indicate it can be switched to.
if context.status.is_runnable() {
UpdateResult::CanSwitch
} else {
@@ -95,7 +75,7 @@ pub fn tick(token: &mut CleanLockToken) {
let new_ticks = ticks_cell.get() + 1;
ticks_cell.set(new_ticks);
- // Trigger a context switch after every 3 ticks (approx. 6.75 ms).
+ // Trigger a context switch after every 3 ticks.
if new_ticks >= 3 {
switch(token);
crate::context::signal::signal_handler(token);
@@ -167,10 +147,7 @@ pub fn switch(token: &mut CleanLockToken) -> SwitchResult {
let mut prev_context_guard = unsafe { prev_context_lock.write_arc() };
if !prev_context_guard.is_preemptable() {
- // Unset global lock
arch::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
-
- // Pretend to have finished switching, so CPU is not idled
return SwitchResult::Switched;
}
@@ -377,6 +354,71 @@ fn select_next_context(
let total_contexts: usize = contexts_list.iter().map(|q| q.len()).sum();
let mut skipped_contexts = 0;
+ // PASS 0: SCHED_FIFO and SCHED_RR — scan for RT contexts to schedule.
+ // When a runnable RT context is found, it takes priority over all SCHED_OTHER.
+ for prio in 0..40 {
+ let rt_contexts = contexts_list
+ .get_mut(prio)
+ .expect("prio should be between [0, 39]");
+ let len = rt_contexts.len();
+ for _ in 0..len {
+ let (rt_ref, rt_lock) = match rt_contexts.pop_front() {
+ Some(lock) => match lock.upgrade() {
+ Some(l) => (lock, l),
+ None => {
+ skipped_contexts += 1;
+ continue;
+ }
+ },
+ None => break,
+ };
+ if Arc::ptr_eq(&rt_lock, &idle_context) {
+ rt_contexts.push_back(rt_ref);
+ continue;
+ }
+ // Current RT thread: if runnable with no higher-prio RT found yet,
+ // keep it running (no demotion to SCHED_OTHER)
+ if Arc::ptr_eq(&rt_lock, &prev_context_lock) {
+ let mut rt_guard = unsafe { rt_lock.write_arc() };
+ if rt_guard.status.is_runnable()
+ && (rt_guard.sched_policy == SchedPolicy::Fifo
+ || rt_guard.sched_policy == SchedPolicy::RoundRobin)
+ {
+ percpu.balance.set(balance);
+ percpu.last_queue.set(i);
+ return Ok(Some(rt_guard));
+ }
+ rt_contexts.push_back(rt_ref);
+ continue;
+ }
+ let mut rt_guard = unsafe { rt_lock.write_arc() };
+ if !rt_guard.status.is_runnable() || rt_guard.running
+ || !rt_guard.sched_affinity.contains(cpu_id)
+ {
+ rt_contexts.push_back(rt_ref);
+ continue;
+ }
+ if rt_guard.sched_policy == SchedPolicy::Fifo
+ || rt_guard.sched_policy == SchedPolicy::RoundRobin
+ {
+ percpu.balance.set(balance);
+ percpu.last_queue.set(i);
+ if !Arc::ptr_eq(&prev_context_lock, &idle_context) {
+ let prev_ctx = WeakContextRef(Arc::downgrade(&prev_context_lock));
+ if prev_context_guard.status.is_runnable() {
+ contexts_list[prev_context_guard.prio].push_back(prev_ctx);
+ } else {
+ idle_contexts(token.token()).push_back(prev_ctx);
+ }
+ }
+ return Ok(Some(rt_guard));
+ }
+ rt_contexts.push_back(rt_ref);
+ }
+ }
+
+ // PASS 1: SCHED_OTHER — existing DWRR deficit tracking
+
'priority: loop {
i = (i + 1) % 40;
total_iters += 1;
@@ -0,0 +1,20 @@
diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs
index d30272c..9da2b28 100644
--- a/src/scheme/mod.rs
+++ b/src/scheme/mod.rs
@@ -777,6 +777,7 @@ pub struct CallerCtx {
pub pid: usize,
pub uid: u32,
pub gid: u32,
+ pub groups: alloc::vec::Vec<u32>,
}
impl CallerCtx {
pub fn filter_uid_gid(self, euid: u32, egid: u32) -> Self {
@@ -785,6 +786,7 @@ impl CallerCtx {
pid: self.pid,
uid: euid,
gid: egid,
+ groups: self.groups,
}
} else {
self
@@ -0,0 +1,112 @@
diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs
index 022f873..ab96dea 100644
--- a/redox-rt/src/signal.rs
+++ b/redox-rt/src/signal.rs
@@ -1,4 +1,10 @@
-use core::{ffi::c_int, ptr::NonNull, sync::atomic::Ordering};
+use core::{
+ ffi::c_int,
+ hint::unreachable_unchecked,
+ panic::AssertUnwindSafe,
+ ptr::NonNull,
+ sync::atomic::Ordering,
+};
use syscall::{
CallFlags, EAGAIN, EINTR, EINVAL, ENOMEM, EPERM, Error, RawAction, Result, SenderInfo,
@@ -103,6 +109,47 @@ pub struct SiginfoAbi {
pub si_value: usize, // sigval
}
+fn invoke_signal_handler<F: FnOnce()>(f: AssertUnwindSafe<F>) -> bool {
+ fn do_call<F: FnOnce()>(data: *mut u8) {
+ let callback = unsafe { &mut *data.cast::<Option<AssertUnwindSafe<F>>>() };
+ if let Some(callback) = callback.take() {
+ callback.0();
+ }
+ }
+
+ fn do_catch<F: FnOnce()>(_data: *mut u8, _payload: *mut u8) {}
+
+ let mut callback = Some(f);
+ unsafe {
+ core::intrinsics::catch_unwind(
+ do_call::<F>,
+ (&mut callback as *mut Option<AssertUnwindSafe<F>>).cast(),
+ do_catch::<F>,
+ ) != 0
+ }
+}
+
+#[inline(always)]
+unsafe fn return_ignored_signal(
+ os: &RtTcb,
+ stack: &SigStack,
+ signals_were_disabled: bool,
+) {
+ unsafe {
+ (*os.arch.get()).last_sig_was_restart = true;
+ (*os.arch.get()).last_sigstack = NonNull::new(stack.link);
+ }
+
+ if !signals_were_disabled {
+ core::sync::atomic::compiler_fence(Ordering::Release);
+ let control_flags = &os.control.control_flags;
+ control_flags.store(
+ control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(),
+ Ordering::Relaxed,
+ );
+ }
+}
+
#[inline(always)]
unsafe fn inner(stack: &mut SigStack) {
let os = unsafe { &Tcb::current().unwrap().os_specific };
@@ -168,7 +215,10 @@ unsafe fn inner(stack: &mut SigStack) {
// and reaching this code. If so, we do already know whether the signal is IGNORED *now*,
// and so we should return early ideally without even temporarily touching the signal mask.
SigactionKind::Ignore => {
- panic!("ctl {:#x?} signal {}", os.control, stack.sig_num)
+ unsafe {
+ return_ignored_signal(os, stack, signals_were_disabled);
+ }
+ return;
}
// this case should be treated equally as the one above
//
@@ -183,7 +233,9 @@ unsafe fn inner(stack: &mut SigStack) {
CallFlags::empty(),
&[ProcCall::Exit as u64, u64::from(sig) << 8],
);
- panic!()
+ // SAFETY: ProcCall::Exit terminates the current process when it succeeds, so reaching
+ // this point would violate the proc manager exit contract.
+ unsafe { unreachable_unchecked() }
}
SigactionKind::Handled { handler } => handler,
};
@@ -224,15 +276,21 @@ unsafe fn inner(stack: &mut SigStack) {
si_uid: sender_uid as i32,
si_value: stack.sival,
};
- unsafe {
+ if invoke_signal_handler(AssertUnwindSafe(|| unsafe {
sigaction(
stack.sig_num as c_int,
core::ptr::addr_of!(info).cast(),
stack as *mut SigStack as *mut (),
)
- };
+ })) {
+ let _ = syscall::write(2, b"redox-rt: sa_siginfo handler panicked; continuing\n");
+ }
} else if let Some(handler) = unsafe { handler.handler } {
- handler(stack.sig_num as c_int);
+ if invoke_signal_handler(AssertUnwindSafe(|| {
+ handler(stack.sig_num as c_int);
+ })) {
+ let _ = syscall::write(2, b"redox-rt: sa_handler panicked; continuing\n");
+ }
}
// Disable signals while we modify the sigmask again
@@ -0,0 +1,101 @@
diff --git a/src/start.rs b/src/start.rs
--- a/src/start.rs
+++ b/src/start.rs
@@ -1,10 +1,7 @@
//! Startup code.
use alloc::{boxed::Box, vec::Vec};
-use core::{intrinsics, ptr};
-
-#[cfg(target_os = "redox")]
-use generic_rt::ExpectTlsFree;
+use core::{fmt::Write, intrinsics, panic::AssertUnwindSafe, ptr};
use crate::{
ALLOCATOR,
@@ -143,6 +141,29 @@ fn io_init() {
stdio::stderr = stdio::default_stderr().get();
}
}
+
+fn catch_unwind<F: FnOnce()>(f: AssertUnwindSafe<F>) -> Result<(), ()> {
+ fn do_call<F: FnOnce()>(data: *mut u8) {
+ let callback = unsafe { &mut *data.cast::<Option<AssertUnwindSafe<F>>>() };
+ if let Some(callback) = callback.take() {
+ callback.0();
+ }
+ }
+
+ fn do_catch<F: FnOnce()>(_data: *mut u8, _payload: *mut u8) {}
+
+ let mut callback = Some(f);
+ let panicked = unsafe {
+ intrinsics::catch_unwind(
+ do_call::<F>,
+ (&mut callback as *mut Option<AssertUnwindSafe<F>>).cast(),
+ do_catch::<F>,
+ ) != 0
+ };
+
+ if panicked { Err(()) } else { Ok(()) }
+}
+
#[cold]
fn abort_startup(args: core::fmt::Arguments<'_>) -> ! {
let mut w = platform::FileWriter::new(2);
@@ -164,14 +184,23 @@ pub unsafe extern "C" fn relibc_start_v1(
unsafe { relibc_verify_host() };
#[cfg(target_os = "redox")]
- let thr_fd = redox_rt::proc::FdGuard::new(
- unsafe {
- crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD)
- }
- .expect_notls("no thread fd present"),
- )
- .to_upper()
- .expect_notls("failed to move thread fd to upper table");
+ let thr_fd = {
+ let thr_fd = match unsafe {
+ crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD)
+ } {
+ Some(thr_fd) => thr_fd,
+ None => abort_startup(format_args!(
+ "relibc_start_v1: missing AT_REDOX_THR_FD auxv entry; no thread fd present\n"
+ )),
+ };
+
+ match redox_rt::proc::FdGuard::new(thr_fd).to_upper() {
+ Ok(thr_fd) => thr_fd,
+ Err(err) => abort_startup(format_args!(
+ "relibc_start_v1: failed to move thread fd to upper table: {err:?}\n"
+ )),
+ }
+ };
// Initialize TLS, if necessary
unsafe {
@@ -237,7 +266,10 @@ pub unsafe extern "C" fn relibc_start_v1(
let mut f = unsafe { &__preinit_array_start } as *const _;
#[allow(clippy::op_ref)]
while f < &raw const __preinit_array_end {
- (unsafe { *f })();
+ let func = unsafe { *f };
+ if catch_unwind(AssertUnwindSafe(|| unsafe { (*f)() })).is_err() {
+ log_initializer_panic(".preinit_array", func);
+ }
f = unsafe { f.offset(1) };
}
}
@@ -247,7 +279,10 @@ pub unsafe extern "C" fn relibc_start_v1(
let mut f = unsafe { &__init_array_start } as *const _;
#[allow(clippy::op_ref)]
while f < &raw const __init_array_end {
- (unsafe { *f })();
+ let func = unsafe { *f };
+ if catch_unwind(AssertUnwindSafe(|| unsafe { (*f)() })).is_err() {
+ log_initializer_panic(".init_array", func);
+ }
f = unsafe { f.offset(1) };
}
}