#!/bin/bash # This file is part of curtin. See LICENSE file for copyright and license info. VERBOSITY=0 TEMP_D="" PAYLOAD_MARKER="_____PAYLOAD_____" error() { echo "$@" 1>&2; } fail() { [ $# -eq 0 ] || error "$@"; exit 1; } bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; } cleanup() { [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}" } debug() { local level=${1}; shift; [ "${level}" -gt "${VERBOSITY}" ] && return error "${@}" } print_vars() { local k karray t="" cur="" tic="'" repltic="'\''" for k in "$@"; do karray="$k[@]" karray=( "${!karray}" ) if [ ${#karray[@]} -gt 1 ]; then cur="(" for t in "${karray[@]}"; do cur="${cur} '${t//${tic}/${repltic}}'" done cur="${cur} )" else t=${!k} cur="'${t//${tic}/${repltic}}'" #printf "%s=\"%s\"" "$k" "${t//'/'\''}" fi printf "%s=%s\n" "$k" "$cur" done } write_extractor() { echo "#!/bin/bash" echo "# vi: ts=4 expandtab syntax=sh" print_vars "$@" echo "CREATE_TIME='$(date -R)'" echo "PAYLOAD_MARKER='$PAYLOAD_MARKER'" cat <<"END_EXTRACTOR" VERBOSITY=0 INFO_KEYS=("LABEL" "PREFIX" "COMMAND" "CREATE_TIME" "MD5SUM") error() { echo "$@" 1>&2; } fail() { [ $# -eq 0 ] || error "$@"; exit 1; } Usage() { cat <&2; [ $# -eq 0 ] || error "$@"; return 1; } debug() { local level=${1}; shift; [ "${level}" -gt "${VERBOSITY}" ] && return error "${@}" } print_vars() { local k karray t="" cur="" tic="'" repltic="'\''" for k in "$@"; do karray="$k[@]" karray=( "${!karray}" ) if [ ${#karray[@]} -gt 1 ]; then cur="(" for t in "${karray[@]}"; do cur="${cur} '${t//${tic}/${repltic}}'" done cur="${cur} )" else t=${!k} cur="'${t//${tic}/${repltic}}'" #printf "%s=\"%s\"" "$k" "${t//'/'\''}" fi printf "%s=%s\n" "$k" "$cur" done } dump_b64() { sed -n "1,/^${PAYLOAD_MARKER}$/!p" "$1" } dump_bin() { dump_b64 "$@" | base64 --decode } extract() { mkdir "$2" || { error "failed to make '$2'"; return 1; } # Do not use tar [-S, --sparse] flag, see LP: #1757565 dump_bin "$1" | tar -xzf - -C "$2" } main() { local short_opts="hp:v" local long_opts="help,no-execute,prefix:,verbose" local getopt_out=$(getopt --name "${0##*/}" \ --options "${short_opts}" --long "${long_opts}" -- "$@") && eval set -- "${getopt_out}" || { bad_Usage; return; } local cur="" next="" local prefix="$PREFIX" execute=true while [ $# -ne 0 ]; do cur="$1"; next="$2"; case "$cur" in -h|--help) Usage ; exit 0;; --no-execute) execute=false;; -p|--prefix) prefix="$next"; shift;; -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));; --) shift; break;; esac shift; done [ $# -lt 2 ] || { bad_Usage "got $# args. expected only 1"; return; } mode="$1" case "${mode:-extract}" in info) print_vars "${INFO_KEYS[@]}"; return;; check) found=$(dump_bin "$0" | md5sum) || { error "failed to calculate checksum"; return 1; } found=${found% -} [ "$found" = "$MD5SUM" ] && error "found = expected = $found" && return 0 error "found = ${found}. expected = ${MD5SUM}" return 1;; dump) dump_bin "$0"; return;; extract) extract "$0" "$prefix" || { error "failed extraction"; return 1; } if [ "${#COMMAND[@]}" = "1" -a -z "${COMMAND}" ]; then error "extracted to '$PWD/$prefix'. no command to run." return 0; fi if ! $execute; then error "extracted to '$PWD/$prefix'. disabled command" return 0; fi cd "$prefix" || { error "failed to change to $prefix"; return 1; } local np="" if [ -n "$PYPATH" ]; then np="${PYPATH//_pwd_/$PWD}${PYTHONPATH:+:${PYTHONPATH}}" export PYTHONPATH="$np" fi if [ -n "$BINPATH" ]; then np="${BINPATH//_pwd_/$PWD}${PATH:+:${PATH}}" export PATH="$np" fi debug 1 "executing: ${COMMAND[*]}" exec "${COMMAND[@]}" ;; esac return 0 } set -o pipefail main "$@" exit END_EXTRACTOR echo "$PAYLOAD_MARKER" } Usage() { cat < "$output" || { error "failed to redirect output to $output"; return 1; } fi write_extractor MD5SUM PREFIX LABEL COMMAND PYPATH BINPATH || { error "failed to write extractro"; return 1; } base64 < "$payload" || { error "failed to base64 encode payload"; return 1; } return 0 } main "$@" # vi: ts=4 expandtab syntax=sh