328 Commits

Author SHA1 Message Date
Red Bear OS 6afa6e5035 0.3.0: refresh Cargo.lock for +rb0.3.0 local forks 2026-07-06 20:41:33 +03:00
vasilito 3559b6b969 0.3.0: bump version suffix to +rb0.3.0 2026-07-06 19:47:22 +03:00
Red Bear OS d90f84883e fix: use local path deps for redox_syscall, redoxfs, libredox 2026-07-05 23:54:35 +03:00
Red Bear OS e604868baf version: use +rb0.2.5 build metadata instead of -rb0.2.5 pre-release
Semver pre-release suffix (-rb0.2.5) breaks Cargo's [patch.crates-io]
matching for transitive deps. Build metadata (+rb0.2.5) is semver-
compatible: ^0.9.0 matches 0.9.0+rb0.2.5, patch redirection works,
and the Red Bear suffix is still visible in the version string.
2026-07-05 09:16:12 +03:00
Red Bear OS 386b19566d fork: add Red Bear author attribution to Cargo.toml 2026-07-05 08:48:16 +03:00
vasilito 4591fbabcc fork: rebased onto upstream 0.2.42 with Red Bear additions
This rebases the local installer fork onto upstream 0.2.42
(commit ed6013c295) and reapplies
the documented Red Bear OS additions from the local state.

  * Cargo.toml: bumped version to 0.2.42-rb1 per the no-fake-version-
    label policy. Also bumped dep versions (libc 0.2.70 -> with
    optional, pkgar 0.2 -> 0.2.2, redox-pkg 0.3 -> 0.3.1, ring with
    optional, libredox with optional) so the build matches the local
    fork ecosystem.

  * src/installer.rs: integrate the collision detection Red Bear
    added in Phase J. The installer now aborts on init-service file
    collisions (e.g. /usr/lib/init.d/ vs /etc/init.d/) and prints
    a clear error pointing to the local docs.

  * src/lib.rs: declare the collision module and re-export the
    CollisionDetector.

  * src/config/package.rs: extend PackageConfig with PartialEq so
    the new package-groups feature (added in commit e45ce4d) can
    compare configs.

  * src/bin/installer.rs, src/bin/installer_tui.rs: expose the
    --strict-collision / REDBEAR_STRICT_COLLISION env var to
    optionally make non-critical file collisions fatal.

  * gui/: new redox_installer_gui binary — the TUI installer. This
    is the new binary added in Red Bear OS Phase 3 and lives in
    local/patches/installer/0001-redbear-os-additions.patch as a
    documented Red Bear addition.

The previous redox.patch in local/patches/installer/ is removed
and replaced with this regenerated 0001-redbear-os-additions.patch
that applies cleanly with --fuzz=0 to upstream 0.2.42.

Verified by local/scripts/verify-fork-versions.sh: the local
installer-0.2.42-rb1 branch source content matches upstream 0.2.42
plus this single documented patch.
2026-07-05 05:57:10 +03:00
Jeremy Soller ed6013c295 Merge branch 'bump-argon' into 'master'
Bump argon deps

See merge request redox-os/installer!76
2026-03-17 05:46:41 -06:00
Wildan M e79c1be43e Bump argon deps 2026-03-16 21:27:44 +07:00
Jeremy Soller b5b9bfd825 Merge branch 'bump-ver' into 'master'
Bump redox_syscall and version

See merge request redox-os/installer!75
2026-03-15 13:23:48 -06:00
Wildan M 8c2b0f9de7 Bump redox_syscall and version 2026-03-15 18:44:08 +07:00
Jeremy Soller 9800eac87c Merge branch 'misc_changes2' into 'master'
Make arg_parser non-optional

See merge request redox-os/installer!74
2026-03-11 14:42:10 -06:00
bjorn3 e61506c50f Make arg_parser non-optional
It is used by a Debug impl in the config code.
2026-03-11 21:01:48 +01:00
Jeremy Soller b29021c352 Merge branch 'misc_changes' into 'master'
Misc changes

See merge request redox-os/installer!73
2026-03-11 14:00:12 -06:00
bjorn3 474ff08431 Fix bootloader location 2026-03-11 20:53:46 +01:00
bjorn3 f691afabab Fix usage message 2026-03-11 20:31:03 +01:00
bjorn3 f74e3fad19 Make home directories 700 instead of 777 2026-03-11 20:12:40 +01:00
Jeremy Soller 3ef2cac56d Merge branch 'new-pkg' into 'master'
Update pkg to use new API

See merge request redox-os/installer!72
2026-03-08 13:25:42 -06:00
Wildan M aa9c978f90 Resolve ring dependency 2026-03-08 21:04:32 +07:00
Wildan M a6fd457652 Update pkg to use new API 2026-03-08 20:53:33 +07:00
Jeremy Soller 7806f87c56 Merge branch 'move_bootloader_to_user' into 'master'
Bootloader is now stored in /usr/lib/boot

See merge request redox-os/installer!71
2026-03-07 08:36:04 -07:00
bjorn3 70b8cb0e37 Bootloader is now stored in /usr/lib/boot 2026-03-07 16:30:35 +01:00
Jeremy Soller 397974cb68 Workaround for existing symlinks by overwriting them 2026-03-04 11:18:14 -07:00
Jeremy Soller 8765c51696 Log target of symlink 2026-03-04 10:53:22 -07:00
Jeremy Soller 2d3b2ed38a Improve some error reporting 2026-03-04 10:49:09 -07:00
Jeremy Soller 1840ceac85 Merge branch 'fix-redox-err' into 'master'
Fix redox compilation error

See merge request redox-os/installer!70
2026-02-14 12:31:56 -07:00
Wildan M 59d0872197 Fix redox compilation error 2026-02-15 01:47:13 +07:00
Jeremy Soller 7f918e544e Merge branch 'skel-copy' into 'master'
Copy /etc/skel to users directory

See merge request redox-os/installer!69
2026-02-14 06:41:32 -07:00
Wildan M 730eb9a606 Copy /etc/skel to users directory 2026-02-14 18:13:27 +07:00
Jeremy Soller a790f1c228 Merge branch 'local-err-help' into 'master'
Make missing file clear when locally installing

See merge request redox-os/installer!68
2026-02-10 05:59:32 -07:00
Wildan M b33f3c1a80 Make missing file clear when locally installing 2026-02-10 01:35:44 +07:00
Jeremy Soller b0f90da7b8 Merge branch 'cli-enh' into 'master'
Some improvement as a standalone CLI

See merge request redox-os/installer!67
2026-01-30 20:28:01 -07:00
Wildan M c4ed26e3d4 Don't confirm password if empty 2026-01-31 05:10:03 +07:00
Wildan M 753256cfaf Strip fallocate from CI test 2026-01-31 05:02:08 +07:00
Wildan M cfc7938ecc Shorten remote packages log 2026-01-31 04:53:30 +07:00
Wildan M 15de2b4272 Add help hint, remove repo_binary 2026-01-31 04:17:54 +07:00
Wildan M fed265252d Unify password prompt code 2026-01-31 04:17:11 +07:00
Wildan M d40619d66c Implement Display for Config 2026-01-31 04:15:10 +07:00
Jeremy Soller 64f46052db 0.2.41 - update dependencies 2026-01-22 10:39:26 -07:00
Jeremy Soller eff771e640 0.2.40: downgrade libredox to 0.1.11 for redox_syscall 0.6 compatibility 2026-01-02 20:00:13 -07:00
Jeremy Soller 397749f1f5 0.2.39: update redox_syscall and redoxfs 2026-01-02 19:42:55 -07:00
Jeremy Soller 753c8af0e5 Merge branch 'expose-fuse-opt' into 'master'
Make FUSE feature can be opted out

See merge request redox-os/installer!66
2026-01-01 08:15:36 -07:00
Wildan M 846e8446e0 Make FUSE feature can be opted out 2026-01-01 14:46:54 +07:00
Jeremy Soller 385696d84a Merge branch 'update-redoxfs' into 'master'
Bump redoxfs

See merge request redox-os/installer!64
2025-12-16 11:08:07 -07:00
Wildan M ca9748f1ba Bump redoxfs 2025-12-16 22:51:05 +07:00
Jeremy Soller 7e697cfb3a Merge branch 'bump-ver' into 'master'
Expose custom mount API and bump version

See merge request redox-os/installer!63
2025-12-15 15:54:52 -07:00
Wildan M 86d2af6ca0 Expose custom mount API and bump version 2025-12-16 05:27:09 +07:00
Jeremy Soller 8ba8d6e15b Merge branch 'no-mount' into 'master'
Add no_mount option and tidy up flags

See merge request redox-os/installer!62
2025-12-15 12:38:41 -07:00
Wildan M 3dba5827f2 Try fix CI 2025-12-16 01:55:54 +07:00
Wildan M 433aa99660 Add no_mount option and tidy up flags 2025-12-16 01:41:55 +07:00
Jeremy Soller 990d9d343e Merge branch 'bump-pkg' into 'master'
Update pkg version

See merge request redox-os/installer!61
2025-12-09 08:48:25 -07:00
Wildan M 8bc7c9d88d Update pkg version 2025-12-09 10:22:36 -05:00
Jeremy Soller 4fcd97e8da Merge branch 'split-cargo-features' into 'master'
Split installer code to cargo feature

See merge request redox-os/installer!60
2025-11-22 11:31:56 -07:00
Wildan M 7a85862733 Split installer code to cargo feature 2025-11-22 09:15:25 -08:00
Wildan M 7308cfe259 Move installer code 2025-11-22 09:15:24 -08:00
Jeremy Soller 58f161e019 Fix compilation on Redox 2025-11-20 08:58:51 -07:00
Jeremy Soller 693d9470f9 Merge branch 'always-local' into 'master'
Always Install binaries locally if cookbook set

See merge request redox-os/installer!59
2025-11-20 06:48:09 -07:00
Jeremy Soller 2a910e7058 Merge branch 'tidy-up' into 'master'
Remove list_packages

See merge request redox-os/installer!58
2025-11-20 06:46:28 -07:00
Wildan M 5fad110e5e Always Install binaries locally if cookbook set 2025-11-20 01:50:47 -08:00
Wildan M 09531dfdc8 Fix fmt 2025-11-20 01:24:41 -08:00
Wildan M e5233171ae Remove list_packages 2025-11-20 01:22:02 -08:00
Jeremy Soller 8281316190 Merge branch 'pkgar-local-path' into 'master'
Fix local package head install path

See merge request redox-os/installer!57
2025-11-12 06:58:47 -07:00
Wildan M 9594e87937 Fix local package head install path 2025-11-12 20:55:33 +07:00
Jeremy Soller bb9fa4ec7c Merge branch 'i586_target' into 'master'
Allow installing for i586-unknown-redox

See merge request redox-os/installer!56
2025-11-01 09:34:59 -06:00
bjorn3 f30179a889 Allow installing for i586-unknown-redox 2025-11-01 16:33:21 +01:00
Jeremy Soller 97dd77918e Merge branch 'update-pkg' into 'master'
Bump pkgar and rand

See merge request redox-os/installer!54
2025-10-01 13:31:25 -06:00
Wildan M 8e6a1c3aa4 Bump pkgar and rand 2025-10-01 21:41:02 +07:00
Jeremy Soller c35c9a88a9 Merge branch 'fix-deps' into 'master'
Fix local dependency install

See merge request redox-os/installer!53
2025-09-30 19:57:16 -06:00
Wildan M 43c1cd987f Fix local dependency install 2025-09-30 19:19:01 +07:00
Jeremy Soller 727c703bad Merge branch 'deterministic-source' into 'master'
Make install order predictable

See merge request redox-os/installer!52
2025-09-29 07:50:48 -06:00
Wildan M 0fa085c0f2 Make install order predictable 2025-09-29 20:29:43 +07:00
Jeremy Soller 69de3d62a1 Fix build on non-Redox 2025-09-26 15:52:31 -06:00
Jeremy Soller c540ed8f9d 0.2.37 - add support for fast install 2025-09-26 15:49:04 -06:00
Jeremy Soller 7023dc0eb4 0.2.36 2025-09-26 15:47:29 -06:00
Jeremy Soller 039ded92a4 Merge branch 'overridable-config' into 'master'
Allow overwriting package files

See merge request redox-os/installer!51
2025-09-26 14:25:40 -06:00
Wildan M e74c9279cf Apply postconfig configuration 2025-09-26 17:27:27 +07:00
Wildan M ee5a94dbe4 Tidy up file config init 2025-09-26 17:26:09 +07:00
Wildan Mubarok b425b12cf5 Allow overwriting package files 2025-09-26 08:32:28 +00:00
Jeremy Soller 432abd9249 0.2.35: relax serde requirement 2025-09-07 21:24:59 -06:00
Jeremy Soller 01a3adb662 Merge branch 'opt-pkg' into 'master'
Handle metapackages for local install

See merge request redox-os/installer!50
2025-07-27 10:31:27 -06:00
Wildan M 81e8bc09f8 Handle metapackages for local install 2025-07-27 22:49:37 +07:00
Jeremy Soller 5758ba854a Merge branch 'add-ci' into 'master'
Add CI Tests

See merge request redox-os/installer!49
2025-07-09 12:42:59 -06:00
Wildan Mubarok 64b047195d Add CI Tests 2025-07-09 12:42:59 -06:00
Jeremy Soller 2730f1a70c 0.2.34: update to redoxfs 0.7 2025-07-02 13:44:45 -06:00
Jeremy Soller d82dd8998d Merge branch 'clippy_lints' into 'master'
apply some simple clippy lints

See merge request redox-os/installer!48
2025-07-01 08:31:00 -06:00
auronandace 721d49adfb apply some simple clippy lints 2025-06-30 17:11:48 +01:00
Jeremy Soller a86aec193d Merge branch 'ignore-package' into 'master'
Add option to ignore packages

See merge request redox-os/installer!47
2025-06-27 07:09:14 -06:00
Wildan Mubarok 55a0bd1643 Add option to ignore packages 2025-06-27 08:25:59 +00:00
Jeremy Soller 2c3afb4956 0.2.33: fix compilation with new pkgar 2025-06-12 12:07:52 -06:00
Jeremy Soller 2c8c6bf30f update dependencies 2025-06-12 11:56:24 -06:00
Jeremy Soller 0db88e3cb4 Merge branch 'write_bootloader' into 'master'
Add flag to write bootloader to chosen location

See merge request redox-os/installer!46
2025-06-12 10:52:00 -06:00
bjorn3 7ce72b7299 Add flag to write bootloader to chosen location
The build system needs the bootloader separately for netboot support.
2025-06-01 20:53:01 +02:00
Jeremy Soller 9e888c06fa 0.2.32: update redoxfs 2025-04-20 18:55:44 -06:00
Jeremy Soller a4032c27b7 0.2.31: update pkgar 2025-03-27 15:47:03 -06:00
Jeremy Soller fcc2dfb1c8 Merge branch 'skip_partitions' into 'master'
Add support for only creating redoxfs partition installer

See merge request redox-os/installer!45
2025-03-27 13:49:21 +00:00
4lDO2 d85eceac71 Add support for only creating redoxfs partition installer. 2025-03-27 14:27:40 +01:00
Jeremy Soller a78377da19 0.2.30: update redoxfs 2025-03-25 15:46:05 -06:00
Jeremy Soller 2bf4865794 installer_tui: fix disk detection 2025-03-25 15:40:01 -06:00
Jeremy Soller d53435420b Merge branch 'repo-error-messages' into 'master'
Update to get better error messages

See merge request redox-os/installer!44
2024-12-06 21:57:56 +00:00
Ron Williams 3a084e1c27 Update to get better error messages 2024-12-06 11:43:32 -08:00
Jeremy Soller e17550b6bd Merge branch 'master' into 'master'
fix: install runtime dependencies of locally built packages

See merge request redox-os/installer!43
2024-12-06 17:36:23 +00:00
Anhad Singh 183e18be31 fix: install runtime dependencies of locally built packages
This is the same behavior as remote prebuilt packages and what the
package manager already does. It seems to be only unimplemented for
locally built packages.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2024-12-07 01:38:16 +11:00
Jeremy Soller 729c5631bc Merge branch 'source-recipe' into 'master'
Accept "source" as an alternative to "recipe"

See merge request redox-os/installer!42
2024-11-21 15:07:55 +00:00
Ron Williams 47282ba9dd Accept "source" as an alternative to "recipe" 2024-11-21 02:17:25 -08:00
Jeremy Soller 7c359f1622 Update dependencies 2024-11-06 06:13:23 -07:00
Jeremy Soller 37cc477d5c 0.2.29: update redoxfs 2024-10-29 08:55:39 -06:00
Jeremy Soller dc7d923e5a 0.2.28 2024-10-20 14:09:50 -06:00
Jeremy Soller 71ac2646bb Merge branch 'master' of https://gitlab.redox-os.org/redox-os/installer 2024-10-20 14:09:21 -06:00
Jeremy Soller 17db563677 0.2.27 - update pkgar 2024-10-20 14:08:47 -06:00
Jeremy Soller cf83106610 Merge branch 'fix-hostname-space' into 'master'
fix: Invalid space in `/etc/hostname`

See merge request redox-os/installer!41
2024-10-20 12:33:04 +00:00
Josh Megnauth 0ee8e95f62 fix: Invalid space in /etc/hostname
Spaces and newlines are invalid in hostnames. However, the base config inadvertently creates an `/etc/hostname` with a newline after "redox".

This can cause programs to fail.
2024-10-20 02:23:04 -04:00
Jeremy Soller b3e90be70b Link to ring issue requiring patch 2024-10-18 14:11:24 -06:00
Jeremy Soller 20fa660797 Patch ring to fix i686 build 2024-10-18 14:09:52 -06:00
Jeremy Soller eebccba932 0.2.26: Update to use pkgutils rewrite 2024-10-18 12:20:09 -06:00
Jeremy Soller 4b9e9e17ab 0.2.25 2024-10-16 13:26:17 -06:00
Jeremy Soller 17263316d9 Merge branch 'deps' into 'master'
Bump dependencies

See merge request redox-os/installer!40
2024-10-16 19:25:00 +00:00
Andrey Turkin 5c8cdd8950 Bump dependencies 2024-10-16 22:13:50 +03:00
Jeremy Soller 5c52a2e80e Merge branch 'riscv' into 'master'
Risc-v support

See merge request redox-os/installer!39
2024-10-16 18:02:45 +00:00
Andrey Turkin 7ccaccee4e Risc-v support 2024-10-16 20:26:51 +03:00
Jeremy Soller afc225c8d6 Merge branch 'ext' into 'master'
Modernize code and add support for local binary packages

See merge request redox-os/installer!38
2024-10-06 15:32:39 +00:00
4lDO2 098fd8bbc9 Support local binary packages. 2024-10-06 17:12:08 +02:00
4lDO2 66d66a537c Switch from failure to anyhow. 2024-10-06 13:08:17 +02:00
4lDO2 bfe70c409f 2021 edition. 2024-10-06 13:02:44 +02:00
4lDO2 cb707c3ce4 Update edition and rustfmt. 2024-10-06 13:02:16 +02:00
Jeremy Soller 9c3c5228df 0.2.24 2024-09-19 20:45:09 -06:00
Jeremy Soller caebc0d6f7 Add XDG user dirs configuration 2024-09-18 09:42:05 -06:00
Jeremy Soller 087810a252 Merge branch 'no_legacy_scheme' into 'master'
Remove all usages of the legacy scheme syntax

See merge request redox-os/installer!37
2024-08-18 22:16:53 +00:00
bjorn3 34a832b43e Remove all usages of the legacy scheme syntax 2024-08-18 21:44:10 +02:00
Jeremy Soller d352203794 Merge branch 'package-lister' into 'master'
Add list_packages binary

See merge request redox-os/installer!36
2024-08-17 23:58:19 +00:00
Ron Williams ad54d088d5 Add list_packages binary 2024-08-16 23:26:25 -07:00
Jeremy Soller a5534b8699 Install config before package files to ensure usr symlinks are properly handled 2024-06-24 21:04:31 -06:00
Jeremy Soller e409c11e67 0.2.23: fix install from inside Redox 2024-06-24 20:05:38 -06:00
Jeremy Soller 6895d9a9aa 0.2.22: pin cc to prevent ring build failure 2024-06-24 11:28:03 -06:00
Jeremy Soller 31d4816fcb 0.2.21 2024-06-24 11:21:14 -06:00
Jeremy Soller 2058101f61 Update dependencies 2024-05-27 09:37:39 -06:00
Jeremy Soller 69d4db511a 0.2.20 2024-04-22 15:28:20 -06:00
Jeremy Soller 52281ea9b5 0.2.19 2024-04-19 13:33:16 -06:00
Jeremy Soller 7b9f9f663d Update redoxfs 2024-04-01 13:31:54 -06:00
Jeremy Soller 7bcc07f357 Merge branch 'redox-users' into 'master'
Update Cargo.lock for redox_users

See merge request redox-os/installer!35
2024-04-01 13:25:03 +00:00
Ron Williams 5b7c64d587 Update Cargo.lock for redox_users 2024-03-31 22:11:37 -07:00
Jeremy Soller 248990b5ef Merge branch 'group' into 'master'
Add missing password field in /etc/group

See merge request redox-os/installer!34
2024-03-25 19:56:03 +00:00
Piotr Wójcik 2acf506d16 Add missing password field in /etc/group 2024-03-25 19:34:22 +01:00
Jeremy Soller f725079176 0.2.18: Update redoxfs 2024-03-23 08:57:20 -06:00
Jeremy Soller 1c30f4a3c1 0.2.17: update redoxfs 2024-02-15 16:04:43 -07:00
Jeremy Soller 17219dab9f 0.2.16 2024-02-07 20:00:51 -07:00
Jeremy Soller 6dfcee04ad Add output-config parameter to installer for getting merged config 2024-02-07 19:44:05 -07:00
Jeremy Soller dbfdd417f1 Remove file: prefix from /etc/passwd 2024-01-18 13:43:20 -07:00
Jeremy Soller 51f6efbaad Merge branch 'fix_config_serialization' into 'master'
Update the toml crate

See merge request redox-os/installer!33
2024-01-10 20:50:04 +00:00
bjorn3 3d417f7742 Update the toml crate
This fixes serialization of the config when using specifying that
packages should be downloaded as binary.
2024-01-10 21:48:05 +01:00
Jeremy Soller a258044dcc Merge branch 'limit_progressbar_rate' into 'master'
Update pkgutils

See merge request redox-os/installer!32
2024-01-10 15:55:29 +00:00
bjorn3 9a1463dd11 Update pkgutils 2024-01-10 16:08:06 +01:00
Jeremy Soller 7a7790e9bd Merge branch 'installer_groups' into 'master'
Move /etc/group generation to the installer

See merge request redox-os/installer!30
2024-01-06 16:28:32 +00:00
bjorn3 09da116ccd Move /etc/group generation to the installer
This ensures that the gid's for the auto-generated user groups stay in
sync with the gid in /etc/passwd. It also makes it easier to evolve the
format of /etc/group in the future.
2024-01-06 17:24:48 +01:00
Jeremy Soller 6a4802d556 Add flag to print filesystem size 2024-01-04 12:18:41 -07:00
Jeremy Soller 352407371c Make general config optional 2024-01-04 11:58:21 -07:00
Jeremy Soller 6f40e32d49 Make general.prompt optional 2024-01-04 11:54:48 -07:00
Jeremy Soller b84146edd5 Merge branch 'config_include' into 'master'
Support including other config files from a config file

See merge request redox-os/installer!29
2024-01-04 15:23:21 +00:00
bjorn3 adfee95484 Support including other config files from a config file
This will allow significantly reducing the amount of duplication
between all the different configs used by Redox OS.
2024-01-04 15:29:15 +01:00
bjorn3 1f4bbece4a Introduce Config::from_file for parsing the config toml 2024-01-04 14:54:13 +01:00
bjorn3 5cdec46800 Reserialize filesystem.toml instead of copying the original config
This will be necessary to handle including other configs from the config
to use as these configs will not be copied.
2024-01-04 14:53:05 +01:00
bjorn3 c9e091be67 Remove mention of /games
This is no longer used since redox-os/redox!1397
2024-01-03 21:58:52 +01:00
Jeremy Soller aa1a982479 Merge branch 'symlinks' into 'master'
Create symlinks before installing packages

See merge request redox-os/installer!27
2024-01-03 19:17:52 +00:00
bjorn3 b4f2f01d73 Create symlinks before installing packages
This allows redirecting the location packages are installed using
symlinks. This makes it much easier to change the filesystem hierarchy
by not having to change every recipe in the cookbook.
2023-12-29 15:16:56 +01:00
Jeremy Soller 38f6aa70bd 0.2.15 2023-12-13 14:11:29 -07:00
Jeremy Soller 39f4b1c8b6 Make bootloader install directory per-process 2023-12-13 14:11:09 -07:00
Jeremy Soller ba2fc38a3f Remove temporary mount directory 2023-12-13 14:10:56 -07:00
Jeremy Soller f241649bba 0.2.14 2023-12-12 13:10:15 -07:00
Jeremy Soller 4821c55242 Update redoxfs 2023-12-12 13:10:01 -07:00
Jeremy Soller cf9e2c9719 Use per-process mount path 2023-12-12 11:11:17 -07:00
Jeremy Soller 59e0f9e7ae Update redoxfs 2023-12-12 11:10:53 -07:00
Jeremy Soller e0c909536c Merge branch 'ivan/efi_size' into 'master'
add option for variable size of EFI system partition

See merge request redox-os/installer!26
2023-12-07 15:34:54 +00:00
Ivan Tan cbdea61a61 add option for variable size of EFI system partition 2023-11-18 02:50:06 +00:00
Jeremy Soller c5335d4aae Merge branch 'rw_van_231024' into 'master'
Allow package spec "binary" or "recipe" to override REPO_BINARY=0 or REPO_BINARY=1

See merge request redox-os/installer!25
2023-11-04 18:33:52 +00:00
Ron Williams 2b34b31956 Allow package spec "binary" or "recipe" to override REPO_BINARY=0 or REPO_BINARY=1 2023-11-04 18:33:52 +00:00
Jeremy Soller d61b30de3f 0.2.13: update redoxfs and redox_syscall 2023-09-07 16:22:13 -06:00
Jeremy Soller 970cbfaef6 Update redoxfs and uuid 2023-09-07 16:12:50 -06:00
Jeremy Soller 7a85c43974 Merge branch 'master' into 'master'
config: misc changes for GPU drivers

See merge request redox-os/installer!23
2023-07-07 14:09:05 +00:00
Anhad Singh 7b35a76e49 config: misc changes for GPU drivers
Signed-off-by: Anhad Singh <andypythonappdeveloper@gmail.com>
2023-07-07 17:55:10 +10:00
Jeremy Soller 363166ad1e Merge branch 'update-pkgar' into 'master'
Update pkgar to 0.1.10

See merge request redox-os/installer!22
2023-04-05 21:32:32 +00:00
Will Angenent 3f306765ad Update pkgar to 0.1.10 2023-04-05 22:30:51 +01:00
Jeremy Soller 20c0bdf60f Merge branch 'update-to-use-redoxfs-unmount' into 'master'
Update installer to use redoxfs unmount function

See merge request redox-os/installer!21
2023-04-03 17:16:27 +00:00
Will Angenent 46e14ea06f Update installer to use redoxfs unmount function
This fixes completing the image build on gentoo and MacOS.
2023-04-01 20:57:43 +01:00
Jeremy Soller 7e0f635d0e Merge branch 'update-cargo-lock' into 'master'
Update Cargo.toml

See merge request redox-os/installer!20
2023-03-21 20:16:11 +00:00
Will Angenent 46e39bc109 Update Cargo.toml 2023-03-21 10:45:21 +00:00
Jeremy Soller b04fcab423 Merge branch 'rw_van_230309' into 'master'
fix mixed build in a new clone

See merge request redox-os/installer!19
2023-03-10 14:13:48 +00:00
Ron Williams b23b2f6e5d fix mixed build in a new clone 2023-03-09 21:17:13 -08:00
Jeremy Soller c4a7020e93 Merge branch 'rw_van_230307' into 'master'
Add ability to read package = recipe from filesystem config

See merge request redox-os/installer!18
2023-03-09 02:24:13 +00:00
Ron Williams 1411257784 add ability to read package = recipe from filesystem config 2023-03-08 14:18:45 -08:00
Jeremy Soller cfd556f3b3 Merge branch 'fix_warnings' into 'master'
Remove unused imports and function

See merge request redox-os/installer!17
2023-02-24 22:01:22 +00:00
andrewdavidmackenzie 257020852d Remove unused imports and function 2023-02-24 22:48:17 +01:00
Jeremy Soller c91bea9452 Update libc crate 2023-02-11 14:42:31 -07:00
Jeremy Soller 41a656af92 Ignore live disks and partitions in TUI 2023-01-12 08:50:04 -07:00
Jeremy Soller fadb0a1c1d 0.2.12 2023-01-11 14:11:55 -07:00
Jeremy Soller f710fa79db Recursively set permissions on home directories 2022-11-21 14:55:08 -07:00
Jeremy Soller b724e714d3 Move EFI partition to second megabyte 2022-09-21 14:42:45 -06:00
Jeremy Soller c6d7cf16e1 Fix EFI partition alignment 2022-09-21 13:54:14 -06:00
Jeremy Soller e24f5ef8e3 Only use cookbook argument if not doing list-packages 2022-09-12 10:14:51 -06:00
Jeremy Soller fa836008c0 Rely on packages being built prior to installer running 2022-09-12 07:32:24 -06:00
Jeremy Soller 5e8e596d40 Fix seek not changing in last commit 2022-09-07 10:48:39 -06:00
Jeremy Soller 7b24f868b8 Optimization for block aligned I/O in disk wrapper 2022-09-07 10:46:24 -06:00
Jeremy Soller 0b4f836f2a Use same logic for read and write in disk wrapper 2022-09-07 10:40:41 -06:00
Jeremy Soller 8d2d4cd62d Add disk wrapper to ensure block aligned I/O 2022-09-07 10:29:15 -06:00
Jeremy Soller 9666c62036 Fix copying EFI partition message 2022-09-07 09:55:02 -06:00
Jeremy Soller f103b5c4b9 Fixup for last commit 2022-09-07 09:48:12 -06:00
Jeremy Soller 4b1df136a6 Write BIOS and EFI partitions in memory 2022-09-07 09:45:27 -06:00
Jeremy Soller ddf59d8c7d Print debug messages while doing partitioning 2022-09-07 09:02:06 -06:00
Jeremy Soller c3e679d5f1 Fix 32-bit x86 target name 2022-09-05 10:51:13 -06:00
Jeremy Soller ad11b2adb2 Ensure config and cookbook key are installed 2022-09-05 09:55:15 -06:00
Jeremy Soller e8e4687c05 Pass live argument from CLI to library 2022-09-05 09:10:46 -06:00
Jeremy Soller 1ecb9b49fc Support fetching live bootloader 2022-09-05 09:07:40 -06:00
Jeremy Soller f1a806b288 0.2.11 - allow installer to create full disk installs supporting both BIOS and EFI 2022-09-05 08:58:53 -06:00
Jeremy Soller 4e7f7d8413 Update to use new boot directory format 2022-08-26 17:56:22 -06:00
Jeremy Soller be5eefd44f Update Cargo.lock 2022-07-26 17:26:26 -06:00
Jeremy Soller 2b1107c856 Also copy initfs 2022-07-22 10:30:44 -06:00
Jeremy Soller 2418286a29 Improve installer size formatting 2022-04-26 08:22:58 -06:00
4lDO2 0ed65d7d3d Use crates.io version of syscall 2022-03-27 12:25:09 +02:00
4lDO2 f76771491c Update syscall 2022-03-27 11:25:01 +02:00
Jeremy Soller f8ec4d28bc Ensure pkg folder exists 2022-03-23 15:04:53 -06:00
Jeremy Soller e666636ab7 Create pkgar_head files when installing 2022-03-23 13:53:10 -06:00
Jeremy Soller 900f77e7f2 Use pkgar_head files for installer_tui 2022-03-23 13:52:33 -06:00
Jeremy Soller adebf727dc Update pkgar and lock file 2022-03-23 13:52:16 -06:00
Jeremy Soller 9ea9a6ecac 0.2.10: update pkgar 2022-03-17 16:35:15 -06:00
Jeremy Soller 3c03576518 0.2.9: add tests and make it possible to install to disk 2022-03-17 08:50:01 -06:00
Jeremy Soller 0c731043ac Use fs::copy to ensure metadata is copied 2022-03-16 14:13:41 -06:00
Jeremy Soller 2c54a9b868 installer_tui: support password encryption 2022-03-15 13:50:48 -06:00
Jeremy Soller b35e132153 Update Cargo.lock 2022-03-11 09:14:45 -07:00
Jeremy Soller 41eba65942 Merge branch 'redoxfs-0.5.0' into 'master'
Redoxfs 0.5.0

See merge request redox-os/installer!16
2022-03-11 16:14:20 +00:00
Jeremy Soller 1634877666 0.2.8 2022-03-11 09:14:07 -07:00
Jeremy Soller ff2fdeca84 Switch to crates.io version of RedoxFS 0.5 2022-03-11 09:13:33 -07:00
Jeremy Soller 621a4dee2c Update to RedoxFS 0.5.0 2022-02-28 12:24:00 -07:00
Jeremy Soller 84856f459d Update patches 2021-08-10 16:08:02 -06:00
Jeremy Soller 7f0a57108d Fix size formatting in installer TUI 2021-08-02 17:44:52 -06:00
4lDO2 70a2dc7532 Update Cargo.lock, again. 2021-06-18 09:23:19 +02:00
4lDO2 224bb047dc Update dependencies. 2021-06-17 18:10:32 +02:00
Jeremy Soller 150d65c31b Update syscall 2020-08-02 15:26:52 -06:00
Jeremy Soller af5f64b807 Remove pbr patch 2020-05-28 11:56:13 -06:00
Jeremy Soller 03320a2025 Remove libc and tar patch 2020-05-26 10:27:19 -06:00
Jeremy Soller 03f996c70f 0.2.7 - add patches for libc, pbr, ring, and tar-rs 2020-05-21 13:47:57 -06:00
Jeremy Soller c22b1cf71b Add cookbook pkgar support 2020-03-13 20:04:43 -06:00
Jeremy Soller 6a49914f0f 0.2.6 - update dependencies 2020-01-20 10:04:24 -07:00
Jeremy Soller 3a1a257f0f Update redoxfs 2020-01-20 09:58:10 -07:00
Jeremy Soller 1fccae679d Add default-run attribute 2019-11-29 10:15:45 -07:00
Jeremy Soller 7c5236fe35 0.2.5 - update dependencies and prepare for publishing 2019-11-29 10:09:27 -07:00
Jeremy Soller 3b0f59cbb0 Copy include, lib, and pkg 2019-09-22 10:58:55 -06:00
Jeremy Soller cd9e026705 Fix issue of trying to run read_dir on disk/live: 2019-09-22 10:06:25 -06:00
Jeremy Soller 9ff577792b Disable creation of liner context - it causes installer_tui to lock 2019-09-22 09:27:27 -06:00
Jeremy Soller fbfc4edf6f Add message when installer is successful 2019-09-19 21:22:05 -06:00
Jeremy Soller 505dec6069 Optimized file copy 2019-09-19 19:39:53 -06:00
Jeremy Soller 89dcc2c060 Add unmounting message 2019-09-15 13:31:59 -06:00
Jeremy Soller 7ef2567da6 Copy locally installed package files 2019-09-15 13:14:46 -06:00
Jeremy Soller 5762840f79 Installer TUI (WIP) 2019-09-08 20:47:05 -06:00
Jeremy Soller 39d68618ca Switch to using rust-argon2 crate, which is more actively maintained 2019-09-08 08:59:50 -06:00
Jeremy Soller b75b1c2f86 Revert libc to 0.2.54 to support older Redox 2019-06-10 17:37:05 -06:00
Jeremy Soller acb7bced58 0.2.4 - allow empty configuration sections and update dependencies 2019-06-10 17:31:44 -06:00
Jeremy Soller f30987b1e5 0.2.3: Update dependencies 2019-05-12 08:34:49 -06:00
Jeremy Soller 713359252a 0.2.2 - fix cargo doc 2019-05-12 08:15:18 -06:00
Jeremy Soller f794ab2a66 Add metadata 2019-05-12 08:02:59 -06:00
Jeremy Soller 40addc7020 Bump version and update dependencies 2019-05-12 08:01:30 -06:00
Jeremy Soller 8e88231ede Update for newer rust 2019-04-07 10:36:45 -06:00
Jeremy Soller a262db6f25 Merge branch 'get-target-from-env' into 'master'
Get TARGET from the environment

See merge request redox-os/installer!11
2019-03-02 21:07:12 +00:00
Robin Randhawa 78e9f77950 Get TARGET from the environment
This enables flexible cross-installation of packages as opposed to only
compiling for the x86_64-unknown-redox target.

This also permits native builds.
2019-03-01 21:02:10 +00:00
Jeremy Soller 03fc74e21f Update installer depends 2018-12-10 14:23:50 -07:00
Jeremy Soller ed25899b0e Update Cargo.lock 2018-10-14 19:58:26 -06:00
Jeremy Soller 49b7a5f427 Fix types when compiling for Redox 2018-08-19 12:33:51 -06:00
Jeremy Soller 7f38ffac1f Use forked libc crate, update lock file 2018-08-19 11:39:22 -06:00
Jeremy Soller 33fa0af521 Fix uid and gid unwrap 2018-08-17 19:59:22 -06:00
Jeremy Soller 91c303df7d Do not set uid or gid if not asked to 2018-08-17 19:34:29 -06:00
Jeremy Soller 123350ae60 Merge remote-tracking branch 'origin/v0.3' 2018-08-17 17:16:16 -06:00
Jeremy Soller be2e09472a Update lock file 2018-08-17 17:13:05 -06:00
MggMuggins 03cae0ca37 Implement shadowfile 2018-08-17 17:26:11 -05:00
Jeremy Soller 8e39b2ea32 Merge branch 'mggmuggins/shadowfile' into 'master'
Use shadowfile for user creation

See merge request redox-os/installer!7
2018-08-17 12:24:04 +00:00
MggMuggins 66b24d1116 Support Directories 2018-07-28 10:41:39 -05:00
MggMuggins e58815f89c Rudimentary support for permissions
I sorta OOP'ed this, combining the logic of what needs to happen for
each config object with those objects. More things are coming, this is a
very WIP commit.
2018-07-27 10:55:11 -05:00
MggMuggins ce6e96bd20 Major Refactor; Create passwd hashes
Maybe some of the refactoring things I did don't make much sense, but I
did them. The goal was to get rid of those macros (because macro
definitions are really hard to read). I replaced two of them with very
similar functions, and rearranged the `install` function.

The installer now generates password hashes from the password entered by
the user or listed in the toml file. This value is NO LONGER the
password hash. The example configs have been changed to reflect this.
2018-07-26 14:58:14 -05:00
MggMuggins 80add18dc9 Functional Partial rewrite 2018-07-26 12:43:57 -05:00
MggMuggins 1359501d3f Use shadowfile for user creation 2018-07-25 15:20:15 -05:00
Jeremy Soller a1afbb144f Update links to gitlab 2018-06-12 12:30:44 -06:00
Jeremy Soller 999db45b0e Update redoxfs 2017-11-19 16:24:25 -07:00
Jeremy Soller f6c5fd94a7 Merge pull request #6 from chebykinn/redox_users
Migrate to redox_users
2017-11-11 12:54:12 -07:00
Ivan Chebykin 681fd3d0ef Migrated to redox_users 2017-11-11 22:12:55 +03:00
Jeremy Soller 62412ef548 Create LICENSE 2017-10-20 20:08:54 -06:00
Jeremy Soller 43e506c447 Update Cargo.lock 2017-10-11 20:54:45 -06:00
Jeremy Soller ac759a17bd Update Cargo.lock 2017-10-04 20:29:41 -06:00
Jeremy Soller a01dc9f37a Switch to arg_parser 2017-09-27 20:53:13 -06:00
Jeremy Soller a82a577180 Change format of installer arguments 2017-09-26 20:52:54 -06:00
Jeremy Soller a7b16dcb97 Update configs, update dependencies 2017-09-26 20:00:50 -06:00
Jeremy Soller 093ae7de55 Fix method of adding scheme 2017-08-23 20:29:27 -06:00
Jeremy Soller 25d6a0fec4 Add scheme to paths 2017-08-23 20:16:45 -06:00
Jeremy Soller 7ad7827497 Merge pull request #5 from ids1024/symlink
Support adding symlinks in configuration
2017-08-21 15:07:56 -06:00
Ian Douglas Scott a4adb124d0 Support adding symlinks in configuration
I'm not sure if this is the best syntax...
2017-08-21 13:24:36 -07:00
Jeremy Soller 5cfe357821 Update Cargo.lock and Cargo.toml 2017-08-19 14:51:08 -06:00
Jeremy Soller a76c8df867 Update Cargo.lock 2017-08-02 21:14:10 -06:00
Jeremy Soller a9a1f0e76d Update Cargo.lock 2017-08-02 19:55:53 -06:00
Jeremy Soller ed468af4c3 Update Cargo.lock 2017-07-29 08:27:31 -06:00
Jeremy Soller 3efca19473 Update userutils 2017-07-26 20:35:27 -06:00
Jeremy Soller c0bc46b954 Update Cargo.lock 2017-07-26 08:25:05 -06:00
Jeremy Soller 2c0e14cadf Add Cargo.lock file 2017-07-26 08:02:37 -06:00
Jeremy Soller d73dd18f07 Add Cargo.lock 2017-07-26 07:54:39 -06:00
Jeremy Soller 15d37cea36 Merge pull request #4 from ids1024/list
--list-packages argument
2017-07-10 21:30:42 -06:00
Ian Douglas Scott e47108a70e --list-packages argument 2017-07-10 20:04:06 -07:00
Jeremy Soller d6f2936a53 Remove redoxfs submodule 2017-06-29 18:13:10 -06:00
Jeremy Soller f99fac30ea Update redoxfs 2017-06-23 17:59:16 -06:00
Jeremy Soller af1dd3b9fd Use .tar.gz for packages 2017-06-18 15:14:51 -06:00
Jeremy Soller 31a60eb8a3 Update for new location of script 2017-05-11 20:52:42 -06:00
Jeremy Soller 318e7bb89f Merge commit '8d6a4d7' 2017-05-10 21:38:17 -06:00
Jeremy Soller 8d6a4d7071 Add RedoxFS as submodule. Do not create passwd if no users are provided 2017-05-10 21:38:05 -06:00
Jeremy Soller 7e9f15e54f Print message when installing from cookbook 2017-05-08 21:20:15 -06:00
Jeremy Soller c2bae24835 Merge pull request #3 from ids1024/package
Update for pkgutils refactoring
2017-04-26 06:24:09 -06:00
Ian Douglas Scott 160a793017 Update for pkgutils refactoring 2017-04-25 21:57:04 -07:00
Jeremy Soller 7c7b30c16e Merge pull request #2 from ids1024/pkgutils_cookbook
Use install methods from pkgutils, and allow installing directly from cookbook with --cookbook=path
2017-04-09 12:59:47 -06:00
Ian Douglas Scott bb94edcb15 Support building directly from cookbook with --cookbook= 2017-04-09 10:11:49 -07:00
Ian Douglas Scott e2aa3c3032 Move package installing logic to function 2017-04-09 09:19:24 -07:00
Ian Douglas Scott bb56cee678 Let pkgutils handle downloading and extracting package 2017-04-09 09:06:07 -07:00
Jeremy Soller 4e9d22ada4 Fix installer paths 2017-04-07 19:57:00 -06:00
Jeremy Soller cfdb2a4968 Log creation of parent dirs 2017-01-09 22:29:03 -07:00
Jeremy Soller be092f3754 Create parent directories 2017-01-09 22:16:47 -07:00
Jeremy Soller eb2c0aafd4 Fix package loop 2017-01-09 22:11:11 -07:00
Jeremy Soller 5303301d3d Download packages from repo 2017-01-09 19:25:58 -07:00
Jeremy Soller 9125d089fb Add package extraction 2017-01-09 19:03:54 -07:00
Jeremy Soller aeb9f89ec1 Fix prompt macro, add ability to insert files in config 2017-01-09 16:05:27 -07:00
Jeremy Soller 7d5baf798e Macros 2017-01-09 15:41:40 -07:00
Jeremy Soller a56ec333ae Add sysroot config 2017-01-09 15:23:30 -07:00
Jeremy Soller dd0a541bfe Fix comment 2017-01-09 14:50:22 -07:00
Jeremy Soller a5773c3504 Add prompt example 2017-01-09 14:49:09 -07:00
Jeremy Soller e4db84e1d7 Add prompt example 2017-01-09 14:48:29 -07:00
Jeremy Soller 542ca6cb3d Fix example 2017-01-09 14:46:56 -07:00
Jeremy Soller 961983e788 Cleanup prompt macros 2017-01-09 14:46:21 -07:00
Jeremy Soller f666d06485 User configuration 2017-01-09 14:35:33 -07:00
Jeremy Soller 1abfd39b8d Initial commit 2017-01-09 10:12:49 -07:00
25 changed files with 5416 additions and 1226 deletions
-1
View File
@@ -1 +0,0 @@
{"v":1}
-6
View File
@@ -1,6 +0,0 @@
{
"git": {
"sha1": "7040cf71b3a5d15d91802810d0a50aa197970c43"
},
"path_in_vcs": ""
}
+4 -2
View File
@@ -1,2 +1,4 @@
/target pkg
/Cargo.lock sysroot
/target/
/test.bin
+24
View File
@@ -0,0 +1,24 @@
image: "rust:latest"
stages:
- lint
- test
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
fmt:
stage: lint
script:
- rustup component add rustfmt
- cargo fmt -- --check
cargo-test:
stage: test
script:
- apt update && apt install -y fuse3 libfuse3-dev
- cargo build --locked
- cargo test
- ./target/debug/redox_installer -c res/test.toml test.bin --no-mount
Generated
+2683
View File
File diff suppressed because it is too large Load Diff
+64 -29
View File
@@ -1,38 +1,73 @@
[package] [package]
name = "libredox" name = "redox_installer"
authors = ["4lDO2 <4lDO2@protonmail.com>", "vasilito <adminpupkin@gmail.com>"] version = "0.2.42+rb0.3.0"
version = "0.1.18+rb0.3.0" description = "A Redox filesystem builder"
edition = "2021"
license = "MIT" license = "MIT"
description = "Redox stable ABI" authors = ["Jeremy Soller <jackpot51@gmail.com>", "vasilito <adminpupkin@gmail.com>"]
repository = "https://gitea.redbearos.org/vasilito/RedBear-OS" repository = "https://gitlab.redox-os.org/redox-os/installer"
exclude = ["target"] default-run = "redox_installer"
edition = "2021"
[features] [[bin]]
default = ["base", "call", "std", "protocol", "redox_syscall"] name = "redox_installer"
base = ["libc"] path = "src/bin/installer.rs"
call = ["base"] required-features = ["installer"]
std = ["base"]
protocol = ["plain", "bitflags"] [[bin]]
mkns = ["ioslice"] name = "redox_installer_tui"
# The `redox_syscall` feature activates the optional `redox_syscall` path = "src/bin/installer_tui.rs"
# dep below. The `#[cfg(feature = "redox_syscall")]` attributes in required-features = ["installer"]
# src/lib.rs gate the `From` impls between `libredox::error::Error`
# and `syscall::Error`; without the feature, those impls are absent [lib]
# and `?` propagation between the two types fails. Mirroring name = "redox_installer"
# upstream `libredox 0.1.18`'s feature structure. path = "src/lib.rs"
redox_syscall = ["dep:redox_syscall"]
[dependencies] [dependencies]
bitflags = { version = "2", optional = true } anyhow = "1"
libc = { version = "0.2", optional = true } arg_parser = "0.1.0"
# The redox_syscall package has [lib] name = "syscall", so fatfs = { version = "0.3.0", optional = true }
# in Rust code it is imported as `syscall`, NOT `redox_syscall`. fscommon = { version = "0.1.1", optional = true }
# This dep is optional and gated by the `redox_syscall` feature gpt = { version = "3.0.0", optional = true }
# above. Matching upstream `libredox 0.1.18` structure. libc = "0.2.70"
pkgar = { version = "0.2", optional = true }
pkgar-core = { version = "0.2", optional = true }
pkgar-keys = { version = "0.2", optional = true }
rand = { version = "0.9", optional = true }
redox-pkg = { version = "0.3", features = ["indicatif"], optional = true }
redox_syscall = { path = "../syscall", optional = true } redox_syscall = { path = "../syscall", optional = true }
ioslice = { version = "0.6", optional = true } redoxfs = { path = "../redoxfs", optional = true, default-features = false, features = ["std", "log"] }
plain = { version = "0.2", optional = true } rust-argon2 = { version = "3", optional = true }
serde = "1"
serde_derive = "1.0"
termion = { version = "4", optional = true }
toml = "0.8"
uuid = { version = "1.4", features = ["v4"], optional = true }
[target.'cfg(target_os = "redox")'.dependencies]
libredox = { path = "../libredox" }
ring = "=0.17.8"
[features]
default = ["installer", "fuse"]
installer = [
"fatfs",
"fscommon",
"gpt",
"pkgar",
"pkgar-core",
"pkgar-keys",
"rand",
"redox-pkg",
"redox_syscall",
"redoxfs",
"rust-argon2",
"termion",
"uuid",
]
fuse = ["redoxfs/fuse"]
[patch.crates-io] [patch.crates-io]
# https://github.com/briansmith/ring/issues/1999
ring = { git = "https://gitlab.redox-os.org/redox-os/ring.git", branch = "redox-0.17.8" }
redox_syscall = { path = "../syscall" } redox_syscall = { path = "../syscall" }
libredox = { path = "../libredox" }
-44
View File
@@ -1,44 +0,0 @@
[package]
name = "libredox"
authors = ["4lDO2 <4lDO2@protonmail.com>"]
# Red Bear OS Phase J: version is 0.1.18 upstream. The
# redox_syscall dep is now required (not optional) because
# the local fork's acpi module (added in this commit) re-
# exports AcPiVerb from redox_syscall, and downstream recipes
# that don't enable the redox_syscall feature get an
# "unresolved import" error. Making the dep non-optional
# also matches the upstream 0.1.18 Cargo.toml pattern where
# the redox_syscall dep is unconditional.
version = "0.1.18"
edition = "2021"
license = "MIT"
description = "Redox stable ABI"
# Red Bear OS fork lives at the canonical outer repo
# (gitea.redbearos.org/vasilito/RedBear-OS).
repository = "https://gitea.redbearos.org/vasilito/RedBear-OS"
exclude = ["target"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["base", "call", "std", "protocol"]
base = ["libc"]
call = ["base"]
std = ["base"]
protocol = ["plain", "bitflags", "redox_syscall"]
mkns = ["ioslice"]
[dependencies]
bitflags = { version = "2", optional = true }
libc = { version = "0.2", optional = true }
# Phase J: path override to the local fork (../syscall
# relative to the libredox fork's local/sources/libredox/
# path). This gives libredox access to the EnterS2Idle /
# ExitS2Idle AcpiVerb variants. Cargo's [patch.crates-io]
# in the workspace's outer Cargo.toml (in base/ and kernel/)
# is what wires this path through to the actual
# redox_syscall crate; this path entry is the libredox-
# side patch override for the same crate.
redox_syscall = { path = "../syscall", version = "0.8" }
ioslice = { version = "0.6", optional = true }
plain = { version = "0.2", optional = true }
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 4lDO2 Copyright (c) 2017 Redox OS
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+50
View File
@@ -0,0 +1,50 @@
# Redox OS installer
The Redox installer will allow you to produce a Redox OS image. You will
be able to specify:
- Output device (raw image, ISO, QEMU, VirtualBox, drive)
- Filesystem
- Included packages
- Method of installation (from source, from binary)
- User accounts
You will be prompted to install dependencies, based on your OS and method of
installation. The easiest method is to install from binaries.
## Usage
It is recommended to compile with `cargo`, in release mode:
```bash
cargo build --release
```
By default, you will be prompted to supply configuration options. You can
use the scripted mode by supplying a configuration file:
```bash
cargo run --release -- config/example.toml
```
An example configuration can be found in [config/example.toml](./config/example.toml).
Unsuplied configuration will use the default. You can use the `general.prompt`
setting to prompt when configuration is not set. Multiple configurations can
be specified, they will be built in order.
## Embedding
The installer can also be used inside of other crates, as a library:
```toml
# Cargo.toml
[dependencies]
redox_installer = "0.1"
```
```rust
// src/main.rs
extern crate redox_installer;
fn main() {
let mut config = redox_installer::Config::default();
...
redox_installer::install(config);
}
```
+174
View File
@@ -0,0 +1,174 @@
# This is the default configuration file
# General settings
[general]
# Do not prompt if settings are not defined
prompt = false
# Package settings
[packages]
#acid = {}
#autoconf = {}
#automake = {}
#bash = {}
#binutils = {}
#ca-certificates = {}
#cargo = {}
#contain = {}
coreutils = {}
#curl = {}
#dash = {}
#diffutils = {}
drivers = {}
extrautils = {}
findutils = {}
#games = {}
#gawk = {}
#gcc = {}
#git = {}
#gnu-binutils = {}
#gnu-make = {}
#installer = {}
ion = {}
#lua = {}
#nasm = {}
netstack = {}
netutils = {}
#newlib = {}
#openssl = {}
orbdata = {}
orbital = {}
orbterm = {}
orbutils = {}
pastel = {}
#patch = {}
#pixelcannon = {}
pkgutils = {}
ptyd = {}
#python = {}
randd = {}
#redoxfs = {}
#rust = {}
#rustual-boy = {}
#sed = {}
smith = {}
sodium = {}
userutils = {}
uutils = {}
#xz = {}
# User settings
[users.root]
password = "password"
uid = 0
gid = 0
name = "root"
home = "/root"
[users.user]
# Password is unset
password = ""
[groups.sudo]
gid = 1
members = ["user"]
[[files]]
path = "/etc/init.d/00_base"
data = """
pcid /etc/pcid/filesystem.toml
randd
ptyd
"""
[[files]]
path = "/etc/init.d/10_net"
data = """
ethernetd
ipd
icmpd
tcpd
udpd
dhcpd -b
"""
[[files]]
path = "/etc/init.d/20_orbital"
data = """
orbital orblogin launcher
"""
[[files]]
path = "/etc/init.d/30_console"
data = """
getty display/vesa:2
getty debug: -J
"""
[[files]]
path = "/etc/net/dns"
data = """
208.67.222.222
"""
[[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
"""
[[files]]
path = "/etc/net/mac"
data = """
54-52-00-ab-cd-ef
"""
[[files]]
path = "/etc/pkg.d/50_redox"
data = "https://static.redox-os.org/pkg"
[[files]]
path = "/etc/hostname"
data = "redox"
[[files]]
path = "/etc/issue"
data = """
########## Redox OS ##########
# Login with the following: #
# `user` #
# `root`:`password` #
##############################
"""
[[files]]
path = "/etc/motd"
data = """
Welcome to Redox OS!
"""
[[files]]
path = "/usr"
data = "/"
symlink = true
[[files]]
path = "/tmp"
data = ""
directory = true
# 0o1777
mode = 1023
+24
View File
@@ -0,0 +1,24 @@
# This is the default configuration file
# General settings
[general]
# Do not prompt if settings are not defined
prompt = false
# Package settings
[packages]
binutils = {}
coreutils = {}
extrautils = {}
ion = {}
netutils = {}
pkgutils = {}
userutils = {}
# User settings
[users.root]
password = "password"
uid = 0
gid = 0
name = "root"
home = "/root"
+411
View File
@@ -0,0 +1,411 @@
# Automatically generated by update.sh
include = []
[general]
prompt = false
filesystem_size = 256
[packages.base]
[packages.base-initfs]
[packages.bootloader]
[packages.ca-certificates]
[packages.coreutils]
[packages.extrautils]
[packages.findutils]
[packages.ion]
[packages.kernel]
[packages.kibi]
[packages.libgcc]
[packages.libstdcxx]
[packages.netdb]
[packages.netutils]
[packages.pkgutils]
[packages.relibc]
[packages.userutils]
[packages.uutils]
[[files]]
path = "/usr/lib/init.d/00_base"
data = """
# clear and recreate tmpdir with 0o1777 permission
rm -rf /tmp
mkdir -m a=rwxt /tmp
ipcd
ptyd
nowait sudo --daemon
"""
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/lib/init.d/00_drivers"
data = """
pcid-spawner /etc/pcid.d/
"""
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/etc/hostname"
data = "redox"
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/lib/os-release"
data = """
PRETTY_NAME="Redox OS 0.9.0"
NAME="Redox OS"
VERSION_ID="0.9.0"
VERSION="0.9.0"
ID="redox-os"
HOME_URL="https://redox-os.org/"
DOCUMENTATION_URL="https://redox-os.org/docs/"
SUPPORT_URL="https://redox-os.org/community/"
"""
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/etc/os-release"
data = "../usr/lib/os-release"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/etc/pkg.d/50_redox"
data = "https://static.redox-os.org/pkg"
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/usr"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/bin"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/bin"
data = "usr/bin"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/include"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/include"
data = "usr/include"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/lib"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/lib"
data = "usr/lib"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/libexec"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/share"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/share"
data = "usr/share"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/share/fonts"
data = "../../ui/fonts"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/var"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/var/cache"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/var/lib"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/var/lock"
data = ""
symlink = false
directory = true
mode = 1023
recursive_chown = false
postinstall = false
[[files]]
path = "/var/log"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/var/run"
data = ""
symlink = false
directory = true
mode = 493
recursive_chown = false
postinstall = false
[[files]]
path = "/var/tmp"
data = ""
symlink = false
directory = true
mode = 1023
recursive_chown = false
postinstall = false
[[files]]
path = "/dev/null"
data = "/scheme/null"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/dev/random"
data = "/scheme/rand"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/dev/urandom"
data = "/scheme/rand"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/dev/zero"
data = "/scheme/zero"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/dev/tty"
data = "libc:tty"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/dev/stdin"
data = "libc:stdin"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/dev/stdout"
data = "libc:stdout"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/dev/stderr"
data = "libc:stderr"
symlink = true
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/lib/init.d/10_net"
data = """
smolnetd
nowait dhcpd
"""
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/etc/net/dns"
data = """
9.9.9.9
"""
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/etc/net/ip"
data = """
10.0.2.15
"""
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/etc/net/ip_router"
data = """
10.0.2.2
"""
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/etc/net/ip_subnet"
data = """
255.255.255.0
"""
symlink = false
directory = false
recursive_chown = false
postinstall = false
[[files]]
path = "/usr/lib/init.d/30_console"
data = """
inputd -A 2
nowait getty 2
nowait getty /scheme/debug -J
"""
symlink = false
directory = false
recursive_chown = false
postinstall = false
[users.root]
password = "password"
uid = 0
gid = 0
name = "root"
home = "/root"
shell = "/usr/bin/ion"
[users.user]
password = ""
shell = "/usr/bin/ion"
[groups.sudo]
gid = 1
members = ["user"]
Executable
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -e
RES_PATH="$(dirname "$0")"
if [ -d "$1" ]
then
REDOX_PATH="$1"
else
echo "$0 [path to redox repository]" >&2
exit 1
fi
set -x
# Update res/test.toml from the redoxer.toml template
"${REDOX_PATH}/build/fstools/bin/redox_installer" \
--config="${REDOX_PATH}/config/x86_64/minimal-net.toml" \
--output-config="${RES_PATH}/test.toml"
sed -i '1s/^/# Automatically generated by update.sh\n\n/' "${RES_PATH}/test.toml"
+134
View File
@@ -0,0 +1,134 @@
extern crate arg_parser;
extern crate redox_installer;
extern crate serde;
extern crate toml;
use std::path::Path;
use std::{env, fs, process};
use arg_parser::ArgParser;
use redox_installer::{Config, PackageConfig};
const HELP_STR: &str = r#"
redox_installer - Redox Installer.
Refer to link below for filesystem config reference:
https://doc.redox-os.org/book/configuration-settings.html
Using redox_installer as an installer:
redox_installer <diskpath.img> [--config=file.toml] [--write-bootloader=file.img] [--live] [--no-mount] [--skip-partition]
<diskpath.img> Disk file to write
--config Path to filesystem config TOML
--write-bootloader Path to write UEFI bootloader to in addition to the embedded ESP
--skip-partition Skip writing GPT partition tables
Use this only if you plan to use other partition tool
--live Use bootloader configured for live disk
--no-mount Use RedoxFS AR instead of FUSE to write files
--cookbook Use local Redox OS build system rather than downloading packages
Using redox_installer as a configuration parser:
redox_installer --config=file.toml [--list-packages|--filesystem-size|--output-config path]
--list-packages List packages will be installed
--filesystem-size Output filesystem size in MB
--output-config Path to write the parsed config as another TOML
"#;
fn main() {
let mut parser = ArgParser::new(4)
.add_opt("b", "cookbook")
.add_opt("c", "config")
.add_opt("o", "output-config")
.add_opt("", "write-bootloader")
.add_flag(&["skip-partition"])
.add_flag(&["filesystem-size"])
.add_flag(&["r", "repo-binary"]) // TODO: Remove
.add_flag(&["l", "list-packages"])
.add_flag(&["live"])
.add_flag(&["no-mount"]);
parser.parse(env::args());
let skip_partition = parser.found("skip-partition");
let mut config = if let Some(path) = parser.get_opt("config") {
match Config::from_file(Path::new(&path)) {
Ok(config) => config,
Err(err) => {
eprintln!("installer: {err}");
process::exit(1);
}
}
} else {
redox_installer::Config::default()
};
// Get toml of merged config
let merged_toml = toml::to_string_pretty(&config).unwrap();
// Just output merged config and exit
if let Some(path) = parser.get_opt("output-config") {
fs::write(path, merged_toml).unwrap();
return;
}
// Add filesystem.toml to config
config.files.push(redox_installer::FileConfig {
path: "filesystem.toml".to_string(),
data: merged_toml,
..Default::default()
});
if skip_partition {
config.general.skip_partitions = Some(true);
}
if parser.found("filesystem-size") {
println!("{}", config.general.filesystem_size.unwrap_or(0));
} else if parser.found("list-packages") {
// List the packages that should be fetched or built by the cookbook
for (packagename, package) in &config.packages {
match package {
PackageConfig::Build(rule) if rule == "ignore" => {
// skip this package
}
_ => {
println!("{}", packagename);
}
}
}
} else {
let cookbook = if let Some(path) = parser.get_opt("cookbook") {
if !Path::new(&path).is_dir() {
eprintln!("installer: {}: cookbook not found", path);
process::exit(1);
}
Some(path)
} else {
None
};
if cookbook.is_some() {
config.general.cookbook = cookbook;
}
if parser.found("live") {
config.general.live_disk = Some(true);
}
if parser.found("no-mount") {
config.general.no_mount = Some(true);
}
let write_bootloader = parser.get_opt("write-bootloader");
if write_bootloader.is_some() {
config.general.write_bootloader = write_bootloader;
}
if let Some(path) = parser.args.first() {
if let Err(err) = redox_installer::install(config, path) {
eprintln!("installer: failed to install: {:?}", err);
process::exit(1);
}
} else {
eprint!("{}", HELP_STR);
process::exit(1);
}
}
}
+392
View File
@@ -0,0 +1,392 @@
use anyhow::{anyhow, bail, Result};
use pkgar::{ext::EntryExt, PackageHead};
use pkgar_core::PackageSrc;
use pkgar_keys::PublicKeyFile;
use redox_installer::{try_fast_install, with_redoxfs_mount, with_whole_disk, Config, DiskOption};
use std::{
ffi::OsStr,
fs,
io::{self, Read, Write},
os::unix::fs::{symlink, MetadataExt, OpenOptionsExt},
path::{Path, PathBuf},
process,
};
// TODO: This is not the TUI a regular user would expect it does
// 1. Linux: Implement disk listing, use "dd" to write into whole disk
// 2. Allow partitioning to allow dual boot, possibly an integration with systemd-boot/grub
// 3. Prompt everything (disk password, users, preconfigured packages, import from existing img)
#[cfg(not(target_os = "redox"))]
fn disk_paths(_paths: &mut Vec<(PathBuf, u64)>) {}
#[cfg(target_os = "redox")]
fn disk_paths(paths: &mut Vec<(PathBuf, u64)>) {
let mut schemes = Vec::new();
match fs::read_dir("/scheme") {
Ok(entries) => {
for entry_res in entries {
if let Ok(entry) = entry_res {
if let Ok(file_name) = entry.file_name().into_string() {
if file_name.starts_with("disk") {
schemes.push(entry.path());
}
}
}
}
}
Err(err) => {
eprintln!("redox_installer_tui: failed to list schemes: {}", err);
}
}
for scheme in schemes {
if scheme.is_dir() {
match fs::read_dir(&scheme) {
Ok(entries) => {
for entry_res in entries {
if let Ok(entry) = entry_res {
if let Ok(file_name) = entry.file_name().into_string() {
if file_name.contains('p') {
// Skip partitions
continue;
}
if let Ok(metadata) = entry.metadata() {
let size = metadata.len();
if size > 0 {
paths.push((entry.path(), size));
}
}
}
}
}
}
Err(err) => {
eprintln!(
"redox_installer_tui: failed to list '{}': {}",
scheme.display(),
err
);
}
}
}
}
}
const KIB: u64 = 1024;
const MIB: u64 = 1024 * KIB;
const GIB: u64 = 1024 * MIB;
const TIB: u64 = 1024 * GIB;
fn format_size(size: u64) -> String {
if size >= 4 * TIB {
format!("{:.1} TiB", size as f64 / TIB as f64)
} else if size >= GIB {
format!("{:.1} GiB", size as f64 / GIB as f64)
} else if size >= MIB {
format!("{:.1} MiB", size as f64 / MIB as f64)
} else if size >= KIB {
format!("{:.1} KiB", size as f64 / KIB as f64)
} else {
format!("{} B", size)
}
}
fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<()> {
if let Some(parent) = dest.parent() {
// Parent may be a symlink
if !parent.is_symlink() {
match fs::create_dir_all(&parent) {
Ok(()) => (),
Err(err) => {
bail!("failed to create directory {}: {}", parent.display(), err);
}
}
}
}
let metadata = match fs::symlink_metadata(&src) {
Ok(ok) => ok,
Err(err) => {
bail!("failed to read metadata of {}: {}", src.display(), err);
}
};
if metadata.file_type().is_symlink() {
let real_src = match fs::read_link(&src) {
Ok(ok) => ok,
Err(err) => {
bail!("failed to read link {}: {}", src.display(), err);
}
};
match symlink(&real_src, &dest) {
Ok(()) => (),
Err(err) => {
bail!(
"failed to copy link {} ({}) to {}: {}",
src.display(),
real_src.display(),
dest.display(),
err
);
}
}
} else {
let mut src_file = match fs::File::open(&src) {
Ok(ok) => ok,
Err(err) => {
bail!("failed to open file {}: {}", src.display(), err);
}
};
let mut dest_file = match fs::OpenOptions::new()
.write(true)
.create_new(true)
.mode(metadata.mode())
.open(&dest)
{
Ok(ok) => ok,
Err(err) => {
bail!("failed to create file {}: {}", dest.display(), err);
}
};
loop {
let count = match src_file.read(buf) {
Ok(ok) => ok,
Err(err) => {
bail!("failed to read file {}: {}", src.display(), err);
}
};
if count == 0 {
break;
}
match dest_file.write_all(&buf[..count]) {
Ok(()) => (),
Err(err) => {
bail!("failed to write file {}: {}", dest.display(), err);
}
}
}
}
Ok(())
}
fn package_files(
root_path: &Path,
config: &mut Config,
files: &mut Vec<String>,
) -> Result<(), anyhow::Error> {
//TODO: Remove packages from config where all files are located (and have valid shasum?)
config.packages.clear();
let pkey_path = "pkg/id_ed25519.pub.toml";
let pkey = PublicKeyFile::open(&root_path.join(pkey_path))?.pkey;
files.push(pkey_path.to_string());
for item_res in fs::read_dir(&root_path.join("pkg"))? {
let item = item_res?;
let pkg_path = item.path();
if pkg_path.extension() == Some(OsStr::new("pkgar_head")) {
let mut pkg = PackageHead::new(&pkg_path, &root_path, &pkey)?;
for entry in pkg.read_entries()? {
files.push(entry.check_path()?.to_str().unwrap().to_string());
}
files.push(
pkg_path
.strip_prefix(root_path)
.unwrap()
.to_str()
.unwrap()
.to_string(),
);
}
}
Ok(())
}
fn choose_disk() -> PathBuf {
let mut paths = Vec::new();
disk_paths(&mut paths);
loop {
for (i, (path, size)) in paths.iter().enumerate() {
eprintln!(
"\x1B[1m{}\x1B[0m: {}: {}",
i + 1,
path.display(),
format_size(*size)
);
}
if paths.is_empty() {
eprintln!("redox_installer_tui: no RedoxFS partition found");
eprintln!("redox_installer_tui: this tool is used to overwrite unmounted RedoxFS disk in Redox OS");
process::exit(1);
} else {
eprint!("Select a drive from 1 to {}: ", paths.len());
let mut line = String::new();
match io::stdin().read_line(&mut line) {
Ok(0) => {
eprintln!("redox_installer_tui: failed to read line: end of input");
process::exit(1);
}
Ok(_) => (),
Err(err) => {
eprintln!("redox_installer_tui: failed to read line: {}", err);
process::exit(1);
}
}
match line.trim().parse::<usize>() {
Ok(i) => {
if i >= 1 && i <= paths.len() {
break paths[i - 1].0.clone();
} else {
eprintln!("{} not from 1 to {}", i, paths.len());
}
}
Err(err) => {
eprintln!("invalid input: {}", err);
}
}
}
}
}
fn main() {
let root_path = Path::new("/");
let disk_path = choose_disk();
let Ok(password_opt) = redox_installer::prompt_password(
"redox_installer_tui: redoxfs password (empty for none)",
"redox_installer_tui: confirm password",
) else {
process::exit(1);
};
let instant = std::time::Instant::now();
let bootloader_bios = {
let path = root_path.join("usr/lib/boot/bootloader.bios");
if path.exists() {
match fs::read(&path) {
Ok(ok) => ok,
Err(err) => {
eprintln!(
"redox_installer_tui: {}: failed to read: {}",
path.display(),
err
);
process::exit(1);
}
}
} else {
Vec::new()
}
};
let bootloader_efi = {
let path = root_path.join("usr/lib/boot/bootloader.efi");
if path.exists() {
match fs::read(&path) {
Ok(ok) => ok,
Err(err) => {
eprintln!(
"redox_installer_tui: {}: failed to read: {}",
path.display(),
err
);
process::exit(1);
}
}
} else {
Vec::new()
}
};
let disk_option = DiskOption {
bootloader_bios: &bootloader_bios,
bootloader_efi: &bootloader_efi,
password_opt: password_opt.as_ref().map(|x| x.as_bytes()),
efi_partition_size: None,
skip_partitions: false, // TODO?
};
let res = with_whole_disk(&disk_path, &disk_option, |mut fs| {
// Fast install method via filesystem clone
let mut last_percent = 0;
if try_fast_install(&mut fs, move |used, used_old| {
let percent = (used * 100) / used_old;
if percent != last_percent {
eprint!(
"\r{}%: {} MB/{} MB",
percent,
used / 1000 / 1000,
used_old / 1000 / 1000
);
last_percent = percent;
}
})? {
eprintln!("\rfinished installing using fast mode");
return Ok(());
}
// Slow install method via file copy
with_redoxfs_mount(fs, None, |mount_path| {
let mut config: Config = Config::from_file(&root_path.join("filesystem.toml"))?;
// Copy filesystem.toml, which is not packaged
let mut files = vec!["filesystem.toml".to_string()];
// Copy files from locally installed packages
package_files(&root_path, &mut config, &mut files)
// TODO: implement Error trait
.map_err(|err| anyhow!("failed to read package files: {err}"))?;
// Perform config install (after packages have been converted to files)
eprintln!("configuring system");
let cookbook: Option<&'static str> = None;
redox_installer::install_dir(config, mount_path, cookbook)
.map_err(|err| io::Error::other(err))?;
// Sort and remove duplicates
files.sort();
files.dedup();
// Install files
let mut buf = vec![0; 4 * MIB as usize];
for (i, name) in files.iter().enumerate() {
eprintln!("copy {} [{}/{}]", name, i, files.len());
let src = root_path.join(name);
let dest = mount_path.join(name);
copy_file(&src, &dest, &mut buf)?;
}
eprintln!("finished installing, unmounting filesystem");
Ok(())
})
});
match res {
Ok(()) => {
eprintln!(
"redox_installer_tui: installed successfully in {:?}",
instant.elapsed()
);
process::exit(0);
}
Err(err) => {
eprintln!("redox_installer_tui: failed to install: {:?}", err);
process::exit(1);
}
}
}
+83
View File
@@ -0,0 +1,83 @@
use std::fmt::Display;
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct FileConfig {
pub path: String,
pub data: String,
#[serde(default)]
pub symlink: bool,
#[serde(default)]
pub directory: bool,
pub mode: Option<u32>,
pub uid: Option<u32>,
pub gid: Option<u32>,
#[serde(default)]
pub recursive_chown: bool,
#[serde(default)]
pub postinstall: bool,
}
impl FileConfig {
pub fn new_file(path: String, data: String) -> FileConfig {
FileConfig {
path,
data,
..Default::default()
}
}
pub fn new_directory(path: String) -> FileConfig {
FileConfig {
path,
data: String::new(),
directory: true,
..Default::default()
}
}
pub fn with_mod(&mut self, mode: u32, uid: u32, gid: u32) -> &mut FileConfig {
self.mode = Some(mode);
self.uid = Some(uid);
self.gid = Some(gid);
self
}
pub fn with_recursive_mod(&mut self, mode: u32, uid: u32, gid: u32) -> &mut FileConfig {
self.with_mod(mode, uid, gid);
self.recursive_chown = true;
self
}
}
impl Display for FileConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.path)?;
if self.symlink {
write!(f, " -> {}", self.data)?;
} else if self.directory {
write!(f, " type=dir")?;
if self.recursive_chown {
write!(f, " chown=yes")?;
}
} else {
write!(
f,
" size={}B",
arg_parser::to_human_readable_string(self.data.len() as u64)
)?;
if self.postinstall {
write!(f, "!")?;
}
}
if let Some(uid) = self.uid {
write!(f, " uid={}", uid)?;
}
if let Some(uid) = self.uid {
write!(f, " gid={}", uid)?;
}
if let Some(mode) = self.mode {
write!(f, " mode={:3o}", mode)?;
}
Ok(())
}
}
+88
View File
@@ -0,0 +1,88 @@
use anyhow::{Context, Result};
use libc::{gid_t, uid_t};
use std::ffi::{CString, OsStr};
use std::fs::{self, File};
use std::io::{Error, Write};
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::{symlink, PermissionsExt};
use std::path::Path;
fn chown<P: AsRef<Path>>(path: P, uid: uid_t, gid: gid_t, recursive: bool) -> Result<()> {
let path = path.as_ref();
let c_path = CString::new(path.as_os_str().as_bytes()).unwrap();
if unsafe { libc::chown(c_path.as_ptr(), uid, gid) } != 0 {
return Err(Error::last_os_error().into());
}
if recursive && path.is_dir() {
for entry_res in fs::read_dir(path)? {
let entry = entry_res?;
chown(entry.path(), uid, gid, recursive)?;
}
}
Ok(())
}
// TODO: Rewrite impls
impl crate::FileConfig {
pub(crate) fn create<P: AsRef<Path>>(&self, prefix: P) -> Result<()> {
let path = self.path.trim_start_matches('/');
let target_file = prefix.as_ref().join(path);
if self.directory {
println!("Create directory {}", target_file.display());
fs::create_dir_all(&target_file)
.with_context(|| format!("failed to create directory {}", target_file.display()))?;
self.apply_perms(&target_file)?;
return Ok(());
} else if let Some(parent) = target_file.parent() {
println!("Create file parent {}", parent.display());
fs::create_dir_all(parent)
.with_context(|| format!("failed to create file parent {}", parent.display()))?;
}
if self.symlink {
println!("Create symlink {} to {}", target_file.display(), self.data);
if target_file.is_symlink() {
fs::remove_file(&target_file).with_context(|| {
format!("failed to remove old symlink {}", target_file.display())
})?;
}
symlink(&OsStr::new(&self.data), &target_file).with_context(|| {
format!(
"failed to create symlink {} to {}",
target_file.display(),
self.data
)
})?;
Ok(())
} else {
println!("Create file {}", target_file.display());
let mut file = File::create(&target_file)
.with_context(|| format!("failed to create file {}", target_file.display()))?;
file.write_all(self.data.as_bytes())?;
self.apply_perms(target_file)
}
}
fn apply_perms<P: AsRef<Path>>(&self, target: P) -> Result<()> {
let path = target.as_ref();
let mode = self
.mode
.unwrap_or_else(|| if self.directory { 0o0755 } else { 0o0644 });
let uid = self.uid.unwrap_or(!0);
let gid = self.gid.unwrap_or(!0);
// chmod
fs::set_permissions(path, fs::Permissions::from_mode(mode))
.with_context(|| format!("failed to set permissions on {}", path.display()))?;
// chown
chown(path, uid, gid, self.recursive_chown)
.with_context(|| format!("failed to chown {}", path.display()))
}
}
+42
View File
@@ -0,0 +1,42 @@
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct GeneralConfig {
/// Specify a path where cookbook exists, all packages will be installed locally
pub cookbook: Option<String>,
/// Allow prompts for missing information such as user password
pub prompt: Option<bool>,
/// Total filesystem size in MB
pub filesystem_size: Option<u32>,
/// EFI partition size in MB, default to 2MB
pub efi_partition_size: Option<u32>,
/// Skip disk partitioning, assume whole disk is a partition
pub skip_partitions: Option<bool>,
/// Set a plain text password to encrypt the disk
pub encrypt_disk: Option<String>,
/// Use live disk for bootloader config, default is false
pub live_disk: Option<bool>,
/// If set, write bootloader disk into this path
pub write_bootloader: Option<String>,
/// Use AR to write files instead of FUSE-based mount
/// (bypasses FUSE, but slower and requires namespaced context such as "podman unshare")
pub no_mount: Option<bool>,
}
impl GeneralConfig {
/// Merge two config, "other" is more dominant
pub(super) fn merge(&mut self, other: GeneralConfig) {
if let Some(cookbook) = other.cookbook {
self.cookbook = Some(cookbook);
}
self.filesystem_size = other.filesystem_size.or(self.filesystem_size);
self.efi_partition_size = other.efi_partition_size.or(self.efi_partition_size);
self.skip_partitions = other.skip_partitions.or(self.skip_partitions);
if let Some(encrypt_disk) = other.encrypt_disk {
self.encrypt_disk = Some(encrypt_disk);
}
self.live_disk = other.live_disk.or(self.live_disk);
if let Some(write_bootloader) = other.write_bootloader {
self.write_bootloader = Some(write_bootloader);
}
self.no_mount = other.no_mount.or(self.no_mount);
}
}
+134
View File
@@ -0,0 +1,134 @@
use std::collections::BTreeMap;
use std::fmt::Display;
use std::fs;
use std::mem;
use std::path::{Path, PathBuf};
use anyhow::bail;
use anyhow::Context;
use anyhow::Result;
use crate::PackageConfig;
pub mod file;
#[cfg(feature = "installer")]
pub mod file_impl;
pub mod general;
pub mod package;
pub mod user;
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Config {
#[serde(default)]
pub include: Vec<PathBuf>,
#[serde(default)]
pub general: general::GeneralConfig,
#[serde(default)]
pub packages: BTreeMap<String, package::PackageConfig>,
#[serde(default)]
pub files: Vec<file::FileConfig>,
#[serde(default)]
pub users: BTreeMap<String, user::UserConfig>,
#[serde(default)]
pub groups: BTreeMap<String, user::GroupConfig>,
}
impl Config {
/// Load installer config from a TOML path
pub fn from_file(path: &Path) -> Result<Self> {
let mut config: Config = match fs::read_to_string(&path) {
Ok(config_data) => match toml::from_str(&config_data) {
Ok(config) => config,
Err(err) => {
bail!("failed to decode '{}': {}", path.display(), err);
}
},
Err(err) => {
bail!("failed to read '{}': {}", path.display(), err);
}
};
let config_dir = path.parent().unwrap();
let mut configs = mem::take(&mut config.include)
.into_iter()
.map(|path| {
Config::from_file(&config_dir.join(&path))
.with_context(|| format!("Importing from {}", path.display()))
})
.collect::<Result<Vec<Config>>>()?;
configs.push(config); // Put ourself last to ensure that it overwrites anything else.
config = configs.remove(0);
for other_config in configs {
config.merge(other_config);
}
Ok(config)
}
/// Load hardcoded install config to fetch bootloaders
pub fn bootloader_config() -> Self {
let mut bootloader_config = Config::default();
// TODO: This is unused
bootloader_config.files.push(file::FileConfig {
path: "/etc/pkg.d/50_redox".to_string(),
data: "https://static.redox-os.org/pkg".to_string(),
..Default::default()
});
bootloader_config
.packages
.insert("bootloader".to_string(), PackageConfig::default());
bootloader_config
}
pub fn merge(&mut self, other: Config) {
assert!(self.include.is_empty());
assert!(other.include.is_empty());
let Config {
include: _,
general: other_general,
packages: other_packages,
files: other_files,
users: other_users,
groups: other_groups,
} = other;
self.general.merge(other_general);
for (package, package_config) in other_packages {
self.packages.insert(package, package_config);
}
self.files.extend(other_files);
for (user, user_config) in other_users {
self.users.insert(user, user_config);
}
for (group, group_config) in other_groups {
self.groups.insert(group, group_config);
}
}
}
impl Display for Config {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "files:")?;
for file in &self.files {
writeln!(f, "- {}", file)?;
}
writeln!(f, "users:")?;
for (name, user) in &self.users {
writeln!(f, "- {}:{}", name, user)?;
}
write!(f, "packages: ")?;
for name in self.packages.keys() {
write!(f, " {}", name)?;
}
writeln!(f, "")?;
Ok(())
}
}
+19
View File
@@ -0,0 +1,19 @@
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum PackageConfig {
Empty,
Build(String),
// TODO: Sum type
Spec {
version: Option<String>,
git: Option<String>,
path: Option<String>,
},
}
impl Default for PackageConfig {
fn default() -> Self {
Self::Empty
}
}
+43
View File
@@ -0,0 +1,43 @@
use std::fmt::Display;
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct UserConfig {
pub password: Option<String>,
pub uid: Option<u32>,
pub gid: Option<u32>,
pub name: Option<String>,
pub home: Option<String>,
pub shell: Option<String>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct GroupConfig {
pub gid: Option<u32>,
// FIXME move this to the UserConfig struct as extra_groups
pub members: Vec<String>,
}
impl Display for UserConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(uid) = &self.uid {
write!(f, " uid={}", uid)?;
}
if let Some(gid) = &self.gid {
write!(f, " gid={}", gid)?;
}
if let Some(name) = &self.name {
write!(f, " name={}", name)?;
}
if let Some(home) = &self.home {
write!(f, " home={}", home)?;
}
if let Some(shell) = &self.shell {
write!(f, " shell={}", shell)?;
}
if self.password.as_ref().is_some_and(|s| !s.is_empty()) {
write!(f, " password=yes")?;
}
Ok(())
}
}
+127
View File
@@ -0,0 +1,127 @@
use std::{
cmp,
convert::TryInto,
fs::{File, OpenOptions},
io::{Read, Result, Seek, SeekFrom, Write},
path::Path,
};
#[derive(Debug)]
pub struct DiskWrapper {
disk: File,
size: u64,
block: Box<[u8]>,
seek: u64,
}
enum Buffer<'a> {
Read(&'a mut [u8]),
Write(&'a [u8]),
}
impl DiskWrapper {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
let disk = OpenOptions::new().read(true).write(true).open(path)?;
let metadata = disk.metadata()?;
let size = metadata.len();
// TODO: get real block size: disk_metadata.blksize() works on disks but not image files
let block_size = 512;
let block = vec![0u8; block_size].into_boxed_slice();
Ok(Self {
disk,
size,
block,
seek: 0,
})
}
pub fn block_size(&self) -> usize {
self.block.len()
}
pub fn size(&self) -> u64 {
self.size
}
fn io<'a>(&mut self, buf: &mut Buffer<'a>) -> Result<usize> {
let buf_len = match buf {
Buffer::Read(read) => read.len(),
Buffer::Write(write) => write.len(),
};
let block_len: u64 = self.block.len().try_into().unwrap();
// Do aligned I/O quickly
if self.seek % block_len == 0 && buf_len as u64 % block_len == 0 {
self.disk.seek(SeekFrom::Start(self.seek))?;
match buf {
Buffer::Read(read) => self.disk.read_exact(read)?,
Buffer::Write(write) => self.disk.write_all(write)?,
}
self.seek = self.seek.checked_add(buf_len.try_into().unwrap()).unwrap();
return Ok(buf_len);
}
let mut i = 0;
while i < buf_len {
let block = self.seek / block_len;
let offset: usize = (self.seek % block_len).try_into().unwrap();
let remaining = buf_len.checked_sub(i).unwrap();
let len = cmp::min(remaining, self.block.len().checked_sub(offset).unwrap());
self.disk
.seek(SeekFrom::Start(block.checked_mul(block_len).unwrap()))?;
self.disk.read_exact(&mut self.block)?;
match buf {
Buffer::Read(read) => {
read[i..i.checked_add(len).unwrap()]
.copy_from_slice(&self.block[offset..offset.checked_add(len).unwrap()]);
}
Buffer::Write(write) => {
self.block[offset..offset.checked_add(len).unwrap()]
.copy_from_slice(&write[i..i.checked_add(len).unwrap()]);
self.disk
.seek(SeekFrom::Start(block.checked_mul(block_len).unwrap()))?;
self.disk.write_all(&mut self.block)?;
}
}
i = i.checked_add(len).unwrap();
self.seek = self.seek.checked_add(len.try_into().unwrap()).unwrap();
}
Ok(i)
}
}
impl Read for DiskWrapper {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
self.io(&mut Buffer::Read(buf))
}
}
impl Seek for DiskWrapper {
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
let current: i64 = self.seek.try_into().unwrap();
let end: i64 = self.size.try_into().unwrap();
self.seek = match pos {
SeekFrom::Start(offset) => cmp::min(self.size, offset),
SeekFrom::End(offset) => cmp::max(0, cmp::min(end, end.wrapping_add(offset))) as u64,
SeekFrom::Current(offset) => {
cmp::max(0, cmp::min(end, current.wrapping_add(offset))) as u64
}
};
Ok(self.seek)
}
}
impl Write for DiskWrapper {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.io(&mut Buffer::Write(buf))
}
fn flush(&mut self) -> Result<()> {
self.disk.flush()
}
}
+855
View File
@@ -0,0 +1,855 @@
use anyhow::Context;
use anyhow::{bail, Result};
use pkg::Library;
use rand::{rngs::OsRng, TryRngCore};
use redoxfs::{unmount_path, Disk, DiskIo, FileSystem, BLOCK_SIZE};
use termion::input::TermRead;
use crate::config::file::FileConfig;
use crate::config::package::PackageConfig;
use crate::config::Config;
use crate::disk_wrapper::DiskWrapper;
use std::{
cell::RefCell,
collections::BTreeMap,
env, fs,
io::{self, Seek, SeekFrom, Write},
path::{Path, PathBuf},
process,
rc::Rc,
sync::mpsc::channel,
thread,
time::{SystemTime, UNIX_EPOCH},
};
pub struct DiskOption<'a> {
pub bootloader_bios: &'a [u8],
pub bootloader_efi: &'a [u8],
pub password_opt: Option<&'a [u8]>,
pub efi_partition_size: Option<u32>, //MiB
pub skip_partitions: bool,
}
fn get_target() -> String {
// TODO: Configurable from filesystem config?
env::var("TARGET").unwrap_or(
option_env!("TARGET").map_or("x86_64-unknown-redox".to_string(), |x| x.to_string()),
)
}
/// Converts a password to a serialized argon2rs hash, understandable
/// by redox_users. If the password is blank, the hash is blank.
fn hash_password(password: &str) -> Result<String> {
if !password.is_empty() {
let salt = format!("{:X}", OsRng.try_next_u64()?);
let config = argon2::Config::default();
let hash = argon2::hash_encoded(password.as_bytes(), salt.as_bytes(), &config)?;
Ok(hash)
} else {
Ok("".into())
}
}
fn syscall_error(err: syscall::Error) -> io::Error {
io::Error::from_raw_os_error(err.errno)
}
/// Returns a password collected from the user (plaintext)
pub fn prompt_password(prompt: &str, confirm_prompt: &str) -> Result<Option<String>> {
let stdin = io::stdin();
let mut stdin = stdin.lock();
let stdout = io::stdout();
let mut stdout = stdout.lock();
for i in 0..3 {
print!("{}", prompt);
let mut password = stdin.read_passwd(&mut stdout)?;
if let Some(password) = password.as_mut() {
*password = password.trim().to_string();
}
password.take_if(|s| s.is_empty());
if password.is_none() {
return Ok(None);
}
print!("\n{}", confirm_prompt);
let confirm_password = stdin.read_passwd(&mut stdout)?;
// Note: Actually comparing two Option<String> values
if confirm_password == password {
return Ok(password);
} else if i < 2 {
eprintln!("passwords do not match, please try again");
}
}
bail!("passwords do not match, giving up");
}
fn install_packages(config: &Config, dest: &Path, cookbook: Option<&str>) -> anyhow::Result<()> {
let target = &get_target();
let packages: Vec<&String> = config
.packages
.iter()
.filter_map(|(packagename, package)| match package {
PackageConfig::Build(rule) if rule == "ignore" => None,
_ => Some(packagename),
})
.collect();
let mut library = if let Some(cookbook) = cookbook {
let callback = pkg::callback::PlainCallback::new();
let repo = Path::new(cookbook).join("repo");
let pubkey = Path::new(cookbook).join("build");
Library::new_local(
repo,
pubkey,
dest.to_path_buf(),
target,
Rc::new(RefCell::new(callback)),
)
} else {
let callback = pkg::callback::IndicatifCallback::new();
Library::new_remote(
&vec!["https://static.redox-os.org/pkg"],
dest,
target,
Rc::new(RefCell::new(callback)),
)
}?;
let packages = pkg::PackageName::from_list(packages)?;
library.install(packages)?;
library.apply()?;
Ok(())
}
pub fn install_dir(
config: Config,
output_dir: impl AsRef<Path>,
cookbook: Option<&str>,
) -> Result<()> {
let output_dir = output_dir.as_ref();
let output_dir = output_dir.to_owned();
for file in &config.files {
if !file.postinstall {
file.create(&output_dir)?;
}
}
install_packages(&config, &output_dir, cookbook)?;
for file in &config.files {
if file.postinstall {
file.create(&output_dir)?;
}
}
let mut passwd = String::new();
let mut shadow = String::new();
let mut next_uid = 1000;
let mut next_gid = 1000;
let mut groups = vec![];
for (username, user) in config.users {
// plaintext
let password = if let Some(password) = user.password {
password
} else if config.general.prompt.unwrap_or(true) {
prompt_password(
&format!("{}: enter password: ", username),
&format!("{}: confirm password: ", username),
)?
.unwrap_or_default()
} else {
String::new()
};
let uid = user.uid.unwrap_or(next_uid);
if uid >= next_uid {
next_uid = uid + 1;
}
let gid = user.gid.unwrap_or(next_gid);
if gid >= next_gid {
next_gid = gid + 1;
}
let name = user.name.unwrap_or(username.clone());
let home = user.home.unwrap_or(format!("/home/{}", username));
let shell = user.shell.unwrap_or("/bin/ion".into());
println!("Adding user {username}:");
if password.is_empty() {
println!("\tPassword: unset");
} else {
println!("\tPassword: set");
}
println!("\tUID: {uid}");
println!("\tGID: {gid}");
println!("\tName: {name}");
println!("\tHome: {home}");
println!("\tShell: {shell}");
FileConfig::new_directory(home.clone())
.with_recursive_mod(0o700, uid, gid)
.create(&output_dir)?;
if uid >= 1000 {
prepare_user_home(&output_dir, uid, gid, &home)?;
}
let password = hash_password(&password)?;
passwd.push_str(&format!("{username};{uid};{gid};{name};{home};{shell}\n",));
shadow.push_str(&format!("{username};{password}\n"));
groups.push((username.clone(), gid, vec![username]));
}
for (group, group_config) in config.groups {
// FIXME this assumes there is no overlap between auto-created groups for users
// and explicitly specified groups.
let gid = group_config.gid.unwrap_or(next_gid);
if gid >= next_gid {
next_gid = gid + 1;
}
groups.push((group, gid, group_config.members));
}
if !passwd.is_empty() {
FileConfig::new_file("/etc/passwd".to_string(), passwd).create(&output_dir)?;
}
if !shadow.is_empty() {
FileConfig::new_file("/etc/shadow".to_string(), shadow)
.with_mod(0o0600, 0, 0)
.create(&output_dir)?;
}
if !groups.is_empty() {
let mut groups_data = String::new();
for (name, gid, members) in groups {
use std::fmt::Write;
writeln!(groups_data, "{name};x;{gid};{}", members.join(","))?;
println!("Adding group {name}:");
println!("\tGID: {gid}");
println!("\tMembers: {}", members.join(", "));
}
FileConfig::new_file("/etc/group".to_string(), groups_data)
.with_mod(0o0600, 0, 0)
.create(&output_dir)?;
}
Ok(())
}
fn prepare_user_home(
output_dir: &PathBuf,
uid: u32,
gid: u32,
home: &String,
) -> Result<(), anyhow::Error> {
for xdg_folder in &[
"Desktop",
"Documents",
"Downloads",
"Music",
"Pictures",
"Public",
"Templates",
"Videos",
".config",
".local",
".local/share",
".local/share/Trash",
".local/share/Trash/info",
] {
FileConfig::new_directory(format!("{}/{}", home, xdg_folder))
.with_mod(0o0700, uid, gid)
.create(output_dir)?;
}
FileConfig::new_file(
format!("{}/.config/user-dirs.dirs", home),
r#"# Produced by redox installer
XDG_DESKTOP_DIR="$HOME/Desktop"
XDG_DOCUMENTS_DIR="$HOME/Documents"
XDG_DOWNLOAD_DIR="$HOME/Downloads"
XDG_MUSIC_DIR="$HOME/Music"
XDG_PICTURES_DIR="$HOME/Pictures"
XDG_PUBLICSHARE_DIR="$HOME/Public"
XDG_TEMPLATES_DIR="$HOME/Templates"
XDG_VIDEOS_DIR="$HOME/Videos"
"#
.to_string(),
)
.with_mod(0o0600, uid, gid)
.create(output_dir)?;
let skel_dir = output_dir.join("etc/skel");
if skel_dir.is_dir() {
copy_dir_all(&skel_dir, home.clone(), output_dir, uid, gid)?;
}
Ok(())
}
fn copy_dir_all(
src: impl AsRef<Path>,
dst: String,
output_dir: &Path,
uid: u32,
gid: u32,
) -> anyhow::Result<()> {
if !Path::new(dst.as_str()).is_dir() {
FileConfig::new_directory(dst.clone())
.with_mod(0o0700, uid, gid)
.create(&output_dir)?;
}
for entry in fs::read_dir(src)? {
let entry = entry?;
let file_type = entry.file_type()?;
let dst_path = format!("{}/{}", dst, entry.file_name().display());
if file_type.is_dir() {
copy_dir_all(entry.path(), dst_path, output_dir, uid, gid)?;
} else if file_type.is_file() {
FileConfig::new_file(
dst_path,
fs::read_to_string(entry.path())
.with_context(|| format!("Reading {}", entry.path().display()))?,
)
.with_mod(0o0600, uid, gid)
.create(&output_dir)?;
} else if file_type.is_symlink() {
// TODO
}
}
Ok(())
}
pub fn with_redoxfs<D, T, F>(disk: D, password_opt: Option<&[u8]>, callback: F) -> Result<T>
where
D: Disk + Send + 'static,
F: FnOnce(FileSystem<D>) -> Result<T>,
{
let ctime = SystemTime::now().duration_since(UNIX_EPOCH)?;
let fs = FileSystem::create(disk, password_opt, ctime.as_secs(), ctime.subsec_nanos())
.map_err(syscall_error)?;
callback(fs)
}
fn decide_mount_path(mount_path: Option<&Path>) -> PathBuf {
let mount_path = mount_path.map(|p| p.to_path_buf()).unwrap_or_else(|| {
PathBuf::from(if cfg!(target_os = "redox") {
format!("file.redox_installer_{}", process::id())
} else {
format!("/tmp/redox_installer_{}", process::id())
})
});
mount_path
}
pub fn with_redoxfs_mount<D, T, F>(
fs: FileSystem<D>,
mount_path: Option<&Path>,
callback: F,
) -> Result<T>
where
D: Disk + Send + 'static,
F: FnOnce(&Path) -> Result<T>,
{
let mount_path = decide_mount_path(mount_path);
if cfg!(not(target_os = "redox")) && !mount_path.exists() {
fs::create_dir(&mount_path)?;
}
let (tx, rx) = channel();
let join_handle = {
let mount_path = mount_path.clone();
thread::spawn(move || {
let res = redoxfs::mount(fs, &mount_path, |real_path| {
tx.send(Ok(real_path.to_owned())).unwrap();
});
match res {
Ok(()) => (),
Err(err) => {
tx.send(Err(err)).unwrap();
}
};
})
};
let res = match rx.recv() {
Ok(ok) => match ok {
Ok(real_path) => callback(&real_path),
Err(err) => return Err(err.into()),
},
Err(_) => {
return Err(io::Error::new(
io::ErrorKind::NotConnected,
"redoxfs thread did not send a result",
)
.into())
}
};
unmount_path(&mount_path.as_os_str().to_str().unwrap())?;
join_handle.join().unwrap();
if cfg!(not(target_os = "redox")) {
fs::remove_dir_all(&mount_path)?;
}
res
}
pub fn with_redoxfs_ar<D, T, F>(
mut fs: FileSystem<D>,
mount_path: Option<&Path>,
callback: F,
) -> Result<T>
where
D: Disk + Send + 'static,
F: FnOnce(&Path) -> Result<T>,
{
let mount_path = decide_mount_path(mount_path);
let res = callback(Path::new(&mount_path));
if res.is_ok() {
let _end_block = fs
.tx(|tx| {
// Archive_at root node
redoxfs::archive_at(tx, Path::new(&mount_path), redoxfs::TreePtr::root())
.map_err(|err| syscall::Error::new(err.raw_os_error().unwrap()))?;
// Squash alloc log
tx.sync(true)?;
let end_block = tx.header.size() / BLOCK_SIZE;
/* TODO: Cut off any free blocks at the end of the filesystem
let mut end_changed = true;
while end_changed {
end_changed = false;
let allocator = fs.allocator();
let levels = allocator.levels();
for level in 0..levels.len() {
let level_size = 1 << level;
for &block in levels[level].iter() {
if block < end_block && block + level_size >= end_block {
end_block = block;
end_changed = true;
}
}
}
}
*/
// Update header
tx.header.size = (end_block * BLOCK_SIZE).into();
tx.header_changed = true;
tx.sync(false)?;
Ok(end_block)
})
.map_err(syscall_error)?;
// let size = (fs.block + end_block) * BLOCK_SIZE;
// fs.disk.file.set_len(size)?;
}
fs::remove_dir_all(&mount_path)?;
res
}
pub fn fetch_bootloaders(
config: &Config,
cookbook: Option<&str>,
live: bool,
) -> Result<(Vec<u8>, Vec<u8>)> {
let bootloader_dir =
PathBuf::from(format!("/tmp/redox_installer_bootloader_{}", process::id()));
if bootloader_dir.exists() {
fs::remove_dir_all(&bootloader_dir)?;
}
fs::create_dir(&bootloader_dir)?;
let mut bootloader_config = Config::bootloader_config();
bootloader_config.general = config.general.clone();
install_packages(&bootloader_config, &bootloader_dir, cookbook)?;
let boot_dir = bootloader_dir.join("usr/lib/boot");
let bios_path = boot_dir.join(if live {
"bootloader-live.bios"
} else {
"bootloader.bios"
});
let efi_path = boot_dir.join(if live {
"bootloader-live.efi"
} else {
"bootloader.efi"
});
let bios_data = if bios_path.exists() {
fs::read(bios_path)?
} else {
Vec::new()
};
let efi_data = if efi_path.exists() {
fs::read(efi_path)?
} else {
Vec::new()
};
fs::remove_dir_all(&bootloader_dir)?;
Ok((bios_data, efi_data))
}
//TODO: make bootloaders use Option, dynamically create BIOS and EFI partitions
pub fn with_whole_disk<P, F, T>(disk_path: P, disk_option: &DiskOption, callback: F) -> Result<T>
where
P: AsRef<Path>,
F: FnOnce(FileSystem<DiskIo<fscommon::StreamSlice<DiskWrapper>>>) -> Result<T>,
{
let target = get_target();
let bootloader_efi_name = match target.as_str() {
"aarch64-unknown-redox" => "BOOTAA64.EFI",
"i586-unknown-redox" | "i686-unknown-redox" => "BOOTIA32.EFI",
"x86_64-unknown-redox" => "BOOTX64.EFI",
"riscv64gc-unknown-redox" => "BOOTRISCV64.EFI",
_ => {
bail!("target '{target}' not supported");
}
};
// Open disk and read metadata
eprintln!("Opening disk {}", disk_path.as_ref().display());
let mut disk_file = DiskWrapper::open(disk_path.as_ref())?;
let disk_size = disk_file.size();
let block_size = disk_file.block_size() as u64;
if disk_option.skip_partitions {
return with_redoxfs(
DiskIo(fscommon::StreamSlice::new(
disk_file,
0,
disk_size.next_multiple_of(block_size),
)?),
disk_option.password_opt,
callback,
);
}
let gpt_block_size = match block_size {
512 => gpt::disk::LogicalBlockSize::Lb512,
_ => {
// TODO: support (and test) other block sizes
bail!("block size {block_size} not supported");
}
};
// Calculate partition offsets
let gpt_reserved = 34 * 512; // GPT always reserves 34 512-byte sectors
let mibi = 1024 * 1024;
// First megabyte of the disk is reserved for BIOS partition, wich includes GPT tables
let bios_start = gpt_reserved / block_size;
let bios_end = (mibi / block_size) - 1;
// Second megabyte of the disk is reserved for EFI partition
let efi_start = bios_end + 1;
let efi_size = if let Some(size) = disk_option.efi_partition_size {
size as u64
} else {
1
};
let efi_end = efi_start + (efi_size * mibi / block_size) - 1;
// The rest of the disk is RedoxFS, reserving the GPT table mirror at the end of disk
let redoxfs_start = efi_end + 1;
let redoxfs_end = ((((disk_size - gpt_reserved) / mibi) * mibi) / block_size) - 1;
// Format and install BIOS partition
{
// Write BIOS bootloader to disk
eprintln!(
"Write bootloader with size {:#x}",
disk_option.bootloader_bios.len()
);
disk_file.seek(SeekFrom::Start(0))?;
disk_file.write_all(&disk_option.bootloader_bios)?;
// Replace MBR tables with protective MBR
// TODO: div_ceil
let mbr_blocks = ((disk_size + block_size - 1) / block_size) - 1;
eprintln!("Writing protective MBR with disk blocks {mbr_blocks:#x}");
gpt::mbr::ProtectiveMBR::with_lb_size(mbr_blocks as u32)
.update_conservative(&mut disk_file)?;
// Open disk, mark it as not initialized
let mut gpt_disk = gpt::GptConfig::new()
.initialized(false)
.writable(true)
.logical_block_size(gpt_block_size)
.create_from_device(Box::new(&mut disk_file), None)?;
// Add BIOS boot partition
let mut partitions = BTreeMap::new();
let mut partition_id = 1;
partitions.insert(
partition_id,
gpt::partition::Partition {
part_type_guid: gpt::partition_types::BIOS,
part_guid: uuid::Uuid::new_v4(),
first_lba: bios_start,
last_lba: bios_end,
flags: 0, // TODO
name: "BIOS".to_string(),
},
);
partition_id += 1;
// Add EFI boot partition
partitions.insert(
partition_id,
gpt::partition::Partition {
part_type_guid: gpt::partition_types::EFI,
part_guid: uuid::Uuid::new_v4(),
first_lba: efi_start,
last_lba: efi_end,
flags: 0, // TODO
name: "EFI".to_string(),
},
);
partition_id += 1;
// Add RedoxFS partition
partitions.insert(
partition_id,
gpt::partition::Partition {
//TODO: Use REDOX_REDOXFS type (needs GPT crate changes)
part_type_guid: gpt::partition_types::LINUX_FS,
part_guid: uuid::Uuid::new_v4(),
first_lba: redoxfs_start,
last_lba: redoxfs_end,
flags: 0,
name: "REDOX".to_string(),
},
);
eprintln!("Writing GPT tables: {partitions:#?}");
// Initialize GPT table
gpt_disk.update_partitions(partitions)?;
// Write partition layout, returning disk file
gpt_disk.write()?;
}
// Format and install EFI partition
{
let disk_efi_start = efi_start * block_size;
let disk_efi_end = (efi_end + 1) * block_size;
let mut disk_efi =
fscommon::StreamSlice::new(&mut disk_file, disk_efi_start, disk_efi_end)?;
eprintln!(
"Formatting EFI partition with size {:#x}",
disk_efi_end - disk_efi_start
);
fatfs::format_volume(&mut disk_efi, fatfs::FormatVolumeOptions::new())?;
eprintln!("Opening EFI partition");
let fs = fatfs::FileSystem::new(&mut disk_efi, fatfs::FsOptions::new())?;
eprintln!("Creating EFI directory");
let root_dir = fs.root_dir();
root_dir.create_dir("EFI")?;
eprintln!("Creating EFI/BOOT directory");
let efi_dir = root_dir.open_dir("EFI")?;
efi_dir.create_dir("BOOT")?;
eprintln!(
"Writing EFI/BOOT/{} file with size {:#x}",
bootloader_efi_name,
disk_option.bootloader_efi.len()
);
let boot_dir = efi_dir.open_dir("BOOT")?;
let mut file = boot_dir.create_file(bootloader_efi_name)?;
file.truncate()?;
file.write_all(&disk_option.bootloader_efi)?;
}
// Format and install RedoxFS partition
eprintln!(
"Installing to RedoxFS partition with size {:#x}",
(redoxfs_end - redoxfs_start) * block_size
);
let disk_redoxfs = DiskIo(fscommon::StreamSlice::new(
disk_file,
redoxfs_start * block_size,
(redoxfs_end + 1) * block_size,
)?);
with_redoxfs(disk_redoxfs, disk_option.password_opt, callback)
}
#[cfg(not(target_os = "redox"))]
pub fn try_fast_install<D: redoxfs::Disk, F: FnMut(u64, u64)>(
_fs: &mut redoxfs::FileSystem<D>,
_progress: F,
) -> Result<bool> {
Ok(false)
}
/// Try fast install using live disk memory
#[cfg(target_os = "redox")]
pub fn try_fast_install<D: redoxfs::Disk, F: FnMut(u64, u64)>(
fs: &mut redoxfs::FileSystem<D>,
mut progress: F,
) -> Result<bool> {
use libredox::{call::MmapArgs, flag};
use std::os::fd::AsRawFd;
use syscall::PAGE_SIZE;
let phys = env::var("DISK_LIVE_ADDR")
.ok()
.and_then(|x| usize::from_str_radix(&x, 16).ok())
.unwrap_or(0);
let size = env::var("DISK_LIVE_SIZE")
.ok()
.and_then(|x| usize::from_str_radix(&x, 16).ok())
.unwrap_or(0);
if phys == 0 || size == 0 {
return Ok(false);
}
let start = (phys / PAGE_SIZE) * PAGE_SIZE;
let end = phys
.checked_add(size)
.context("phys + size overflow")?
.next_multiple_of(PAGE_SIZE);
let size = end - start;
let original = unsafe {
//TODO: unmap this memory
let file = fs::File::open("/scheme/memory/physical")?;
let base = libredox::call::mmap(MmapArgs {
fd: file.as_raw_fd() as usize,
addr: core::ptr::null_mut(),
offset: start as u64,
length: size,
prot: flag::PROT_READ,
flags: flag::MAP_SHARED,
})
.map_err(|err| anyhow::anyhow!("failed to mmap livedisk: {}", err))?;
std::slice::from_raw_parts(base as *const u8, size)
};
struct DiskLive {
original: &'static [u8],
}
impl redoxfs::Disk for DiskLive {
unsafe fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result<usize> {
let offset = (block * redoxfs::BLOCK_SIZE) as usize;
if offset + buffer.len() > self.original.len() {
return Err(syscall::Error::new(syscall::EINVAL));
}
buffer.copy_from_slice(&self.original[offset..offset + buffer.len()]);
Ok(buffer.len())
}
unsafe fn write_at(&mut self, _block: u64, _buffer: &[u8]) -> syscall::Result<usize> {
Err(syscall::Error::new(syscall::EINVAL))
}
fn size(&mut self) -> syscall::Result<u64> {
Ok(self.original.len() as u64)
}
}
let mut fs_old = redoxfs::FileSystem::open(DiskLive { original }, None, None, false)?;
let size_old = fs_old.header.size();
let free_old = fs_old.allocator().free() * redoxfs::BLOCK_SIZE;
let used_old = size_old - free_old;
redoxfs::clone(&mut fs_old, fs, move |used| {
progress(used, used_old);
})?;
Ok(true)
}
fn install_inner(config: Config, output: &Path) -> Result<()> {
println!("Installing to {}:\n{}", output.display(), config);
let cookbook = config.general.cookbook.clone();
let cookbook = cookbook.as_ref().map(|p| p.as_str());
if output.is_dir() {
install_dir(config, output, cookbook)
} else {
if !output.is_file() {
let fs_size = config.general.filesystem_size.unwrap_or(0) as u64;
// arbitrary size approximately fit just for initfs
if fs_size < 32 {
bail!("Refusing to create image disk less than 32 MB");
}
eprintln!(
"Creating a new file to {} with size {} MB",
output.display(),
fs_size
);
let file = fs::File::create(output)?;
file.set_len(fs_size * 1024 * 1024)?;
}
let live = config.general.live_disk.unwrap_or(false);
let password_opt = config.general.encrypt_disk.clone();
let password_opt = password_opt.as_ref().map(|p| p.as_bytes());
let (bootloader_bios, bootloader_efi) = fetch_bootloaders(&config, cookbook, live)?;
if let Some(write_bootloader) = &config.general.write_bootloader {
std::fs::write(write_bootloader, &bootloader_efi)?;
}
let disk_option = DiskOption {
bootloader_bios: &bootloader_bios,
bootloader_efi: &bootloader_efi,
password_opt: password_opt,
efi_partition_size: config.general.efi_partition_size,
skip_partitions: config.general.skip_partitions.unwrap_or(false),
};
with_whole_disk(output, &disk_option, move |fs| {
if config.general.no_mount.unwrap_or(false) {
with_redoxfs_ar(fs, None, move |mount_path| {
install_dir(config, mount_path, cookbook)
})
} else {
with_redoxfs_mount(fs, None, move |mount_path| {
install_dir(config, mount_path, cookbook)
})
}
})
}
}
/// Install RedoxFS into a new disk file, or a sysroot directory.
/// This function assumes all interactive prompts resolved by the caller.
pub fn install(config: Config, output: impl AsRef<Path>) -> Result<()> {
install_inner(config, output.as_ref())
}
+14 -1143
View File
File diff suppressed because it is too large Load Diff
Executable
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
IMAGE=test.bin
QEMU_ARGS=(
-cpu max
-machine q35
-m 2048
-smp 4
-serial mon:stdio
-netdev user,id=net0
-device e1000,netdev=net0
)
if [ -e /dev/kvm ]
then
QEMU_ARGS+=(-accel kvm)
fi
set -ex
cargo build --release
rm -f "${IMAGE}"
fallocate -l 1GiB "${IMAGE}"
target/release/redox_installer -c res/test.toml "${IMAGE}"
qemu-system-x86_64 "${QEMU_ARGS[@]}" -drive "file=${IMAGE},format=raw"