From ed115df97982117d08d4357a78a9e30d5ab0332e Mon Sep 17 00:00:00 2001 From: askiiart Date: Tue, 1 Oct 2024 12:24:46 -0500 Subject: [PATCH 01/10] initial commit - switches to rate-mirrors, some minor updates, etc --- akshara | 62 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/akshara b/akshara index 37fc2da..2cd3f2f 100755 --- a/akshara +++ b/akshara @@ -19,15 +19,11 @@ import os import sys -import time import yaml -import shutil import filecmp import argparse import requests -import platform import fasteners -from threading import Event import subprocess __version = '1.0.0' @@ -136,34 +132,44 @@ def update_system(): with open('/system.yaml') as blend_release_file: blend_release = yaml.load( blend_release_file, Loader=yaml.FullLoader) + + + + # TODO: Add check that all packages actually exist info('downloading Arch tarball...') + # TODO: currently it errors if it doesn't have arch-repo anyways, so this doesn't need any extra checking, maybe add a check for that later though + # The mirror to use for downloading the bootstrap image + # For example, for the Arch mirror at mirrors.acm.wpi.edu, you'd use https://mirrors.acm.wpi.edu/archlinux + # Not sure why this wouldn't just use `arch-repo` but whatever + bootstrap_mirror = blend_release.get("arch-repo") + if not os.path.isfile('/.update.tar.zst'): - if exec('wget', '-q', '--show-progress', 'https://geo.mirror.pkgbuild.com/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0: + if exec('wget', '-q', '--show-progress', f'{bootstrap_mirror}/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0: warn('failed download') print() info('trying download again...') print() exec('rm', '-f', '/.update.tar.zst') - if exec('wget', '-q', '--show-progress', 'https://geo.mirror.pkgbuild.com/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0: + if exec('wget', '-q', '--show-progress', f'{bootstrap_mirror}/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0: error('failed download') print() error('update failed') sys.exit(50) - if exec('bash', '-c', 'sha256sum -c --ignore-missing <(wget -qO- https://geo.mirror.pkgbuild.com/iso/latest/sha256sums.txt | sed "s/archlinux-bootstrap-x86_64\\.tar\\.zst/.update.tar.zst/g") 2>/dev/null') != 0: + if exec('bash', '-c', f'sha256sum -c --ignore-missing <(wget -qO- {bootstrap_mirror}/iso/latest/sha256sums.txt | sed "s/archlinux-bootstrap-x86_64\\.tar\\.zst/.update.tar.zst/g") 2>/dev/null') != 0: error('failed checksum verification') print() info('trying download again...') exec('rm', '-f', '/.update.tar.zst') - if exec('wget', '-q', '--show-progress', 'https://geo.mirror.pkgbuild.com/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0: + if exec('wget', '-q', '--show-progress', f'{bootstrap_mirror}/iso/latest/archlinux-bootstrap-x86_64.tar.zst', '-O', '/.update.tar.zst') != 0: error('failed download') print() error('update failed') sys.exit(50) return - if exec('bash', '-c', 'sha256sum -c --ignore-missing <(wget -qO- https://geo.mirror.pkgbuild.com/iso/latest/sha256sums.txt | sed "s/archlinux-bootstrap-x86_64\\.tar\\.zst/.update.tar.zst/g") 2>/dev/null') != 0: + if exec('bash', '-c', f'sha256sum -c --ignore-missing <(wget -qO- {bootstrap_mirror}/iso/latest/sha256sums.txt | sed "s/archlinux-bootstrap-x86_64\\.tar\\.zst/.update.tar.zst/g") 2>/dev/null') != 0: error('failed checksum verification') print() error('update failed') @@ -196,9 +202,7 @@ def update_system(): 'blend-files' ] - keep = [ - '/usr/share' - ] + persistent_files = [] if (type(blend_release.get('impl')) == str and type(blend_release.get('track')) != 'custom'): @@ -224,6 +228,9 @@ def update_system(): if type(blend_release.get('user-services')) == list: user_services += blend_release.get('user-services') + if type(blend_release.get('persistent-files')) == list: + persistent_files += blend_release.get('persistent-files') + exec_chroot('rm', '-f', '/.new_rootfs/etc/resolv.conf') with open('/.new_rootfs/etc/resolv.conf', 'w') as pacman_mirrorlist_conf: @@ -243,17 +250,8 @@ def update_system(): exec_chroot('pacman-key', '--init') exec_chroot('pacman-key', '--populate') - counter = 0 - while True: - return_val = exec_chroot('pacman', '-Sy', '--ask=4', 'reflector') - counter += 1 - if counter > 30: - error('failed to download packages') - exit(50) - if return_val == 0: - break - - exec_chroot('reflector', '--latest', '5', '--protocol', 'https', '--sort', 'rate', '--save', '/etc/pacman.d/mirrorlist') + exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \\")') + exec_chroot('bash', '-c', 'cd /tmp/rate-mirrors/; tar -xzf rate-mirrors*; cd $(find /tmp/rate-mirrors/ -mindepth 1 -maxdepth 1 -type d); ./rate_mirrors --disable-comments-in-file --entry-country=US --protocol=https arch --max-delay 7200 | sudo tee /etc/pacman.d/mirrorlist') #exec_chroot('sed', 's/#//g', '-i', '/etc/pacman.d/mirrorlist') #exec_chroot('bash', '-c', 'grep "^Server =" /etc/pacman.d/mirrorlist > /etc/pacman.d/mirrorlist.tmp; mv /etc/pacman.d/mirrorlist.tmp /etc/pacman.d/mirrorlist') @@ -293,6 +291,7 @@ Server = {package_repo["repo-url"]} counter = 0 while True: + print('running packages again') return_val = exec_chroot('pacman', '-S', '--ask=4', *packages) counter += 1 if counter > 30: @@ -304,6 +303,7 @@ Server = {package_repo["repo-url"]} counter = 0 if aur_packages != []: while True: + print('running aur_packages again') exec_chroot('useradd', '-m', '-G', 'wheel', '-s', '/bin/bash', 'aur') exec_chroot('bash', '-c', 'echo "aur ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/aur') return_val = exec_chroot( @@ -327,6 +327,12 @@ Server = {package_repo["repo-url"]} if type(user_service) is str: exec_chroot('systemctl', 'enable', '--global', user_service) + for persistent_file in persistent_files: + if type(persistent_file) is str: + if os.path.exists(persistent_file): + exec('mkdir', '-p', '/.new_rootfs/'+ os.path.dirname(persistent_file)) + exec('cp', persistent_file, '/.new_rootfs/'+ persistent_file) + if type(blend_release.get('commands')) == list: for command in blend_release.get('commands'): if type(command) == str: @@ -403,7 +409,8 @@ Server = {package_repo["repo-url"]} exec('cp', '-ax', '/.new_rootfs/var/lib/pacman', '/.new.var.lib/pacman') exec('mv', '.new_rootfs', '.update_rootfs') - exec('cp', '-ax', '/.update_rootfs/etc', '/.update_rootfs/usr/etc') + # don't move /etc/shells to /usr/etc + exec('bash', '-c', 'shopt -s extglob; cd /.update_rootfs/etc; cp -ax !(shells) /.update_rootfs/usr/etc; cd -') new_boot_files = [] @@ -492,3 +499,10 @@ try: command() except KeyboardInterrupt: error('aborting') + # remove update and akshara stuff if the program is exited + exec('rm', '-rf', '/.new_rootfs/') + exec('rm', '-rf', '/.update_rootfs') + # it's basically impossible to ^C before akshara has exited but after it's created this file + # and i don't *think* that "update" would be destructive at all (unless it failed to run and would't boot), but i don't quite understand it soooo just to be on the safe side + exec('rm', '-f', '/.update') + # TODO: add similar handling for errors, and an option to not delete stuff on error/early exit From 73d9f01926dcad0fd503390cf758ad49b2cb7c5a Mon Sep 17 00:00:00 2001 From: askiiart Date: Wed, 9 Oct 2024 09:39:45 -0500 Subject: [PATCH 02/10] add /opt --- akshara.hook | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/akshara.hook b/akshara.hook index bdcda9f..d26594d 100755 --- a/akshara.hook +++ b/akshara.hook @@ -23,6 +23,12 @@ run_latehook() { mv /new_root/.new.etc /new_root/etc fi + # Same for /opt + if [[ -d /new_root/.update_rootfs/opt ]]; then + mv /new_root/opt /new_root/.old.opt + mv /new_root/.update_rootfs/opt /new_root/opt + fi + # Same for /var. if [[ -d /new_root/.new.var.lib ]]; then mv /new_root/var/lib /new_root/.old.var.lib From b08d876b5320bf93c264b9eeec2019f133e152ba Mon Sep 17 00:00:00 2001 From: askiiart Date: Tue, 15 Oct 2024 10:10:54 -0500 Subject: [PATCH 03/10] un-`sudo tee` it --- akshara | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/akshara b/akshara index 2cd3f2f..78b9e9c 100755 --- a/akshara +++ b/akshara @@ -251,7 +251,7 @@ def update_system(): exec_chroot('pacman-key', '--populate') exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \\")') - exec_chroot('bash', '-c', 'cd /tmp/rate-mirrors/; tar -xzf rate-mirrors*; cd $(find /tmp/rate-mirrors/ -mindepth 1 -maxdepth 1 -type d); ./rate_mirrors --disable-comments-in-file --entry-country=US --protocol=https arch --max-delay 7200 | sudo tee /etc/pacman.d/mirrorlist') + exec_chroot('bash', '-c', 'cd /tmp/rate-mirrors/; tar -xzf rate-mirrors*; cd $(find /tmp/rate-mirrors/ -mindepth 1 -maxdepth 1 -type d); ./rate_mirrors --disable-comments-in-file --entry-country=US --protocol=https arch --max-delay 7200 > /etc/pacman.d/mirrorlist') #exec_chroot('sed', 's/#//g', '-i', '/etc/pacman.d/mirrorlist') #exec_chroot('bash', '-c', 'grep "^Server =" /etc/pacman.d/mirrorlist > /etc/pacman.d/mirrorlist.tmp; mv /etc/pacman.d/mirrorlist.tmp /etc/pacman.d/mirrorlist') From 2d1b46aa409e5253ad0c19f7e6959fa6e098f1f3 Mon Sep 17 00:00:00 2001 From: askiiart Date: Fri, 8 Nov 2024 20:00:05 -0600 Subject: [PATCH 04/10] fix rate-mirrors --- akshara | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/akshara b/akshara index 78b9e9c..b7484b6 100755 --- a/akshara +++ b/akshara @@ -250,7 +250,8 @@ def update_system(): exec_chroot('pacman-key', '--init') exec_chroot('pacman-key', '--populate') - exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \\")') + # FIXME: If the GitHub API is down or something, this completely breaks + exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \" | tr -d " ")') exec_chroot('bash', '-c', 'cd /tmp/rate-mirrors/; tar -xzf rate-mirrors*; cd $(find /tmp/rate-mirrors/ -mindepth 1 -maxdepth 1 -type d); ./rate_mirrors --disable-comments-in-file --entry-country=US --protocol=https arch --max-delay 7200 > /etc/pacman.d/mirrorlist') #exec_chroot('sed', 's/#//g', '-i', '/etc/pacman.d/mirrorlist') From efa4c78976d842548401bd620c1b4830805d675f Mon Sep 17 00:00:00 2001 From: askiiart Date: Fri, 8 Nov 2024 20:06:56 -0600 Subject: [PATCH 05/10] remove /.new_rootfs/ properly --- akshara | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/akshara b/akshara index b7484b6..3f69416 100755 --- a/akshara +++ b/akshara @@ -498,10 +498,11 @@ try: command() else: command() -except KeyboardInterrupt: +except: error('aborting') # remove update and akshara stuff if the program is exited - exec('rm', '-rf', '/.new_rootfs/') + exec('umount', '-rf', '/.new_rootfs/') + exec('rmdir', '/.new_rootfs/') exec('rm', '-rf', '/.update_rootfs') # it's basically impossible to ^C before akshara has exited but after it's created this file # and i don't *think* that "update" would be destructive at all (unless it failed to run and would't boot), but i don't quite understand it soooo just to be on the safe side From 4e1977087ebb546f797982a2581f52f97064fd3d Mon Sep 17 00:00:00 2001 From: askiiart Date: Fri, 8 Nov 2024 20:12:07 -0600 Subject: [PATCH 06/10] oops we need another backslash --- akshara | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/akshara b/akshara index 3f69416..4832ab1 100755 --- a/akshara +++ b/akshara @@ -251,7 +251,7 @@ def update_system(): exec_chroot('pacman-key', '--populate') # FIXME: If the GitHub API is down or something, this completely breaks - exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \" | tr -d " ")') + exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \\" | tr -d " ")') exec_chroot('bash', '-c', 'cd /tmp/rate-mirrors/; tar -xzf rate-mirrors*; cd $(find /tmp/rate-mirrors/ -mindepth 1 -maxdepth 1 -type d); ./rate_mirrors --disable-comments-in-file --entry-country=US --protocol=https arch --max-delay 7200 > /etc/pacman.d/mirrorlist') #exec_chroot('sed', 's/#//g', '-i', '/etc/pacman.d/mirrorlist') From 08c7a4d235859dc19758aad944fa8df4b93e8b2e Mon Sep 17 00:00:00 2001 From: askiiart Date: Fri, 8 Nov 2024 20:15:50 -0600 Subject: [PATCH 07/10] i give up (on rate-mirrors, for now) --- akshara | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/akshara b/akshara index 4832ab1..911a507 100755 --- a/akshara +++ b/akshara @@ -251,8 +251,8 @@ def update_system(): exec_chroot('pacman-key', '--populate') # FIXME: If the GitHub API is down or something, this completely breaks - exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \\" | tr -d " ")') - exec_chroot('bash', '-c', 'cd /tmp/rate-mirrors/; tar -xzf rate-mirrors*; cd $(find /tmp/rate-mirrors/ -mindepth 1 -maxdepth 1 -type d); ./rate_mirrors --disable-comments-in-file --entry-country=US --protocol=https arch --max-delay 7200 > /etc/pacman.d/mirrorlist') + #exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \\" | tr -d " ")') + #exec_chroot('bash', '-c', 'cd /tmp/rate-mirrors/; tar -xzf rate-mirrors*; cd $(find /tmp/rate-mirrors/ -mindepth 1 -maxdepth 1 -type d); ./rate_mirrors --disable-comments-in-file --entry-country=US --protocol=https arch --max-delay 7200 > /etc/pacman.d/mirrorlist') #exec_chroot('sed', 's/#//g', '-i', '/etc/pacman.d/mirrorlist') #exec_chroot('bash', '-c', 'grep "^Server =" /etc/pacman.d/mirrorlist > /etc/pacman.d/mirrorlist.tmp; mv /etc/pacman.d/mirrorlist.tmp /etc/pacman.d/mirrorlist') From c968609b60b8364fcd2fbd5bd5a5c9a3cc2b4734 Mon Sep 17 00:00:00 2001 From: askiiart Date: Mon, 11 Nov 2024 10:48:05 -0600 Subject: [PATCH 08/10] tmp: add benchmarking for package building and installation --- akshara | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/akshara b/akshara index 911a507..6361d58 100755 --- a/akshara +++ b/akshara @@ -25,7 +25,7 @@ import argparse import requests import fasteners import subprocess - +from datetime import datetime __version = '1.0.0' @@ -114,6 +114,8 @@ def interpret_track(blend_release): def update_system(): + benchmark = True + if os.path.isdir('/.update_rootfs'): error('update already downloaded, you must reboot first') sys.exit(75) @@ -182,7 +184,11 @@ def update_system(): info('generating new system...') + before = datetime.now() exec('tar', '--acls', '--xattrs', '-xf', '.update.tar.zst') + after = datetime.now() + if benchmark: + print(f'[BENCH]: {(before - after).seconds} seconds to extract tarball') exec('mv', 'root.x86_64', '.new_rootfs') exec('rm', '-f', '/.new_rootfs/pkglist.x86_64.txt') exec('rm', '-f', '/.new_rootfs/version') @@ -250,7 +256,9 @@ def update_system(): exec_chroot('pacman-key', '--init') exec_chroot('pacman-key', '--populate') - # FIXME: If the GitHub API is down or something, this completely breaks + # If the GitHub API is down or something, this completely breaks + # also it's broken currently and reflector is working now anyways soooooo + # commented out #exec_chroot('sh', '-c', 'mkdir /tmp/rate-mirrors/; cd /tmp/rate-mirrors/; curl -LO $(curl -s https://api.github.com/repos/westandskif/rate-mirrors/releases/latest | grep "browser_download_url.*rate-mirrors-v.*-x86_64-unknown-linux-musl.tar.gz" | cut -d : -f 2,3 | tr -d \\" | tr -d " ")') #exec_chroot('bash', '-c', 'cd /tmp/rate-mirrors/; tar -xzf rate-mirrors*; cd $(find /tmp/rate-mirrors/ -mindepth 1 -maxdepth 1 -type d); ./rate_mirrors --disable-comments-in-file --entry-country=US --protocol=https arch --max-delay 7200 > /etc/pacman.d/mirrorlist') @@ -278,6 +286,7 @@ SigLevel = Never Server = {package_repo["repo-url"]} ''') + before = datetime.now() counter = 0 while True: return_val = exec_chroot('pacman', '-Syu', '--noconfirm') @@ -287,9 +296,13 @@ Server = {package_repo["repo-url"]} exit(50) if return_val == 0: break + after = datetime.now() + if benchmark: + print(f'[BENCH]: {(before - after).seconds} seconds to update packages') exec('cp', '/etc/mkinitcpio.conf', '/.new_rootfs/etc/mkinitcpio.conf') + before = datetime.now() counter = 0 while True: print('running packages again') @@ -300,6 +313,9 @@ Server = {package_repo["repo-url"]} exit(50) if return_val == 0: break + after = datetime.now() + if benchmark: + print(f'[BENCH]: {(before - after).seconds} seconds to install packages') counter = 0 if aur_packages != []: @@ -307,10 +323,14 @@ Server = {package_repo["repo-url"]} print('running aur_packages again') exec_chroot('useradd', '-m', '-G', 'wheel', '-s', '/bin/bash', 'aur') exec_chroot('bash', '-c', 'echo "aur ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/aur') + before = datetime.now() return_val = exec_chroot( 'runuser', '-u', 'aur', '--', 'paru', '-Sy', '--noconfirm', '--needed', '--noprogressbar', '--skipreview', '--removemake', '--cleanafter', '--ask=4', *aur_packages) + after = datetime.now() + if benchmark: + print(f'[BENCH]: {(before - after).seconds} seconds to install AUR packages') exec_chroot('userdel', '-r', 'aur') exec_chroot('rm', '-f', '/etc/sudoers.d/aur') counter += 1 @@ -319,6 +339,7 @@ Server = {package_repo["repo-url"]} exit(50) if return_val == 0: break + for service in services: if type(service) is str: From 541589ca19f881fd6acfc196d0ed1e887bb22874 Mon Sep 17 00:00:00 2001 From: askiiart Date: Thu, 21 Nov 2024 11:56:50 -0600 Subject: [PATCH 09/10] oops i forgot to remove the dir --- akshara | 1 + 1 file changed, 1 insertion(+) diff --git a/akshara b/akshara index 6361d58..c369229 100755 --- a/akshara +++ b/akshara @@ -524,6 +524,7 @@ except: # remove update and akshara stuff if the program is exited exec('umount', '-rf', '/.new_rootfs/') exec('rmdir', '/.new_rootfs/') + exec('rm', '-rf', '/.new_rootfs') exec('rm', '-rf', '/.update_rootfs') # it's basically impossible to ^C before akshara has exited but after it's created this file # and i don't *think* that "update" would be destructive at all (unless it failed to run and would't boot), but i don't quite understand it soooo just to be on the safe side From 278b3ef2a8152f5b67b13f9f572eb3e895837de7 Mon Sep 17 00:00:00 2001 From: askiiart Date: Wed, 27 Nov 2024 22:25:24 -0600 Subject: [PATCH 10/10] remove broken and useless line --- akshara | 2 -- 1 file changed, 2 deletions(-) diff --git a/akshara b/akshara index c369229..623c2c3 100755 --- a/akshara +++ b/akshara @@ -431,8 +431,6 @@ Server = {package_repo["repo-url"]} exec('cp', '-ax', '/.new_rootfs/var/lib/pacman', '/.new.var.lib/pacman') exec('mv', '.new_rootfs', '.update_rootfs') - # don't move /etc/shells to /usr/etc - exec('bash', '-c', 'shopt -s extglob; cd /.update_rootfs/etc; cp -ax !(shells) /.update_rootfs/usr/etc; cd -') new_boot_files = []