commit dc45472bcc2d12ae851437912c602b9847b70b6b Author: Sergiotarxz Date: Sun Oct 1 00:09:58 2023 +0200 Initial commit. diff --git a/generate_system.pl b/generate_system.pl new file mode 100644 index 0000000..ee84325 --- /dev/null +++ b/generate_system.pl @@ -0,0 +1,80 @@ +#!/usr/bin/env perl + +use v5.36.0; + +use strict; +use warnings; +use utf8; +use GnuPG; + +use Path::Tiny; +use Mojo::UserAgent; + +my $target_dir = shift @ARGV or die 'No target dir passed.'; + +my $gpg_temp_dir = Path::Tiny::tempdir; +my $gpg_bin = 'gpg'; +my @args = ( '--command-fd', '0', '--homedir', $gpg_temp_dir ); + +my $gentoo_pk_id = '13EBBDBEDE7A12775DFDB1BABB572E0E2D182910'; +my $stage_destination = path('stage.tar.xz'); +my $stage_destination_asc = path($stage_destination . '.asc'); + +_doNothingIfTargetDirExists($target_dir); +_fetchKey($gentoo_pk_id); +_trustKey($gentoo_pk_id); +_downloadGentooStage($stage_destination, $stage_destination_asc); +_verifyStage($stage_destination_asc); +_extractStageIntoTarget($target_dir, $stage_destination); + +sub _extractStageIntoTarget($target, $stage) { + system 'mkdir', $target; + system 'sudo', 'tar', '-xpvf', $stage, '-C', $target, '--numeric-owner', q/--xattrs-include='*.*'/; +} + +sub _doNothingIfTargetDirExists($target) { + if (-e $target) { + die "$target exists, doing nothing."; + } +} + +sub _verifyStage($stage_asc) { + my $return_code = system $gpg_bin, @args, '--verify', $stage_asc; + if ($return_code != 0) { + die 'Signature is not valid, maybe someone is trying to eavesdrop your connection?'; + } +} + +sub _downloadGentooStage($stage, $stage_asc) { + if (-e $stage && -e $stage_asc) { + return; + } + my $ua = Mojo::UserAgent->new; + my $dom = $ua->get('https://www.gentoo.org/downloads/')->result->dom; + for my $h4 ($dom->find('h4')->each) { + next if $h4->text !~ /Stage/; + my @next_list_groups = $h4->following('div.list-group')->each; + my $url = $next_list_groups[0]->at('a')->attr('href'); + $stage->spew_raw($ua->get($url)->result->body); + $stage_asc->spew_raw($ua->get($url . '.asc')->result->body); + last; + } +} + +sub _fetchKey ($key) { + my $return_code = system $gpg_bin, @args, '--recv-keys', $key; + if ( $return_code != 0 ) { + die 'Unable to fetch gentoo gpg key.'; + } +} + +sub _trustKey ($key) { + open( my $fh, '|-', $gpg_bin, @args, '--edit-key', $key, 'trust' ); + say $fh 5; + say $fh 'y'; + close $fh; + my $return_code = $?; + if ( $return_code != 0 ) { + die 'Unable to trust gentoo gpg key.'; + } +} diff --git a/gentoo.conf b/gentoo.conf new file mode 100644 index 0000000..6cb6e3b --- /dev/null +++ b/gentoo.conf @@ -0,0 +1,19 @@ +[DEFAULT] +main-repo = gentoo + +[gentoo] +location = /var/db/repos/gentoo +sync-type = rsync +sync-uri = rsync://rsync.gentoo.org/gentoo-portage +auto-sync = yes +sync-rsync-verify-jobs = 1 +sync-rsync-verify-metamanifest = yes +sync-rsync-verify-max-age = 24 +sync-openpgp-key-path = /usr/share/openpgp-keys/gentoo-release.asc +sync-openpgp-keyserver = hkps://keys.gentoo.org +sync-openpgp-key-refresh-retry-count = 40 +sync-openpgp-key-refresh-retry-overall-timeout = 1200 +sync-openpgp-key-refresh-retry-delay-exp-base = 2 +sync-openpgp-key-refresh-retry-delay-max = 60 +sync-openpgp-key-refresh-retry-delay-mult = 4 +sync-webrsync-verify-signature = yes diff --git a/make.conf b/make.conf new file mode 100644 index 0000000..eebc809 --- /dev/null +++ b/make.conf @@ -0,0 +1,17 @@ +# These settings were set by the catalyst build script that automatically +# built this stage. +# Please consult /usr/share/portage/config/make.conf.example for a more +# detailed example. +COMMON_FLAGS="-O2 -pipe" +CFLAGS="${COMMON_FLAGS}" +CXXFLAGS="${COMMON_FLAGS}" +FCFLAGS="${COMMON_FLAGS}" +FFLAGS="${COMMON_FLAGS}" +MAKEOPTS="-j12" +FEATURES="buildpkg" + +# NOTE: This stage was built with the bindist Use flag enabled + +# This sets the language of build output to English. +# Please keep this setting intact when reporting bugs. +LC_MESSAGES=C.utf8 diff --git a/packages b/packages new file mode 100644 index 0000000..0ec7197 --- /dev/null +++ b/packages @@ -0,0 +1,5 @@ +vim +app-misc/screen +sudo +nginx +certbot diff --git a/prepare_system.pl b/prepare_system.pl new file mode 100644 index 0000000..40d4fbf --- /dev/null +++ b/prepare_system.pl @@ -0,0 +1,205 @@ +#!/usr/bin/env perl + +use v5.36.0; + +use strict; +use warnings; +use utf8; + +use Path::Tiny; + +main(); + +sub main { + die 'Must be superuser.' if $< != 0; + my $target_dir = shift @ARGV or die 'No target dir passed.'; + my $rebuild_bin = shift @ARGV // 0; + + $target_dir = path($target_dir); + + my $gentoo_conf = path('gentoo.conf'); + my $make_conf = path('make.conf'); + my $resolv_conf = path('/etc/resolv.conf'); + my $zz_use = path('zz-use'); + + + my $packages = _readPackagesToInstall(); + _checkValidSystem($target_dir); + + my $make_conf_changed = _installMakeConf( $target_dir, $make_conf ); + _installGentooConf($target_dir, $gentoo_conf); + _installResolvConf($target_dir,$resolv_conf); + my $package_use_changed = _installPackageUse($target_dir, $zz_use); + + _mountNecessaryFilesystems($target_dir); + _webrsync($target_dir); + if ($rebuild_bin && $package_use_changed || $make_conf_changed) { + _rebuildBinaries($target_dir); + } + _installNeededPackages($target_dir, $packages); +} + +sub _rebuildBinaries($target) { + _forkWait() or return; + _chroot($target); + my $return_code = system 'emerge', '-e', '@system'; + if ($return_code != 0) { + die 'Unable to rebuild binaries for system.'; + } + my $return_code = system 'emerge', '-e', '@world'; + if ($return_code != 0) { + die 'Unable to rebuild binaries for world.'; + } +} + +sub _installNeededPackages($target, $packages) { + _forkWait() or return; + _chroot($target); + my $return_code = system 'emerge', '--noreplace', @$packages; + if ($return_code != 0) { + exit $return_code; + } + exit 0; +} + +sub _readPackagesToInstall { + my @packages; + open my $fh, '<', 'packages'; + while (my $line = <$fh>) { + chomp $line; + push @packages, $line; + } + close $fh; + return \@packages; +} + +sub _forkWait { + my $pid = fork; + if ($pid) { + wait; + my $return_code = $?; + if ($? != 0) { + exit $?; + } + return 0; + } + return 1; +} + +sub _webrsync($target) { + _forkWait() or return; + _chroot($target); + my $return_code = system 'emerge-webrsync'; + if ($return_code != 0) { + return $return_code; + } + exit 0; +} + +sub _chroot($target) { + chroot "$target"; + chdir '/'; +} + +sub _mountNecessaryFilesystems($target) { + my $dest_proc = $target->child('proc'); + my $dest_dev = $target->child('dev'); + my $dest_sys = $target->child('sys'); + + _mountType('proc', $dest_proc) if !_checkMounted($dest_proc); + _mountType('sysfs', $dest_sys) if !_checkMounted($dest_sys); + _mountRbind('/dev', $dest_dev) if !_checkMounted($dest_dev); +} + +sub _checkMounted($fs) { + $fs = $fs->realpath; + my $return = index(_getMounts(), $fs) != -1; + say "$fs is mounted." if $return; + return $return; +} + +sub _mountRbind($source, $fs) { + my $return_code = system 'sudo', 'mount', '--rbind', $source, $fs; + if ($return_code != 0) { + die "Unable to mount $fs."; + } +} + +{ + my $mounts; + sub _getMounts { + if (!defined $mounts) { + open my $fh, '-|', 'sudo', 'mount'; + $mounts = join '', <$fh>; + close $fh; + } + return $mounts; + } +} + +sub _mountType($fs_type, $fs) { + my $return_code = system 'sudo', 'mount', '-t', $fs_type, $fs_type, $fs; + if ($return_code != 0) { + die "Unable to mount $fs."; + } +} + +sub _checkValidSystem ($target) { + if ( !-d $target ) { + die 'Target system not populated yet.'; + } +} + +sub _installResolvConf($target, $resolv_conf) { + my $dest_resolv_conf = $target->child('etc/resolv.conf'); + _install($resolv_conf, $dest_resolv_conf); +} + +sub _installGentooConf($target, $gentoo_conf) { + my $dest_gentoo_conf = $target->child('etc/portage/repos.conf/gentoo.conf'); + my $repos_conf = $dest_gentoo_conf->parent; + my $return_code = system 'sudo', 'mkdir', '-p', $repos_conf; + if ($return_code != 0) { + say "Unable to create $repos_conf."; + } + _install($gentoo_conf, $dest_gentoo_conf); +} + +sub _installPackageUse($target, $zz_use) { + my $dest_zz_use = $target->child('etc/portage/package.use/zz-use'); + my $package_use = $dest_zz_use->parent; + my $return_code = system 'sudo', 'mkdir', '-p', $package_use; + if ($return_code != 0) { + say "Unable to create $package_use."; + } + _install($zz_use, $dest_zz_use); +} + +sub _installMakeConf ( $target, $make_conf ) { + my $dest_make_conf = $target->child('etc/portage/make.conf'); + return _install($make_conf, $dest_make_conf); +} + +sub _install($source, $dest) { + if ( -e $dest + && _getSha512SumFile($dest) eq _getSha512SumFile($source) ) + { + say "$source is already installed, skipping."; + return; + } + say "Target $source differs, installing..."; + my $return_code = system 'sudo', 'cp', '-L', $source, $dest; + if ( $return_code != 0 ) { + die "Unable to install $dest"; + } + return 1; +} + +sub _getSha512SumFile ($file) { + open my $fh, '-|', 'sha512sum', $file; + my $text = <$fh>; + close $fh; + + my ($sha512sum) = $text =~ /^(\S+)/; + return $sha512sum; +} diff --git a/zz-use b/zz-use new file mode 100644 index 0000000..03161e2 --- /dev/null +++ b/zz-use @@ -0,0 +1,2 @@ +app-misc/mime-types nginx +