#!/usr/bin/env bash # ------------------------------------------------------------------------------ # Init.sh: initialise a computer and conform it # Copyright (c) 2019-2021 Geoffray Levasseur # ------------------------------------------------------------------------------ # This file is distributed under 3-clause BSD license. # The complete license agreement can be obtained at: # https://opensource.org/licenses/BSD-3-Clause # ------------------------------------------------------------------------------ # Global variables: # * INSTALL_MODE: if dev is declared here, packages will be installed one by # one instead of sending the whole package list to the package manage # * LOGFILE: Define manually output log file name. Can be superseeded through # command line parameter. ATTENTION: That variable cannot be set in # configuration file as it is treated before loading those, so it must be # defined before calling that script. # ------------------------------------------------------------------------------ # trace ERR through pipes set -o pipefail # trace ERR through 'time command' and other functions set -o errtrace # set -e : exit the script if any statement returns a non-true return value # exeption to that will need a special function call set -o errexit # set +u: allow undeclared variables because configuration files don't need # to be complete (even if it's bad practice) set +o nounset # We want english messages, all the time (can be redefined in configuration) export LC_ALL=C export LANG=C # Version of init export VERSION="0.99.11" # Store script's path (realpath -s resolve symlinks if init.sh is a symlink) export MYPATH=$(dirname $(realpath -s $0)) # Get hostname export HOSTNAME=$(hostname) # Load libraries for lib in $MYPATH/lib/*.sh; do . $lib done unset lib # ============================= # ==== Basic sanity checks ==== # ============================= function_exists prnt || ( echo "*** FATAL ERROR!" echo "*** Some vital functions comming from libraries are missing." exit 3 ) # ====================== # ==== Main Program ==== # ====================== # Set system dependent vars set_sys_vars $(uname -m) $(get_os_version) # Initializing global variables export CHECK_ONLY=false export JUMP=false export KEEPGOING=false export RESUME=false export STAGE_FILE="$MYPATH/stage" read_commandline $@ # After this we need to be root # (--help and --version are allowed as unprivileged user) check_root # ------------------------------------------------------------------------------ # Logfile variable treatment -- cannot be a function if [[ -n $NEW_LOGFILE ]]; then export LOGFILE=$NEW_LOGFILE else export LOGFILE=${LOGFILE:-"$MYPATH/log/init-$(uname -n)-$(stdtime).log"} fi prnt I "Creating log files welcoming directory..." if [[ ! -d $(dirname $LOGFILE) ]]; then mkdir -pv $(dirname $LOGFILE) fi # Log all outputs to the logfile exec 3>&1 4>&2 trap 'exec 2>&4 1>&3' 0 1 2 3 exec > >(tee -a $LOGFILE) exec 2> >(tee -a $LOGFILE >&2) prnt I "Starting init.sh version $VERSION." prnt I "The log file is $LOGFILE." if [[ -n $SYS_CODE ]]; then prnt I "Launch on $SYS_DIST version $SYS_VER ($SYS_CODE) on $SYS_ARCH architecture" else prnt I "Launch on $SYS_DIST version $SYS_VER on $SYS_ARCH architecture" fi # -- Cannot be a function ends here # ------------------------------------------------------------------------------ if [[ -n $CHROOT_PATH && -z $CHROOT_DONE ]]; then chroot_bootstrap $@ prnt I "Normal end of chrooted execution!" exit 0 fi load_autoconf load_configuration # Load pre and post actions for package manager for prepost in $MYPATH/prepost.d/*.sh; do . $prepost done unset $prepost process_commandline_and_vars set_system_proxy # Reinit stage file if no resuming if [[ $RESUME != true ]]; then [[ -f $STAGE_FILE ]] && rm -f $STAGE_FILE fi # Loading modules for mod in $MODULE_LIST; do . modules/$mod.sh done unset mod if [[ $RUN_SHELL == true ]]; then prnt I "Launching an interactive shell..." bash --rcfile $MYPATH/bash.rc -i prnt I "Script execution terminated after interactive shell execution." exit 0 fi # If cron mode, run cron tasks then exit if [[ $CRON_MODE == true ]]; then for mod in $MODULE_LIST; do if [[ $(function_exists cron_$mod) ]]; then prnt I "Running cron task for module $mod ..." cron_$mod else prnt I "No cron task for module $mod." fi done prnt I "All cron executed successfully !" exit 0 fi # Install basic dependencies if needed if ! command -v wget &> /dev/null; then prnt I "Installing wget as a requirement for init.sh to work..." pkginst wget fi # Run prechecks if [[ JUMP != true ]]; then tmpfile=$(mktemp /tmp/init-XXXXXX) if [[ -n $MANUAL_MODULE_LIST ]]; then prnt W "Dependency checks are deactivated with a manual module list." fi if [[ $NO_DEPS == true ]]; then prnt W "Dependency checks have been deactivated manually." fi if [[ $RESUME == true ]]; then cat $STAGE_FILE >> $tmpfile fi for mod in $MODULE_LIST; do version=VER_$mod if [[ $RESUME == true ]] && [[ $(grep $mod $STAGE_FILE) ]]; then prnt I "Checks previously executed for $mod version ${!version}." continue fi prnt I "Running initial checks for $mod version ${!version}..." if [[ -z $MANUAL_MODULE_LIST && $NO_DEPS != true ]]; then deps=DEP_$mod for dep in ${!deps}; do if [[ ! $(grep $dep $tmpfile) ]]; then prnt E "Module $mod have unsatisfied dependencies or is executed too early." prnt E " * $dep must be executed before $mod, please check your module list." die 9 fi done unset deps fi precheck_$mod echo $mod >> $tmpfile done rm -f $tmpfile unset mod fi # If we only checks, we stop here if [[ $CHECK_ONLY == true ]]; then prnt I "Checking mode only, not going any further." exit 0 fi if [[ $JUMP == true ]]; then prnt W "Not doing any checks, please use with care!" else prnt I "All checks have been run successfully." fi echo if [[ $KEEPGOING == true ]]; then echo -e "${BRed}ATTENTION : You asked to continue the script even if error occurs.${DEFAULTCOL}" echo -e "${BRed}ATTENTION : That option could produce some chaotic results.${DEFAULTCOL}" echo -e "${BRed}ATTENTION : That option should be only used on test systems.${DEFAULTCOL}" echo fi echo -e "${BYellow}If you continue after that step system will have changes!${DEFAULTCOL}" echo dump_key_buffer read -n 1 -rsp $"Press pour key to continue or an other one to stop now..." key echo if [[ $key == "C" || $key == 'c' ]]; then # We launch modules one after one for mod in $MODULE_LIST; do if [[ $RESUME == true ]] && [[ $(grep $mod $STAGE_FILE) ]]; then continue fi # We need this only if JUMP is set but doesn't matter if it's done again version=VER_$mod prnt I "Applying changes for $mod version ${!version}..." $mod echo $mod >> $STAGE_FILE # Mark as done for resuming function done unset mod echo else echo -e "${Yellow}The system has not undergone any modification.${DEFAULTCOL}" echo fi prnt I "That's all folks !" rm -f $STAGEFILE # EOF