#!/bin/sh # # Copyright (C) 2012, 2014 Etersoft # Copyright (C) 2012, 2014 Vitaly Lipatov <lav@etersoft.ru> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # copied from /etc/init.d/outformat (ALT Linux) check_core_commands() { #which --help >/dev/null || fatal "Can't find which command (which package is missed?)" # broken which on Debian systems which which >/dev/null || fatal "Can't find which command (which or debianutils package is missed?)" which grep >/dev/null || fatal "Can't find grep command (coreutils package is missed?)" which sed >/dev/null || fatal "Can't find sed command (sed package is missed?)" } # FIXME on Android: FIX ME! implement ttyname_r() bionic/libc/bionic/stubs.c:366 inputisatty() { # check stdin #tty -s 2>/dev/null test -t 0 } isatty() { # check stdout test -t 1 } isatty2() { # check stderr test -t 2 } check_tty() { isatty2 || return # Set a sane TERM required for tput [ -n "$TERM" ] || TERM=dumb export TERM check_core_commands # grep -E from busybox may not --color # grep -E from MacOS print help to stderr if grep -E --help 2>&1 | grep -q -- "--color" ; then export EGREPCOLOR="--color" fi which tput >/dev/null 2>/dev/null || return # FreeBSD does not support tput -S echo | tput -S >/dev/null 2>/dev/null || return [ -z "$USETTY" ] || return export USETTY=1 } : ${BLACK:=0} ${RED:=1} ${GREEN:=2} ${YELLOW:=3} ${BLUE:=4} ${MAGENTA:=5} ${CYAN:=6} ${WHITE:=7} set_boldcolor() { [ "$USETTY" = "1" ] || return { echo bold echo setaf $1 } |tput -S } restore_color() { [ "$USETTY" = "1" ] || return { echo op; # set Original color Pair. echo sgr0; # turn off all special graphics mode (bold in our case). } |tput -S } echover() { [ -z "$verbose" ] && return echo "$*" >&2 } # echo string without EOL echon() { # default /bin/sh on MacOS does not recognize -n /bin/echo -n "$*" } # Used DISTRNAME set_target_pkg_env() { [ -n "$DISTRNAME" ] || fatal "Missing DISTRNAME in set_target_pkg_env." local ver="$DISTRVERSION" [ -n "$ver" ] && ver="/$ver" PKGFORMAT=$($DISTRVENDOR -p "$DISTRNAME$ver") PKGVENDOR=$($DISTRVENDOR -s "$DISTRNAME$ver") RPMVENDOR=$($DISTRVENDOR -n "$DISTRNAME$ver") } # Print command line and run command line showcmd() { if [ -z "$quiet" ] ; then set_boldcolor $GREEN local PROMTSIG="\$" is_root && PROMTSIG="#" echo " $PROMTSIG $*" restore_color fi >&2 } # Print command line and run command line docmd() { showcmd "$*$EXTRA_SHOWDOCMD" #FIXME $@ } # Run every arg with docmd docmd_foreach() { local cmd pkg cmd="$1" #showcmd "$@" shift for pkg in "$@" ; do docmd "$cmd" $pkg done } # run command line with SUDO sudorun() { set_sudo if [ -z "$SUDO" ] ; then "$@" return fi $SUDO "$@" } # Print command line and run command line with SUDO sudocmd() { set_sudo [ -n "$SUDO" ] && showcmd "$SUDO $*" || showcmd "$*" sudorun "$@" } # Run every arg with sudocmd # Returns on any error sudocmd_foreach() { local cmd pkg cmd="$1" #showcmd "$@" shift for pkg in "$@" ; do # don't quote $cmd here: it can be a command with an args sudocmd $cmd $pkg || return done } # add realpath if missed if ! which realpath 2>/dev/null >/dev/null ; then realpath() { readlink -f "$@" } fi # print full path to files make_filepath() { local i for i in "$@" ; do [ -f "$i" ] || continue echo "$i" | grep -q "/" && echo "$i" && continue echo "./$i" done } get_firstarg() { echon "$1" } get_lastarg() { local lastarg eval "lastarg=\${$#}" echon "$lastarg" } # TODO: see etersoft-build-utils/tests/test_isnumber.sh isnumber() { echo "$*" | filter_strip_spaces | grep -q "^[0-9]\+$" } # copied from strings # CHECKME: the same like estrlist has ? # Note: used grep -E! write '[0-9]+(first|two)', not '[0-9]\+...' rhas() { echo "$1" | grep -E -q -- "$2" } # copied from strings is_dirpath() { [ "$1" = "." ] && return $? rhas "$1" "/" } filter_strip_spaces() { # possible use just #xargs echo sed -e "s| \+| |g" | \ sed -e "s|^ ||" | sed -e "s| \$||" } strip_spaces() { echo "$*" | filter_strip_spaces } # param true false subst_option() { eval "[ -n \"\$$1\" ]" && echo "$2" || echo "$3" } store_output() { # use make_temp_file from etersoft-build-utils RC_STDOUT=$(mktemp) local CMDSTATUS=$RC_STDOUT.pipestatus echo 1 >$CMDSTATUS #RC_STDERR=$(mktemp) ( LANG=C $@ 2>&1 ; echo $? >$CMDSTATUS ) | tee $RC_STDOUT return "$(cat $CMDSTATUS)" # bashism # http://tldp.org/LDP/abs/html/bashver3.html#PIPEFAILREF #return $PIPESTATUS } showcmd_store_output() { showcmd "$@" store_output "$@" } clean_store_output() { rm -f $RC_STDOUT $RC_STDOUT.pipestatus } # run epm, possible from side repo epm() { [ -n "$PROGNAME" ] || fatal "Can't use epm call from the piped script" $PROGDIR/$PROGNAME --inscript "$@" } # run $SUDO epm, possible from side repo sudoepm() { [ -n "$PROGNAME" ] || fatal "Can't use epm call from the piped script" sudorun $PROGDIR/$PROGNAME --inscript "$@" } # Print error message and stop the program fatal() { if [ -z "$TEXTDOMAIN" ] ; then echo "Error: $*" >&2 # else # echog "Error in $0: $@" >&2 fi # [ "$TERM" = "screen" ] && echo "(screen detected: waiting ten seconds to exit ...)" >&2 && sleep 10 exit 1 } # Print warning message warning() { if [ -z "$TEXTDOMAIN" ] ; then echo "Warning: $*" >&2 # else # echog "Error in $0: $@" >&2 fi } info() { [ -n "$quiet" ] && return # print message to stderr if stderr forwarded to (a file) if isatty2 ; then isatty || return 0 echo "$*" else echo "$*" >&2 fi } # if we have not sudo, returns 1 and set SUDO variable to fatal SUDO_TESTED='' SUDO_CMD='sudo' set_sudo() { local nofail="$1" # cache the result [ -n "$SUDO_TESTED" ] && return "$SUDO_TESTED" SUDO_TESTED="0" SUDO="" # skip SUDO if disabled [ -n "$EPMNOSUDO" ] && return if [ "$DISTRNAME" = "Cygwin" ] || [ "$DISTRNAME" = "Windows" ] ; then # skip sudo using on Windows return fi # if we are root, do not need sudo is_root && return # start error section SUDO_TESTED="1" if ! which $SUDO_CMD >/dev/null 2>/dev/null ; then [ "$nofail" = "nofail" ] || SUDO="fatal 'Can't find sudo. Please install and tune sudo ('# epm install sudo') or run epm under root.'" return "$SUDO_TESTED" fi # if input is a console if inputisatty && isatty && isatty2 ; then if ! $SUDO_CMD -l >/dev/null ; then [ "$nofail" = "nofail" ] || SUDO="fatal 'Can't use sudo (only passwordless sudo is supported in non interactive using). Please run epm under root.'" return "$SUDO_TESTED" fi else # use sudo if one is tuned and tuned without password if ! $SUDO_CMD -l -n >/dev/null 2>/dev/null ; then [ "$nofail" = "nofail" ] || SUDO="fatal 'Can't use sudo (only passwordless sudo is supported). Please run epm under root or check http://altlinux.org/sudo.'" return "$SUDO_TESTED" fi fi SUDO_TESTED="0" SUDO="$SUDO_CMD --" # check for < 1.7 version which do not support -- (and --help possible too) $SUDO_CMD -h 2>/dev/null | grep -q " --" || SUDO="$SUDO_CMD" } # return TRUE if we can run privileged command sudo_allowed() { set_sudo nofail } # wait for n seconds (if possible) during executing command # args: seconds command withtimeout() { local TO=$(which timeout 2>/dev/null || which gtimeout 2>/dev/null) if [ -x "$TO" ] ; then $TO "$@" return fi fatal "Possible indefinite wait due timeout command is missed" # fallback: drop time arg and run without timeout #shift #"$@" } set_eatmydata() { # don't use eatmydata (useless) return 0 # skip if disabled [ -n "$EPMNOEATMYDATA" ] && return # use if possible which eatmydata >/dev/null 2>/dev/null || return set_sudo # FIXME: check if SUDO already has eatmydata [ -n "$SUDO" ] && SUDO="$SUDO eatmydata" || SUDO="eatmydata" [ -n "$verbose" ] && info "Uwaga! eatmydata is installed, we will use it for disable all sync operations." return 0 } # __get_package_for_command() { case "$1" in equery|revdep-rebuild) echo 'gentoolkit' ;; update-kernel|remove-old-kernels) echo 'update-kernel' ;; esac } # TODO: confirm() { local response # call with a prompt string or use a default read -r -p "${1:-Are you sure? [y/N]} " response case $response in [yY][eE][sS]|[yY]) true ;; *) false ;; esac } confirm_info() { info "$*" if [ -z "$non_interactive" ] ; then confirm "Are you sure? [y/N]" || fatal "Exiting" fi } is_root() { local EFFUID="$(id -u)" [ "$EFFUID" = "0" ] } assure_root() { is_root || fatal "run me only under root" } regexp_subst() { local expression="$1" shift sed -i -r -e "$expression" "$@" } # TODO: we we can't use epm directly? assure_exists() { load_helper epm-assure local package="$2" local textpackage= [ -n "$package" ] || package="$(__get_package_for_command "$1")" [ -n "$3" ] && textpackage=" >= $3" ( direct='' epm_assure "$1" $package $3 ) || fatal "Can't assure in '$1' command from $package$textpackage package" } # will replaced within disabled_eget in packaged version eget() { local EGET # use internal eget only if exists if [ -s $SHAREDIR/tools_eget ] ; then $SHAREDIR/tools_eget "$@" return fi fatal "Internal error: missed tools_eget" # FIXME: we need disable output here, eget can be used for get output assure_exists eget eget 3.3 >/dev/null # run external command, not the function EGET=$(which eget) || fatal "Missed command eget from installed package eget" $EGET "$@" } estrlist() { if [ -s $SHAREDIR/tools_estrlist ] ; then $SHAREDIR/tools_estrlist "$@" return fi fatal "missed tools_estrlist" } onefile_estrlist() { internal_tools_estrlist "$@" } # will replaced within eget() in packed version onefile_eget() { assure_exists wget internal_tools_eget "$@" } # TODO: improve and drop! get_package_type() { local i case $1 in *.deb) echo "deb" return ;; *.rpm) echo "rpm" return ;; *.txz) echo "txz" return ;; *.tbz) echo "tbz" return ;; *.exe) echo "exe" return ;; *.msi) echo "msi" return ;; *.AppImage) echo "AppImage" return ;; *) #fatal "Don't know type of $1" # return package name for info echo "$1" return 1 ;; esac } # print options description from HELPCMD/HELPOPT lines in the code # args: section_name, [file with code] get_help() { if [ "$0" = "/dev/stdin" ] || [ "$0" = "sh" ] ; then return fi local F="$0" if [ -n "$2" ] ; then is_dirpath "$2" && F="$2" || F="$(dirname $0)/$2" fi cat "$F" | grep -- "# $1" | while read -r n ; do if echo "$n" | grep -q "# $1: PART: " ; then echo echo "$n" | sed -e "s|# $1: PART: ||" continue fi echo "$n" | grep -q "^ *#" && continue opt=`echo $n | sed -e "s|) # $1:.*||g" -e 's|"||g' -e 's@^|@@'` desc=`echo $n | sed -e "s|.*) # $1:||g"` printf " %-20s %s\n" "$opt" "$desc" done } # TODO: get all info by one request (too slow) set_distro_info() { # use external distro_info if internal one is missed DISTRVENDOR=$PROGDIR/distr_info [ -x $DISTRVENDOR ] || DISTRVENDOR=distro_info export DISTRVENDOR [ -n "$DISTRNAME" ] || DISTRNAME=$($DISTRVENDOR -d) || fatal "Can't get distro name." [ -n "$DISTRVERSION" ] || DISTRVERSION=$($DISTRVENDOR -v) if [ -z "$DISTRARCH" ] ; then DISTRARCH=$($DISTRVENDOR --distro-arch) fi DISTRCONTROL="$($DISTRVENDOR -y)" } # FIXME: detect if not recognized set_pm_type() { local CMD set_distro_info set_target_pkg_env # override package manager detection result if [ -n "$FORCEPM" ] ; then PMTYPE=$FORCEPM return fi PMTYPE="$($DISTRVENDOR -g $DISTRNAME/$DISTRVERSION)" } is_active_systemd() { [ "$DISTRCONTROL" = "systemd" ] } assure_distr() { local TEXT="this option" [ -n "$2" ] && TEXT="$2" [ "$DISTRNAME" = "$1" ] || fatal "$TEXT supported only for $1 distro" } # return delimiter sign in depend of package type get_pkg_name_delimiter() { local pkgtype="$1" [ -n "$pkgtype" ] || pkgtype="$($DISTRVENDOR -p)" [ "$pkgtype" = "deb" ] && echo "_" && return echo "-" } has_space() { estrlist -- has_space "$@" }