331 lines
11 KiB
Bash
331 lines
11 KiB
Bash
# ------------------------------------------------------------------------------
|
|
# Main program functions
|
|
# This file is part of the init.sh project
|
|
# Copyright (c) 2019-2021 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
|
|
# ------------------------------------------------------------------------------
|
|
# This file is distributed under 3-clause BSD license.
|
|
# The complete license agreement can be obtained at:
|
|
# https://opensource.org/licenses/BSD-3-Clause
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Read command line and set appropriate vars. Some basic checks can trigger
|
|
# errors with immediate exit.
|
|
read_commandline()
|
|
{
|
|
syntax_error()
|
|
{
|
|
prnt E "Error while analysing command line parameters."
|
|
die 1 --force
|
|
}
|
|
|
|
# Processing command line options
|
|
local want_module=false
|
|
local want_logfile=false
|
|
local want_conffile=false
|
|
local want_chroot=false
|
|
local opt=
|
|
for opt in $@; do
|
|
case $opt in
|
|
"-h"|"--help")
|
|
disp_help
|
|
exit 0
|
|
;;
|
|
"-v"|"--version")
|
|
show_version
|
|
exit 0
|
|
;;
|
|
"-m"|"--module")
|
|
local want_module=true
|
|
;;
|
|
"-c"|"--check-only")
|
|
export CHECK_ONLY=true
|
|
;;
|
|
"-j"|"--jump")
|
|
export JUMP=true
|
|
;;
|
|
"-k"|"--keep-going")
|
|
export KEEPGOING=true
|
|
;;
|
|
"-r"|"--resume")
|
|
if [[ -s $STAGE_FILE ]]; then
|
|
export RESUME=true
|
|
else
|
|
prnt E "The status file doesn't exists or is empty!"
|
|
prnt E "Without it, resuming is impossible."
|
|
die 17 --force
|
|
fi
|
|
;;
|
|
"-R"|"--no-root-check")
|
|
export NO_ROOT_CHECK=true
|
|
;;
|
|
"-D"|"--no-deps")
|
|
export NO_DEPS=true
|
|
;;
|
|
"-P"|"--no-proxy")
|
|
export NO_PROXY=true
|
|
;;
|
|
"-l"|"--logfile")
|
|
local want_logfile=true
|
|
;;
|
|
"-f"|"--file")
|
|
local want_conffile=true
|
|
;;
|
|
"-s"|"--shell")
|
|
export RUN_SHELL=true
|
|
;;
|
|
"--chroot")
|
|
local want_chroot=true
|
|
;;
|
|
"--cron")
|
|
export CRON_MODE=true
|
|
;;
|
|
*)
|
|
if [[ $want_module == true ]]; then
|
|
[[ $want_logfile == true ]] && synthax_error
|
|
[[ $want_conffile == true ]] && synthax_error
|
|
[[ $want_chroot == true ]] && synthax_error
|
|
if [[ -z $MANUAL_MODULE_LIST ]]; then
|
|
export MANUAL_MODULE_LIST=$opt
|
|
want_module=false
|
|
else
|
|
prnt E "A module list have already been given!"
|
|
prnt E "Commande line only tolerate one --module parameter."
|
|
die 1 --force
|
|
fi
|
|
elif [[ $want_logfile == true ]]; then
|
|
[[ $want_module == true ]] && synthax_error
|
|
[[ $want_conffile == true ]] && synthax_error
|
|
[[ $want_chroot == true ]] && synthax_error
|
|
if [[ -z $NEW_LOGFILE ]]; then
|
|
export NEW_LOGFILE=$opt
|
|
want_logfile=false
|
|
else
|
|
prnt E "Impossible to specify several log files."
|
|
die 1 --force
|
|
fi
|
|
elif [[ $want_conffile == true ]]; then
|
|
[[ $want_module == true ]] && synthax_error
|
|
[[ $want_logfile == true ]] && synthax_error
|
|
[[ $want_chroot == true ]] && synthax_error
|
|
export CONFFILES="$CONFFILES $opt"
|
|
want_logfile=false
|
|
elif [[ $want_chroot == true ]]; then
|
|
[[ $want_module == true ]] && synthax_error
|
|
[[ $want_logfile == true ]] && synthax_error
|
|
[[ $want_conffile == true ]] && synthax_error
|
|
if [[ -z $CHROOT_PATH ]]; then
|
|
export CHROOT_PATH=$opt
|
|
want_chroot=false
|
|
else
|
|
prnt E "A chroot path have already been given."
|
|
die 1 --force
|
|
fi
|
|
else
|
|
prnt E "Unknow parameter \"$opt\"."
|
|
die 1 --force
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
unset opt
|
|
|
|
# If those var are true at that point, something is wrong
|
|
if [[ $want_logfile == true ]] || [[ $want_module == true ]] ||
|
|
[[ $want_conffile == true ]] || [[ $want_chroot == true ]]; then
|
|
syntax_error
|
|
fi
|
|
|
|
unset want_conffile want_logfile want_module
|
|
}
|
|
export -f read_commandline
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# If chrooted, we need to bootstrap to a new copy of our directory tree
|
|
chroot_bootstrap()
|
|
{
|
|
if [[ ! -d $CHROOT_PATH ]]; then
|
|
prnt E "The path given to chroot don't exists."
|
|
die 14
|
|
fi
|
|
if [[ ! -d $CHROOT_PATH/tmp ]]; then
|
|
prnt E "The target filesystem doesn't seems to be a valid installation."
|
|
die 15
|
|
fi
|
|
|
|
local tmpdir=$(mktemp -d $CHROOT_PATH/tmp/init.sh-XXXX)
|
|
local bootstrap_items="conf lib modules repo bash.rc init.sh prepost.d"
|
|
if [[ $RESUME == true ]]; then
|
|
bootstrap_items="$bootstrap_items $STAGE_FILE"
|
|
fi
|
|
|
|
prnt I "Preparing root change."
|
|
cp -av $bootstrap_items $tmpdir
|
|
|
|
prnt I "Changing root and starting a fork of init.sh..."
|
|
chroot $CHROOT_PATH /bin/bash -c 'CHROOT_DONE=true; $tmpdir/init.sh $@'
|
|
|
|
# If stage file still exists we copy it to be able to resume later
|
|
if [[ -e $tmpdir/$(basename $STAGE_FILE) ]]; then
|
|
cp $tmpdir/$(basename $STAGE_FILE) $STAGE_FILE
|
|
fi
|
|
|
|
prnt I "Back to host system and clean up."
|
|
rm -rf $tmpdir
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Automatically load system specific configuration if file exist in the
|
|
# following order:
|
|
# 1) auto/arch.conf.sh
|
|
# 2) auto/distro.conf.sh
|
|
# 3) auto/distro-arch.conf.sh
|
|
# 4) auto/distro-version.conf.sh
|
|
# 5) auto/distro-codename.conf.sh (if sys_code defined)
|
|
# 6) auto/distro-version-arch.conf.sh
|
|
# 7) auto/distro-codename-arch.conf.sh (if sys_code defined)
|
|
load_autoconf()
|
|
{
|
|
local prefix="$MYPATH/conf/auto"
|
|
|
|
if [[ -e $prefix/$SYS_ARCH.conf.sh ]]; then
|
|
. $prefix/$SYS_ARCH.conf.sh
|
|
fi
|
|
if [[ -e $prefix/$SYS_DIST.conf.sh ]]; then
|
|
. $prefix/$SYS_DIST.conf.sh
|
|
fi
|
|
if [[ -e $prefix/$SYS_DIST-$SYS_ARCH.conf.sh ]]; then
|
|
. $prefix/$SYS_DIST-$SYS_ARCH.conf.sh
|
|
fi
|
|
if [[ -e $prefix/$SYS_DIST-$SYS_VER.conf.sh ]]; then
|
|
. $prefix/$SYS_DIST-$SYS_VER.conf.sh
|
|
fi
|
|
if [[ -n $SYS_CODE && -e $prefix/$SYS_DIST-$SYS_CODE.conf.sh ]]; then
|
|
. $prefix/$SYS_DIST-$SYS_CODE.conf.sh
|
|
fi
|
|
if [[ -e $prefix/$SYS_DIST-$SYS_VER-$SYS_ARCH.conf.sh ]]; then
|
|
. $prefix/$SYS_DIST-$SYS_VER-$SYS_ARCH.conf.sh
|
|
fi
|
|
if [[ -n $SYS_CODE && -e $prefix/$SYS_DIST-$SYS_CODE-$SYS_ARCH.conf.sh ]]; then
|
|
. $prefix/$SYS_DIST-$SYS_CODE-$SYS_ARCH.conf.sh
|
|
fi
|
|
|
|
unset prefix
|
|
}
|
|
export -f load_autoconf
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Load configuration with the following priorities:
|
|
# 1) Those given on command line, if any
|
|
# 2) <workingdir>/conf/<hostname>.conf (Hostname based and specific)
|
|
# 3) <workingdir>/conf/init.conf.sh (Generic default)
|
|
load_configuration()
|
|
{
|
|
if [[ -n $CONFFILES ]]; then
|
|
local f=
|
|
for f in $CONFFILES; do
|
|
prnt I "Loading $f manually specified."
|
|
if [[ -s $f ]]; then
|
|
. $f
|
|
else
|
|
prnt E "The $f file doesn't exists or is empty."
|
|
die 6 --force
|
|
fi
|
|
done
|
|
unset f
|
|
else
|
|
prnt I "Loading configuration..."
|
|
if [[ -e $MYPATH/conf/$HOSTNAME.conf.sh ]]; then
|
|
prnt I "A specific configuration will be used."
|
|
. $MYPATH/conf/$HOSTNAME.conf.sh
|
|
else
|
|
if [[ -e $MYPATH/conf/init.conf.sh ]]; then
|
|
prnt I "A generic configuration will be used."
|
|
. $MYPATH/conf/init.conf.sh
|
|
else
|
|
prnt E "No configuration found, impossible to continue."
|
|
die 6 --force
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
export -f load_configuration
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Load pre and post actions for package manager
|
|
load_prepost_actions()
|
|
{
|
|
local prepost=
|
|
for prepost in $MYPATH/prepost.d/*.sh; do
|
|
prnt I "Loading prepost actions in $prepost ..."
|
|
. $prepost
|
|
done
|
|
unset prepost
|
|
}
|
|
export -f load_prepost_actions
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Do deeper command line analysis to detect unconsistancies
|
|
process_commandline_and_vars()
|
|
{
|
|
# Check unconsistant parameters
|
|
if [[ $CHECK_ONLY == true ]]; then
|
|
if [[ $JUMP == true ]]; then
|
|
prnt E "The options --check-only and --jump are mutually exclusive!"
|
|
die 1 --force
|
|
fi
|
|
if [[ $KEEPGOING == true ]]; then
|
|
prnt E "The options --keep-going and --check-only are not compatible!"
|
|
die 1 --force
|
|
fi
|
|
fi
|
|
if [[ $RESUME == true ]]; then
|
|
if [[ $CHECK_ONLY == true ]]; then
|
|
prnt E "Resuming doesn't make sense with --check-only."
|
|
die 1 --force
|
|
fi
|
|
if [[ $MANUAL_MODULE_LIST ]]; then
|
|
prnt E "Recovery mode can't work with a manual module list."
|
|
die 1 --force
|
|
fi
|
|
fi
|
|
|
|
if [[ $CRON_MODE == true ]]; then
|
|
if [[ $CHECK_ONLY == true || $JUMP == true ]]; then
|
|
prnt E "Some parameters are incompatible with cron mode."
|
|
die 16 --force
|
|
fi
|
|
fi
|
|
|
|
# Configure module list
|
|
if [[ -n $MANUAL_MODULE_LIST ]]; then
|
|
prnt W "A manual module list will be used."
|
|
export MODULE_LIST=$(echo $MANUAL_MODULE_LIST | sed "s/,/ /g")
|
|
fi
|
|
|
|
# Check for module list existance and basic syntax
|
|
if [[ -n $MODULE_LIST ]]; then
|
|
for mod in $MODULE_LIST; do
|
|
if [[ $mod =~ ['-!@#$%\&*=+'] ]]; then
|
|
prnt E "The module \"$mod\" contains a forbidden character in its name."
|
|
die 5
|
|
fi
|
|
if [[ ! -s "modules/$mod.sh" ]]; then
|
|
prnt E "The asked module \"$mod\", doesn't have any module file or module file is empty."
|
|
die 18
|
|
fi
|
|
done
|
|
else
|
|
prnt E "No module to execute!"
|
|
die 5
|
|
fi
|
|
}
|
|
export -f process_commandline_and_vars
|
|
|
|
# EOF
|