#!/bin/sh { set -ue if [ -n "${ZSH_VERSION:-}" ]; then emulate sh -o err_exit -o no_unset fi readonly url_base=https://github.com/romkatv/tmux-bin/releases/download/v3.1.0 readonly archives=' --------------------- file:tmux-darwin-arm64.tar.gz; md5:2e312f7555a6395f1d81bfa3b083d710; sha256:134a9afc1184269810af9feae41fdc19bad7d5e0ce90ee7376a22946759d5cd7; file:tmux-darwin-x86_64.tar.gz; md5:1857c31a650ef7dada3940b3d45b95f1; sha256:a2f359975ac8b471713e82f91700b75049fed82930bf72678d74ea730dbc89e9; file:tmux-linux-aarch64.tar.gz; md5:de566f3edf53cd1a94555495618d99ff; sha256:a8d0b937e124d9bd8bb312c026fc55bfaec4d41fb0f729a52c50de5222d86594; file:tmux-linux-armv6l.tar.gz; md5:417ce72afb8f2ff823e75429c9bf7065; sha256:9ddc576b39e35b9186936246bc6e632f2e691be27ea52372eee8bdaf2d51de90; file:tmux-linux-armv7l.tar.gz; md5:6750b5cb7993c411d88904e6eeaa8c4c; sha256:9fd3918371c48a4795f22b600a646974a312621611a024792d296f69b26aa2af; file:tmux-linux-i386.tar.gz; md5:3e8a9286e6f80c6e9abad5eaf1d85eea; sha256:b8f62934b3ea4817a32c915a98dcc415a762ff5169f9aa0ec367796f505fb6bb; file:tmux-linux-i586.tar.gz; md5:7bced5f298d8c59c7638e22b1e1ae6ae; sha256:59b53cc3331c84eee46bd79b55b4289a8ac81853f53233e880bc057e45646620; file:tmux-linux-i686.tar.gz; md5:2a411bd0737b00326509da8ba4cf26e0; sha256:520898915c5575da0f06abf89cc044f35f428828de2fa6956ce786fb53d983f7; file:tmux-linux-x86_64.tar.gz; md5:6aa7a656836540efadaf4b45ac7312fe; sha256:2e16b79a6638c9b450eb7a807696ea21395761f2d9a7ee8036d1a396be3cf643;' readonly lf=" " if [ -t 1 ]; then readonly _0="$(printf '\033[0m')" readonly _B="$(printf '\033[1m')" readonly _U="$(printf '\033[4m')" readonly _R="$(printf '\033[31m')" readonly _G="$(printf '\033[32m')" readonly _Y="$(printf '\033[33m')" else readonly _0= readonly _B= readonly _U= readonly _R= readonly _G= readonly _Y= fi usage="$(cat <]... [OPTIONS] -f FILE [OPTIONS] -u URL If '-f FILE' is specified, install tmux from the specified *.tar.gz file produced by the build script. If '-u URL' is specified, download the file and install as if with '-f FILE'. If neither '-f' nor '-u' is specified, download the appopriate file from https://github.com/romkatv/tmux-bin/releases and install as if with '-f FILE'. If '-a ' is specified at least once, abort installation if integrity of the downloaded package cannot be verified with at least one of the listed hashing algorithms. Options: -q Produce no output on success. -d DIR Install to this directory. If specified more than once, present an interactive dialog to choose the directory. Empty argument means a custom directory (requires manual user input). If '-d' is not specified, the effect is idential to this: -d /usr/local -d ~/.local -d "" Except on Termux: -d "\$PREFIX"/local -d ~/.local -d "" -s FD On success, write the path to the installation directory to this file descriptor. END )" absfile() { if [ ! -e "$1" ]; then >&2 echo "${_R}error${_0}: file not found: ${_U}$1${_0}" return 1 fi local dir base dir="$(dirname -- "$1")" base="$(basename -- "$1")" ( cd -- "$dir" && dir="$(pwd)" && printf '%s/%s\n' "${dir%/}" "${base}" ) } check_dir() { if [ -z "$1" ]; then >&2 echo "${_R}error${_0}: directory cannot be empty string" exit 1 fi if [ -z "${1##~*}" ]; then >&2 echo "${_R}error${_0}: please expand ${_U}~${_0} in directory name: ${_U}$1${_0}" exit 1 fi if [ -z "${1##//*}" ]; then >&2 echo "${_R}error${_0}: directory cannot start with ${_U}//${_0}: ${_U}$1${_0}" exit 1 fi } add_dir() { num_dirs=$((num_dirs + 1)) dirs="$dirs${num_dirs}${1}${lf}" if [ -n "$1" ]; then dirs_c="$dirs_c ${_B}($num_dirs)${_0} ${_U}${1}${_0}${lf}" else dirs_c="$dirs_c ${_B}($num_dirs)${_0} custom directory (input required)${lf}" fi } check_sudo() { local dir="$1" sudo= while true; do if [ -e "$dir" ]; then if [ ! -d "$dir" ]; then >&2 echo "${_R}error${_0}: not a directory: ${_U}$dir${_0}" return 1 fi if [ ! -w "$dir" ]; then if [ "$euid" = 0 ]; then >&2 echo "${_R}error${_0}: directory not writable: ${_U}$dir${_0}" return 1 else if [ -z "$quiet" ]; then echo "${_Y}===>${_0} using ${_U}${_G}sudo${_0} for installation" fi sudo=sudo fi fi break fi if [ "$dir" = / ] || [ "$dir" = . ]; then break fi dir="$(dirname -- "$dir")" done } dirs= dirs_c= num_dirs=0 quiet= algos= url= file= sudo= fd= asked= command -v sudo >/dev/null 2>&1 && euid="$(id -u 2>/dev/null)" || euid=0 while getopts ':hqd:s:a:f:u:' opt "$@"; do case "$opt" in h) printf '%s\n' "$usage" exit ;; q) if [ -n "$quiet" ]; then >&2 echo "${_R}error${_0} duplicate option: ${_B}-${opt}${_0}" exit 1 fi quiet=1 ;; d) if printf "%s" "$dirs" | cut -b 2- | grep -qxF -- "$OPTARG"; then >&2 echo "${_R}error${_0}: duplicate option: ${_B}-${opt} ${OPTARG}${_0}" exit 1 fi if [ "$(printf "%s" "$OPTARG" | wc -l | tr -Cd '0-9')" != 0 ]; then >&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}" exit 1 fi if [ "$num_dirs" = 9 ]; then >&2 echo "${_R}error${_0}: too many options: ${_B}-${opt}${_0}" exit 1 fi if [ -n "$OPTARG" ]; then check_dir "$OPTARG" fi add_dir "$OPTARG" ;; s) if [ -n "$fd" ]; then >&2 echo "${_R}error${_0} duplicate option: ${_B}-${opt}${_0}" exit 1 fi if ! printf '%s' "$OPTARG" | tr '\n' x | grep -qxE '[1-9][0-9]*'; then >&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}" exit 1 fi fd="$OPTARG" ;; a) case "$OPTARG" in sha256|md5) if [ -n "$algos" -a -z "${algos##*<$OPTARG>*}" ]; then >&2 echo "${_R}error${_0}: duplicate option: ${_B}-${opt} ${OPTARG}${_0}" exit 1 fi algos="$algos<$OPTARG>" ;; *) >&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}" exit 1 ;; esac ;; f) if [ -n "$file" ]; then >&2 echo "${_R}error${_0}: duplicate option: ${_B}-${opt}${_0}" exit 1 fi if [ -z "$OPTARG" ]; then >&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}" exit 1 fi file="$(absfile "$OPTARG")" ;; u) if [ -n "$url" ]; then >&2 echo "${_R}error${_0}: duplicate option: ${_B}-${opt}${_0}" exit 1 fi if [ -z "$OPTARG" ]; then >&2 echo "${_R}error${_0}: incorrect value of ${_B}-${opt}${_0}: ${_B}${OPTARG}${_0}" exit 1 fi url="$OPTARG" ;; \?) >&2 echo "${_R}error${_0}: invalid option: ${_B}-${OPTARG}${_0}" ; exit 1;; :) >&2 echo "${_R}error${_0}: missing required argument: ${_B}-${OPTARG}${_0}"; exit 1;; *) >&2 echo "${_R}internal error${_0}: unhandled option: ${_B}-${opt}${_0}" ; exit 1;; esac done if [ "$OPTIND" -le $# ]; then >&2 echo "${_R}error${_0}: unexpected positional argument" return 1 fi if [ -n "$algos" ]; then if [ -n "$file" ]; then >&2 echo "${_R}error${_0}: incompatible options: ${_B}-f${_0} and ${_B}-a${_0}" exit 1 fi if [ -n "$url" ]; then >&2 echo "${_R}error${_0}: incompatible options: ${_B}-u${_0} and ${_B}-a${_0}" exit 1 fi fi if [ "$num_dirs" = 0 ]; then if [ "$(uname -s 2>/dev/null)" = Linux ] && [ "$(uname -o 2>/dev/null)" = Android ] && [ -d "${PREFIX:-/data/data/com.termux/files/usr}" ]; then usr_local="${PREFIX:-/data/data/com.termux/files/usr}"/local usr_local_d="${_U}\$PREFIX/local${_0}" else usr_local=/usr/local usr_local_d="${_U}/usr/local${_0} " fi add_dir "$usr_local" add_dir ~/.local add_dir "" dirs_c=" ${_B}(1)${_0} $usr_local_d ${_Y}<=${_0}" if check_sudo "$usr_local" >/dev/null 2>/dev/null; then if [ -n "$sudo" ]; then dirs_c="${dirs_c} uses ${_U}${_G}sudo${_0}" else dirs_c="${dirs_c} does not need ${_U}${_G}sudo${_0}" fi if [ -d "$usr_local" ]; then dirs_c="${dirs_c} (${_B}recommended${_0})" fi else dirs_c="${dirs_c} ${_R}not writable${_0}" fi dirs_c="${dirs_c}${lf} ${_B}(2)${_0} ${_U}~/.local${_0} ${_Y}<=${_0}" if check_sudo ~/.local >/dev/null 2>/dev/null; then if [ -n "$sudo" ]; then dirs_c="${dirs_c} uses ${_U}${_G}sudo${_0}" else dirs_c="${dirs_c} does not need ${_U}${_G}sudo${_0}" fi else dirs_c="${dirs_c} ${_R}not writable${_0}" fi dirs_c="${dirs_c}${lf} ${_B}(3)${_0} custom directory ${_Y}<=${_0} manual input required${lf}" fi if [ "$num_dirs" = 1 ]; then choice=1 else while true; do echo "Choose installation directory for ${_G}tmux${_0}:" echo "" printf "%s" "$dirs_c" echo "" printf "Choice: " read -r choice if printf "%s" "$dirs" | cut -b 1 | grep -qxF -- "$choice"; then break fi if [ -n "$choice" ]; then >&2 echo "Invalid choice: ${_R}$choice${_0}. Try again." fi echo done asked=1 fi dir="$(printf "%s" "$dirs" | sed "${choice}!d" | cut -b 2-)" if [ -z "$dir" ]; then printf "Custom directory: " read -r dir check_dir "$dir" if [ -z "$quiet" ]; then echo fi asked=1 elif [ -z "$quiet" ] && [ "$num_dirs" != 1 ]; then echo fi if [ -z "$quiet" ]; then printf "%s\n" "${_Y}===>${_0} installing ${_G}tmux${_0} to ${_U}$dir${_0}" fi check_sudo "$dir" $sudo mkdir -p -- "$dir" cd -- "$dir" dir="$(pwd)" if [ -z "$file" -a -z "$url" ]; then kernel="$(uname -s | tr '[A-Z]' '[a-z]')" arch="$(uname -m | tr '[A-Z]' '[a-z]')" case "$kernel" in linux-armv8l) kernel=linux-aarch64;; msys_nt-6.*) kernel=msys_nt-10.0;; msys_nt-10.*) kernel=msys_nt-10.0;; mingw32_nt-6.*) kernel=msys_nt-10.0;; mingw32_nt-10.*) kernel=msys_nt-10.0;; mingw64_nt-6.*) kernel=msys_nt-10.0;; mingw64_nt-10.*) kernel=msys_nt-10.0;; cygwin_nt-6.*) kernel=cygwin_nt-10.0;; cygwin_nt-10.*) kernel=cygwin_nt-10.0;; esac filename="tmux-${kernel}-${arch}.tar.gz" url="$url_base/$filename" if [ -n "${archives##*file:$filename;*}" ]; then >&2 echo "${_R}error${_0}: there is no prebuilt binary for your architecture" >&2 echo >&2 echo "See ${_U}https://github.com/romkatv/tmux-bin#compiling${_0} for building one." exit 1 fi check_sig=1 else check_sig=0 fi if [ -n "$url" ]; then if [ -n "${TMPDIR-}" -a '(' '(' -d "${TMPDIR-}" -a -w "${TMPDIR-}" ')' -o '!' '(' -d /tmp -a -w /tmp ')' ')' ]; then tmpdir="$TMPDIR" else tmpdir=/tmp fi file="$tmpdir"/tmux-bin.tmp.$$.tar.gz cleanup() { rm -f -- "$file"; } trap cleanup INT QUIT TERM EXIT ILL PIPE if [ -z "$quiet" ]; then echo "${_Y}===>${_0} fetching ${_U}${url##*/}${_0}" fi ( cd -- "${file%/*}" file="${file##*/}" set +e if command -v curl >/dev/null 2>&1; then err="$(command curl -fsSLo "$file" -- "$url" 2>&1)" elif command -v wget >/dev/null 2>&1; then err="$(command wget -O "$file" -- "$url" 2>&1)" else >&2 echo "${_R}error${_0}: please install ${_G}curl${_0} or ${_G}wget${_0} and retry" exit 1 fi if [ $? != 0 ]; then >&2 printf "%s\n" "$err" >&2 echo "${_R}error${_0}: failed to download ${_U}$url${_0}" exit 1 fi ) else cleanup() { true; } fi if [ "$check_sig" = 1 ]; then if [ -z "$quiet" ]; then echo "${_Y}===>${_0} verifying archive integrity" fi for algo in sha256 md5; do hash=none case "$algo" in sha256) { command -v shasum >/dev/null 2>/dev/null && hash="$(shasum -b -a 256 -- "$file" /dev/null)" && hash="${hash%% *}" && [ ${#hash} -eq 64 ] } || { command -v sha256sum >/dev/null 2>/dev/null && hash="$(sha256sum -b -- "$file" /dev/null)" && hash="${hash%% *}" && [ ${#hash} -eq 64 ] } || { # Note: sha256 can be from hashalot. It's incompatible. # Thankfully, it produces shorter output. command -v sha256 >/dev/null 2>/dev/null && hash="$(sha256 -- "$file" /dev/null)" && hash="${hash##* }" && [ ${#hash} -eq 64 ] } || { hash=none } ;; md5) { command -v md5sum >/dev/null 2>/dev/null && hash="$(md5sum -b -- "$file" /dev/null)" && hash="${hash%% *}" && [ ${#hash} -eq 32 ] } || { command -v md5 >/dev/null 2>/dev/null && hash="$(md5 -- "$file" /dev/null)" && hash="${hash##* }" && [ ${#hash} -eq 32 ] } || { hash=none } ;; *) >&2 echo "${_R}internal error${_0}: unhandled algorithm: ${_B}$algo${_0}" exit 1 ;; esac if [ "$hash" != none ]; then if [ -n "${archives##* $algo:$hash;*}" ]; then >&2 echo "${_R}error${_0}: ${_B}$algo${_0} signature mismatch" >&2 echo "" >&2 echo "Expected:" >&2 echo "" >&2 echo " ${_G}$(printf "%s" "$archives" | grep -F -- "${url##*/}" | sed 's/ */ /g')${_0}" >&2 echo "" >&2 echo "Found:" >&2 echo "" >&2 echo " ${_R}$algo:$hash${_0}" exit 1 fi if [ -z "$quiet" ]; then echo "${_Y}===>${_0} ${_B}$algo${_0} signature matches" fi algos="${algos##*<$algo>*}" else if [ -z "$quiet" ]; then echo "${_Y}===>${_0} no tools to verify ${_B}$algo${_0} signature" fi fi done fi if [ -n "$algos" ]; then >&2 echo "${_R}error${_0}: no tools available to verify archive integrity" exit 1 fi if [ -z "$quiet" ]; then echo "${_Y}===>${_0} extracting files" fi $sudo tar -xzf "$file" cleanup if [ -z "$quiet" ]; then echo "" echo "Installed ${_G}tmux${_0} to ${_U}$dir${_0}" echo fi if [ -n "$fd" ]; then printf "%s\n" "$dir" >&"$fd" fi }