#!/bin/bash NAME="kfg" VERSION="0.4" HOME_PATH="$HOME" TMP_PATH="$HOME_PATH/.tmp/kfg_install" CONFIG_PATH="$HOME_PATH/.config" BINARY_PATH="/usr/bin" RC_FILE=".zshrc" ASK="\e[38;5;9m" INFO="\e[38;5;39m" ADD="\e[32m\e[1m" ERROR="\033[0;31m" ENDCOLOR="\e[0m" declare -A TOOLS || typeset -A TOOLS TOOLS[all]="Install everything" TOOLS[zsh]="Powerful Shell" TOOLS[tmux]="Terminal Multiplexer - https://github.com/tmux/tmux" TOOLS[unp]="Perl script to make file archive extraction easier" TOOLS[bat]="cat replacement with syntax highlighting and git integration - https://github.com/sharkdp/bat" TOOLS[lsd]="ls replacement with colors, icons, tree-view and more - https://github.com/lsd-rs/lsd" TOOLS[omp]="Customisable shell prompt renderer - https://github.com/jandedobbeleer/oh-my-pos" TOOLS[zoxide]="A smarter cd command. - https://github.com/ajeetdsouza/zoxide" function show_help_name { echo "$NAME v$VERSION" } function show_help_cmd { echo -e "cmd := { ${INFO}update${ENDCOLOR} \t\t Update $NAME, ${INFO}install${ENDCOLOR}\t\t Install configs :), ${INFO}version${ENDCOLOR}\t\t Print the version number }\n" } function show_help_opt { echo -en "opt := { ${INFO}-h${ENDCOLOR} | ${INFO}--help${ENDCOLOR} \t\t Show this help, ${INFO}-y${ENDCOLOR} | ${INFO}--yes${ENDCOLOR} \t\t Skip confirmation questions, ${INFO}-a${ENDCOLOR} | ${INFO}--arch STRING${ENDCOLOR} \t Set the architecture string to be used when downloading files from repositories. Most common are "amd64", "arm64", "armhf", etc, ${INFO}-d${ENDCOLOR} | ${INFO}--debug${ENDCOLOR}\t\t Print debug output, }\n" } function show_help { show_help_name echo -e "Usage: $NAME [ opt ]\n" show_help_cmd show_help_opt exit 2 } function version { echo "v$VERSION" } function log { color $1 "[$2]" echo "$3" } function log_add { log $ADD "+" "$1" } function log_info { log $INFO "*" "$1" } function log_error { echo "$(log $ERROR "!" "$1")" >&2 } function err { log_error "Error: $1" exit 1 } function log_debug { if [ -z "$P_Debug" ]; then return 0; fi log $INFO "&" "$1" } function ask { color $ASK "[?]" read -d '' -p "$1 [Y/n] " -N 1 -r } function color { echo -en "$1$2$ENDCOLOR " } function user_confirm { if [ ! -z "$P_Yes" ]; then return 0; fi ask "$1" while [ true ]; do if [[ ! $REPLY =~ ^[$'\n']$ ]]; then echo -e -n "\n"; fi case $REPLY in [Yy$'\n']* ) return 0;; [Nn]* ) return 1;; * ) ask "Please enter";; esac done } function user_confirm_overwrite { user_confirm "$1 already exists. Do you want to overwrite?" return $? } function download_config { if [ -z "$P_CONFIG" ]; then return 0; fi mkdir -p "$CONFIG_PATH/$1/" contains_path="${2%*/*}" if [ -z $contains_path ]; then mkdir -p "$CONFIG_PATH/$1/$contains_path/" fi FILE="$CONFIG_PATH/$1/$2" if [ ! -e "$FILE" ] || user_confirm_overwrite "$FILE"; then download "$3" "$FILE" #wget -O "$FILE" "$3" > /dev/null 2>&1 log_add "Added $FILE" fi } function install_rc { if [ -z "$P_RC" ]; then return 0; fi # Make sure the directory exists mkdir -p "$CONFIG_PATH/$1/" # This is the config file FILE="$CONFIG_PATH/$1/.$1.rc" # Does the file already exist? or does the user want to overwrite it? if [ ! -e "$FILE" ] || user_confirm_overwrite "$FILE"; then # Download the file and save it download "$2" "$FILE" #wget -O "$FILE" "$2" > /dev/null 2>&1 log_add "Added $FILE" fi # Add the file to the rc file as source $file SOURCE_CMD=$( echo "source $FILE" ) RC="$HOME_PATH/$RC_FILE" if ! cat "$RC" | grep "$SOURCE_CMD" > /dev/null; then echo "$SOURCE_CMD" >> "$RC" log_add "Added \"$SOURCE_CMD\" to $RC" else log_info "\"$SOURCE_CMD\" already in $RC" fi # Add the file to the rc file as source $file in root RC_ROOT="/root/$RC_FILE" if ! sudo cat "$RC_ROOT" | grep "$SOURCE_CMD" > /dev/null; then echo "$SOURCE_CMD" | sudo tee -a "$RC_ROOT" log_add "Added \"$SOURCE_CMD\" to $RC_ROOT" else log_info "\"$SOURCE_CMD\" already in $RC_ROOT" fi } function init_install_rc { if [ -z "$P_RC" ]; then return 0; fi # Add the file to the rc file as source $file SOURCE_CMD="$1" RC="$HOME_PATH/$RC_FILE" if ! cat "$RC" | grep "$SOURCE_CMD" > /dev/null; then echo "$SOURCE_CMD" >> "$RC" log_add "Added \"$SOURCE_CMD\" to $RC" else log_info "\"$SOURCE_CMD\" already in $RC" fi # Add the file to the rc file as source $file in root RC_ROOT="/root/$RC_FILE" if ! sudo cat "$RC_ROOT" | grep "$SOURCE_CMD" > /dev/null; then echo "$SOURCE_CMD" | sudo tee -a "$RC_ROOT" log_add "Added \"$SOURCE_CMD\" to $RC_ROOT" else log_info "\"$SOURCE_CMD\" already in $RC_ROOT" fi } function download { local _url=$1 local _path=$2 local _result if check_cmd curl; then _dld=curl elif check_cmd wget; then _dld=wget else need_cmd 'curl or wget' fi if [ ! -z $_path ]; then mkdir -p "$(dirname "$_path")" log_info "Downloading $_url to $_path" case "${_dld}" in curl) _args="-sLo $_path" ;; wget) _args="-qO $_path" ;; esac else case "${_dld}" in curl) _args="-sL" ;; wget) _args="-qO-" ;; esac fi case "${_dld}" in curl) _result="$(curl $_args "${_url}")" || _result="$(sudo curl $_args "${_url}")" || err "curl: failed to download ${_url}" ;; wget) _result="$(wget $_args "${_url}")" || _result="$(sudo wget $_args "${_url}")" || err "wget: failed to download ${_url}" ;; *) err "unsupported downloader: ${_dld}" ;; esac RETVAL="${_result}" return 0 } function github_install { ensure get_architecture local _program=$1 local _arch="${RETVAL}" local _url="https://api.github.com/repos/$2/releases/latest" assert_nz "${_arch}" "arch" need_cmd grep download "${_url}" local _releases=$RETVAL (echo "${_releases}" | grep -q 'API rate limit exceeded') && (log_error "GitHub API rate limit exceeded. Please try again later." || return 1) local _package_url _package_urls _package_urls="$(echo "${_releases}" | grep "browser_download_url" | cut -d '"' -f 4)" #log_debug "Packages: ${_package_urls}" # Check for Rust package local _rust_package_url="$(echo "$_package_urls" | grep $_arch)" local _other_package_url="$(echo "$_package_urls" | grep $ARCH | grep -vE "$APP_FILTER")" log_debug "Rust package: $_rust_package_url" log_debug "Filter: $APP_FILTER" log_debug "Other package: $_other_package_url" if [ ! -z "$_other_package_url" ]; then _package_url="${_other_package_url}" elif [ ! -z "$_rust_package_url" ]; then _package_url="${_rust_package_url}" else log_error "Can not find installable package for '$_program' for the detected architecture (${_arch})." return 0 fi log_debug "Selected package: ${_package_url}" # Check the extension local _ext case "${_package_url}" in *.tar.gz) _ext="tar.gz" ;; *.deb) _ext="deb" ;; *.zip) _ext="zip" ;; *) _ext="" ;; esac local _package if [ -z $_ext ]; then _package="$TMP_PATH/$_program" else _package="$TMP_PATH/$_program.$_ext" fi download "$_package_url" "$_package" # unpack cd "${TMP_PATH}" case "${_package}" in *.tar.gz) need_cmd tar log_info "Unpacking ${_package}" tar -xf "${_package}" ;; *.zip) need_cmd unzip log_info "Unpacking ${_package}" unzip -oq "${_package}" ;; *) ;; # ignore esac # install local _binary case "${_ext}" in tar.gz) _binary="$(tar --list -f "${_package}" | grep -E "^(.*/)?$_program$")" log_debug $_binary install_binary "$_program" "$TMP_PATH/$_binary" return 0 ;; deb) install_deb "${_program}" "${_package}" return 0 ;; zip) _binary="$(unzip -l "${_package}" | sed -E 's/ {1,}/ /g' | cut -d ' ' -f 5 | grep -E "^(.*/)?$_program$")" log_debug $_binary install_binary "$_program" "$TMP_PATH/$_binary" return 0 ;; *) _binary="${_program}" log_debug $_binary log_debug "Installing binary!" install_binary "$_program" "$TMP_PATH/$_binary" ;; esac } function install_deb_check { CHECK_CURRENT=$(dpkg -s "$1" | grep -E "Status|Version") INSTALLED_CURRENT=$(echo $CHECK_CURRENT | grep -oE "Status: .*" | cut -d ' ' -f 2) VERSION_CURRENT=$(echo $CHECK_CURRENT | grep -oE "Version: .*" | cut -d ' ' -f 2) CHECK_NEW=$(sudo dpkg -I $2 | grep -E "Status|Version") INSTALLED_NEW=$(echo $CHECK_NEW | grep -oE "Status: .*" | cut -d ' ' -f 2) VERSION_NEW=$(echo $CHECK_NEW | grep -oE "Version: .*" | cut -d ' ' -f 2) if [ ! -z "$CHECK_CURRENT" ]; then if [[ "$VERSION_CURRENT" != "$VERSION_NEW" ]]; then log_info "$1 ($VERSION_CURRENT) is installed." else log_info "$1 ($VERSION_CURRENT) is already installed. Skipping ..." return 1 fi if ! user_confirm "Do you want to install $1 ($VERSION_NEW)?"; then return 1 fi fi return 0 } function install_deb { local _file=$2 local _program=$1 #if [ -z "$P_DEB" ]; then return 0; fi #log_info "Downloading $2 to $TMP_PATH ..." #wget -O $TMP_PATH/$1.deb $2 > /dev/null 2>&1 if ! install_deb_check "$_program" "$_file"; then return 1 fi INSTALL=$(sudo dpkg -i $_file) UNPACK=$(echo -n "$INSTALL" | grep -oE "Unpacking .*") PROG=$(echo -n $UNPACK | cut -d '(' -f 1 | cut -d ' ' -f 2) CURR_VERSION=$(echo -n $UNPACK | cut -d '(' -f 2 | cut -d ')' -f 1) PREV_VERSION=$(echo -n $UNPACK | cut -d '(' -f 3 | cut -d ')' -f 1) color $ADD "[+]" echo -n "Installed $PROG ($CURR_VERSION)" if [ ! -z ${PREV_VERSION+x} ]; then echo " over ($PREV_VERSION)" else echo "" fi #rm $TMP_PATH/$1.deb return 0 } function init { #if [ ! -z "$P_BINARY" ] || [ ! -z "$P_DEB" ]; then # log_info "Found Architecture: $ARCH" # if ! user_confirm "Is '$ARCH' the correct architecture to download programs?"; then # log_info "Exiting ..." # exit 0 # fi #fi if [ ! -z "$P_APT" ]; then log_info "Running apt update ..." sudo apt update > /dev/null 2>&1 fi mkdir -p $TMP_PATH/ mkdir -p $CONFIG_PATH/ } function cleanup { rm -R $TMP_PATH } function apt_install { if [ -z "$P_APT" ]; then return 0; fi RESULT=$(sudo apt install -y $1 2>&1 ) if echo "$1 is already the newest version" | grep "$RESULT" > /dev/null; then log_info "$1 is already installed" else log_add "Installed $1" fi } #function github_latest { # VERSION=$(curl -I "https://github.com/$1/releases/latest/" 2> /dev/null | grep -iE "^Location:" | tr -s ' ' | cut -d '/' -f 8 2> /dev/null) # echo -n ${VERSION//[$'\t\r\n']} #} #function install_deb_github { # if [ -z "$P_DEB" ]; then return 0; fi # local PATTERN=${3/ARCH/$ARCH}; # log_debug "Loading most recent version for $1" # local VERSION=$(github_latest $2 2> /dev/null ) # VERSION=${VERSION/v/} # log_debug "Found version $VERSION" # local FILE=${PATTERN/VERSION/$VERSION} # local LINK="https://github.com/$2/releases/latest/download/$FILE" # log_debug "Download link: $LINK" # install_deb "$1" ${LINK//[$'\t\r\n']} #} function git_clone { CLONE=$(git clone "$1" "$2" 2>&1) if [[ $CLONE =~ "already exists" ]]; then log_debug "$1 already exists. Running 'git pull'." PULL=$(git -C "$2" pull) log_info "$PULL" fi } function install_binary { local _app=$1 local _path=$2 log_debug $_path log_debug $BINARY_PATH/$_app sudo cp $_path $BINARY_PATH/$_app sudo chmod +x $BINARY_PATH/$_app log_add "Installed $_app into $BINARY_PATH/$_app" } #function install_binary_github { # if [ -z "$P_BINARY" ]; then return 0; fi # local PATTERN=${3/ARCH/$ARCH}; # log_debug "Loading most recent version for $1" # VERSION=$(github_latest $2 2> /dev/null) # VERSION=${VERSION/v/} # log_debug "Found version $VERSION" # local FILE=${PATTERN/VERSION/$VERSION} # local LINK="https://github.com/$2/releases/latest/download/$FILE" # log_debug "Download link: $LINK" # install_binary "$1" ${LINK//[$'\t\r\n']} #} function set_shell { if [ -z "$P_ZSH" ]; then return 0; fi CURR_U=$(grep "^$USER" /etc/passwd | cut -d ':' -f 7 | cut -d '/' -f 4) CURR_R=$(grep "^root" /etc/passwd | cut -d ':' -f 7 | cut -d '/' -f 4) if [[ $1 != $CURR_U ]]; then log_add "Setting default shell to $1" sudo -u $USER chsh -s $(which $1) sudo chsh -s $(which $1) else log_info "Shell already set to $1" fi } # -------------------------------------------------------------------------------------------------- function update { cd "$(dirname "$0")" download "https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/kfg" "kfg" exit 0 } function show_help_install { show_help_name echo -e "Usage: $NAME install [ opt ]\n" echo -e "program := {" local _length _space for key in ${!TOOLS[@]}; do _length="$(echo -n $key | wc -m)" if [ "$_length" -gt 21 ]; then _space="" elif [ "$_length" -gt 13 ]; then _space="\t" elif [ "$_length" -gt 5 ]; then _space="\t\t" else _space="\t\t\t" fi echo -e " ${INFO}${key}${ENDCOLOR}${_space} ${TOOLS[$key]}" done echo -e "}\n" show_help_opt exit 2 } function p_all { p_zsh p_tmux p_unp p_bat p_lsd p_omp p_zoxide } function p_zsh { # ----------------- # zsh # ----------------- apt_install zsh set_shell zsh # --- TODO --- : Keyboard navigation, Suggestions, ... #wget -O .zshrc https://git.grml.org/f/grml-etc-core/etc/zsh/zshrc #git clone https://github.com/zsh-users/zsh-autosuggestions "$HOME/.config/zsh/zsh-autosuggestions" # source ~/.config/zsh/zsh-autosuggestions/zsh-autosuggestions.zsh } function p_tmux { # ----------------- # tmux # ----------------- apt_install tmux download_config tmux tmux.conf https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.tmux.conf download_config tmux tmux.theme https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.tmux.theme download_config tmux myip.sh https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/myip.sh sudo chmod +x ${CONFIG_PATH}/tmux/myip.sh install_rc tmux https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.tmux.rc git_clone "https://github.com/tmux-plugins/tpm" "${CONFIG_PATH}/tmux/plugins/tpm" } function p_unp { # ----------------- # unp # ----------------- apt_install unp # --- TODO --- : rc file } function p_bat { # ----------------- # bat # ----------------- github_install bat "sharkdp/bat" #install_deb_github bat "sharkdp/bat" "bat_VERSION_ARCH.deb" install_rc bat https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.bat.rc } function p_lsd { # ----------------- # Install lsd https://github.com/Peltoche/lsd # ----------------- github_install "lsd" "lsd-rs/lsd" #install_deb_github "lsd" "lsd-rs/lsd" "lsd_VERSION_ARCH.deb" install_rc lsd https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.lsd.rc download_config lsd "config.yaml" "https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.lsd.conf" download_config lsd "themes/kamu.yaml" "https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.lsd.theme" } function p_zoxide { github_install "zoxide" "ajeetdsouza/zoxide" install_rc "zoxide" "https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.zoxide.rc" } function p_omp { # ----------------- # Install OhMyPosh # ----------------- github_install "oh-my-posh" "JanDeDobbeleer/oh-my-posh" download_config "omp" "omp.json" "https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.omp.json" install_rc "omp" "https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.omp.rc" #install_binary_github "oh-my-posh" "JanDeDobbeleer/oh-my-posh" "posh-linux-ARCH" } function install { if [ -z $1 ]; then show_help_install exit 0 fi init P_APT=1; P_DEB=1; P_CONFIG=1; P_RC=1; P_BINARY=1; P_ZSH=1 # ----------------- # General Config # ----------------- init_install_rc "export KHOME=$HOME_PATH" init_install_rc "export XDG_CONFIG_HOME=$CONFIG_PATH" install_rc "shell" "https://git.cbeck.tech/kamu/dotfiles/raw/branch/main/.general.rc" while : do case "$1" in help) show_help_install; exit 0 ;; "") break ;; all) p_all; shift ;; zsh) p_zsh; shift ;; bat) p_bat; shift ;; tmux) p_tmux; shift ;; unp) p_unp; shift ;; lsd) p_lsd; shift ;; omp) p_omp; shift ;; zoxide) p_zoxide; shift ;; # If invalid options were passed, then getopt should have reported an error, # which we checked as VALID_ARGUMENTS when getopt was called... *) log_error "Unrecognised program: $1"; shift ;; esac done #cleanup exit 0 } function main { if [ -z $1 ]; then show_help fi PARSED_ARGUMENTS=$(getopt -a -n install.sh -o hvdya: --long yes,help,debug,arch,verbose: -- "$@") VALID_ARGUMENTS=$? if [ "$VALID_ARGUMENTS" != "0" ]; then show_help fi ARCH=$(/usr/bin/dpkg --print-architecture) #echo "PARSED_ARGUMENTS is $PARSED_ARGUMENTS" eval set -- "$PARSED_ARGUMENTS" while : do case "$1" in -h | --help) show_help ;; -v | --verbose) P_Verbose=1 ; shift ;; -d | --debug) P_Debug=1 ; shift ;; -y | --yes) P_Yes=1 ; shift ;; -a | --arch) ARCH="$2" ; shift 2 ;; # -- means the end of the arguments; drop this, and break out of the while loop --) shift; break ;; # If invalid options were passed, then getopt should have reported an error, # which we checked as VALID_ARGUMENTS when getopt was called... *) log_error "Unexpected option: $1" show_help ;; esac done #echo "Parameters remaining are: $@" case "$1" in update) update ;; version) version ;; install) shift; install $@;; # -- means the end of the arguments; drop this, and break out of the while loop --) shift; break ;; # If invalid options were passed, then getopt should have reported an error, # which we checked as VALID_ARGUMENTS when getopt was called... *) log_error "Unexpected command: $1"; show_help ;; esac } # The following is from (with modifications): https://github.com/rust-lang/rustup/blob/4c1289b2c3f3702783900934a38d7c5f912af787/rustup-init.sh function get_architecture { _ostype="$(uname -s)" _cputype="$(uname -m)" _clibtype="gnu" APP_FILTER="arm64|amd64|aarch64|i686|x86_64|x86-64|x64|musl|gnu|windows|darwin|linux|android|exe|sig|sha256" if [ "${_ostype}" = Linux ]; then if [ "$(uname -o || true)" = Android ]; then _ostype=Android fi if ldd --version 2>&1 | grep -q 'musl'; then _clibtype="musl" APP_FILTER=$(echo $APP_FILTER | sed -e "s/musl|//gi") else APP_FILTER=$(echo $APP_FILTER | sed -e "s/gnu|//gi") fi fi if [ "${_ostype}" = Darwin ] && [ "${_cputype}" = i386 ]; then # Darwin `uname -m` lies if sysctl hw.optional.x86_64 | grep -q ': 1'; then _cputype=x86_64 fi fi if [ "${_ostype}" = SunOS ]; then # Both Solaris and illumos presently announce as "SunOS" in "uname -s" # so use "uname -o" to disambiguate. We use the full path to the # system uname in case the user has coreutils uname first in PATH, # which has historically sometimes printed the wrong value here. if [ "$(/usr/bin/uname -o || true)" = illumos ]; then _ostype=illumos fi # illumos systems have multi-arch userlands, and "uname -m" reports the # machine hardware name; e.g., "i86pc" on both 32- and 64-bit x86 # systems. Check for the native (widest) instruction set on the # running kernel: if [ "${_cputype}" = i86pc ]; then _cputype="$(isainfo -n)" fi fi case "${_ostype}" in Android) _ostype=linux-android APP_FILTER=$(echo $APP_FILTER | sed -e "s/android|//gi") ;; Linux) check_proc _ostype=unknown-linux-${_clibtype} _bitness=$(get_bitness) APP_FILTER=$(echo $APP_FILTER | sed -e "s/linux|//gi") ;; FreeBSD) _ostype=unknown-freebsd ;; NetBSD) _ostype=unknown-netbsd ;; DragonFly) _ostype=unknown-dragonfly ;; Darwin) _ostype=apple-darwin APP_FILTER=$(echo $APP_FILTER | sed -e "s/darwin|//gi") ;; illumos) _ostype=unknown-illumos ;; MINGW* | MSYS* | CYGWIN* | Windows_NT) _ostype=pc-windows-msvc ;; *) err "unrecognized OS type: ${_ostype}" ;; esac case "${_cputype}" in i386 | i486 | i686 | i786 | x86) _cputype=i686 APP_FILTER=$(echo $APP_FILTER | sed -e "s/i686|//gi") ;; xscale | arm) _cputype=arm if [ "${_ostype}" = "linux-android" ]; then _ostype=linux-androideabi fi ;; armv6l) _cputype=arm if [ "${_ostype}" = "linux-android" ]; then _ostype=linux-androideabi else _ostype="${_ostype}eabihf" fi ;; armv7l | armv8l) _cputype=armv7 if [ "${_ostype}" = "linux-android" ]; then _ostype=linux-androideabi else _ostype="${_ostype}eabihf" fi ;; aarch64 | arm64) _cputype=aarch64 APP_FILTER=$(echo $APP_FILTER | sed -e "s/aarch64|//gi") APP_FILTER=$(echo $APP_FILTER | sed -e "s/arm64|//gi") ;; x86_64 | x86-64 | x64 | amd64) _cputype=x86_64 APP_FILTER=$(echo $APP_FILTER | sed -e "s/amd64|//gi") APP_FILTER=$(echo $APP_FILTER | sed -e "s/x86_64|//gi") APP_FILTER=$(echo $APP_FILTER | sed -e "s/x86-64|//gi") APP_FILTER=$(echo $APP_FILTER | sed -e "s/x64|//gi") ;; mips) _cputype=$(get_endianness mips '' el) ;; mips64) if [ "${_bitness}" -eq 64 ]; then # only n64 ABI is supported for now _ostype="${_ostype}abi64" _cputype=$(get_endianness mips64 '' el) fi ;; ppc) _cputype=powerpc ;; ppc64) _cputype=powerpc64 ;; ppc64le) _cputype=powerpc64le ;; s390x) _cputype=s390x ;; riscv64) _cputype=riscv64gc ;; *) err "unknown CPU type: ${_cputype}" ;; esac # Detect 64-bit linux with 32-bit userland if [ "${_ostype}" = unknown-linux-musl ] && [ "${_bitness}" -eq 32 ]; then case ${_cputype} in x86_64) # 32-bit executable for amd64 = x32 if is_host_amd64_elf; then { echo "x32 userland is unsupported" 1>&2 exit 1 }; else _cputype=i686 fi ;; mips64) _cputype=$(get_endianness mips '' el) ;; powerpc64) _cputype=powerpc ;; aarch64) _cputype=armv7 if [ "${_ostype}" = "linux-android" ]; then _ostype=linux-androideabi else _ostype="${_ostype}eabihf" fi ;; riscv64gc) err "riscv64 with 32-bit userland unsupported" ;; *) ;; esac fi # Detect armv7 but without the CPU features Rust needs in that build, # and fall back to arm. # See https://github.com/rust-lang/rustup.rs/issues/587. if [ "${_ostype}" = "unknown-linux-musleabihf" ] && [ "${_cputype}" = armv7 ]; then if ensure grep '^Features' /proc/cpuinfo | grep -q -v neon; then # At least one processor does not have NEON. _cputype=arm fi fi _arch="${_cputype}-${_ostype}" log_debug "Detected architecture: ${_arch}" log_debug "APP_FILTER: $APP_FILTER" RETVAL="${_arch}" } function get_bitness { need_cmd head # Architecture detection without dependencies beyond coreutils. # ELF files start out "\x7fELF", and the following byte is # 0x01 for 32-bit and # 0x02 for 64-bit. # The printf builtin on some shells like dash only supports octal # escape sequences, so we use those. local _current_exe_head _current_exe_head=$(head -c 5 /proc/self/exe) if [ "${_current_exe_head}" = "$(printf '\177ELF\001')" ]; then echo 32 elif [ "${_current_exe_head}" = "$(printf '\177ELF\002')" ]; then echo 64 else err "unknown platform bitness" fi } function get_endianness { local cputype=$1 local suffix_eb=$2 local suffix_el=$3 # detect endianness without od/hexdump, like get_bitness() does. need_cmd head need_cmd tail local _current_exe_endianness _current_exe_endianness="$(head -c 6 /proc/self/exe | tail -c 1)" if [ "${_current_exe_endianness}" = "$(printf '\001')" ]; then echo "${cputype}${suffix_el}" elif [ "${_current_exe_endianness}" = "$(printf '\002')" ]; then echo "${cputype}${suffix_eb}" else err "unknown platform endianness" fi } function is_host_amd64_elf() { need_cmd head need_cmd tail # ELF e_machine detection without dependencies beyond coreutils. # Two-byte field at offset 0x12 indicates the CPU, # but we're interested in it being 0x3E to indicate amd64, or not that. local _current_exe_machine _current_exe_machine=$(head -c 19 /proc/self/exe | tail -c 1) [ "${_current_exe_machine}" = "$(printf '\076')" ] } function check_proc() { # Check for /proc by looking for the /proc/self/exe link. # This is only run on Linux. if ! test -L /proc/self/exe; then err "unable to find /proc/self/exe. Is /proc mounted? Installation cannot proceed without /proc." fi } function need_cmd() { if ! check_cmd "$1"; then err "need '$1' (command not found)" fi } function check_cmd() { command -v "$1" >/dev/null 2>&1 } function ensure() { if ! "$@"; then err "command failed: $*"; fi } function assert_nz() { if [ -z "$1" ]; then err "found empty string: $2"; fi } { main "$@" || exit 1 }