mirror of
https://github.com/nchevsky/systemrescue-zfs.git
synced 2026-01-08 09:40:08 +01:00
Initial support for defining the global configuration with yaml file (#170)
This commit is contained in:
parent
2e90f77b0a
commit
7c5ce8cfdf
|
|
@ -1,123 +1,234 @@
|
|||
#! /usr/bin/env python3
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import subprocess
|
||||
import yaml
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
print(f"Script {sys.argv[0]} starting ...")
|
||||
# ==============================================================================
|
||||
# Initialization
|
||||
# ==============================================================================
|
||||
print(f"====> Script {sys.argv[0]} starting ...")
|
||||
errcnt = 0
|
||||
|
||||
# ==============================================================================
|
||||
# Define the default configuration
|
||||
# ==============================================================================
|
||||
config_global = {
|
||||
'dostartx': False,
|
||||
'dovnc': False,
|
||||
'noautologin': False,
|
||||
'nofirewall': False,
|
||||
'rootshell': None,
|
||||
'rootpass': None,
|
||||
'rootcryptpass': None,
|
||||
'setkmap': None,
|
||||
'vncpass': None,
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# Load configuration from the yaml files
|
||||
# ==============================================================================
|
||||
print(f"====> Loading configuration from yaml files located on the boot device ...")
|
||||
yamlconfdirs = ["/run/archiso/bootmnt/config.d", "/run/archiso/copytoram/config.d"]
|
||||
|
||||
def parse_config_file(yamlfile):
|
||||
print(f"Parsing yaml file: {yamlfile} ...")
|
||||
with open(yamlfile) as myfile:
|
||||
try:
|
||||
curconfig = yaml.safe_load(myfile)
|
||||
if 'global' in curconfig:
|
||||
curglobal = curconfig['global']
|
||||
for entry in config_global:
|
||||
if entry in curglobal:
|
||||
config_global[entry] = curglobal[entry]
|
||||
return True
|
||||
except yaml.YAMLError as err:
|
||||
print(err)
|
||||
errcnt+=1
|
||||
return False
|
||||
|
||||
for yamlconfdir in yamlconfdirs:
|
||||
if os.path.isdir(yamlconfdir):
|
||||
conffiles = glob.glob(os.path.join(yamlconfdir, '*.yaml'), recursive=True)
|
||||
conffiles.sort() # Load yaml files in the alphabetical order
|
||||
for curfile in conffiles:
|
||||
parse_config_file(curfile)
|
||||
|
||||
# ==============================================================================
|
||||
# Load configuration from the boot command line
|
||||
# ==============================================================================
|
||||
print(f"====> Parsing configuration from the boot command line ...")
|
||||
|
||||
bootcmdline = open("/proc/cmdline","r").readline()
|
||||
bootopts = bootcmdline.split()
|
||||
|
||||
for curopt in bootopts:
|
||||
|
||||
# Configure keyboard layout if requested in the boot command line
|
||||
# Configure keyboard layout
|
||||
match = re.search(r"^setkmap=(\S+)$", curopt)
|
||||
if match != None:
|
||||
curval = match.group(1)
|
||||
print(f"=> Found option '{curopt}' on the boot command line")
|
||||
p = subprocess.run(["localectl", "set-keymap", curval], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the keymap successfully")
|
||||
else:
|
||||
print (f"Failed to change keymap")
|
||||
errcnt+=1
|
||||
print(f"Found option '{curopt}' on the boot command line")
|
||||
config_global['setkmap'] = match.group(1)
|
||||
|
||||
# Configure root login shell if requested in the boot command line
|
||||
# Configure root login shell
|
||||
match = re.search(r"^rootshell=(\S+)$", curopt)
|
||||
if match != None:
|
||||
curval = match.group(1)
|
||||
print(f"=> Found option '{curopt}' on the boot command line")
|
||||
p = subprocess.run(["chsh", "--shell", curval, "root"], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the root shell successfully")
|
||||
else:
|
||||
print (f"Failed to change the root shell")
|
||||
errcnt+=1
|
||||
print(f"Found option '{curopt}' on the boot command line")
|
||||
config_global['rootshell'] = match.group(1)
|
||||
|
||||
# Set the system root password from a clear password
|
||||
match = re.search(r"^rootpass=(\S+)$", curopt)
|
||||
if match != None:
|
||||
curval = match.group(1)
|
||||
print(f"=> Found option 'rootpass=******' on the boot command line")
|
||||
p = subprocess.run(["chpasswd", "--crypt-method", "SHA512"], text=True, input=f"root:{curval}")
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the root password successfully")
|
||||
else:
|
||||
print (f"Failed to change the root password")
|
||||
errcnt+=1
|
||||
print(f"Found option 'rootpass=******' on the boot command line")
|
||||
config_global['rootpass'] = match.group(1)
|
||||
|
||||
# Set the system root password from an encrypted password
|
||||
# A password can be encrypted using a one-line python3 command such as:
|
||||
# python3 -c 'import crypt; print(crypt.crypt("MyPassWord123", crypt.mksalt(crypt.METHOD_SHA512)))'
|
||||
match = re.search(r"^rootcryptpass=(\S+)$", curopt)
|
||||
if match != None:
|
||||
curval = match.group(1)
|
||||
print(f"=> Found option 'rootcryptpass=******' on the boot command line")
|
||||
p = subprocess.run(["chpasswd", "--encrypted"], text=True, input=f"root:{curval}")
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the root password successfully")
|
||||
else:
|
||||
print (f"Failed to change the root password")
|
||||
errcnt+=1
|
||||
print(f"Found option 'rootcryptpass=******' on the boot command line")
|
||||
config_global['rootcryptpass'] = match.group(1)
|
||||
|
||||
# Disable the firewall
|
||||
match = re.search(r"^nofirewall$", curopt)
|
||||
if match != None:
|
||||
print(f"=> Found option 'nofirewall' on the boot command line")
|
||||
# The firewall service(s) must be in the Before-section of sysrescue-initialize.service
|
||||
p = subprocess.run(["systemctl", "disable", "--now", "iptables.service", "ip6tables.service"], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have disabled the firewall successfully")
|
||||
else:
|
||||
print (f"Failed to disable the firewall")
|
||||
errcnt+=1
|
||||
print(f"Found option '{curopt}' on the boot command line")
|
||||
config_global['nofirewall'] = True
|
||||
|
||||
# Auto-start the graphical environment (tty1 only), dovnc implies dostartx
|
||||
match = re.search(r"^dostartx|dovnc$", curopt)
|
||||
match = re.search(r"^dostartx$", curopt)
|
||||
if match != None:
|
||||
print(f"=> Found option '{match.group(0)}' on the boot command line")
|
||||
str = '[[ ! $DISPLAY ]] && [[ ! $SSH_TTY ]] && [[ $XDG_VTNR == 1 ]] && startx'
|
||||
if (os.path.exists("/root/.bash_profile") == False) or (open("/root/.bash_profile", 'r').read().find(str) == -1):
|
||||
file1 = open("/root/.bash_profile", "a")
|
||||
file1.write(f"{str}\n")
|
||||
file1.close()
|
||||
file2 = open("/root/.zlogin", "w")
|
||||
file2.write(f"{str}\n")
|
||||
file2.close()
|
||||
print(f"Found option '{curopt}' on the boot command line")
|
||||
config_global['dostartx'] = True
|
||||
|
||||
# Require authenticated console access
|
||||
match = re.search(r"^noautologin$", curopt)
|
||||
if match != None:
|
||||
print(f"=> Found option '{match.group(0)}' on the boot command line")
|
||||
p = subprocess.run(["systemctl", "revert", "getty@.service", "serial-getty@.service"], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have enabled authenticated console access successfully")
|
||||
else:
|
||||
print (f"Failed to enable authenticated console access")
|
||||
errcnt+=1
|
||||
print(f"Found option '{curopt}' on the boot command line")
|
||||
config_global['noautologin'] = True
|
||||
|
||||
# Set the VNC password from a clear password
|
||||
match = re.search(r"^vncpass=(\S+)$", curopt)
|
||||
if match != None:
|
||||
curval = match.group(1)
|
||||
print(f"=> Found option 'vncpass=******' on the boot command line")
|
||||
os.makedirs("/root/.vnc", exist_ok = True)
|
||||
p = subprocess.run(["x11vnc", "-storepasswd", curval, "/root/.vnc/passwd"], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the vnc password successfully")
|
||||
else:
|
||||
print (f"Failed to change the vnc password")
|
||||
errcnt+=1
|
||||
print(f"Found option 'vncpass=******' on the boot command line")
|
||||
config_global['vncpass'] = match.group(1)
|
||||
|
||||
# Auto-start x11vnc with the graphical environment
|
||||
# Auto-start x11vnc with the graphical environment, "dovnc" implies "dostartx"
|
||||
match = re.search(r"^dovnc$", curopt)
|
||||
if match != None:
|
||||
# No need to print "Found option 'dovnc' on the boot command line" a second time
|
||||
file = open("/root/.xprofile", "w")
|
||||
file.write("""[ -f ~/.vnc/passwd ] && pwopt="-usepw" || pwopt="-nopw"\n""")
|
||||
file.write("""x11vnc $pwopt -nevershared -forever -logfile /var/log/x11vnc.log &\n""")
|
||||
file.close()
|
||||
print(f"Found option '{curopt}' on the boot command line")
|
||||
config_global['dovnc'] = True
|
||||
config_global['dostartx'] = True
|
||||
|
||||
# ==============================================================================
|
||||
# Show the effective configuration
|
||||
# ==============================================================================
|
||||
print(f"====> Showing the effective global configuration (except clear passwords) ...")
|
||||
print(f"config['setkmap']={config_global['setkmap']}")
|
||||
print(f"config['rootshell']={config_global['rootshell']}")
|
||||
print(f"config['rootcryptpass']={config_global['rootcryptpass']}")
|
||||
print(f"config['nofirewall']={config_global['nofirewall']}")
|
||||
print(f"config['dostartx']={config_global['dostartx']}")
|
||||
print(f"config['noautologin']={config_global['noautologin']}")
|
||||
print(f"config['dovnc']={config_global['dovnc']}")
|
||||
|
||||
# ==============================================================================
|
||||
# Apply the effective configuration
|
||||
# ==============================================================================
|
||||
print(f"====> Applying configuration ...")
|
||||
|
||||
# Configure keyboard layout if requested in the configuration
|
||||
if config_global['setkmap'] != None:
|
||||
p = subprocess.run(["localectl", "set-keymap", config_global['setkmap']], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the keymap successfully")
|
||||
else:
|
||||
print (f"Failed to change keymap")
|
||||
errcnt+=1
|
||||
|
||||
# Configure root login shell if requested in the configuration
|
||||
if config_global['rootshell'] != None:
|
||||
p = subprocess.run(["chsh", "--shell", config_global['rootshell'], "root"], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the root shell successfully")
|
||||
else:
|
||||
print (f"Failed to change the root shell")
|
||||
errcnt+=1
|
||||
|
||||
# Set the system root password from a clear password
|
||||
if config_global['rootpass'] != None:
|
||||
p = subprocess.run(["chpasswd", "--crypt-method", "SHA512"], text=True, input=f"root:{config_global['rootpass']}")
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the root password successfully")
|
||||
else:
|
||||
print (f"Failed to change the root password")
|
||||
errcnt+=1
|
||||
|
||||
# Set the system root password from an encrypted password
|
||||
# A password can be encrypted using a one-line python3 command such as:
|
||||
# python3 -c 'import crypt; print(crypt.crypt("MyPassWord123", crypt.mksalt(crypt.METHOD_SHA512)))'
|
||||
if config_global['rootcryptpass'] != None:
|
||||
p = subprocess.run(["chpasswd", "--encrypted"], text=True, input=f"root:{config_global['rootcryptpass']}")
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the root password successfully")
|
||||
else:
|
||||
print (f"Failed to change the root password")
|
||||
errcnt+=1
|
||||
|
||||
# Disable the firewall
|
||||
if config_global['nofirewall'] == True:
|
||||
# The firewall service(s) must be in the Before-section of sysrescue-initialize.service
|
||||
p = subprocess.run(["systemctl", "disable", "--now", "iptables.service", "ip6tables.service"], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have disabled the firewall successfully")
|
||||
else:
|
||||
print (f"Failed to disable the firewall")
|
||||
errcnt+=1
|
||||
|
||||
# Auto-start the graphical environment (tty1 only)
|
||||
if config_global['dostartx'] == True:
|
||||
str = '[[ ! $DISPLAY ]] && [[ ! $SSH_TTY ]] && [[ $XDG_VTNR == 1 ]] && startx'
|
||||
if (os.path.exists("/root/.bash_profile") == False) or (open("/root/.bash_profile", 'r').read().find(str) == -1):
|
||||
file1 = open("/root/.bash_profile", "a")
|
||||
file1.write(f"{str}\n")
|
||||
file1.close()
|
||||
file2 = open("/root/.zlogin", "w")
|
||||
file2.write(f"{str}\n")
|
||||
file2.close()
|
||||
|
||||
# Require authenticated console access
|
||||
if config_global['noautologin'] == True:
|
||||
p = subprocess.run(["systemctl", "revert", "getty@.service", "serial-getty@.service"], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have enabled authenticated console access successfully")
|
||||
else:
|
||||
print (f"Failed to enable authenticated console access")
|
||||
errcnt+=1
|
||||
|
||||
# Set the VNC password from a clear password
|
||||
if config_global['vncpass'] != None:
|
||||
os.makedirs("/root/.vnc", exist_ok = True)
|
||||
p = subprocess.run(["x11vnc", "-storepasswd", config_global['vncpass'], "/root/.vnc/passwd"], text=True)
|
||||
if p.returncode == 0:
|
||||
print (f"Have changed the vnc password successfully")
|
||||
else:
|
||||
print (f"Failed to change the vnc password")
|
||||
errcnt+=1
|
||||
|
||||
# Auto-start x11vnc with the graphical environment
|
||||
if config_global['dovnc'] == True:
|
||||
print (f"Enabling VNC Server in /root/.xprofile ...")
|
||||
file = open("/root/.xprofile", "w")
|
||||
file.write("""[ -f ~/.vnc/passwd ] && pwopt="-usepw" || pwopt="-nopw"\n""")
|
||||
file.write("""x11vnc $pwopt -nevershared -forever -logfile /var/log/x11vnc.log &\n""")
|
||||
file.close()
|
||||
|
||||
# ==============================================================================
|
||||
# End of the script
|
||||
# ==============================================================================
|
||||
print(f"====> Script {sys.argv[0]} completed with {errcnt} errors ...")
|
||||
sys.exit(errcnt)
|
||||
|
|
|
|||
23
build.sh
23
build.sh
|
|
@ -84,7 +84,7 @@ determine_snapshot_date() {
|
|||
snapshot_date=`cat ${work_dir}/build.snapshot_date`
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
if [[ -z "$snapshot_date" ]]; then
|
||||
# while archive.archlinux.org offers lastsync files we could read out, archive.archlinux32.org doesn't
|
||||
# so use the current date (UTC), check if it's dir exists on the mirror, use the day before if not
|
||||
|
|
@ -111,7 +111,7 @@ determine_snapshot_date() {
|
|||
fi
|
||||
# we got a snapshot date that looks valid, use it without further network tests
|
||||
fi
|
||||
|
||||
|
||||
echo "$snapshot_date" >${work_dir}/build.snapshot_date
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ make_pacman_conf() {
|
|||
s|^Architecture\s*=.*$|Architecture = ${arch}|;
|
||||
s|^Include =.*$|Include = ${work_dir}/mirrorlist|g" \
|
||||
${script_path}/pacman.conf > ${work_dir}/pacman.conf
|
||||
|
||||
|
||||
sed "s|%SNAPSHOT_DATE%|${snapshot_date}|g;" \
|
||||
${script_path}/${archive_mirrorlist_file} > ${work_dir}/mirrorlist
|
||||
}
|
||||
|
|
@ -155,19 +155,19 @@ make_documentation() {
|
|||
echo "ERROR: current version not in changelog. Did you update the website submodule?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
mkdir -p "${work_dir}/${arch}/airootfs/${documentation_dir}"
|
||||
|
||||
# parameters are all relative to --source dir
|
||||
/usr/bin/hugo --source "website/" --config "config-offline.toml" --gc --verbose \
|
||||
--destination "../${work_dir}/${arch}/airootfs/${documentation_dir}"
|
||||
RET=$?
|
||||
|
||||
|
||||
if ! [ "$RET" -eq 0 ]; then
|
||||
echo "error generating offline documentation (returned $RET), aborting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# post-process hugo output and add index.hmtl to all directory links
|
||||
# required until https://github.com/gohugoio/hugo/issues/4428 is implemented
|
||||
find "${work_dir}/${arch}/airootfs/${documentation_dir}" -name "*.html" \
|
||||
|
|
@ -192,7 +192,7 @@ make_customize_airootfs() {
|
|||
s|%ISO_ARCH%|${arch}|g;
|
||||
s|%INSTALL_DIR%|${install_dir}|g" \
|
||||
${script_path}/airootfs/etc/issue > ${work_dir}/${arch}/airootfs/etc/issue
|
||||
|
||||
|
||||
# delete the target file first because it is a symlink
|
||||
rm -f ${work_dir}/${arch}/airootfs/etc/os-release
|
||||
sed "s|%ARCHISO_LABEL%|${iso_label}|g;
|
||||
|
|
@ -206,18 +206,18 @@ make_customize_airootfs() {
|
|||
|
||||
sed "s|%SNAPSHOT_DATE%|${snapshot_date}|g;" \
|
||||
${script_path}/${archive_mirrorlist_file} > ${work_dir}/${arch}/airootfs/etc/pacman.d/mirrorlist-snapshot
|
||||
|
||||
|
||||
mkdir -p ${work_dir}/${arch}/airootfs/var/lib/pacman-rolling/local
|
||||
|
||||
|
||||
setarch ${arch} mkarchiso ${verbose} -w "${work_dir}/${arch}" -C "${work_dir}/pacman.conf" -D "${install_dir}" -r '/root/customize_airootfs.sh' run
|
||||
|
||||
|
||||
rm -f ${work_dir}/${arch}/airootfs/root/customize_airootfs.sh
|
||||
|
||||
# change pacman config in airootfs to use snapshot repo by default
|
||||
# we can just do this after the mkarchiso run, it would flatten the symlink otherwise
|
||||
rm -f ${work_dir}/${arch}/airootfs/etc/pacman.conf
|
||||
ln -s pacman-snapshot.conf ${work_dir}/${arch}/airootfs/etc/pacman.conf
|
||||
|
||||
|
||||
# strip large binaries
|
||||
find ${work_dir}/${arch}/airootfs/usr/lib -type f -name "lib*.so.*" -exec strip --strip-all {} \;
|
||||
}
|
||||
|
|
@ -345,6 +345,7 @@ make_prepare() {
|
|||
# Build ISO
|
||||
make_iso() {
|
||||
cp ${version_file} ${work_dir}/iso/${install_dir}/
|
||||
cp -r config.d/ ${work_dir}/iso/
|
||||
(
|
||||
shopt -s nullglob
|
||||
rm -vf ${work_dir}/iso/${install_dir}/*.srm
|
||||
|
|
|
|||
4
config.d/01-sysrescue.yaml
Normal file
4
config.d/01-sysrescue.yaml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
global:
|
||||
dostartx: false
|
||||
nofirewall: false
|
||||
1
packages
1
packages
|
|
@ -178,6 +178,7 @@ pv
|
|||
python
|
||||
python-llfuse
|
||||
python-pip
|
||||
python-yaml
|
||||
qemu-guest-agent
|
||||
rdesktop
|
||||
rdiff-backup
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
diff --git a/archiso/initcpio/hooks/archiso b/archiso/initcpio/hooks/archiso
|
||||
index 3eb7ac7..e4585af 100644
|
||||
--- a/archiso/initcpio/hooks/archiso
|
||||
+++ b/archiso/initcpio/hooks/archiso
|
||||
@@ -247,6 +247,14 @@ archiso_mount_handler() {
|
||||
|
||||
_mnt_sfs "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs" "/run/archiso/sfs/airootfs"
|
||||
|
||||
+ if [[ "${copytoram}" == "y" ]] && ls -lh /run/archiso/bootmnt/autorun* >/dev/null 2>/dev/null; then
|
||||
+ msg -n ":: Copying autorun scripts to RAM..."
|
||||
+ if ! cp /run/archiso/bootmnt/autorun* /run/archiso/copytoram/ ; then
|
||||
+ echo "ERROR: while copy '/run/archiso/bootmnt/autorun*' to '/run/archiso/copytoram/'"
|
||||
+ launch_interactive_shell
|
||||
+ fi
|
||||
+ fi
|
||||
+
|
||||
[[ "${loadsrm}" == "y" ]] && _mnt_srm "/run/archiso/bootmnt/${archisobasedir}"
|
||||
|
||||
if [[ -f "/run/archiso/sfs/airootfs/airootfs.img" ]]; then
|
||||
27
patches/archiso-v43-06-copytoram.patch
Normal file
27
patches/archiso-v43-06-copytoram.patch
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
diff -urN archiso-43-a/archiso/initcpio/hooks/archiso archiso-43-b/archiso/initcpio/hooks/archiso
|
||||
--- archiso-43-a/archiso/initcpio/hooks/archiso 2021-12-31 23:32:15.547000000 +0000
|
||||
+++ archiso-43-b/archiso/initcpio/hooks/archiso 2021-12-31 23:36:53.081000000 +0000
|
||||
@@ -247,6 +247,23 @@
|
||||
|
||||
_mnt_sfs "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs" "/run/archiso/sfs/airootfs"
|
||||
|
||||
+ if [[ "${copytoram}" == "y" ]]; then
|
||||
+ if ls -lh /run/archiso/bootmnt/autorun* >/dev/null 2>/dev/null; then
|
||||
+ msg -n ":: Copying autorun scripts to RAM ..."
|
||||
+ if ! cp /run/archiso/bootmnt/autorun* /run/archiso/copytoram/ ; then
|
||||
+ echo "ERROR: failed to copy '/run/archiso/bootmnt/autorun*' to '/run/archiso/copytoram/'"
|
||||
+ launch_interactive_shell
|
||||
+ fi
|
||||
+ fi
|
||||
+ if ls -lh /run/archiso/bootmnt/config.d >/dev/null 2>/dev/null; then
|
||||
+ msg -n ":: Copying configuration files to RAM ..."
|
||||
+ if ! cp -r /run/archiso/bootmnt/config.d /run/archiso/copytoram/ ; then
|
||||
+ echo "ERROR: failed to copy '/run/archiso/bootmnt/config.d' to '/run/archiso/copytoram/'"
|
||||
+ launch_interactive_shell
|
||||
+ fi
|
||||
+ fi
|
||||
+ fi
|
||||
+
|
||||
[[ "${loadsrm}" == "y" ]] && _mnt_srm "/run/archiso/bootmnt/${archisobasedir}"
|
||||
|
||||
if [[ -f "/run/archiso/sfs/airootfs/airootfs.img" ]]; then
|
||||
Loading…
Reference in a new issue