3
# Copyright (C) 2012, 2014 Etersoft
4
# Copyright (C) 2012, 2014 Vitaly Lipatov <lav@etersoft.ru>
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU Affero General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU Affero General Public License for more details.
16
# You should have received a copy of the GNU Affero General Public License
17
# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
# copied from /etc/init.d/outformat (ALT Linux)
23
# FIXME on Android: FIX ME! implement ttyname_r() bionic/libc/bionic/stubs.c:366
47
# Set a sane TERM required for tput
48
[ -n "$TERM" ] || TERM=dumb
53
# grep -E from busybox may not --color
54
# grep -E from MacOS print help to stderr
55
if grep -E --help 2>&1 | grep -q -- "--color" ; then
56
export EGREPCOLOR="--color"
59
is_command tput || return
60
# FreeBSD does not support tput -S
61
echo | a= tput -S >/dev/null 2>/dev/null || return
65
: ${BLACK:=0} ${RED:=1} ${GREEN:=2} ${YELLOW:=3} ${BLUE:=4} ${MAGENTA:=5} ${CYAN:=6} ${WHITE:=7}
69
[ -n "$USETTY" ] || return
78
[ -n "$USETTY" ] || return
86
[ -n "$USETTY" ] || return
88
echo op; # set Original color Pair.
89
echo sgr0; # turn off all special graphics mode (bold in our case).
95
[ -z "$verbose" ] && return
99
# echo string without EOL
102
# default /bin/sh on MacOS does not recognize -n
103
echo -n "$*" 2>/dev/null || a= /bin/echo -n "$*"
107
# Print command line and run command line
110
if [ -z "$quiet" ] ; then
113
is_root && PROMTSIG="#"
124
is_root && PROMTSIG="#"
125
echo -n "$PROMTSIG $*"
129
# Print command line and run command line
132
showcmd "$*$EXTRA_SHOWDOCMD"
136
# Run every arg with docmd
148
# run command line with SUDO
152
if [ -z "$SUDO" ] ; then
159
# Print command line and run command line with SUDO
163
[ -n "$SUDO" ] && showcmd "$SUDO $*" || showcmd "$*"
167
# Run every arg with sudocmd
168
# Returns on any error
176
# don't quote $cmd here: it can be a command with an args
177
sudocmd $cmd $pkg || return
181
# print full path to files
186
[ -f "$i" ] || continue
187
echo "$i" | grep -q "/" && echo "$i" && continue
200
eval "lastarg=\${$#}"
204
# TODO: see etersoft-build-utils/tests/test_isnumber.sh
207
echo "$*" | filter_strip_spaces | grep -q "^[0-9]\+$"
211
# CHECKME: the same like estrlist has ?
212
# Note: used grep -E! write '[0-9]+(first|two)', not '[0-9]\+...'
215
echo "$1" | grep -E -q -- "$2"
227
#echo "$1" | grep -q "^/"
234
[ "$1" = "." ] && return $?
244
sed -e "s| \+| |g" | \
245
sed -e "s|^ ||" | sed -e "s| \$||"
250
echo "$*" | filter_strip_spaces
254
# https://superuser.com/questions/422459/substitution-in-text-file-without-regular-expressions
255
# http://stackoverflow.com/a/2705678/120999
256
# use for subst complex string with symbols treating as regexp
259
echo "$*" | sed -e 's/[]()$*.^|[]/\\&/g'
266
eval "[ -n \"\$$1\" ]" && echo "$2" || echo "$3"
271
# use make_temp_file from etersoft-build-utils
272
RC_STDOUT="$(mktemp)" || fatal
273
remove_on_exit $RC_STDOUT
274
local CMDSTATUS=$RC_STDOUT.pipestatus
277
( LC_ALL=C $@ 2>&1 ; echo $? >$CMDSTATUS ) | tee $RC_STDOUT
278
return "$(cat $CMDSTATUS)"
280
# http://tldp.org/LDP/abs/html/bashver3.html#PIPEFAILREF
284
showcmd_store_output()
292
rm -f $RC_STDOUT $RC_STDOUT.pipestatus
295
# run epm, possible from side repo
298
if [ "$EPMMODE" = "pipe" ] ; then
299
epm_main --inscript "$@"
303
# run epm again to full initialization
305
[ -n "$debug" ] && bashopt='-x'
307
$CMDSHELL $bashopt $PROGDIR/$PROGNAME --inscript "$@"
310
# run $SUDO epm, possible from side repo
313
[ "$EPMMODE" = "pipe" ] && fatal "Can't use sudo epm call from the piped script"
316
[ -n "$debug" ] && bashopt='-x'
318
sudorun $CMDSHELL $bashopt $PROGDIR/$PROGNAME --inscript "$@"
321
# Print error message and stop the program
324
local PROMOMESSAGE="$EPMPROMOMESSAGE"
325
[ -n "$PROMOMESSAGE" ] || PROMOMESSAGE=" (you can discuss the epm $EPMVERSION problem in Telegram: https://t.me/useepm)"
326
if [ -z "$TEXTDOMAIN" ] ; then
328
echo -n "ERROR: " >&2
330
echo "$* $PROMOMESSAGE" >&2
332
# echog "Error in $0: $@" >&2
334
# [ "$TERM" = "screen" ] && echo "(screen detected: waiting ten seconds to exit ...)" >&2 && sleep 10
341
[ -n "$debug" ] || return
342
if [ -z "$TEXTDOMAIN" ] ; then
343
set_color $YELLOW >&2
344
echo -n "WARNING: " >&2
348
# echog "Error in $0: $@" >&2
353
# Print warning message
356
if [ -z "$TEXTDOMAIN" ] ; then
357
set_color $YELLOW >&2
358
echo -n "WARNING: " >&2
362
# echog "Error in $0: $@" >&2
368
[ -n "$quiet" ] && return
370
# print message to stderr if stderr forwarded to (a file)
382
[ "$BASEDISTRNAME" = "alt" ] || return 0
386
echo "$PATH" | grep -q "/usr/sbin" && return 0
388
fatal "There is missed /usr/sbin path in PATH. Probably you have used 'su' without '-' to get root access. Use 'esu' or 'su -' command to get root permissions."
392
# if we have not sudo, returns 1 and set SUDO variable to fatal
400
[ -n "$SUDO_TESTED" ] && return "$SUDO_TESTED"
404
# skip SUDO if disabled
405
[ -n "$EPMNOSUDO" ] && return
406
if [ "$DISTRNAME" = "Cygwin" ] || [ "$DISTRNAME" = "Windows" ] ; then
407
# skip sudo using on Windows
413
# if we are root, do not need sudo
416
# start error section
419
if ! is_command $SUDO_CMD ; then
420
[ "$nofail" = "nofail" ] || SUDO="fatal 'For this operation run epm under root, or install and tune sudo (http://altlinux.org/sudo)'"
422
return "$SUDO_TESTED"
425
# if input is a console
426
if inputisatty && isatty && isatty2 ; then
427
if ! $SUDO_CMD -n true ; then
428
info "Please enter sudo user password to use sudo in the current session."
429
if ! $SUDO_CMD -l >/dev/null ; then
430
[ "$nofail" = "nofail" ] || SUDO="fatal 'For this operation run epm under root, or install and tune sudo (http://altlinux.org/sudo)'"
432
return "$SUDO_TESTED"
436
# use sudo if one is tuned and tuned without password
437
if ! $SUDO_CMD -l -n >/dev/null 2>/dev/null ; then
438
[ "$nofail" = "nofail" ] || SUDO="fatal 'Can't use sudo (only passwordless sudo is supported here). Please run epm under root or check http://altlinux.org/sudo '"
440
return "$SUDO_TESTED"
445
# FIXME: does not work: sudo -- VARIABLE=some command
448
# check for < 1.7 version which do not support -- (and --help possible too)
449
#$SUDO_CMD -h 2>/dev/null | grep -q " --" || SUDO="$SUDO_CMD"
453
# return TRUE if we can run privileged command
459
# wait for n seconds (if possible) during executing command
460
# args: seconds command
463
local TO=$(print_command_path timeout || print_command_path gtimeout)
464
if [ -x "$TO" ] ; then
468
fatal "Possible indefinite wait due timeout command is missed"
469
# fallback: drop time arg and run without timeout
476
# don't use eatmydata (useless)
479
[ -n "$EPMNOEATMYDATA" ] && return
481
is_command eatmydata || return
483
# FIXME: check if SUDO already has eatmydata
484
[ -n "$SUDO" ] && SUDO="$SUDO eatmydata" || SUDO="eatmydata"
485
[ -n "$verbose" ] && info "Uwaga! eatmydata is installed, we will use it for disable all sync operations."
490
__get_package_for_command()
493
equery|revdep-rebuild)
496
update-kernel|remove-old-kernels)
505
# call with a prompt string or use a default
506
read -r -p "${1:-Are you sure? [y/N]} " response
521
if [ -z "$non_interactive" ] ; then
522
confirm "Are you sure? [y/N]" || fatal "Exiting"
530
local EFFUID="$(id -u)"
536
is_root || fatal "run me only under root"
541
is_command su && return
542
[ ! -f /bin/su ] && warning "/bin/su is missed. Try install su package (http://altlinux.org/su)." && return 1
543
local group="$(stat -c '%G' /bin/su)" || fatal
544
warning "Check if you are in $group group to have access to su command."
550
is_command sudo && return
553
for i in /bin/sudo /usr/bin/sudo ; do
554
[ -f $i ] && cmd="$i"
556
[ ! -f "$cmd" ] && warning "sudo command is missed. Try install sudo package (http://altlinux.org/sudo)." && return 1
557
local group="$(stat -c '%G' "$cmd")" || fatal
558
warning "Check if you are in $group group to have access to sudo command."
562
check_sudo_access_only()
564
is_command sudo && return
567
for i in /bin/sudo /usr/bin/sudo ; do
568
[ -f $i ] && cmd="$i"
570
[ ! -f "$cmd" ] && return 1
571
local group="$(stat -c '%G' "$cmd")" || fatal
572
warning "sudo command is presence, but is not accessible for you. Check if you are in $group group to have access to sudo command."
579
if [ -n "$*" ] ; then
580
[ -n "$quiet" ] || showcmd "$*"
595
# printf '%s\n' "$arg" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/"
602
while [ -n "$1" ] ; do
603
if has_space "$1" ; then
604
[ -n "$output" ] && output="$output '$1'" || output="'$1'"
606
[ -n "$output" ] && output="$output $1" || output="$1"
613
escaped="$(escape_args "$@")"
615
check_sudo_access_only
616
# sudo is not accessible, will ask root password
619
#info "Enter root password:"
620
if [ -n "$*" ] ; then
621
[ -n "$quiet" ] || showcmd "su - -c $escaped"
622
a= exec su - -c "$escaped"
632
#info "You can be asked about your password:"
633
if [ -n "$*" ] ; then
634
[ -n "$quiet" ] || showcmd "$SUDO su - -c $escaped"
635
$SUDO su - -c "$escaped"
644
local expression="$1"
646
sed -i -r -e "$expression" "$@"
649
# TODO: we we can't use epm directly?
652
load_helper epm-assure
654
[ -n "$package" ] || package="$(__get_package_for_command "$1")"
656
# ask for install: https://bugzilla.altlinux.org/42240
658
[ -n "$non_interactive" ] || ask=1
660
( verbose='' direct='' interactive=$ask epm_assure "$1" $package $3 ) || fatal
665
load_helper epm-assure
667
( direct='' epm_assure "$package" ) || epm ei erc || fatal "erc is not available to install."
670
# will replaced within disabled_eget in packaged version
673
# use internal eget only if exists
674
if [ -s $SHAREDIR/tools_eget ] ; then
675
( EGET_BACKEND=$eget_backend $CMDSHELL $SHAREDIR/tools_eget "$@" )
678
fatal "Internal error: missed tools_eget"
681
# FIXME: we need disable output here, eget can be used for get output
682
assure_exists eget eget 3.3 >/dev/null
683
# run external command, not the function
684
EGET=$(print_command_path eget) || fatal "Missed command eget from installed package eget"
691
# install 7zip in any case (can be used)
692
if is_command 7z || is_command 7za || is_command 7zr || is_command 7zz ; then
695
epm install 7-zip || epm install p7zip
699
# will replaced within disabled_erc in packaged version
705
# use internal eget only if exists
706
if [ -s $SHAREDIR/tools_erc ] ; then
707
$CMDSHELL $SHAREDIR/tools_erc "$@"
710
fatal "Internal error: missed tools_erc"
712
# FIXME: we need disable output here, ercat can be used for get output
713
assure_exists_erc >/dev/null
714
# run external command, not the function
716
ERC=$(print_command_path erc) || fatal "Missed command erc from installed package erc"
720
# will replaced within disabled_ercat in packaged version
724
# use internal eget only if exists
725
if [ -s $SHAREDIR/tools_ercat ] ; then
726
$CMDSHELL $SHAREDIR/tools_ercat "$@"
729
fatal "Internal error: missed tools_ercat"
731
# FIXME: we need disable output here, ercat can be used for get output
732
assure_exists_erc >/dev/null
733
# run external command, not the function
734
ERCAT=$(print_command_path ercat) || fatal "Missed command ercat from installed package erc"
740
if [ -s $SHAREDIR/tools_estrlist ] ; then
741
$CMDSHELL $SHAREDIR/tools_estrlist "$@"
744
fatal "missed tools_estrlist"
749
internal_tools_estrlist "$@"
752
# will replaced within eget() in packed version
756
# we really need that cross here,
757
is_command curl || assure_exists wget
758
is_command wget || assure_exists curl
759
internal_tools_eget "$@"
762
# TODO: improve and drop!
796
if [ -r "$1" ] && file "$1" | grep -q " ELF " ; then
800
# print extension by default
801
echo "$1" | sed -e 's|.*\.||'
808
# print options description from HELPCMD/HELPOPT lines in the code
809
# args: section_name, [file with code]
812
if [ "$0" = "/dev/stdin" ] || [ "$0" = "sh" ] ; then
816
if [ -n "$2" ] ; then
817
is_dirpath "$2" && F="$2" || F="$(dirname $0)/$2"
820
cat "$F" | grep -- "# $1" | while read -r n ; do
821
if echo "$n" | grep -q "# $1: PART: " ; then
823
echo "$n" | sed -e "s|# $1: PART: ||"
826
echo "$n" | grep -q "^ *#" && continue
827
opt=`echo $n | sed -e "s|) # $1:.*||g" -e 's|"||g' -e 's@^|@@'`
828
desc=`echo $n | sed -e "s|.*) # $1:||g"`
829
printf " %-20s %s\n" "$opt" "$desc"
835
# TODO: improve BIGTMPDIR conception
836
# https://bugzilla.mozilla.org/show_bug.cgi?id=69938
837
# https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch05s15.html
838
# https://geekpeach.net/ru/%D0%BA%D0%B0%D0%BA-systemd-tmpfiles-%D0%BE%D1%87%D0%B8%D1%89%D0%B0%D0%B5%D1%82-tmp-%D0%B8%D0%BB%D0%B8-var-tmp-%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D0%B0-tmpwatch-%D0%B2-centos-rhel-7
839
if [ -z "$BIGTMPDIR" ] ; then
841
[ -d "$BIGTMPDIR" ] || BIGTMPDIR="$TMPDIR"
848
if [ -z "$TMPDIR" ] ; then
850
debug "Your have no TMPDIR defined. Using $TMPDIR as fallback."
853
if [ ! -d "$TMPDIR" ] ; then
854
fatal "TMPDIR $TMPDIR does not exist."
857
if [ ! -w "$TMPDIR" ] ; then
858
fatal "TMPDIR $TMPDIR is not writable."
865
R="$($CMDSHELL /dev/null 2>&1)"
866
[ -n "$R" ] && fatal "$CMDSHELL is broken (bash wrongly printing out '$R'). Check ~/.bashrc and /etc/bashrc, run $CMDSHELL manually for test."
879
# don't run again in subprocesses
880
[ -n "$DISTRVENDOR" ] && return 0
882
DISTRVENDOR=$PROGDIR/distr_info
884
# export pack of variables, see epm print info --print-eepm-env
885
[ -n "$verbose" ] && $DISTRVENDOR --print-eepm-env
886
eval $($DISTRVENDOR --print-eepm-env | grep -v '^ *#')
889
# FIXME: detect if not recognized
895
# override package manager detection result
896
if [ -n "$EPM_BACKEND" ] ; then
901
if [ -n "$FORCEPM" ] ; then
910
[ "$DISTRCONTROL" = "systemd" ]
915
local TEXT="this option"
916
[ -n "$2" ] && TEXT="$2"
917
[ "$DISTRNAME" = "$1" ] || fatal "$TEXT supported only for $1 distro"
920
# return delimiter sign in depend of package type
921
get_pkg_name_delimiter()
924
[ -n "$pkgtype" ] || pkgtype="$PKGFORMAT"
926
[ "$pkgtype" = "deb" ] && echo "_" && return
930
# used via remove_on_exit
931
__epm_remove_tmp_files()
934
[ -n "$DEBUG" ] && return 0
936
[ -n "$verbose" ] && info "Removing tmp files on exit ..."
938
if [ -n "$to_clean_tmp_dirs" ] ; then
939
echo "$to_clean_tmp_dirs" | while read p ; do
940
[ -n "$verbose" ] && echo "rm -rf '$p'"
941
rm -rf "$p" 2>/dev/null
945
if [ -n "$to_clean_tmp_files" ] ; then
946
echo "$to_clean_tmp_files" | while read p ; do
947
rm $verbose -f "$p" 2>/dev/null
957
if [ -z "$set_remove_on_exit" ] ; then
958
trap "__epm_remove_tmp_files" EXIT
961
while [ -n "$1" ] ; do
962
if [ -d "$1" ] ; then
963
to_clean_tmp_dirs="$to_clean_tmp_dirs
965
elif [ -f "$1" ] ; then
966
to_clean_tmp_files="$to_clean_tmp_files
975
# estrlist -- has_space "$@"
977
# use internal implementation for speed
981
[ "$1" != "${1/ //}" ]
982
# [ "$(echo "$*" | sed -e "s| ||")" != "$*" ]
988
echo "$1" | grep -q "^[filehtps]*:/"
991
# print a path to the command if exists in $PATH
992
if a= type -a type 2>/dev/null >/dev/null ; then
995
a= type -fpP -- "$1" 2>/dev/null
997
elif a= which which 2>/dev/null >/dev/null ; then
998
# the best case if we have which command (other ways needs checking)
999
# TODO: don't use which at all, it is a binary, not builtin shell command
1002
a= which -- "$1" 2>/dev/null
1007
a= type "$1" 2>/dev/null | sed -e 's|.* /|/|'
1011
# check if <arg> is a real command
1014
print_command_path "$1" >/dev/null
1017
# compatibility layer
1019
# add realpath if missed (with -s support)
1020
if ! is_command realpath ; then
1023
[ -n "$*" ] || return
1024
if [ "$1" = "-s" ] ; then
1026
echo "$(cd "$(dirname "$1")" && pwd -P)/$(basename "$1")" #"
1034
# TODO: use perl if sed -i is not accessible
1035
# sed -i is only supported in GNU sed.
1036
# sed -i "s/$find/$replace/g" "$@"
1037
# perl -p -i -e "s/$find/$replace/g" "$@"
1039
# add subst if missed
1040
if ! is_command subst ; then
1047
check_core_commands()
1049
#which which >/dev/null || fatal "Can't find which command (which or debianutils package is missed?)"
1050
is_command grep || fatal "Can't find grep command (coreutils package is missed?)"
1051
is_command sed || fatal "Can't find sed command (sed package is missed?)"