Merge branch 'new-ufd-script' into dev
This commit is contained in:
commit
8b4b0c40ce
9 changed files with 1458 additions and 717 deletions
|
|
@ -1,671 +1,148 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/env python3
|
||||
#
|
||||
## Wizard Kit: UFD Build Tool
|
||||
#
|
||||
# Based on a template by BASH3 Boilerplate v2.3.0
|
||||
# http://bash3boilerplate.sh/#authors
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
# as you leave these references intact in the header comments of your source files.
|
||||
|
||||
# Exit on error. Append "|| true" if you expect an error.
|
||||
set -o errexit
|
||||
# Exit on error inside any functions or subshells.
|
||||
set -o errtrace
|
||||
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
|
||||
set -o nounset
|
||||
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
|
||||
set -o pipefail
|
||||
# Turn on traces, useful while debugging but commented out by default
|
||||
# set -o xtrace
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
||||
__i_am_main_script="0" # false
|
||||
|
||||
if [[ "${__usage+x}" ]]; then
|
||||
if [[ "${BASH_SOURCE[1]}" = "${0}" ]]; then
|
||||
__i_am_main_script="1" # true
|
||||
fi
|
||||
|
||||
__b3bp_external_usage="true"
|
||||
__b3bp_tmp_source_idx=1
|
||||
fi
|
||||
else
|
||||
__i_am_main_script="1" # true
|
||||
[[ "${__usage+x}" ]] && unset -v __usage
|
||||
[[ "${__helptext+x}" ]] && unset -v __helptext
|
||||
fi
|
||||
|
||||
# Set magic variables for current file, directory, os, etc.
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")"
|
||||
__base="$(basename "${__file}" .sh)"
|
||||
__wd="$(pwd)"
|
||||
__usage_example="Usage: sudo $(basename "${0}") --ufd-device [device] --linux-iso [path] --main-kit [path] --winpe-iso [path]"
|
||||
__all_args=""
|
||||
for a in "${@}"; do
|
||||
if [[ "${a:0:1}" == "-" ]]; then
|
||||
__all_args="${__all_args} ${a}"
|
||||
else
|
||||
__all_args="${__all_args} \"${a}\""
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
# Define the environment variables (and their defaults) that this script depends on
|
||||
LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
|
||||
NO_COLOR="${NO_COLOR:-}" # true = disable color. otherwise autodetected
|
||||
|
||||
|
||||
### Functions
|
||||
##############################################################################
|
||||
|
||||
function __b3bp_log () {
|
||||
local log_level="${1}"
|
||||
shift
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
local color_debug="\x1b[35m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_info="\x1b[32m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_notice="\x1b[34m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_warning="\x1b[33m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_error="\x1b[31m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_critical="\x1b[1;31m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_alert="\x1b[1;33;41m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_emergency="\x1b[1;4;5;33;41m"
|
||||
|
||||
local colorvar="color_${log_level}"
|
||||
|
||||
local color="${!colorvar:-${color_error}}"
|
||||
local color_reset="\x1b[0m"
|
||||
|
||||
if [[ "${NO_COLOR:-}" = "true" ]] || ( [[ "${TERM:-}" != *"256color"* ]] && [[ "${TERM:-}" != "xterm"* ]] && [[ "${TERM:-}" != "screen"* ]] ) || [[ ! -t 2 ]]; then
|
||||
if [[ "${NO_COLOR:-}" != "false" ]]; then
|
||||
# Don't use colors on pipes or non-recognized terminals
|
||||
color=""; color_reset=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# all remaining arguments are to be printed
|
||||
local log_line=""
|
||||
|
||||
while IFS=$'\n' read -r log_line; do
|
||||
echo -e "$(date -u +"%Y-%m-%d %H:%M:%S UTC") ${color}$(printf "[%9s]" "${log_level}")${color_reset} ${log_line}" 1>&2
|
||||
done <<< "${@:-}"
|
||||
}
|
||||
|
||||
function emergency () { __b3bp_log emergency "${@}"; exit 1; }
|
||||
function alert () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && __b3bp_log alert "${@}"; true; }
|
||||
function critical () { [[ "${LOG_LEVEL:-0}" -ge 2 ]] && __b3bp_log critical "${@}"; true; }
|
||||
function error () { [[ "${LOG_LEVEL:-0}" -ge 3 ]] && __b3bp_log error "${@}"; true; }
|
||||
function warning () { [[ "${LOG_LEVEL:-0}" -ge 4 ]] && __b3bp_log warning "${@}"; true; }
|
||||
function notice () { [[ "${LOG_LEVEL:-0}" -ge 5 ]] && __b3bp_log notice "${@}"; true; }
|
||||
function info () { [[ "${LOG_LEVEL:-0}" -ge 6 ]] && __b3bp_log info "${@}"; true; }
|
||||
function debug () { [[ "${LOG_LEVEL:-0}" -ge 7 ]] && __b3bp_log debug "${@}"; true; }
|
||||
|
||||
function help () {
|
||||
echo "" 1>&2
|
||||
echo " ${*}" 1>&2
|
||||
echo "" 1>&2
|
||||
echo " ${__usage:-No usage available}" 1>&2
|
||||
echo "" 1>&2
|
||||
|
||||
if [[ "${__helptext:-}" ]]; then
|
||||
echo " ${__helptext}" 1>&2
|
||||
echo "" 1>&2
|
||||
fi
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
### Parse commandline options
|
||||
##############################################################################
|
||||
|
||||
# Commandline options. This defines the usage page, and is used to parse cli
|
||||
# opts & defaults from. The parsing is unforgiving so be precise in your syntax
|
||||
# - A short option must be preset for every long option; but every short option
|
||||
# need not have a long option
|
||||
# - `--` is respected as the separator between options and arguments
|
||||
# - We do not bash-expand defaults, so setting '~/app' as a default will not resolve to ${HOME}.
|
||||
# you can use bash variables to work around this (so use ${HOME} instead)
|
||||
|
||||
# shellcheck disable=SC2015
|
||||
[[ "${__usage+x}" ]] || read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
OPTIONS:
|
||||
-u --ufd-device [arg] Device to which the kit will be applied
|
||||
-l --linux-iso [arg] Path to the Linux ISO
|
||||
|
||||
-e --extra-dir [arg] Path to the Extra folder (optional)
|
||||
-m --main-kit [arg] Path to the Main Kit (optional)
|
||||
-w --winpe-iso [arg] Path to the WinPE ISO (optional)
|
||||
-h --help This page
|
||||
|
||||
ADVANCED:
|
||||
-d --debug Enable debug mode
|
||||
-v --verbose Enable verbose mode
|
||||
-M --use-mbr Use real MBR instead of GPT w/ Protective MBR
|
||||
-F --force Bypass all confirmation messages. USE WITH EXTREME CAUTION!
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC2015
|
||||
[[ "${__helptext+x}" ]] || read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
Paths can be relative to the current working directory or absolute
|
||||
EOF
|
||||
|
||||
# Translate usage string -> getopts arguments, and set $arg_<flag> defaults
|
||||
while read -r __b3bp_tmp_line; do
|
||||
if [[ "${__b3bp_tmp_line}" =~ ^- ]]; then
|
||||
# fetch single character version of option string
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_line%% *}"
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_opt:1}"
|
||||
|
||||
# fetch long version if present
|
||||
__b3bp_tmp_long_opt=""
|
||||
|
||||
if [[ "${__b3bp_tmp_line}" = *"--"* ]]; then
|
||||
__b3bp_tmp_long_opt="${__b3bp_tmp_line#*--}"
|
||||
__b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}"
|
||||
fi
|
||||
|
||||
# map opt long name to+from opt short name
|
||||
printf -v "__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}" '%s' "${__b3bp_tmp_opt}"
|
||||
printf -v "__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt}" '%s' "${__b3bp_tmp_long_opt//-/_}"
|
||||
|
||||
# check if option takes an argument
|
||||
if [[ "${__b3bp_tmp_line}" =~ \[.*\] ]]; then
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
|
||||
__b3bp_tmp_init="" # it has an arg. init with ""
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "1"
|
||||
elif [[ "${__b3bp_tmp_line}" =~ \{.*\} ]]; then
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
|
||||
__b3bp_tmp_init="" # it has an arg. init with ""
|
||||
# remember that this option requires an argument
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
|
||||
else
|
||||
__b3bp_tmp_init="0" # it's a flag. init with 0
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "0"
|
||||
fi
|
||||
__b3bp_tmp_opts="${__b3bp_tmp_opts:-}${__b3bp_tmp_opt}"
|
||||
fi
|
||||
|
||||
[[ "${__b3bp_tmp_opt:-}" ]] || continue
|
||||
|
||||
if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Default= ]]; then
|
||||
# ignore default value if option does not have an argument
|
||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}"
|
||||
|
||||
if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then
|
||||
__b3bp_tmp_init="${__b3bp_tmp_line##*Default=}"
|
||||
__b3bp_tmp_re='^"(.*)"$'
|
||||
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
||||
__b3bp_tmp_init="${BASH_REMATCH[1]}"
|
||||
else
|
||||
__b3bp_tmp_re="^'(.*)'$"
|
||||
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
||||
__b3bp_tmp_init="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Required\. ]]; then
|
||||
# remember that this option requires an argument
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
|
||||
fi
|
||||
|
||||
printf -v "arg_${__b3bp_tmp_opt:0:1}" '%s' "${__b3bp_tmp_init}"
|
||||
done <<< "${__usage:-}"
|
||||
|
||||
# run getopts only if options were specified in __usage
|
||||
if [[ "${__b3bp_tmp_opts:-}" ]]; then
|
||||
# Allow long options like --this
|
||||
__b3bp_tmp_opts="${__b3bp_tmp_opts}-:"
|
||||
|
||||
# Reset in case getopts has been used previously in the shell.
|
||||
OPTIND=1
|
||||
|
||||
# start parsing command line
|
||||
set +o nounset # unexpected arguments will cause unbound variables
|
||||
# to be dereferenced
|
||||
# Overwrite $arg_<flag> defaults with the actual CLI options
|
||||
while getopts "${__b3bp_tmp_opts}" __b3bp_tmp_opt; do
|
||||
[[ "${__b3bp_tmp_opt}" = "?" ]] && help "Invalid use of script: ${*} "
|
||||
|
||||
if [[ "${__b3bp_tmp_opt}" = "-" ]]; then
|
||||
# OPTARG is long-option-name or long-option=value
|
||||
if [[ "${OPTARG}" =~ .*=.* ]]; then
|
||||
# --key=value format
|
||||
__b3bp_tmp_long_opt=${OPTARG/=*/}
|
||||
# Set opt to the short option corresponding to the long option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
OPTARG=${OPTARG#*=}
|
||||
else
|
||||
# --key value format
|
||||
# Map long name to short version of option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
# Only assign OPTARG if option takes an argument
|
||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
|
||||
printf -v "OPTARG" '%s' "${@:OPTIND:${!__b3bp_tmp_varname}}"
|
||||
# shift over the argument if argument is expected
|
||||
((OPTIND+=__b3bp_tmp_has_arg_${__b3bp_tmp_opt}))
|
||||
fi
|
||||
# we have set opt/OPTARG to the short value and the argument as OPTARG if it exists
|
||||
fi
|
||||
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}"
|
||||
__b3bp_tmp_default="${!__b3bp_tmp_varname}"
|
||||
|
||||
__b3bp_tmp_value="${OPTARG}"
|
||||
if [[ -z "${OPTARG}" ]] && [[ "${__b3bp_tmp_default}" = "0" ]]; then
|
||||
__b3bp_tmp_value="1"
|
||||
fi
|
||||
|
||||
printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}"
|
||||
debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}"
|
||||
done
|
||||
set -o nounset # no more unbound variable references expected
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
if [[ "${1:-}" = "--" ]] ; then
|
||||
shift
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
### Automatic validation of required option arguments
|
||||
##############################################################################
|
||||
|
||||
for __b3bp_tmp_varname in ${!__b3bp_tmp_has_arg_*}; do
|
||||
# validate only options which required an argument
|
||||
[[ "${!__b3bp_tmp_varname}" = "2" ]] || continue
|
||||
|
||||
__b3bp_tmp_opt_short="${__b3bp_tmp_varname##*_}"
|
||||
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt_short}"
|
||||
[[ "${!__b3bp_tmp_varname}" ]] && continue
|
||||
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt_short}"
|
||||
printf -v "__b3bp_tmp_opt_long" '%s' "${!__b3bp_tmp_varname}"
|
||||
[[ "${__b3bp_tmp_opt_long:-}" ]] && __b3bp_tmp_opt_long=" (--${__b3bp_tmp_opt_long//_/-})"
|
||||
|
||||
help "Option -${__b3bp_tmp_opt_short}${__b3bp_tmp_opt_long:-} requires an argument"
|
||||
done
|
||||
|
||||
|
||||
### Cleanup Environment variables
|
||||
##############################################################################
|
||||
|
||||
for __tmp_varname in ${!__b3bp_tmp_*}; do
|
||||
unset -v "${__tmp_varname}"
|
||||
done
|
||||
|
||||
unset -v __tmp_varname
|
||||
|
||||
|
||||
### Externally supplied __usage. Nothing else to do here
|
||||
##############################################################################
|
||||
|
||||
if [[ "${__b3bp_external_usage:-}" = "true" ]]; then
|
||||
unset -v __b3bp_external_usage
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
### Signal trapping and backtracing
|
||||
##############################################################################
|
||||
|
||||
function __b3bp_cleanup_before_exit () {
|
||||
if [[ "$EUID" -eq 0 ]]; then
|
||||
for d in Dest Linux WinPE; do
|
||||
if [[ -d "/mnt/${d}" ]]; then
|
||||
umount "/mnt/${d}" || true
|
||||
rmdir "/mnt/${d}" || true
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [[ "${?}" != "0" ]]; then
|
||||
info "Sources unmounted"
|
||||
fi
|
||||
if [[ ${arg_F:-} == 0 && "${SILENT:-False}" == "False" ]]; then
|
||||
read -r -p "Press Enter to exit... " ignored_var 2>&1
|
||||
fi
|
||||
}
|
||||
trap __b3bp_cleanup_before_exit EXIT
|
||||
|
||||
# requires `set -o errtrace`
|
||||
__b3bp_err_report() {
|
||||
local error_code
|
||||
error_code=${?}
|
||||
error "Error in ${__file} in function ${1} on line ${2}"
|
||||
exit ${error_code}
|
||||
}
|
||||
# Uncomment the following line for always providing an error backtrace
|
||||
trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
|
||||
|
||||
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
|
||||
##############################################################################
|
||||
|
||||
# debug mode
|
||||
if [[ "${arg_d:?}" = "1" ]]; then
|
||||
set -o xtrace
|
||||
LOG_LEVEL="7"
|
||||
# Enable error backtracing
|
||||
trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
fi
|
||||
|
||||
# verbose mode
|
||||
if [[ "${arg_v:?}" = "1" ]]; then
|
||||
set -o verbose
|
||||
fi
|
||||
|
||||
|
||||
### Validation. Error out if the things required for your script are not present
|
||||
##############################################################################
|
||||
|
||||
if [[ "${arg_F:?}" == 1 ]]; then
|
||||
SILENT="True"
|
||||
else
|
||||
SILENT="False"
|
||||
fi
|
||||
if [[ "${arg_M:?}" == 1 ]]; then
|
||||
USE_MBR="True"
|
||||
else
|
||||
USE_MBR="False"
|
||||
fi
|
||||
|
||||
if [[ "${arg_h:?}" == 1 ]]; then
|
||||
help "${__usage_example}"
|
||||
else
|
||||
# Print warning line
|
||||
[[ "${arg_u:-}" ]] || echo " -u or --ufd-device is required"
|
||||
[[ "${arg_l:-}" ]] || echo " -l or --linux-iso is required"
|
||||
|
||||
# Bail if necessary
|
||||
[[ "${arg_u:-}" ]] || help "${__usage_example}"
|
||||
[[ "${arg_l:-}" ]] || help "${__usage_example}"
|
||||
fi
|
||||
[[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. "
|
||||
|
||||
|
||||
### More functions
|
||||
##############################################################################
|
||||
|
||||
function abort () {
|
||||
local abort_message="Aborted"
|
||||
[[ "${1:-}" ]] && abort_message="${1}" || true
|
||||
error "${abort_message}"
|
||||
#echo -e "${YELLOW}${abort_message}${CLEAR}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function ask() {
|
||||
if [[ "${SILENT}" == "True" ]]; then
|
||||
echo -e "${1:-} Yes ${BLUE}(Silent)${CLEAR}"
|
||||
return 0
|
||||
fi
|
||||
while :; do
|
||||
read -p "${1:-} [Y/N] " -r answer
|
||||
if echo "$answer" | egrep -iq '^(y|yes|sure)$'; then
|
||||
return 0
|
||||
elif echo "$answer" | egrep -iq '^(n|no|nope)$'; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
### Runtime
|
||||
##############################################################################
|
||||
|
||||
# VARIABLES
|
||||
DEST_DEV="${arg_u}"
|
||||
DEST_PAR="${DEST_DEV}1"
|
||||
LOG_FILE="$(getent passwd "$SUDO_USER" | cut -d: -f6)/Logs/build-ufd_${DEST_DEV##*/}_$(date +%Y-%m-%d_%H%M_%z).log"
|
||||
MAIN_PY="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/settings/main.py"
|
||||
RSYNC_ARGS="-hrtuvS --modify-window=1 --progress"
|
||||
MAIN_KIT="$(realpath "${arg_m:-}" 2>/dev/null || true)"
|
||||
LINUX_ISO="$(realpath "${arg_l:-}" 2>/dev/null || true)"
|
||||
WINPE_ISO="$(realpath "${arg_w:-}" 2>/dev/null || true)"
|
||||
EXTRA_DIR="$(realpath "${arg_e:-}" 2>/dev/null || true)"
|
||||
mkdir -p "$(dirname "$LOG_FILE")"
|
||||
chown "$SUDO_USER:$SUDO_USER" -R "$(dirname "$LOG_FILE")"
|
||||
|
||||
# COLORS
|
||||
CLEAR="\e[0m"
|
||||
RED="\e[31m"
|
||||
GREEN="\e[32m"
|
||||
YELLOW="\e[33m"
|
||||
BLUE="\e[34m"
|
||||
|
||||
# Load main.py settings
|
||||
if [ ! -f "${MAIN_PY}" ]; then
|
||||
echo -e "${RED}ERROR${CLEAR}: ${MAIN_PY} not found."
|
||||
abort
|
||||
fi
|
||||
while read line; do
|
||||
if echo "${line}" | egrep -q "^\w+='"; then
|
||||
line="$(echo "${line}" | sed -r 's/[\r\n]+//')"
|
||||
eval "${line}"
|
||||
fi
|
||||
done < "${MAIN_PY}"
|
||||
if [ -z ${KIT_NAME_FULL+x} ]; then
|
||||
# KIT_NAME_FULL is not set, assume main.py missing or malformatted
|
||||
echo -e "${RED}ERROR${CLEAR}: failed to load settings from ${MAIN_PY}"
|
||||
abort
|
||||
fi
|
||||
ISO_LABEL="${KIT_NAME_SHORT}_LINUX"
|
||||
UFD_LABEL="${KIT_NAME_SHORT}_UFD"
|
||||
|
||||
# Check if root
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
echo -e "${RED}ERROR${CLEAR}: This script must be run as root."
|
||||
abort
|
||||
fi
|
||||
|
||||
# Check if in tmux
|
||||
if ! tmux list-session 2>/dev/null | grep -q "build-ufd"; then
|
||||
# Reload in tmux
|
||||
eval tmux new-session -s "build-ufd" "${0:-}" ${__all_args}
|
||||
SILENT="True" # avoid two "Press Enter to exit..." prompts
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Header
|
||||
echo -e "${GREEN}${KIT_NAME_FULL}${CLEAR}: UFD Build Tool"
|
||||
echo ""
|
||||
|
||||
# Verify sources
|
||||
[[ -b "${DEST_DEV}" ]] || abort "${DEST_DEV} is not a valid device."
|
||||
[[ -e "${LINUX_ISO}" ]] || abort "Linux ISO not found."
|
||||
if [[ ! -z "${arg_m:-}" ]]; then
|
||||
[[ -d "${MAIN_KIT}/.bin" ]] || abort "Invalid Main Kit, ${MAIN_KIT}/.bin not found."
|
||||
fi
|
||||
if [[ ! -z "${arg_w:-}" ]]; then
|
||||
[[ -e "${WINPE_ISO}" ]] || abort "WinPE ISO not found."
|
||||
fi
|
||||
if [[ ! -z "${arg_e:-}" ]]; then
|
||||
[[ -d "${EXTRA_DIR}" ]] || abort "Extra Dir not found."
|
||||
fi
|
||||
|
||||
# Print Info
|
||||
echo -e "${BLUE}Sources${CLEAR}" | tee -a "${LOG_FILE}"
|
||||
echo "Main Kit: ${MAIN_KIT}" | tee -a "${LOG_FILE}"
|
||||
echo "Linux ISO: ${LINUX_ISO}" | tee -a "${LOG_FILE}"
|
||||
echo "WinPE ISO: ${WINPE_ISO}" | tee -a "${LOG_FILE}"
|
||||
echo "Extra Dir: ${EXTRA_DIR:-(Not Specified)}" | tee -a "${LOG_FILE}"
|
||||
echo "" | tee -a "${LOG_FILE}"
|
||||
echo -e "${BLUE}Destination${CLEAR}" | tee -a "${LOG_FILE}"
|
||||
lsblk -n -o NAME,LABEL,SIZE,MODEL,SERIAL "${DEST_DEV}" | tee -a "${LOG_FILE}"
|
||||
if [[ "${USE_MBR}" == "True" ]]; then
|
||||
echo -e "${YELLOW}Formatting using legacy MBR${CLEAR}" | tee -a "${LOG_FILE}"
|
||||
fi
|
||||
echo "" | tee -a "${LOG_FILE}"
|
||||
|
||||
# Ask before starting job
|
||||
echo ""
|
||||
if ask "Is the above information correct?"; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}SAFETY CHECK${CLEAR}"
|
||||
echo "All data will be DELETED from the disk and partition(s) listed above."
|
||||
echo -e "This is irreversible and will lead to ${RED}DATA LOSS.${CLEAR}"
|
||||
if ! ask "Asking again to confirm, is this correct?"; then
|
||||
abort
|
||||
fi
|
||||
else
|
||||
abort
|
||||
fi
|
||||
|
||||
# Start Build
|
||||
echo "" | tee -a "${LOG_FILE}"
|
||||
echo -e "${GREEN}Building Kit${CLEAR}" | tee -a "${LOG_FILE}"
|
||||
touch "${LOG_FILE}"
|
||||
tmux split-window -dl 10 tail -f "${LOG_FILE}"
|
||||
|
||||
# Zero beginning of device
|
||||
dd bs=4M count=16 if=/dev/zero of="${DEST_DEV}" >> "${LOG_FILE}" 2>&1
|
||||
|
||||
# Format
|
||||
echo "Formatting drive..." | tee -a "${LOG_FILE}"
|
||||
if [[ "${USE_MBR}" == "True" ]]; then
|
||||
parted "${DEST_DEV}" --script -- mklabel msdos mkpart primary fat32 4MiB -1s >> "${LOG_FILE}" 2>&1
|
||||
parted "${DEST_DEV}" set 1 boot on >> "${LOG_FILE}" 2>&1
|
||||
else
|
||||
parted "${DEST_DEV}" --script -- mklabel gpt mkpart primary fat32 4MiB -4MiB >> "${LOG_FILE}" 2>&1
|
||||
parted "${DEST_DEV}" set 1 legacy_boot on >> "${LOG_FILE}" 2>&1
|
||||
#parted "${DEST_DEV}" disk_set pmbr_boot on >> "${LOG_FILE}" 2>&1
|
||||
# pmbr_boot breaks detection on some UEFI MOBOs
|
||||
fi
|
||||
mkfs.vfat -F 32 -n "${UFD_LABEL}" "${DEST_PAR}" >> "${LOG_FILE}" 2>&1
|
||||
|
||||
# Mount sources and dest
|
||||
echo "Mounting sources and destination..." | tee -a "${LOG_FILE}"
|
||||
mkdir /mnt/{Dest,Linux,WinPE} -p >> "${LOG_FILE}" 2>&1
|
||||
mount ${DEST_PAR} /mnt/Dest >> "${LOG_FILE}" 2>&1
|
||||
mount "${LINUX_ISO}" /mnt/Linux -r >> "${LOG_FILE}" 2>&1
|
||||
if [[ ! -z "${arg_w:-}" ]]; then
|
||||
mount "${WINPE_ISO}" /mnt/WinPE -r >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
|
||||
# Find WinPE source
|
||||
w_boot="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot")"
|
||||
w_boot_bcd="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot/BCD")"
|
||||
w_boot_sdi="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot/boot.sdi")"
|
||||
w_bootmgr="$(find /mnt/WinPE -iwholename "/mnt/WinPE/bootmgr")"
|
||||
w_bootmgr_efi="$(find /mnt/WinPE -iwholename "/mnt/WinPE/bootmgr.efi")"
|
||||
w_efi_boot="$(find /mnt/WinPE -iwholename "/mnt/WinPE/EFI/Boot")"
|
||||
w_efi_microsoft="$(find /mnt/WinPE -iwholename "/mnt/WinPE/EFI/Microsoft")"
|
||||
w_en_us="$(find /mnt/WinPE -iwholename "/mnt/WinPE/en-us")"
|
||||
w_sources="$(find /mnt/WinPE -iwholename "/mnt/WinPE/sources")"
|
||||
|
||||
# Copy files
|
||||
echo "Copying Linux files..." | tee -a "${LOG_FILE}"
|
||||
rsync ${RSYNC_ARGS} /mnt/Linux/* /mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
sed -i "s/${ISO_LABEL}/${UFD_LABEL}/" /mnt/Dest/EFI/boot/refind.conf
|
||||
sed -i "s/${ISO_LABEL}/${UFD_LABEL}/" /mnt/Dest/arch/boot/syslinux/*cfg
|
||||
|
||||
echo "Copying WinPE files..." | tee -a "${LOG_FILE}"
|
||||
if [[ ! -z "${arg_w:-}" ]]; then
|
||||
if [[ ! -z "${w_bootmgr:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_bootmgr}" /mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_bootmgr_efi:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_bootmgr_efi}" /mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_en_us:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_en_us}" /mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_boot:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_boot}"/* /mnt/Dest/Boot/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_efi_boot:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_efi_boot}"/* /mnt/Dest/EFI/Microsoft/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_efi_microsoft:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_efi_microsoft}"/* /mnt/Dest/EFI/Microsoft/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_boot_bcd:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_boot_bcd}" /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_boot_sdi:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_boot_sdi}" /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_bootmgr:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_bootmgr}" /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_sources:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_sources}"/* /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
|
||||
# Uncomment boot entries
|
||||
sed -i "s/#UFD-WINPE#//" /mnt/Dest/EFI/boot/refind.conf
|
||||
sed -i "s/#UFD-WINPE#//" /mnt/Dest/arch/boot/syslinux/*cfg
|
||||
fi
|
||||
|
||||
echo "Copying Main Kit..." | tee -a "${LOG_FILE}"
|
||||
if [[ ! -z "${arg_m:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} \
|
||||
"${MAIN_KIT}/" \
|
||||
"/mnt/Dest/${KIT_NAME_FULL}/" >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
|
||||
if [[ ! -z "${EXTRA_DIR:-}" ]]; then
|
||||
echo "Copying Extra files..." | tee -a "${LOG_FILE}"
|
||||
rsync ${RSYNC_ARGS} \
|
||||
"${EXTRA_DIR}"/ \
|
||||
/mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
|
||||
# Install syslinux
|
||||
echo "Copying Syslinux files..." | tee -a "${LOG_FILE}"
|
||||
rsync ${RSYNC_ARGS} /usr/lib/syslinux/bios/*.c32 /mnt/Dest/arch/boot/syslinux/ >> "${LOG_FILE}" 2>&1
|
||||
syslinux --install -d /arch/boot/syslinux/ ${DEST_PAR} >> "${LOG_FILE}" 2>&1
|
||||
|
||||
echo "Unmounting destination..." | tee -a "${LOG_FILE}"
|
||||
umount /mnt/Dest >> "${LOG_FILE}" 2>&1
|
||||
rmdir /mnt/Dest >> "${LOG_FILE}" 2>&1
|
||||
sync
|
||||
|
||||
echo "Installing Syslinux MBR..." | tee -a "${LOG_FILE}"
|
||||
if [[ "${USE_MBR}" == "True" ]]; then
|
||||
dd bs=440 count=1 if=/usr/lib/syslinux/bios/mbr.bin of=${DEST_DEV} >> "${LOG_FILE}" 2>&1
|
||||
else
|
||||
dd bs=440 count=1 if=/usr/lib/syslinux/bios/gptmbr.bin of=${DEST_DEV} >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
sync
|
||||
|
||||
# Cleanup
|
||||
echo "Hiding boot files..." | tee -a "${LOG_FILE}"
|
||||
echo "drive s: file=\"${DEST_PAR}\"" > /root/.mtoolsrc
|
||||
echo 'mtools_skip_check=1' >> /root/.mtoolsrc
|
||||
for item in arch Boot bootmgr{,.efi} EFI en-us images isolinux sources "${KIT_NAME_FULL}"/{.bin,.cbin}; do
|
||||
yes | mattrib +h "S:/${item}" >> "${LOG_FILE}" 2>&1 || true
|
||||
done
|
||||
sync
|
||||
|
||||
# Unmount Sources
|
||||
echo "Unmounting sources..." | tee -a "${LOG_FILE}"
|
||||
for d in Linux WinPE; do
|
||||
umount "/mnt/${d}" >> "${LOG_FILE}" 2>&1 || true
|
||||
rmdir "/mnt/${d}" >> "${LOG_FILE}" 2>&1 || true
|
||||
done
|
||||
|
||||
# Close progress pane
|
||||
pkill -f "tail.*${LOG_FILE}"
|
||||
|
||||
# Done
|
||||
echo "" | tee -a "${LOG_FILE}"
|
||||
echo "Done." | tee -a "${LOG_FILE}"
|
||||
echo ""
|
||||
exit 0
|
||||
# pylint: disable=no-name-in-module,wildcard-import
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
"""Wizard Kit: UFD build tool"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from docopt import docopt
|
||||
from functions.common import *
|
||||
from functions.ufd import *
|
||||
from settings.ufd import *
|
||||
init_global_vars(silent=True)
|
||||
|
||||
# Main section
|
||||
if __name__ == '__main__':
|
||||
# pylint: disable=invalid-name
|
||||
# Set log
|
||||
try:
|
||||
global_vars['LogDir'] = '{}/Logs'.format(
|
||||
get_user_home(get_user_name()))
|
||||
set_log_file('Build UFD ({Date-Time}).log'.format(**global_vars))
|
||||
except: # pylint: disable=bare-except
|
||||
major_exception()
|
||||
|
||||
# Header
|
||||
print_success(KIT_NAME_FULL)
|
||||
print_standard('UFD Build Tool')
|
||||
print_standard(' ')
|
||||
|
||||
# Check if running as root
|
||||
if not running_as_root():
|
||||
print_error('ERROR: This script is meant to be run as root.')
|
||||
abort(False)
|
||||
|
||||
# Docopt
|
||||
try:
|
||||
args = docopt(DOCSTRING)
|
||||
except SystemExit as sys_exit:
|
||||
# Catch docopt exits
|
||||
exit_script(sys_exit.code)
|
||||
except: # pylint: disable=bare-except
|
||||
major_exception()
|
||||
|
||||
try:
|
||||
# Verify selections
|
||||
ufd_dev = verify_ufd(args['--ufd-device'])
|
||||
sources = verify_sources(args, UFD_SOURCES)
|
||||
show_selections(args, sources, ufd_dev, UFD_SOURCES)
|
||||
if not args['--force']:
|
||||
confirm_selections(args)
|
||||
|
||||
# Prep UFD
|
||||
print_info('Prep UFD')
|
||||
if args['--update']:
|
||||
# Remove arch folder
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Removing Linux...',
|
||||
function=remove_arch,
|
||||
)
|
||||
else:
|
||||
# Format and partition
|
||||
prep_device(ufd_dev, UFD_LABEL, use_mbr=args['--use-mbr'])
|
||||
|
||||
# Mount UFD
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Mounting UFD...',
|
||||
function=mount,
|
||||
mount_source=find_first_partition(ufd_dev),
|
||||
mount_point='/mnt/UFD',
|
||||
)
|
||||
|
||||
# Copy sources
|
||||
print_standard(' ')
|
||||
print_info('Copy Sources')
|
||||
for s_label, s_path in sources.items():
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Copying {}...'.format(s_label),
|
||||
function=copy_source,
|
||||
source=s_path,
|
||||
items=ITEMS[s_label],
|
||||
overwrite=True,
|
||||
)
|
||||
|
||||
# Update boot entries
|
||||
print_standard(' ')
|
||||
print_info('Boot Setup')
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Updating boot entries...',
|
||||
function=update_boot_entries,
|
||||
boot_entries=BOOT_ENTRIES,
|
||||
boot_files=BOOT_FILES,
|
||||
iso_label=ISO_LABEL,
|
||||
ufd_label=UFD_LABEL,
|
||||
)
|
||||
|
||||
# Install syslinux (to partition)
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Syslinux (partition)...',
|
||||
function=install_syslinux_to_partition,
|
||||
partition=find_first_partition(ufd_dev),
|
||||
)
|
||||
|
||||
# Unmount UFD
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Unmounting UFD...',
|
||||
function=unmount,
|
||||
mount_point='/mnt/UFD',
|
||||
)
|
||||
|
||||
# Install syslinux (to device)
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Syslinux (device)...',
|
||||
function=install_syslinux_to_dev,
|
||||
ufd_dev=ufd_dev,
|
||||
use_mbr=args['--use-mbr'],
|
||||
)
|
||||
|
||||
# Hide items
|
||||
print_standard(' ')
|
||||
print_info('Final Touches')
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Hiding items...',
|
||||
function=hide_items,
|
||||
ufd_dev=ufd_dev,
|
||||
items=ITEMS_HIDDEN,
|
||||
)
|
||||
|
||||
# Done
|
||||
if not args['--force']:
|
||||
print_standard('\nDone.')
|
||||
pause('Press Enter to exit...')
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except: # pylint: disable=bare-except
|
||||
major_exception()
|
||||
|
|
|
|||
671
.bin/Scripts/build-ufd.bash
Executable file
671
.bin/Scripts/build-ufd.bash
Executable file
|
|
@ -0,0 +1,671 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
## Wizard Kit: UFD Build Tool
|
||||
#
|
||||
# Based on a template by BASH3 Boilerplate v2.3.0
|
||||
# http://bash3boilerplate.sh/#authors
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
# Copyright (c) 2013 Kevin van Zonneveld and contributors
|
||||
# You are not obligated to bundle the LICENSE file with your b3bp projects as long
|
||||
# as you leave these references intact in the header comments of your source files.
|
||||
|
||||
# Exit on error. Append "|| true" if you expect an error.
|
||||
set -o errexit
|
||||
# Exit on error inside any functions or subshells.
|
||||
set -o errtrace
|
||||
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
|
||||
set -o nounset
|
||||
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
|
||||
set -o pipefail
|
||||
# Turn on traces, useful while debugging but commented out by default
|
||||
# set -o xtrace
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
||||
__i_am_main_script="0" # false
|
||||
|
||||
if [[ "${__usage+x}" ]]; then
|
||||
if [[ "${BASH_SOURCE[1]}" = "${0}" ]]; then
|
||||
__i_am_main_script="1" # true
|
||||
fi
|
||||
|
||||
__b3bp_external_usage="true"
|
||||
__b3bp_tmp_source_idx=1
|
||||
fi
|
||||
else
|
||||
__i_am_main_script="1" # true
|
||||
[[ "${__usage+x}" ]] && unset -v __usage
|
||||
[[ "${__helptext+x}" ]] && unset -v __helptext
|
||||
fi
|
||||
|
||||
# Set magic variables for current file, directory, os, etc.
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")"
|
||||
__base="$(basename "${__file}" .sh)"
|
||||
__wd="$(pwd)"
|
||||
__usage_example="Usage: sudo $(basename "${0}") --ufd-device [device] --linux-iso [path] --main-kit [path] --winpe-iso [path]"
|
||||
__all_args=""
|
||||
for a in "${@}"; do
|
||||
if [[ "${a:0:1}" == "-" ]]; then
|
||||
__all_args="${__all_args} ${a}"
|
||||
else
|
||||
__all_args="${__all_args} \"${a}\""
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
# Define the environment variables (and their defaults) that this script depends on
|
||||
LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
|
||||
NO_COLOR="${NO_COLOR:-}" # true = disable color. otherwise autodetected
|
||||
|
||||
|
||||
### Functions
|
||||
##############################################################################
|
||||
|
||||
function __b3bp_log () {
|
||||
local log_level="${1}"
|
||||
shift
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
local color_debug="\x1b[35m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_info="\x1b[32m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_notice="\x1b[34m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_warning="\x1b[33m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_error="\x1b[31m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_critical="\x1b[1;31m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_alert="\x1b[1;33;41m"
|
||||
# shellcheck disable=SC2034
|
||||
local color_emergency="\x1b[1;4;5;33;41m"
|
||||
|
||||
local colorvar="color_${log_level}"
|
||||
|
||||
local color="${!colorvar:-${color_error}}"
|
||||
local color_reset="\x1b[0m"
|
||||
|
||||
if [[ "${NO_COLOR:-}" = "true" ]] || ( [[ "${TERM:-}" != *"256color"* ]] && [[ "${TERM:-}" != "xterm"* ]] && [[ "${TERM:-}" != "screen"* ]] ) || [[ ! -t 2 ]]; then
|
||||
if [[ "${NO_COLOR:-}" != "false" ]]; then
|
||||
# Don't use colors on pipes or non-recognized terminals
|
||||
color=""; color_reset=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# all remaining arguments are to be printed
|
||||
local log_line=""
|
||||
|
||||
while IFS=$'\n' read -r log_line; do
|
||||
echo -e "$(date -u +"%Y-%m-%d %H:%M:%S UTC") ${color}$(printf "[%9s]" "${log_level}")${color_reset} ${log_line}" 1>&2
|
||||
done <<< "${@:-}"
|
||||
}
|
||||
|
||||
function emergency () { __b3bp_log emergency "${@}"; exit 1; }
|
||||
function alert () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && __b3bp_log alert "${@}"; true; }
|
||||
function critical () { [[ "${LOG_LEVEL:-0}" -ge 2 ]] && __b3bp_log critical "${@}"; true; }
|
||||
function error () { [[ "${LOG_LEVEL:-0}" -ge 3 ]] && __b3bp_log error "${@}"; true; }
|
||||
function warning () { [[ "${LOG_LEVEL:-0}" -ge 4 ]] && __b3bp_log warning "${@}"; true; }
|
||||
function notice () { [[ "${LOG_LEVEL:-0}" -ge 5 ]] && __b3bp_log notice "${@}"; true; }
|
||||
function info () { [[ "${LOG_LEVEL:-0}" -ge 6 ]] && __b3bp_log info "${@}"; true; }
|
||||
function debug () { [[ "${LOG_LEVEL:-0}" -ge 7 ]] && __b3bp_log debug "${@}"; true; }
|
||||
|
||||
function help () {
|
||||
echo "" 1>&2
|
||||
echo " ${*}" 1>&2
|
||||
echo "" 1>&2
|
||||
echo " ${__usage:-No usage available}" 1>&2
|
||||
echo "" 1>&2
|
||||
|
||||
if [[ "${__helptext:-}" ]]; then
|
||||
echo " ${__helptext}" 1>&2
|
||||
echo "" 1>&2
|
||||
fi
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
### Parse commandline options
|
||||
##############################################################################
|
||||
|
||||
# Commandline options. This defines the usage page, and is used to parse cli
|
||||
# opts & defaults from. The parsing is unforgiving so be precise in your syntax
|
||||
# - A short option must be preset for every long option; but every short option
|
||||
# need not have a long option
|
||||
# - `--` is respected as the separator between options and arguments
|
||||
# - We do not bash-expand defaults, so setting '~/app' as a default will not resolve to ${HOME}.
|
||||
# you can use bash variables to work around this (so use ${HOME} instead)
|
||||
|
||||
# shellcheck disable=SC2015
|
||||
[[ "${__usage+x}" ]] || read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
OPTIONS:
|
||||
-u --ufd-device [arg] Device to which the kit will be applied
|
||||
-l --linux-iso [arg] Path to the Linux ISO
|
||||
|
||||
-e --extra-dir [arg] Path to the Extra folder (optional)
|
||||
-m --main-kit [arg] Path to the Main Kit (optional)
|
||||
-w --winpe-iso [arg] Path to the WinPE ISO (optional)
|
||||
-h --help This page
|
||||
|
||||
ADVANCED:
|
||||
-d --debug Enable debug mode
|
||||
-v --verbose Enable verbose mode
|
||||
-M --use-mbr Use real MBR instead of GPT w/ Protective MBR
|
||||
-F --force Bypass all confirmation messages. USE WITH EXTREME CAUTION!
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC2015
|
||||
[[ "${__helptext+x}" ]] || read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered
|
||||
Paths can be relative to the current working directory or absolute
|
||||
EOF
|
||||
|
||||
# Translate usage string -> getopts arguments, and set $arg_<flag> defaults
|
||||
while read -r __b3bp_tmp_line; do
|
||||
if [[ "${__b3bp_tmp_line}" =~ ^- ]]; then
|
||||
# fetch single character version of option string
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_line%% *}"
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_opt:1}"
|
||||
|
||||
# fetch long version if present
|
||||
__b3bp_tmp_long_opt=""
|
||||
|
||||
if [[ "${__b3bp_tmp_line}" = *"--"* ]]; then
|
||||
__b3bp_tmp_long_opt="${__b3bp_tmp_line#*--}"
|
||||
__b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}"
|
||||
fi
|
||||
|
||||
# map opt long name to+from opt short name
|
||||
printf -v "__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}" '%s' "${__b3bp_tmp_opt}"
|
||||
printf -v "__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt}" '%s' "${__b3bp_tmp_long_opt//-/_}"
|
||||
|
||||
# check if option takes an argument
|
||||
if [[ "${__b3bp_tmp_line}" =~ \[.*\] ]]; then
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
|
||||
__b3bp_tmp_init="" # it has an arg. init with ""
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "1"
|
||||
elif [[ "${__b3bp_tmp_line}" =~ \{.*\} ]]; then
|
||||
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
|
||||
__b3bp_tmp_init="" # it has an arg. init with ""
|
||||
# remember that this option requires an argument
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
|
||||
else
|
||||
__b3bp_tmp_init="0" # it's a flag. init with 0
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "0"
|
||||
fi
|
||||
__b3bp_tmp_opts="${__b3bp_tmp_opts:-}${__b3bp_tmp_opt}"
|
||||
fi
|
||||
|
||||
[[ "${__b3bp_tmp_opt:-}" ]] || continue
|
||||
|
||||
if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Default= ]]; then
|
||||
# ignore default value if option does not have an argument
|
||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}"
|
||||
|
||||
if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then
|
||||
__b3bp_tmp_init="${__b3bp_tmp_line##*Default=}"
|
||||
__b3bp_tmp_re='^"(.*)"$'
|
||||
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
||||
__b3bp_tmp_init="${BASH_REMATCH[1]}"
|
||||
else
|
||||
__b3bp_tmp_re="^'(.*)'$"
|
||||
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
||||
__b3bp_tmp_init="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Required\. ]]; then
|
||||
# remember that this option requires an argument
|
||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
|
||||
fi
|
||||
|
||||
printf -v "arg_${__b3bp_tmp_opt:0:1}" '%s' "${__b3bp_tmp_init}"
|
||||
done <<< "${__usage:-}"
|
||||
|
||||
# run getopts only if options were specified in __usage
|
||||
if [[ "${__b3bp_tmp_opts:-}" ]]; then
|
||||
# Allow long options like --this
|
||||
__b3bp_tmp_opts="${__b3bp_tmp_opts}-:"
|
||||
|
||||
# Reset in case getopts has been used previously in the shell.
|
||||
OPTIND=1
|
||||
|
||||
# start parsing command line
|
||||
set +o nounset # unexpected arguments will cause unbound variables
|
||||
# to be dereferenced
|
||||
# Overwrite $arg_<flag> defaults with the actual CLI options
|
||||
while getopts "${__b3bp_tmp_opts}" __b3bp_tmp_opt; do
|
||||
[[ "${__b3bp_tmp_opt}" = "?" ]] && help "Invalid use of script: ${*} "
|
||||
|
||||
if [[ "${__b3bp_tmp_opt}" = "-" ]]; then
|
||||
# OPTARG is long-option-name or long-option=value
|
||||
if [[ "${OPTARG}" =~ .*=.* ]]; then
|
||||
# --key=value format
|
||||
__b3bp_tmp_long_opt=${OPTARG/=*/}
|
||||
# Set opt to the short option corresponding to the long option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
OPTARG=${OPTARG#*=}
|
||||
else
|
||||
# --key value format
|
||||
# Map long name to short version of option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
# Only assign OPTARG if option takes an argument
|
||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
|
||||
printf -v "OPTARG" '%s' "${@:OPTIND:${!__b3bp_tmp_varname}}"
|
||||
# shift over the argument if argument is expected
|
||||
((OPTIND+=__b3bp_tmp_has_arg_${__b3bp_tmp_opt}))
|
||||
fi
|
||||
# we have set opt/OPTARG to the short value and the argument as OPTARG if it exists
|
||||
fi
|
||||
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}"
|
||||
__b3bp_tmp_default="${!__b3bp_tmp_varname}"
|
||||
|
||||
__b3bp_tmp_value="${OPTARG}"
|
||||
if [[ -z "${OPTARG}" ]] && [[ "${__b3bp_tmp_default}" = "0" ]]; then
|
||||
__b3bp_tmp_value="1"
|
||||
fi
|
||||
|
||||
printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}"
|
||||
debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}"
|
||||
done
|
||||
set -o nounset # no more unbound variable references expected
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
if [[ "${1:-}" = "--" ]] ; then
|
||||
shift
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
### Automatic validation of required option arguments
|
||||
##############################################################################
|
||||
|
||||
for __b3bp_tmp_varname in ${!__b3bp_tmp_has_arg_*}; do
|
||||
# validate only options which required an argument
|
||||
[[ "${!__b3bp_tmp_varname}" = "2" ]] || continue
|
||||
|
||||
__b3bp_tmp_opt_short="${__b3bp_tmp_varname##*_}"
|
||||
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt_short}"
|
||||
[[ "${!__b3bp_tmp_varname}" ]] && continue
|
||||
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt_short}"
|
||||
printf -v "__b3bp_tmp_opt_long" '%s' "${!__b3bp_tmp_varname}"
|
||||
[[ "${__b3bp_tmp_opt_long:-}" ]] && __b3bp_tmp_opt_long=" (--${__b3bp_tmp_opt_long//_/-})"
|
||||
|
||||
help "Option -${__b3bp_tmp_opt_short}${__b3bp_tmp_opt_long:-} requires an argument"
|
||||
done
|
||||
|
||||
|
||||
### Cleanup Environment variables
|
||||
##############################################################################
|
||||
|
||||
for __tmp_varname in ${!__b3bp_tmp_*}; do
|
||||
unset -v "${__tmp_varname}"
|
||||
done
|
||||
|
||||
unset -v __tmp_varname
|
||||
|
||||
|
||||
### Externally supplied __usage. Nothing else to do here
|
||||
##############################################################################
|
||||
|
||||
if [[ "${__b3bp_external_usage:-}" = "true" ]]; then
|
||||
unset -v __b3bp_external_usage
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
### Signal trapping and backtracing
|
||||
##############################################################################
|
||||
|
||||
function __b3bp_cleanup_before_exit () {
|
||||
if [[ "$EUID" -eq 0 ]]; then
|
||||
for d in Dest Linux WinPE; do
|
||||
if [[ -d "/mnt/${d}" ]]; then
|
||||
umount "/mnt/${d}" || true
|
||||
rmdir "/mnt/${d}" || true
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [[ "${?}" != "0" ]]; then
|
||||
info "Sources unmounted"
|
||||
fi
|
||||
if [[ ${arg_F:-} == 0 && "${SILENT:-False}" == "False" ]]; then
|
||||
read -r -p "Press Enter to exit... " ignored_var 2>&1
|
||||
fi
|
||||
}
|
||||
trap __b3bp_cleanup_before_exit EXIT
|
||||
|
||||
# requires `set -o errtrace`
|
||||
__b3bp_err_report() {
|
||||
local error_code
|
||||
error_code=${?}
|
||||
error "Error in ${__file} in function ${1} on line ${2}"
|
||||
exit ${error_code}
|
||||
}
|
||||
# Uncomment the following line for always providing an error backtrace
|
||||
trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
|
||||
|
||||
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
|
||||
##############################################################################
|
||||
|
||||
# debug mode
|
||||
if [[ "${arg_d:?}" = "1" ]]; then
|
||||
set -o xtrace
|
||||
LOG_LEVEL="7"
|
||||
# Enable error backtracing
|
||||
trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
fi
|
||||
|
||||
# verbose mode
|
||||
if [[ "${arg_v:?}" = "1" ]]; then
|
||||
set -o verbose
|
||||
fi
|
||||
|
||||
|
||||
### Validation. Error out if the things required for your script are not present
|
||||
##############################################################################
|
||||
|
||||
if [[ "${arg_F:?}" == 1 ]]; then
|
||||
SILENT="True"
|
||||
else
|
||||
SILENT="False"
|
||||
fi
|
||||
if [[ "${arg_M:?}" == 1 ]]; then
|
||||
USE_MBR="True"
|
||||
else
|
||||
USE_MBR="False"
|
||||
fi
|
||||
|
||||
if [[ "${arg_h:?}" == 1 ]]; then
|
||||
help "${__usage_example}"
|
||||
else
|
||||
# Print warning line
|
||||
[[ "${arg_u:-}" ]] || echo " -u or --ufd-device is required"
|
||||
[[ "${arg_l:-}" ]] || echo " -l or --linux-iso is required"
|
||||
|
||||
# Bail if necessary
|
||||
[[ "${arg_u:-}" ]] || help "${__usage_example}"
|
||||
[[ "${arg_l:-}" ]] || help "${__usage_example}"
|
||||
fi
|
||||
[[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. "
|
||||
|
||||
|
||||
### More functions
|
||||
##############################################################################
|
||||
|
||||
function abort () {
|
||||
local abort_message="Aborted"
|
||||
[[ "${1:-}" ]] && abort_message="${1}" || true
|
||||
error "${abort_message}"
|
||||
#echo -e "${YELLOW}${abort_message}${CLEAR}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function ask() {
|
||||
if [[ "${SILENT}" == "True" ]]; then
|
||||
echo -e "${1:-} Yes ${BLUE}(Silent)${CLEAR}"
|
||||
return 0
|
||||
fi
|
||||
while :; do
|
||||
read -p "${1:-} [Y/N] " -r answer
|
||||
if echo "$answer" | egrep -iq '^(y|yes|sure)$'; then
|
||||
return 0
|
||||
elif echo "$answer" | egrep -iq '^(n|no|nope)$'; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
### Runtime
|
||||
##############################################################################
|
||||
|
||||
# VARIABLES
|
||||
DEST_DEV="${arg_u}"
|
||||
DEST_PAR="${DEST_DEV}1"
|
||||
LOG_FILE="$(getent passwd "$SUDO_USER" | cut -d: -f6)/Logs/build-ufd_${DEST_DEV##*/}_$(date +%Y-%m-%d_%H%M_%z).log"
|
||||
MAIN_PY="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/settings/main.py"
|
||||
RSYNC_ARGS="-hrtuvS --modify-window=1 --progress"
|
||||
MAIN_KIT="$(realpath "${arg_m:-}" 2>/dev/null || true)"
|
||||
LINUX_ISO="$(realpath "${arg_l:-}" 2>/dev/null || true)"
|
||||
WINPE_ISO="$(realpath "${arg_w:-}" 2>/dev/null || true)"
|
||||
EXTRA_DIR="$(realpath "${arg_e:-}" 2>/dev/null || true)"
|
||||
mkdir -p "$(dirname "$LOG_FILE")"
|
||||
chown "$SUDO_USER:$SUDO_USER" -R "$(dirname "$LOG_FILE")"
|
||||
|
||||
# COLORS
|
||||
CLEAR="\e[0m"
|
||||
RED="\e[31m"
|
||||
GREEN="\e[32m"
|
||||
YELLOW="\e[33m"
|
||||
BLUE="\e[34m"
|
||||
|
||||
# Load main.py settings
|
||||
if [ ! -f "${MAIN_PY}" ]; then
|
||||
echo -e "${RED}ERROR${CLEAR}: ${MAIN_PY} not found."
|
||||
abort
|
||||
fi
|
||||
while read line; do
|
||||
if echo "${line}" | egrep -q "^\w+='"; then
|
||||
line="$(echo "${line}" | sed -r 's/[\r\n]+//')"
|
||||
eval "${line}"
|
||||
fi
|
||||
done < "${MAIN_PY}"
|
||||
if [ -z ${KIT_NAME_FULL+x} ]; then
|
||||
# KIT_NAME_FULL is not set, assume main.py missing or malformatted
|
||||
echo -e "${RED}ERROR${CLEAR}: failed to load settings from ${MAIN_PY}"
|
||||
abort
|
||||
fi
|
||||
ISO_LABEL="${KIT_NAME_SHORT}_LINUX"
|
||||
UFD_LABEL="${KIT_NAME_SHORT}_UFD"
|
||||
|
||||
# Check if root
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
echo -e "${RED}ERROR${CLEAR}: This script must be run as root."
|
||||
abort
|
||||
fi
|
||||
|
||||
# Check if in tmux
|
||||
if ! tmux list-session 2>/dev/null | grep -q "build-ufd"; then
|
||||
# Reload in tmux
|
||||
eval tmux new-session -s "build-ufd" "${0:-}" ${__all_args}
|
||||
SILENT="True" # avoid two "Press Enter to exit..." prompts
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Header
|
||||
echo -e "${GREEN}${KIT_NAME_FULL}${CLEAR}: UFD Build Tool"
|
||||
echo ""
|
||||
|
||||
# Verify sources
|
||||
[[ -b "${DEST_DEV}" ]] || abort "${DEST_DEV} is not a valid device."
|
||||
[[ -e "${LINUX_ISO}" ]] || abort "Linux ISO not found."
|
||||
if [[ ! -z "${arg_m:-}" ]]; then
|
||||
[[ -d "${MAIN_KIT}/.bin" ]] || abort "Invalid Main Kit, ${MAIN_KIT}/.bin not found."
|
||||
fi
|
||||
if [[ ! -z "${arg_w:-}" ]]; then
|
||||
[[ -e "${WINPE_ISO}" ]] || abort "WinPE ISO not found."
|
||||
fi
|
||||
if [[ ! -z "${arg_e:-}" ]]; then
|
||||
[[ -d "${EXTRA_DIR}" ]] || abort "Extra Dir not found."
|
||||
fi
|
||||
|
||||
# Print Info
|
||||
echo -e "${BLUE}Sources${CLEAR}" | tee -a "${LOG_FILE}"
|
||||
echo "Main Kit: ${MAIN_KIT}" | tee -a "${LOG_FILE}"
|
||||
echo "Linux ISO: ${LINUX_ISO}" | tee -a "${LOG_FILE}"
|
||||
echo "WinPE ISO: ${WINPE_ISO}" | tee -a "${LOG_FILE}"
|
||||
echo "Extra Dir: ${EXTRA_DIR:-(Not Specified)}" | tee -a "${LOG_FILE}"
|
||||
echo "" | tee -a "${LOG_FILE}"
|
||||
echo -e "${BLUE}Destination${CLEAR}" | tee -a "${LOG_FILE}"
|
||||
lsblk -n -o NAME,LABEL,SIZE,MODEL,SERIAL "${DEST_DEV}" | tee -a "${LOG_FILE}"
|
||||
if [[ "${USE_MBR}" == "True" ]]; then
|
||||
echo -e "${YELLOW}Formatting using legacy MBR${CLEAR}" | tee -a "${LOG_FILE}"
|
||||
fi
|
||||
echo "" | tee -a "${LOG_FILE}"
|
||||
|
||||
# Ask before starting job
|
||||
echo ""
|
||||
if ask "Is the above information correct?"; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}SAFETY CHECK${CLEAR}"
|
||||
echo "All data will be DELETED from the disk and partition(s) listed above."
|
||||
echo -e "This is irreversible and will lead to ${RED}DATA LOSS.${CLEAR}"
|
||||
if ! ask "Asking again to confirm, is this correct?"; then
|
||||
abort
|
||||
fi
|
||||
else
|
||||
abort
|
||||
fi
|
||||
|
||||
# Start Build
|
||||
echo "" | tee -a "${LOG_FILE}"
|
||||
echo -e "${GREEN}Building Kit${CLEAR}" | tee -a "${LOG_FILE}"
|
||||
touch "${LOG_FILE}"
|
||||
tmux split-window -dl 10 tail -f "${LOG_FILE}"
|
||||
|
||||
# Zero beginning of device
|
||||
dd bs=4M count=16 if=/dev/zero of="${DEST_DEV}" >> "${LOG_FILE}" 2>&1
|
||||
|
||||
# Format
|
||||
echo "Formatting drive..." | tee -a "${LOG_FILE}"
|
||||
if [[ "${USE_MBR}" == "True" ]]; then
|
||||
parted "${DEST_DEV}" --script -- mklabel msdos mkpart primary fat32 4MiB -1s >> "${LOG_FILE}" 2>&1
|
||||
parted "${DEST_DEV}" set 1 boot on >> "${LOG_FILE}" 2>&1
|
||||
else
|
||||
parted "${DEST_DEV}" --script -- mklabel gpt mkpart primary fat32 4MiB -4MiB >> "${LOG_FILE}" 2>&1
|
||||
parted "${DEST_DEV}" set 1 legacy_boot on >> "${LOG_FILE}" 2>&1
|
||||
#parted "${DEST_DEV}" disk_set pmbr_boot on >> "${LOG_FILE}" 2>&1
|
||||
# pmbr_boot breaks detection on some UEFI MOBOs
|
||||
fi
|
||||
mkfs.vfat -F 32 -n "${UFD_LABEL}" "${DEST_PAR}" >> "${LOG_FILE}" 2>&1
|
||||
|
||||
# Mount sources and dest
|
||||
echo "Mounting sources and destination..." | tee -a "${LOG_FILE}"
|
||||
mkdir /mnt/{Dest,Linux,WinPE} -p >> "${LOG_FILE}" 2>&1
|
||||
mount ${DEST_PAR} /mnt/Dest >> "${LOG_FILE}" 2>&1
|
||||
mount "${LINUX_ISO}" /mnt/Linux -r >> "${LOG_FILE}" 2>&1
|
||||
if [[ ! -z "${arg_w:-}" ]]; then
|
||||
mount "${WINPE_ISO}" /mnt/WinPE -r >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
|
||||
# Find WinPE source
|
||||
w_boot="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot")"
|
||||
w_boot_bcd="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot/BCD")"
|
||||
w_boot_sdi="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot/boot.sdi")"
|
||||
w_bootmgr="$(find /mnt/WinPE -iwholename "/mnt/WinPE/bootmgr")"
|
||||
w_bootmgr_efi="$(find /mnt/WinPE -iwholename "/mnt/WinPE/bootmgr.efi")"
|
||||
w_efi_boot="$(find /mnt/WinPE -iwholename "/mnt/WinPE/EFI/Boot")"
|
||||
w_efi_microsoft="$(find /mnt/WinPE -iwholename "/mnt/WinPE/EFI/Microsoft")"
|
||||
w_en_us="$(find /mnt/WinPE -iwholename "/mnt/WinPE/en-us")"
|
||||
w_sources="$(find /mnt/WinPE -iwholename "/mnt/WinPE/sources")"
|
||||
|
||||
# Copy files
|
||||
echo "Copying Linux files..." | tee -a "${LOG_FILE}"
|
||||
rsync ${RSYNC_ARGS} /mnt/Linux/* /mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
sed -i "s/${ISO_LABEL}/${UFD_LABEL}/" /mnt/Dest/EFI/boot/refind.conf
|
||||
sed -i "s/${ISO_LABEL}/${UFD_LABEL}/" /mnt/Dest/arch/boot/syslinux/*cfg
|
||||
|
||||
echo "Copying WinPE files..." | tee -a "${LOG_FILE}"
|
||||
if [[ ! -z "${arg_w:-}" ]]; then
|
||||
if [[ ! -z "${w_bootmgr:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_bootmgr}" /mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_bootmgr_efi:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_bootmgr_efi}" /mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_en_us:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_en_us}" /mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_boot:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_boot}"/* /mnt/Dest/Boot/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_efi_boot:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_efi_boot}"/* /mnt/Dest/EFI/Microsoft/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_efi_microsoft:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_efi_microsoft}"/* /mnt/Dest/EFI/Microsoft/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_boot_bcd:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_boot_bcd}" /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_boot_sdi:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_boot_sdi}" /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_bootmgr:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_bootmgr}" /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
if [[ ! -z "${w_sources:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} "${w_sources}"/* /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
|
||||
# Uncomment boot entries
|
||||
sed -i "s/#UFD-WINPE#//" /mnt/Dest/EFI/boot/refind.conf
|
||||
sed -i "s/#UFD-WINPE#//" /mnt/Dest/arch/boot/syslinux/*cfg
|
||||
fi
|
||||
|
||||
echo "Copying Main Kit..." | tee -a "${LOG_FILE}"
|
||||
if [[ ! -z "${arg_m:-}" ]]; then
|
||||
rsync ${RSYNC_ARGS} \
|
||||
"${MAIN_KIT}/" \
|
||||
"/mnt/Dest/${KIT_NAME_FULL}/" >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
|
||||
if [[ ! -z "${EXTRA_DIR:-}" ]]; then
|
||||
echo "Copying Extra files..." | tee -a "${LOG_FILE}"
|
||||
rsync ${RSYNC_ARGS} \
|
||||
"${EXTRA_DIR}"/ \
|
||||
/mnt/Dest/ >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
|
||||
# Install syslinux
|
||||
echo "Copying Syslinux files..." | tee -a "${LOG_FILE}"
|
||||
rsync ${RSYNC_ARGS} /usr/lib/syslinux/bios/*.c32 /mnt/Dest/arch/boot/syslinux/ >> "${LOG_FILE}" 2>&1
|
||||
syslinux --install -d /arch/boot/syslinux/ ${DEST_PAR} >> "${LOG_FILE}" 2>&1
|
||||
|
||||
echo "Unmounting destination..." | tee -a "${LOG_FILE}"
|
||||
umount /mnt/Dest >> "${LOG_FILE}" 2>&1
|
||||
rmdir /mnt/Dest >> "${LOG_FILE}" 2>&1
|
||||
sync
|
||||
|
||||
echo "Installing Syslinux MBR..." | tee -a "${LOG_FILE}"
|
||||
if [[ "${USE_MBR}" == "True" ]]; then
|
||||
dd bs=440 count=1 if=/usr/lib/syslinux/bios/mbr.bin of=${DEST_DEV} >> "${LOG_FILE}" 2>&1
|
||||
else
|
||||
dd bs=440 count=1 if=/usr/lib/syslinux/bios/gptmbr.bin of=${DEST_DEV} >> "${LOG_FILE}" 2>&1
|
||||
fi
|
||||
sync
|
||||
|
||||
# Cleanup
|
||||
echo "Hiding boot files..." | tee -a "${LOG_FILE}"
|
||||
echo "drive s: file=\"${DEST_PAR}\"" > /root/.mtoolsrc
|
||||
echo 'mtools_skip_check=1' >> /root/.mtoolsrc
|
||||
for item in arch Boot bootmgr{,.efi} EFI en-us images isolinux sources "${KIT_NAME_FULL}"/{.bin,.cbin}; do
|
||||
yes | mattrib +h "S:/${item}" >> "${LOG_FILE}" 2>&1 || true
|
||||
done
|
||||
sync
|
||||
|
||||
# Unmount Sources
|
||||
echo "Unmounting sources..." | tee -a "${LOG_FILE}"
|
||||
for d in Linux WinPE; do
|
||||
umount "/mnt/${d}" >> "${LOG_FILE}" 2>&1 || true
|
||||
rmdir "/mnt/${d}" >> "${LOG_FILE}" 2>&1 || true
|
||||
done
|
||||
|
||||
# Close progress pane
|
||||
pkill -f "tail.*${LOG_FILE}"
|
||||
|
||||
# Done
|
||||
echo "" | tee -a "${LOG_FILE}"
|
||||
echo "Done." | tee -a "${LOG_FILE}"
|
||||
echo ""
|
||||
exit 0
|
||||
|
|
@ -90,12 +90,13 @@ class SecureBootUnknownError(Exception):
|
|||
|
||||
|
||||
# General functions
|
||||
def abort():
|
||||
def abort(show_prompt=True):
|
||||
"""Abort script."""
|
||||
print_warning('Aborted.')
|
||||
sleep(1)
|
||||
pause(prompt='Press Enter to exit... ')
|
||||
exit_script()
|
||||
if show_prompt:
|
||||
sleep(1)
|
||||
pause(prompt='Press Enter to exit... ')
|
||||
exit_script(1)
|
||||
|
||||
|
||||
def ask(prompt='Kotaero!'):
|
||||
|
|
@ -879,25 +880,19 @@ def make_tmp_dirs():
|
|||
|
||||
def set_common_vars():
|
||||
"""Set common variables."""
|
||||
global_vars['Date'] = time.strftime("%Y-%m-%d")
|
||||
global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z")
|
||||
global_vars['Env'] = os.environ.copy()
|
||||
global_vars['Date'] = time.strftime("%Y-%m-%d")
|
||||
global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z")
|
||||
global_vars['Env'] = os.environ.copy()
|
||||
|
||||
global_vars['ArchivePassword'] = ARCHIVE_PASSWORD
|
||||
global_vars['BinDir'] = r'{BaseDir}\.bin'.format(
|
||||
**global_vars)
|
||||
global_vars['CBinDir'] = r'{BaseDir}\.cbin'.format(
|
||||
**global_vars)
|
||||
global_vars['ClientDir'] = r'{SYSTEMDRIVE}\{prefix}'.format(
|
||||
prefix=KIT_NAME_SHORT, **global_vars['Env'])
|
||||
global_vars['BackupDir'] = r'{ClientDir}\Backups'.format(
|
||||
**global_vars)
|
||||
global_vars['LogDir'] = r'{ClientDir}\Logs\{Date}'.format(
|
||||
**global_vars)
|
||||
global_vars['QuarantineDir'] = r'{ClientDir}\Quarantine'.format(
|
||||
**global_vars)
|
||||
global_vars['TmpDir'] = r'{BinDir}\tmp'.format(
|
||||
**global_vars)
|
||||
global_vars['BinDir'] = r'{BaseDir}\.bin'.format(**global_vars)
|
||||
global_vars['CBinDir'] = r'{BaseDir}\.cbin'.format(**global_vars)
|
||||
global_vars['ClientDir'] = r'{SYSTEMDRIVE}\{prefix}'.format(
|
||||
prefix=KIT_NAME_SHORT, **global_vars['Env'])
|
||||
global_vars['BackupDir'] = r'{ClientDir}\Backups'.format(**global_vars)
|
||||
global_vars['LogDir'] = r'{ClientDir}\Logs\{Date}'.format(**global_vars)
|
||||
global_vars['QuarantineDir'] = r'{ClientDir}\Quarantine'.format(**global_vars)
|
||||
global_vars['TmpDir'] = r'{BinDir}\tmp'.format(**global_vars)
|
||||
|
||||
|
||||
def set_linux_vars():
|
||||
|
|
@ -905,12 +900,12 @@ def set_linux_vars():
|
|||
|
||||
These assume we're running under a WK-Linux build."""
|
||||
result = run_program(['mktemp', '-d'])
|
||||
global_vars['TmpDir'] = result.stdout.decode().strip()
|
||||
global_vars['Date'] = time.strftime("%Y-%m-%d")
|
||||
global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z")
|
||||
global_vars['Env'] = os.environ.copy()
|
||||
global_vars['BinDir'] = '/usr/local/bin'
|
||||
global_vars['LogDir'] = global_vars['TmpDir']
|
||||
global_vars['TmpDir'] = result.stdout.decode().strip()
|
||||
global_vars['Date'] = time.strftime("%Y-%m-%d")
|
||||
global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z")
|
||||
global_vars['Env'] = os.environ.copy()
|
||||
global_vars['BinDir'] = '/usr/local/bin'
|
||||
global_vars['LogDir'] = '{}/Logs'.format(global_vars['Env']['HOME'])
|
||||
global_vars['Tools'] = {
|
||||
'wimlib-imagex': 'wimlib-imagex',
|
||||
'SevenZip': '7z',
|
||||
|
|
@ -919,10 +914,13 @@ def set_linux_vars():
|
|||
|
||||
def set_log_file(log_name):
|
||||
"""Sets global var LogFile and creates path as needed."""
|
||||
folder_path = '{}{}{}'.format(
|
||||
global_vars['LogDir'],
|
||||
os.sep,
|
||||
KIT_NAME_FULL)
|
||||
if psutil.LINUX:
|
||||
folder_path = global_vars['LogDir']
|
||||
else:
|
||||
folder_path = '{}{}{}'.format(
|
||||
global_vars['LogDir'],
|
||||
os.sep,
|
||||
KIT_NAME_FULL)
|
||||
log_file = '{}{}{}'.format(
|
||||
folder_path,
|
||||
os.sep,
|
||||
|
|
|
|||
463
.bin/Scripts/functions/ufd.py
Normal file
463
.bin/Scripts/functions/ufd.py
Normal file
|
|
@ -0,0 +1,463 @@
|
|||
"""Wizard Kit: Functions - UFD"""
|
||||
# pylint: disable=broad-except,wildcard-import
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import pathlib
|
||||
from collections import OrderedDict
|
||||
from functions.common import *
|
||||
|
||||
|
||||
def case_insensitive_search(path, item):
|
||||
"""Search path for item case insensitively, returns str."""
|
||||
regex_match = '^{}$'.format(item)
|
||||
real_path = ''
|
||||
|
||||
# Quick check first
|
||||
if os.path.exists('{}/{}'.format(path, item)):
|
||||
real_path = '{}{}{}'.format(
|
||||
path,
|
||||
'' if path == '/' else '/',
|
||||
item,
|
||||
)
|
||||
|
||||
# Check all items in dir
|
||||
for entry in os.scandir(path):
|
||||
if re.match(regex_match, entry.name, re.IGNORECASE):
|
||||
real_path = '{}{}{}'.format(
|
||||
path,
|
||||
'' if path == '/' else '/',
|
||||
entry.name,
|
||||
)
|
||||
|
||||
# Done
|
||||
if not real_path:
|
||||
raise FileNotFoundError('{}/{}'.format(path, item))
|
||||
|
||||
return real_path
|
||||
|
||||
|
||||
def confirm_selections(args):
|
||||
"""Ask tech to confirm selections, twice if necessary."""
|
||||
if not ask('Is the above information correct?'):
|
||||
abort(False)
|
||||
## Safety check
|
||||
if not args['--update']:
|
||||
print_standard(' ')
|
||||
print_warning('SAFETY CHECK')
|
||||
print_standard(
|
||||
'All data will be DELETED from the disk and partition(s) listed above.')
|
||||
print_standard(
|
||||
'This is irreversible and will lead to {RED}DATA LOSS.{CLEAR}'.format(
|
||||
**COLORS))
|
||||
if not ask('Asking again to confirm, is this correct?'):
|
||||
abort(False)
|
||||
|
||||
print_standard(' ')
|
||||
|
||||
|
||||
def copy_source(source, items, overwrite=False):
|
||||
"""Copy source items to /mnt/UFD."""
|
||||
is_iso = source.name.lower().endswith('.iso')
|
||||
|
||||
# Mount source if necessary
|
||||
if is_iso:
|
||||
mount(source, '/mnt/Source')
|
||||
|
||||
# Copy items
|
||||
for i_source, i_dest in items:
|
||||
i_source = '{}{}'.format(
|
||||
'/mnt/Source' if is_iso else source,
|
||||
i_source,
|
||||
)
|
||||
i_dest = '/mnt/UFD{}'.format(i_dest)
|
||||
try:
|
||||
recursive_copy(i_source, i_dest, overwrite=overwrite)
|
||||
except FileNotFoundError:
|
||||
# Going to assume (hope) that this is fine
|
||||
pass
|
||||
|
||||
# Unmount source if necessary
|
||||
if is_iso:
|
||||
unmount('/mnt/Source')
|
||||
|
||||
|
||||
def find_first_partition(dev_path):
|
||||
"""Find path to first partition of dev, returns str."""
|
||||
cmd = [
|
||||
'lsblk',
|
||||
'--list',
|
||||
'--noheadings',
|
||||
'--output', 'name',
|
||||
'--paths',
|
||||
dev_path,
|
||||
]
|
||||
result = run_program(cmd, encoding='utf-8', errors='ignore')
|
||||
part_path = result.stdout.splitlines()[-1].strip()
|
||||
|
||||
return part_path
|
||||
|
||||
|
||||
def find_path(path):
|
||||
"""Find path case-insensitively, returns pathlib.Path obj."""
|
||||
path_obj = pathlib.Path(path).resolve()
|
||||
|
||||
# Quick check first
|
||||
if path_obj.exists():
|
||||
return path_obj
|
||||
|
||||
# Fix case
|
||||
parts = path_obj.relative_to('/').parts
|
||||
real_path = '/'
|
||||
for part in parts:
|
||||
try:
|
||||
real_path = case_insensitive_search(real_path, part)
|
||||
except NotADirectoryError:
|
||||
# Reclassify error
|
||||
raise FileNotFoundError(path)
|
||||
|
||||
# Raise error if path doesn't exist
|
||||
path_obj = pathlib.Path(real_path)
|
||||
if not path_obj.exists():
|
||||
raise FileNotFoundError(path_obj)
|
||||
|
||||
# Done
|
||||
return path_obj
|
||||
|
||||
|
||||
def get_user_home(user):
|
||||
"""Get path to user's home dir, returns str."""
|
||||
home_dir = None
|
||||
cmd = ['getent', 'passwd', user]
|
||||
result = run_program(cmd, encoding='utf-8', errors='ignore', check=False)
|
||||
try:
|
||||
home_dir = result.stdout.split(':')[5]
|
||||
except Exception:
|
||||
# Just use HOME from ENV (or '/root' if that fails)
|
||||
home_dir = os.environ.get('HOME', '/root')
|
||||
|
||||
return home_dir
|
||||
|
||||
|
||||
def get_user_name():
|
||||
"""Get real user name, returns str."""
|
||||
user = None
|
||||
if 'SUDO_USER' in os.environ:
|
||||
user = os.environ.get('SUDO_USER', 'Unknown')
|
||||
else:
|
||||
user = os.environ.get('USER', 'Unknown')
|
||||
|
||||
return user
|
||||
|
||||
|
||||
def hide_items(ufd_dev, items):
|
||||
"""Set FAT32 hidden flag for items."""
|
||||
# pylint: disable=invalid-name
|
||||
with open('/root/.mtoolsrc', 'w') as f:
|
||||
f.write('drive U: file="{}"\n'.format(
|
||||
find_first_partition(ufd_dev)))
|
||||
f.write('mtools_skip_check=1\n')
|
||||
|
||||
# Hide items
|
||||
for item in items:
|
||||
cmd = ['yes | mattrib +h "U:/{}"'.format(item)]
|
||||
run_program(cmd, check=False, shell=True)
|
||||
|
||||
|
||||
def install_syslinux_to_dev(ufd_dev, use_mbr):
|
||||
"""Install Syslinux to UFD (dev)."""
|
||||
cmd = [
|
||||
'dd',
|
||||
'bs=440',
|
||||
'count=1',
|
||||
'if=/usr/lib/syslinux/bios/{}.bin'.format(
|
||||
'mbr' if use_mbr else 'gptmbr',
|
||||
),
|
||||
'of={}'.format(ufd_dev),
|
||||
]
|
||||
run_program(cmd)
|
||||
|
||||
|
||||
def install_syslinux_to_partition(partition):
|
||||
"""Install Syslinux to UFD (partition)."""
|
||||
cmd = [
|
||||
'syslinux',
|
||||
'--install',
|
||||
'--directory',
|
||||
'/arch/boot/syslinux/',
|
||||
partition,
|
||||
]
|
||||
run_program(cmd)
|
||||
|
||||
|
||||
def is_valid_path(path_obj, path_type):
|
||||
"""Verify path_obj is valid by type, returns bool."""
|
||||
valid_path = False
|
||||
if path_type == 'DIR':
|
||||
valid_path = path_obj.is_dir()
|
||||
elif path_type == 'KIT':
|
||||
valid_path = path_obj.is_dir() and path_obj.joinpath('.bin').exists()
|
||||
elif path_type == 'ISO':
|
||||
valid_path = path_obj.is_file() and path_obj.suffix.lower() == '.iso'
|
||||
elif path_type == 'UFD':
|
||||
valid_path = path_obj.is_block_device()
|
||||
|
||||
return valid_path
|
||||
|
||||
|
||||
def mount(mount_source, mount_point):
|
||||
"""Mount mount_source on mount_point."""
|
||||
os.makedirs(mount_point, exist_ok=True)
|
||||
cmd = ['mount', mount_source, mount_point]
|
||||
run_program(cmd)
|
||||
|
||||
|
||||
def prep_device(dev_path, label, use_mbr=False, indent=2):
|
||||
"""Format device in preparation for applying the WizardKit components
|
||||
|
||||
This is done is four steps:
|
||||
1. Zero-out first 64MB (this deletes the partition table and/or bootloader)
|
||||
2. Create a new partition table (GPT by default, optionally MBR)
|
||||
3. Set boot flag
|
||||
4. Format partition (FAT32, 4K aligned)
|
||||
"""
|
||||
# Zero-out first 64MB
|
||||
cmd = 'dd bs=4M count=16 if=/dev/zero of={}'.format(dev_path).split()
|
||||
try_and_print(
|
||||
indent=indent,
|
||||
message='Zeroing first 64MB...',
|
||||
function=run_program,
|
||||
cmd=cmd,
|
||||
)
|
||||
|
||||
# Create partition table
|
||||
cmd = 'parted {} --script -- mklabel {} mkpart primary fat32 4MiB {}'.format(
|
||||
dev_path,
|
||||
'msdos' if use_mbr else 'gpt',
|
||||
'-1s' if use_mbr else '-4MiB',
|
||||
).split()
|
||||
try_and_print(
|
||||
indent=indent,
|
||||
message='Creating partition table...',
|
||||
function=run_program,
|
||||
cmd=cmd,
|
||||
)
|
||||
|
||||
# Set boot flag
|
||||
cmd = 'parted {} set 1 {} on'.format(
|
||||
dev_path,
|
||||
'boot' if use_mbr else 'legacy_boot',
|
||||
).split()
|
||||
try_and_print(
|
||||
indent=indent,
|
||||
message='Setting boot flag...',
|
||||
function=run_program,
|
||||
cmd=cmd,
|
||||
)
|
||||
|
||||
# Format partition
|
||||
cmd = [
|
||||
'mkfs.vfat', '-F', '32',
|
||||
'-n', label,
|
||||
find_first_partition(dev_path),
|
||||
]
|
||||
try_and_print(
|
||||
indent=indent,
|
||||
message='Formatting partition...',
|
||||
function=run_program,
|
||||
cmd=cmd,
|
||||
)
|
||||
|
||||
|
||||
def recursive_copy(source, dest, overwrite=False):
|
||||
"""Copy source to dest recursively.
|
||||
|
||||
NOTE: This uses rsync style source/dest syntax.
|
||||
If the source has a trailing slash then it's contents are copied,
|
||||
otherwise the source itself is copied.
|
||||
|
||||
Examples assuming "ExDir/ExFile.txt" exists:
|
||||
recursive_copy("ExDir", "Dest/") results in "Dest/ExDir/ExFile.txt"
|
||||
recursive_copy("ExDir/", "Dest/") results in "Dest/ExFile.txt"
|
||||
|
||||
NOTE 2: dest does not use find_path because it might not exist.
|
||||
"""
|
||||
copy_contents = source.endswith('/')
|
||||
source = find_path(source)
|
||||
dest = pathlib.Path(dest).resolve().joinpath(source.name)
|
||||
os.makedirs(dest.parent, exist_ok=True)
|
||||
|
||||
if source.is_dir():
|
||||
if copy_contents:
|
||||
# Trailing slash syntax
|
||||
for item in os.scandir(source):
|
||||
recursive_copy(item.path, dest.parent, overwrite=overwrite)
|
||||
elif not dest.exists():
|
||||
# No conflict, copying whole tree (no merging needed)
|
||||
shutil.copytree(source, dest)
|
||||
elif not dest.is_dir():
|
||||
# Refusing to replace file with dir
|
||||
raise FileExistsError('Refusing to replace file: {}'.format(dest))
|
||||
else:
|
||||
# Dest exists and is a dir, merge dirs
|
||||
for item in os.scandir(source):
|
||||
recursive_copy(item.path, dest, overwrite=overwrite)
|
||||
elif source.is_file():
|
||||
if not dest.exists():
|
||||
# No conflict, copying file
|
||||
shutil.copy2(source, dest)
|
||||
elif not dest.is_file():
|
||||
# Refusing to replace dir with file
|
||||
raise FileExistsError('Refusing to replace dir: {}'.format(dest))
|
||||
elif overwrite:
|
||||
# Dest file exists, deleting and replacing file
|
||||
os.remove(dest)
|
||||
shutil.copy2(source, dest)
|
||||
else:
|
||||
# Refusing to delete file when overwrite=False
|
||||
raise FileExistsError('Refusing to delete file: {}'.format(dest))
|
||||
|
||||
|
||||
def remove_arch():
|
||||
"""Remove arch dir from UFD.
|
||||
|
||||
This ensures a clean installation to the UFD and resets the boot files
|
||||
"""
|
||||
shutil.rmtree(find_path('/mnt/UFD/arch'))
|
||||
|
||||
|
||||
def running_as_root():
|
||||
"""Check if running with effective UID of 0, returns bool."""
|
||||
return os.geteuid() == 0
|
||||
|
||||
|
||||
def show_selections(args, sources, ufd_dev, ufd_sources):
|
||||
"""Show selections including non-specified options."""
|
||||
|
||||
# Sources
|
||||
print_info('Sources')
|
||||
for label in ufd_sources.keys():
|
||||
if label in sources:
|
||||
print_standard(' {label:<18} {path}'.format(
|
||||
label=label+':',
|
||||
path=sources[label],
|
||||
))
|
||||
else:
|
||||
print_standard(' {label:<18} {YELLOW}Not Specified{CLEAR}'.format(
|
||||
label=label+':',
|
||||
**COLORS,
|
||||
))
|
||||
print_standard(' ')
|
||||
|
||||
# Destination
|
||||
print_info('Destination')
|
||||
cmd = [
|
||||
'lsblk', '--nodeps', '--noheadings', '--paths',
|
||||
'--output', 'NAME,FSTYPE,TRAN,SIZE,VENDOR,MODEL,SERIAL',
|
||||
ufd_dev,
|
||||
]
|
||||
result = run_program(cmd, check=False, encoding='utf-8', errors='ignore')
|
||||
print_standard(result.stdout.strip())
|
||||
cmd = [
|
||||
'lsblk', '--noheadings', '--paths',
|
||||
'--output', 'NAME,SIZE,FSTYPE,LABEL,MOUNTPOINT',
|
||||
ufd_dev,
|
||||
]
|
||||
result = run_program(cmd, check=False, encoding='utf-8', errors='ignore')
|
||||
for line in result.stdout.splitlines()[1:]:
|
||||
print_standard(line)
|
||||
|
||||
# Notes
|
||||
if args['--update']:
|
||||
print_warning('Updating kit in-place')
|
||||
elif args['--use-mbr']:
|
||||
print_warning('Formatting using legacy MBR')
|
||||
print_standard(' ')
|
||||
|
||||
|
||||
def unmount(mount_point):
|
||||
"""Unmount mount_point."""
|
||||
cmd = ['umount', mount_point]
|
||||
run_program(cmd)
|
||||
|
||||
|
||||
def update_boot_entries(boot_entries, boot_files, iso_label, ufd_label):
|
||||
"""Update boot files for UFD usage"""
|
||||
configs = []
|
||||
|
||||
# Find config files
|
||||
for c_path, c_ext in boot_files.items():
|
||||
c_path = find_path('/mnt/UFD{}'.format(c_path))
|
||||
for item in os.scandir(c_path):
|
||||
if item.name.lower().endswith(c_ext.lower()):
|
||||
configs.append(item.path)
|
||||
|
||||
# Update Linux labels
|
||||
cmd = [
|
||||
'sed',
|
||||
'--in-place',
|
||||
'--regexp-extended',
|
||||
's/{}/{}/'.format(iso_label, ufd_label),
|
||||
*configs,
|
||||
]
|
||||
run_program(cmd)
|
||||
|
||||
# Uncomment extra entries if present
|
||||
for b_path, b_comment in boot_entries.items():
|
||||
try:
|
||||
find_path('/mnt/UFD{}'.format(b_path))
|
||||
except (FileNotFoundError, NotADirectoryError):
|
||||
# Entry not found, continue to next entry
|
||||
continue
|
||||
|
||||
# Entry found, update config files
|
||||
cmd = [
|
||||
'sed',
|
||||
'--in-place',
|
||||
's/#{}#//'.format(b_comment),
|
||||
*configs,
|
||||
]
|
||||
run_program(cmd, check=False)
|
||||
|
||||
|
||||
def verify_sources(args, ufd_sources):
|
||||
"""Check all sources and abort if necessary, returns dict."""
|
||||
sources = OrderedDict()
|
||||
|
||||
for label, data in ufd_sources.items():
|
||||
s_path = args[data['Arg']]
|
||||
if s_path:
|
||||
try:
|
||||
s_path_obj = find_path(s_path)
|
||||
except FileNotFoundError:
|
||||
print_error('ERROR: {} not found: {}'.format(label, s_path))
|
||||
abort(False)
|
||||
if not is_valid_path(s_path_obj, data['Type']):
|
||||
print_error('ERROR: Invalid {} source: {}'.format(label, s_path))
|
||||
abort(False)
|
||||
sources[label] = s_path_obj
|
||||
|
||||
return sources
|
||||
|
||||
|
||||
def verify_ufd(dev_path):
|
||||
"""Check that dev_path is a valid UFD, returns pathlib.Path obj."""
|
||||
ufd_dev = None
|
||||
|
||||
try:
|
||||
ufd_dev = find_path(dev_path)
|
||||
except FileNotFoundError:
|
||||
print_error('ERROR: UFD device not found: {}'.format(dev_path))
|
||||
abort(False)
|
||||
|
||||
if not is_valid_path(ufd_dev, 'UFD'):
|
||||
print_error('ERROR: Invalid UFD device: {}'.format(ufd_dev))
|
||||
abort(False)
|
||||
|
||||
return ufd_dev
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("This file is not meant to be called directly.")
|
||||
115
.bin/Scripts/settings/ufd.py
Normal file
115
.bin/Scripts/settings/ufd.py
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
'''Wizard Kit: Settings - UFD'''
|
||||
# pylint: disable=C0326,E0611
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
from collections import OrderedDict
|
||||
from settings.main import KIT_NAME_FULL,KIT_NAME_SHORT
|
||||
|
||||
# General
|
||||
DOCSTRING = '''WizardKit: Build UFD
|
||||
|
||||
Usage:
|
||||
build-ufd [options] --ufd-device PATH --linux PATH
|
||||
[--linux-minimal PATH]
|
||||
[--main-kit PATH]
|
||||
[--winpe PATH]
|
||||
[--extra-dir PATH]
|
||||
build-ufd (-h | --help)
|
||||
|
||||
Options:
|
||||
-d PATH, --linux-dgpu PATH
|
||||
-e PATH, --extra-dir PATH
|
||||
-k PATH, --main-kit PATH
|
||||
-l PATH, --linux PATH
|
||||
-m PATH, --linux-minimal PATH
|
||||
-u PATH, --ufd-device PATH
|
||||
-w PATH, --winpe PATH
|
||||
|
||||
-h --help Show this page
|
||||
-M --use-mbr Use real MBR instead of GPT w/ Protective MBR
|
||||
-F --force Bypass all confirmation messages. USE WITH EXTREME CAUTION!
|
||||
-U --update Don't format device, just update
|
||||
'''
|
||||
ISO_LABEL = '{}_LINUX'.format(KIT_NAME_SHORT)
|
||||
UFD_LABEL = '{}_UFD'.format(KIT_NAME_SHORT)
|
||||
UFD_SOURCES = OrderedDict({
|
||||
'Linux': {'Arg': '--linux', 'Type': 'ISO'},
|
||||
'Linux (dGPU)': {'Arg': '--linux-dgpu', 'Type': 'ISO'},
|
||||
'Linux (Minimal)': {'Arg': '--linux-minimal', 'Type': 'ISO'},
|
||||
'WinPE': {'Arg': '--winpe', 'Type': 'ISO'},
|
||||
'Main Kit': {'Arg': '--main-kit', 'Type': 'KIT'},
|
||||
'Extra Dir': {'Arg': '--extra-dir', 'Type': 'DIR'},
|
||||
})
|
||||
|
||||
# Definitions: Boot entries
|
||||
BOOT_ENTRIES = {
|
||||
# Path to check: Comment to remove
|
||||
'/arch_minimal': 'UFD-MINIMAL',
|
||||
'/dgpu': 'UFD-DGPU',
|
||||
'/sources/boot.wim': 'UFD-WINPE',
|
||||
}
|
||||
BOOT_FILES = {
|
||||
# Directory: extension
|
||||
'/arch/boot/syslinux': 'cfg',
|
||||
'/EFI/boot': 'conf',
|
||||
}
|
||||
|
||||
# Definitions: Sources and Destinations
|
||||
## NOTES: Paths are relative to the root of the ISO/UFD
|
||||
## Sources use rsync's trailing slash syntax
|
||||
ITEMS = {
|
||||
'Extra Dir': (
|
||||
('/', '/'),
|
||||
),
|
||||
'Linux': (
|
||||
('/arch', '/'),
|
||||
('/isolinux', '/'),
|
||||
('/EFI/boot', '/EFI/'),
|
||||
('/EFI/memtest86', '/EFI/'),
|
||||
),
|
||||
'Linux (dGPU)': (
|
||||
('/arch/boot/x86_64/archiso.img', '/dgpu/'),
|
||||
('/arch/boot/x86_64/vmlinuz', '/dgpu/'),
|
||||
('/arch/pkglist.x86_64.txt', '/dgpu/'),
|
||||
('/arch/x86_64', '/dgpu/'),
|
||||
),
|
||||
'Linux (Minimal)': (
|
||||
('/arch/boot/x86_64/archiso.img', '/arch_minimal/'),
|
||||
('/arch/boot/x86_64/vmlinuz', '/arch_minimal/'),
|
||||
('/arch/pkglist.x86_64.txt', '/arch_minimal/'),
|
||||
('/arch/x86_64', '/arch_minimal/'),
|
||||
),
|
||||
'Main Kit': (
|
||||
('/', '/{}/'.format(KIT_NAME_FULL)),
|
||||
),
|
||||
'WinPE': (
|
||||
('/bootmgr', '/'),
|
||||
('/bootmgr.efi', '/'),
|
||||
('/en_us', '/'),
|
||||
('/Boot/', '/boot/'),
|
||||
('/EFI/Boot/', '/EFI/Microsoft/'),
|
||||
('/EFI/Microsoft/', '/EFI/Microsoft/'),
|
||||
('/Boot/BCD', '/sources/'),
|
||||
('/Boot/boot.sdi', '/sources/'),
|
||||
('/bootmgr', '/sources/'),
|
||||
('/sources/boot.wim', '/sources/'),
|
||||
),
|
||||
}
|
||||
ITEMS_HIDDEN = (
|
||||
# Linux (all versions)
|
||||
'arch',
|
||||
'arch_minimal',
|
||||
'dgpu',
|
||||
'EFI',
|
||||
'isolinux',
|
||||
# WinPE
|
||||
'boot',
|
||||
'bootmgr',
|
||||
'bootmgr.efi',
|
||||
'en-us',
|
||||
'images',
|
||||
'sources',
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("This file is not meant to be called directly.")
|
||||
BIN
.linux_items/include/EFI/boot/icons/dgpu.png
Normal file
BIN
.linux_items/include/EFI/boot/icons/dgpu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3 KiB |
|
|
@ -26,15 +26,30 @@ menuentry "Linux" {
|
|||
initrd /arch/boot/amd_ucode.img
|
||||
initrd /arch/boot/x86_64/archiso.img
|
||||
options "archisobasedir=arch archisolabel=%ARCHISO_LABEL% copytoram loglevel=3"
|
||||
submenuentry "Linux (i3)" {
|
||||
add_options "i3"
|
||||
}
|
||||
submenuentry "Linux (CLI)" {
|
||||
add_options "loglevel=4 nomodeset nox"
|
||||
add_options "nox"
|
||||
}
|
||||
#UFD-MINIMAL#submenuentry "Linux (Minimal)" {
|
||||
#UFD-MINIMAL# loader /arch_minimal/vmlinuz
|
||||
#UFD-MINIMAL# initrd
|
||||
#UFD-MINIMAL# initrd /arch/boot/intel_ucode.img
|
||||
#UFD-MINIMAL# initrd /arch/boot/amd_ucode.img
|
||||
#UFD-MINIMAL# initrd /arch_minimal/archiso.img
|
||||
#UFD-MINIMAL# options
|
||||
#UFD-MINIMAL# options "archisobasedir=arch_minimal archisolabel=%ARCHISO_LABEL% copytoram loglevel=3"
|
||||
#UFD-MINIMAL#}
|
||||
}
|
||||
#UFD-WINPE#menuentry "WindowsPE" {
|
||||
#UFD-WINPE# ostype windows
|
||||
#UFD-WINPE# icon /EFI/boot/icons/wk_win.png
|
||||
#UFD-WINPE# loader /EFI/microsoft/bootx64.efi
|
||||
#UFD-WINPE#}
|
||||
#UFD-DGPU#menuentry "Mac dGPU Disable Tool" {
|
||||
#UFD-DGPU# icon /EFI/boot/icons/dgpu.png
|
||||
#UFD-DGPU# loader /dgpu/vmlinuz
|
||||
#UFD-DGPU# initrd /arch/boot/intel_ucode.img
|
||||
#UFD-DGPU# initrd /arch/boot/amd_ucode.img
|
||||
#UFD-DGPU# initrd /dgpu/archiso.img
|
||||
#UFD-DGPU# options "archisobasedir=dgpu archisolabel=%ARCHISO_LABEL% nomodeset"
|
||||
#UFD-DGPU#}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,17 +8,6 @@ LINUX boot/x86_64/vmlinuz
|
|||
INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/x86_64/archiso.img
|
||||
APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram loglevel=3
|
||||
|
||||
LABEL wk_linux_i3
|
||||
TEXT HELP
|
||||
A live Linux environment (i3)
|
||||
* HW diagnostics, file-based backups, data recovery, etc
|
||||
ENDTEXT
|
||||
MENU LABEL Linux (i3)
|
||||
LINUX boot/x86_64/vmlinuz
|
||||
INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/x86_64/archiso.img
|
||||
APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram loglevel=3 i3
|
||||
SYSAPPEND 3
|
||||
|
||||
LABEL wk_linux_cli
|
||||
TEXT HELP
|
||||
A live Linux environment (CLI)
|
||||
|
|
@ -27,5 +16,17 @@ ENDTEXT
|
|||
MENU LABEL Linux (CLI)
|
||||
LINUX boot/x86_64/vmlinuz
|
||||
INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/x86_64/archiso.img
|
||||
APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram nox nomodeset
|
||||
APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram nox
|
||||
SYSAPPEND 3
|
||||
|
||||
#UFD-MINIMAL#LABEL wk_linux_minimal
|
||||
#UFD-MINIMAL#TEXT HELP
|
||||
#UFD-MINIMAL#A live Linux environment (Minimal)
|
||||
#UFD-MINIMAL# * HW diagnostics, file-based backups, data recovery, etc
|
||||
#UFD-MINIMAL#ENDTEXT
|
||||
#UFD-MINIMAL#MENU LABEL Linux (Minimal)
|
||||
#UFD-MINIMAL#LINUX ../arch_minimal/vmlinuz
|
||||
#UFD-MINIMAL#INITRD boot/intel_ucode.img,boot/amd_ucode.img,../arch_minimal/archiso.img
|
||||
#UFD-MINIMAL#APPEND archisobasedir=arch_minimal archisolabel=%ARCHISO_LABEL% copytoram loglevel=3
|
||||
#UFD-MINIMAL#SYSAPPEND 3
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ networkmanager
|
|||
p7zip
|
||||
progsreiserfs
|
||||
python
|
||||
python-docopt
|
||||
python-psutil
|
||||
python-pytz
|
||||
python-requests
|
||||
|
|
|
|||
Loading…
Reference in a new issue