Compare commits
10 Commits
6b85556a53
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84e6fdd429 | ||
|
|
8fe11776cb | ||
|
|
0737d0c647 | ||
|
|
d72fa1a712 | ||
|
|
08e9e6c799 | ||
|
|
ac66e896dd | ||
|
|
0712be626b | ||
|
|
3f8b81562b | ||
|
|
96d1dc695d | ||
|
|
c039ab6ea0 |
17
profile.conf
17
profile.conf
@@ -70,26 +70,41 @@ MAKEFLAGS='-j12'
|
||||
PKGSOURCES='/share/src/archives'
|
||||
|
||||
[aliases]
|
||||
# Aliases section is used to set user aliases, it is loaded only for
|
||||
# interactive shells.
|
||||
# Various ls aliases
|
||||
ll='ls -laFh --color=auto'
|
||||
la='ls -Ah --color=auto'
|
||||
l='ls -CF --color=auto'
|
||||
ls='ls --color=auto'
|
||||
|
||||
# Add color to grep output
|
||||
grep='grep --color=auto'
|
||||
egrep='egrep --color=auto'
|
||||
fgrep='fgrep --color=auto'
|
||||
|
||||
# Quick find alias
|
||||
qfind="find . -name "
|
||||
|
||||
# Some alias for compiling
|
||||
mk='make'
|
||||
mkck='make check'
|
||||
mkin='make install'
|
||||
mkdin='make DESTDIR=$PWD/dest-install install'
|
||||
|
||||
# ssh alias with X11 forwarding, without right restriction
|
||||
ssh='ssh -Y'
|
||||
|
||||
# Resume mode for wget
|
||||
wget='wget -c' # resume mode by default
|
||||
myip='curl ip.appspot.com'
|
||||
|
||||
# Human readable by default
|
||||
df='df -H'
|
||||
du='du -ch'
|
||||
sdu='du -sk ./* | sort -n'
|
||||
hdu='du -hs ./* | sort -H'
|
||||
|
||||
# Readable dmesg timestamps
|
||||
dmesg='dmesg -T'
|
||||
|
||||
# End of profile.conf
|
||||
|
||||
@@ -35,32 +35,85 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# expandlist : treat wildcards in a file/directory list
|
||||
# Usage: expandlist <item1 [item2 ... itemN]>
|
||||
# Expand wildcards in a file/directory list and quote the results
|
||||
# Usage: expandlist [options] <item1 [item2 ... itemN]>
|
||||
expandlist()
|
||||
{
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "expandlist: Wraps a list of items in double quotes.\n\n"
|
||||
printf "Usage: expandlist <item1 [item2 ... itemN]>\n\n"
|
||||
local separator=" "
|
||||
local PARSED
|
||||
|
||||
PARSED=$(getopt -o hs:n --long help,separator:,newline -n 'expandlist' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"expandlist --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "expandlist: expand globs and wrap matched items in double quotes.\n\n"
|
||||
printf "Usage: expandlist [options] <item1 [item2 ... itemN]>\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "\t-s, --separator SEP\tSet output separator (default: space)\n"
|
||||
printf "\t-n, --newline\t\tUse a newline as separator\n"
|
||||
return 0
|
||||
;;
|
||||
-s|--separator)
|
||||
separator="$2"
|
||||
shift 2
|
||||
;;
|
||||
-n|--newline)
|
||||
separator=$'\n'
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"expandlist --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local item="" result="" matched=0
|
||||
shopt -s nullglob
|
||||
|
||||
for item in "$@"; do
|
||||
local expanded=()
|
||||
|
||||
# True glob expansion when wildcards are present.
|
||||
if [[ "$item" == *'*'* || "$item" == *'?'* || "$item" == *'['* ]]; then
|
||||
expanded=( $item )
|
||||
else
|
||||
expanded=( "$item" )
|
||||
fi
|
||||
|
||||
local result=""
|
||||
for item in "$@"; do
|
||||
for content in "$item"; do
|
||||
result+="\"$content\" "
|
||||
if [[ ${#expanded[@]} -eq 0 ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
for content in "${expanded[@]}"; do
|
||||
if (( matched )); then
|
||||
result+="$separator"
|
||||
fi
|
||||
result+="\"$content\""
|
||||
matched=1
|
||||
done
|
||||
done
|
||||
echo $result
|
||||
|
||||
shopt -u nullglob
|
||||
printf '%s\n' "$result"
|
||||
}
|
||||
export -f expandlist
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Clean a directory or a tree from temporary or backup files
|
||||
# Clean a directory tree from temporary or backup files
|
||||
# Usage: clean [options] [directory1] [...[directoryX]]
|
||||
# Options:
|
||||
# -h, --help: display help screen
|
||||
@@ -85,7 +138,7 @@ clean()
|
||||
while true; do
|
||||
case "$1" in
|
||||
-r|--recurs)
|
||||
local recursive=1
|
||||
recursive=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
@@ -100,11 +153,11 @@ clean()
|
||||
return 0
|
||||
;;
|
||||
-s|--shell)
|
||||
local outshell=1
|
||||
outshell=1
|
||||
shift
|
||||
;;
|
||||
-f|--force)
|
||||
local force=1
|
||||
force=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
@@ -114,6 +167,7 @@ clean()
|
||||
*)
|
||||
disp E "Invalid parameter, use \"clean --help\" to display options list"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -121,21 +175,24 @@ clean()
|
||||
local dirlist=("$@")
|
||||
[[ ${#dirlist[@]} -eq 0 ]] && dirlist=(".")
|
||||
|
||||
local findopt=() rmopt
|
||||
[[ ! $recursive ]] && findopt=(-maxdepth 1)
|
||||
[[ ! $force ]] && rmopt="-i"
|
||||
unset recursive force
|
||||
local findopt=() rmopt=()
|
||||
(( ! recursive )) && findopt=(-maxdepth 1)
|
||||
(( ! force )) && rmopt=(-i)
|
||||
|
||||
for dir in $dirlist; do
|
||||
find "$dir" "${findopt[@]}" -type f \( -name "*~" -o -name "#*#" -o -name "*.bak" -o -name ".~*#" \) -print0 | while IFS= read -r -d '' f; do
|
||||
if [[ ! $outshell ]]; then
|
||||
rm $rmopt $f
|
||||
for dir in "${dirlist[@]}"; do
|
||||
find "$dir" "${findopt[@]}" -type f \( -name "*~" -o -name "#*#" -o -name "*.bak" -o -name ".~*#" \) -print0 |
|
||||
while IFS= read -r -d '' f; do
|
||||
if (( outshell )); then
|
||||
if (( ${#rmopt[@]} )); then
|
||||
printf 'rm %s -- "%s"\n' "${rmopt[*]}" "$f"
|
||||
else
|
||||
echo "rm $rmopt $f"
|
||||
printf 'rm -- "%s"\n' "$f"
|
||||
fi
|
||||
else
|
||||
rm "${rmopt[@]}" -- "$f"
|
||||
fi
|
||||
done
|
||||
done
|
||||
unset outshell dirlist dellist findopt rmopt
|
||||
}
|
||||
export -f clean
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -168,7 +225,7 @@ export -f mcd
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Rename all files in current directory to replace spaces with _
|
||||
# Rename files and directories to replace spaces with another character
|
||||
# Usage: rmspc [options]
|
||||
# Options:
|
||||
# -h, --help: display help screen
|
||||
@@ -178,8 +235,11 @@ export -f mcd
|
||||
# -s, --shell: do nothing and display commands that would be executed
|
||||
rmspc()
|
||||
{
|
||||
local lst=""
|
||||
local recurs=0 verb=0 shell=0
|
||||
local substchar="_" substchar_set=0
|
||||
local mvopt=()
|
||||
local PARSED
|
||||
|
||||
PARSED=$(getopt -o hr:c::vs --long help,recursive,subst-char::,verbose,shell -n 'rmspc' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"rmspc --help\" to display usage."
|
||||
@@ -203,27 +263,20 @@ rmspc()
|
||||
return 0
|
||||
;;
|
||||
-r|--recursive)
|
||||
local recurs=1
|
||||
recurs=1
|
||||
shift
|
||||
;;
|
||||
-c|--subst-char)
|
||||
# Handle optional argument for short/long options
|
||||
case "$2" in
|
||||
"")
|
||||
substchar=""
|
||||
;;
|
||||
*)
|
||||
substchar_set=1
|
||||
substchar="$2"
|
||||
;;
|
||||
esac
|
||||
shift 2
|
||||
;;
|
||||
-v|--verbose)
|
||||
local verb=1
|
||||
verb=1
|
||||
shift
|
||||
;;
|
||||
-s|--shell)
|
||||
local shell=1
|
||||
shell=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
@@ -232,49 +285,58 @@ rmspc()
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid parameter, use \"rmspc --help\" to display options list"
|
||||
echo
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ ! $substchar ]] && substchar="_"
|
||||
[[ $substchar == "none" ]] && local substchar=""
|
||||
[[ $verb ]] && local mvopt="-v"
|
||||
[[ "$substchar" == "none" ]] && substchar=""
|
||||
(( verb )) && mvopt=(-v)
|
||||
|
||||
shopt -s nullglob
|
||||
for f in *; do
|
||||
[[ $recurs ]] && [[ -d "$f" ]] && (
|
||||
[[ $verb ]] && disp I "Entering directory $(pwd)/$f ..."
|
||||
if (( recurs )) && [[ -d "$f" ]]; then
|
||||
(
|
||||
local lastdir=$f
|
||||
pushd "$f" >/dev/null
|
||||
rmspc ${recurs:+-r} ${substchar:+-c "$substchar"} ${verb:+-v} ${shell:+-s}
|
||||
popd >/dev/null
|
||||
[[ $verb ]] && disp I "Leaving directory $(pwd)/$lastdir"
|
||||
unset lastdir
|
||||
(( verb )) && disp I "Entering directory $(pwd)/$f ..."
|
||||
pushd "$f" >/dev/null || return 1
|
||||
|
||||
if (( substchar_set )); then
|
||||
rmspc ${recurs:+-r} -c "$substchar" ${verb:+-v} ${shell:+-s}
|
||||
else
|
||||
rmspc ${recurs:+-r} ${verb:+-v} ${shell:+-s}
|
||||
fi
|
||||
|
||||
popd >/dev/null || return 1
|
||||
(( verb )) && disp I "Leaving directory $(pwd)/$lastdir"
|
||||
)
|
||||
fi
|
||||
|
||||
if [[ "$f" == *" "* ]]; then
|
||||
local newf="${f// /${substchar}}"
|
||||
[[ "$f" == "$newf" ]] && continue # protection but should never happen
|
||||
if [[ -n $shell ]]; then
|
||||
echo "mv ${mvopt:+$mvopt }\"$f\" \"$newf\""
|
||||
[[ "$f" == "$newf" ]] && continue
|
||||
if (( shell )); then
|
||||
if (( ${#mvopt[@]} )); then
|
||||
printf 'mv %s -- "%s" "%s"\n' "${mvopt[*]}" "$f" "$newf"
|
||||
else
|
||||
mv ${mvopt:+$mvopt} "$f" "$newf" || {
|
||||
printf 'mv -- "%s" "%s"\n' "$f" "$newf"
|
||||
fi
|
||||
else
|
||||
mv "${mvopt[@]}" -- "$f" "$newf" || {
|
||||
disp E "Failed renaming \"$f\" to \"$newf\"."
|
||||
continue
|
||||
}
|
||||
fi
|
||||
fi
|
||||
done
|
||||
unset lst substchar verb shell newf command mvopt
|
||||
shopt -u nullglob
|
||||
}
|
||||
export -f rmspc
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# display stats about a file structure
|
||||
# Display statistics about a file tree
|
||||
# Usage: file_stats [options] [path]
|
||||
# Options:
|
||||
# -H, --human Human readable sizes\n"
|
||||
@@ -290,7 +352,7 @@ export -f rmspc
|
||||
# --max [size] Maximum size (e.g., 100M)
|
||||
file_stats()
|
||||
{
|
||||
local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0
|
||||
local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0
|
||||
local path="." show_all=1 ext_filter="" ext_list="" min_size="" max_size=""
|
||||
|
||||
local PARSED
|
||||
@@ -387,12 +449,12 @@ local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0
|
||||
# Prepare find filters
|
||||
local find_cmd=(find "$path" -type f)
|
||||
|
||||
# Extension simple
|
||||
# Single extension filter
|
||||
if [[ -n "$ext_filter" ]]; then
|
||||
find_cmd+=(-iname "*.$ext_filter")
|
||||
fi
|
||||
|
||||
# Extension liste
|
||||
# Extension list filter
|
||||
if [[ -n "$ext_list" ]]; then
|
||||
IFS=',' read -ra exts <<< "$ext_list"
|
||||
find_cmd+=('(')
|
||||
@@ -403,7 +465,7 @@ local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0
|
||||
find_cmd+=(')')
|
||||
fi
|
||||
|
||||
# Taille min/max (à évaluer en octets)
|
||||
# Minimum/maximum size filters (evaluated in bytes)
|
||||
if [[ -n "$min_size" ]]; then
|
||||
find_cmd+=(-size +"$(numfmt --from=iec "$min_size")"c)
|
||||
fi
|
||||
@@ -411,7 +473,7 @@ local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0
|
||||
find_cmd+=(-size -"$(( $(numfmt --from=iec "$max_size") + 1 ))"c)
|
||||
fi
|
||||
|
||||
# Exécution
|
||||
# Execution
|
||||
"${find_cmd[@]}" -printf "%s\n" 2>/dev/null | sort -n | \
|
||||
awk -v human="$human" -v details="$details" -v only_avg="$only_avg" \
|
||||
-v only_med="$only_med" -v only_count="$only_count" \
|
||||
@@ -512,10 +574,10 @@ export -f file_stats
|
||||
# -l : limit : number of files to return (default is 10)
|
||||
findbig()
|
||||
{
|
||||
local details=0 limit=10 no_change=0 one_fs=0
|
||||
local details=0 limit=10 one_fs=0
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hd:l:x --long help,details,one-fs,limit: -n 'findbig' -- "$@")
|
||||
PARSED=$(getopt -o hdl:x --long help,details,limit:,one-fs -n 'findbig' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"findbig --help\" to display usage."
|
||||
return 1
|
||||
@@ -538,14 +600,18 @@ findbig()
|
||||
details=1
|
||||
shift
|
||||
;;
|
||||
-n|--no-change)
|
||||
no_change=1
|
||||
shift
|
||||
;;
|
||||
-l|--limit)
|
||||
limit="$2"
|
||||
[[ "$limit" =~ ^[0-9]+$ ]] || {
|
||||
disp E "Invalid limit: must be a positive integer."
|
||||
return 1
|
||||
}
|
||||
shift 2
|
||||
;;
|
||||
-x|--one-fs)
|
||||
one_fs=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
@@ -560,13 +626,16 @@ findbig()
|
||||
local dir="${1:-.}"
|
||||
|
||||
# Prepare find arguments in an array for cleaner handling
|
||||
local find_args=("-L" "$dir" "-type" "f")
|
||||
(( one_fs )) && find_args+=("-xdev")
|
||||
local find_args=(-L "$dir")
|
||||
(( one_fs )) && find_args+=(-xdev)
|
||||
find_args+=(-type f)
|
||||
|
||||
# Logic: find files, print size and path, sort numeric reverse, take N
|
||||
if (( details )); then
|
||||
find "${find_args[@]}" -printf "%s %p\n" 2>/dev/null | sort -rn | head -n "$limit" | while read -r size path; do
|
||||
ls -ld "$path"
|
||||
find "${find_args[@]}" -printf "%s %p\n" 2>/dev/null | sort -rn | head -n "$limit" |
|
||||
while IFS= read -r line; do
|
||||
local path="${line#* }"
|
||||
ls -ld -- "$path"
|
||||
done
|
||||
else
|
||||
find "${find_args[@]}" -printf "%s %p\n" 2>/dev/null | sort -rn | head -n "$limit"
|
||||
@@ -586,7 +655,7 @@ export -f findbig
|
||||
# --delete : delete empty files and display their paths
|
||||
findzero()
|
||||
{
|
||||
local delete=0 details=0 one_fs=0 no_change=0
|
||||
local delete=0 details=0 one_fs=0
|
||||
|
||||
local PARSED
|
||||
# o: options, long: long equivalents
|
||||
@@ -660,7 +729,7 @@ export -f findzero
|
||||
# --delete : delete dead links and display their paths
|
||||
finddead()
|
||||
{
|
||||
local delete=0 details=0 one_fs=0 no_change=0
|
||||
local delete=0 details=0 one_fs=0
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hdx --long help,details,one-fs,delete -n 'finddead' -- "$@")
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
# Usage: help
|
||||
help()
|
||||
{
|
||||
printf "${BIWhite}Welcome to your profile! Here is a list of available commands:${DEFAULTCOL}\n\n"
|
||||
printf "check_updates\tCheck for new versions of profile\n"
|
||||
printf "clean\t\tErase backup files\n"
|
||||
printf "disp\t\tDisplay formatted info/warning/error/debug messages\n"
|
||||
printf "dwl\t\tDownload a URL to a local file\n"
|
||||
@@ -60,6 +62,8 @@ help()
|
||||
printf "ppg\t\tDisplay process matching the given parameter\n"
|
||||
printf "ppn\t\tDisplay process matching the exact process name given in parameter\n"
|
||||
printf "ppu\t\tDisplay processes owned by the given user\n"
|
||||
printf "profile_upgrade\tUpgrade profile to the latest version\n"
|
||||
printf "pwdscore\tCalculate password strength score\n"
|
||||
printf "rain\t\tLet the rain fall\n"
|
||||
printf "rmhost\t\tRemove host (IP and/or DNS name) from current known_hosts\n"
|
||||
printf "rmspc\t\tRemove spaces from file and directory names\n"
|
||||
|
||||
@@ -39,11 +39,14 @@
|
||||
# Usage: ver
|
||||
ver()
|
||||
{
|
||||
local PARSED=$(getopt -o h --long help -n 'ver' -- "$@")
|
||||
local PARSED
|
||||
|
||||
PARSED=$(getopt -o h --long help -n 'ver' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"ver --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
|
||||
eval set -- "$PARSED"
|
||||
while true; do
|
||||
case "$1" in
|
||||
@@ -72,11 +75,13 @@ export -f ver
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Display weather of the given city (or default one)
|
||||
# Display weather for the given city (or the default one)
|
||||
# Usage: meteo [city1 city2 ...]
|
||||
meteo()
|
||||
{
|
||||
local PARSED=$(getopt -o h --long help -n 'meteo' -- "$@")
|
||||
local PARSED
|
||||
|
||||
PARSED=$(getopt -o h --long help -n 'meteo' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"meteo --help\" to display usage."
|
||||
return 1
|
||||
@@ -85,7 +90,9 @@ meteo()
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "meteo: Fetch weather data.\nUsage: meteo [city1 city2 ...]\n"
|
||||
printf "meteo: Fetch weather data.\n"
|
||||
printf "Usage: meteo [city1 city2 ...]\n"
|
||||
printf "If no city is provided, the default city from configuration will be used.\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
@@ -100,12 +107,13 @@ meteo()
|
||||
done
|
||||
|
||||
local cities=("$@")
|
||||
local city="" encoded=""
|
||||
[[ $# -eq 0 ]] && cities=("$DEFAULT_CITY")
|
||||
|
||||
for city in "${cities[@]}"; do
|
||||
encoded=$(urlencode "$city")
|
||||
dwl "https://wttr.in/$encoded" || \
|
||||
disp E "Failed fetching datas for $city."
|
||||
disp E "Failed to fetch weather data for $city."
|
||||
done
|
||||
}
|
||||
export -f meteo
|
||||
@@ -117,16 +125,20 @@ export -f meteo
|
||||
# Usage: showinfo
|
||||
showinfo()
|
||||
{
|
||||
local PARSED=$(getopt -o h --long help -n 'showinfo' -- "$@")
|
||||
local PARSED
|
||||
|
||||
PARSED=$(getopt -o h --long help -n 'showinfo' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"showinfo --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "showinfo: Display system information (hostname, kernel, uptime).\nUsage: showinfo\n"
|
||||
printf "showinfo: Display system information (hostname, kernel, uptime and fetch output when available).\n"
|
||||
printf "Usage: showinfo\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
@@ -140,20 +152,20 @@ showinfo()
|
||||
esac
|
||||
done
|
||||
|
||||
local hostname_str
|
||||
local figopt=()
|
||||
hostname_str="$(hostname)"
|
||||
|
||||
printf "\n"
|
||||
if command -v figlet >/dev/null 2>&1; then
|
||||
if [[ -s /usr/share/figlet/ansi_shadow.flf ]]; then
|
||||
local figopt="-f ansi_shadow"
|
||||
fi
|
||||
if [[ -n $figopt ]]; then
|
||||
figlet -k $figopt $(hostname)
|
||||
[[ -s /usr/share/figlet/ansi_shadow.flf ]] && \
|
||||
figopt=(-f ansi_shadow)
|
||||
figlet -k "${figopt[@]}" "$hostname_str"
|
||||
else
|
||||
figlet $(hostname)
|
||||
printf "%s\n" "$hostname_str"
|
||||
fi
|
||||
else
|
||||
hostname -f
|
||||
fi
|
||||
echo ""
|
||||
|
||||
printf "\n"
|
||||
if command -v neofetch >/dev/null 2>&1; then
|
||||
neofetch
|
||||
elif command -v fastfetch >/dev/null 2>&1; then
|
||||
@@ -163,11 +175,11 @@ showinfo()
|
||||
if [[ -s /etc/os-release ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
. /etc/os-release
|
||||
printf "$NAME $VERSION\n"
|
||||
printf "%s %s\n" "$NAME" "$VERSION"
|
||||
else
|
||||
cat /proc/version
|
||||
fi
|
||||
printf "Uptime: $(uptime -p)\n"
|
||||
printf "Uptime: %s\n" "$(uptime -p)"
|
||||
)
|
||||
fi
|
||||
}
|
||||
|
||||
428
profile.d/pwd.sh
428
profile.d/pwd.sh
@@ -53,21 +53,22 @@
|
||||
genpwd()
|
||||
{
|
||||
local length=16
|
||||
local occurs=2 # Bug, if set to 1, seems to be ignored
|
||||
local occurs=2
|
||||
local symb=1 maj=1 min=1 numb=1
|
||||
local nbpwd=1
|
||||
local extcar
|
||||
local extcar=""
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hsnu l e:L:o: --long \
|
||||
help,nosymbols,nonumbers,noup,nolow,extracars:,length:,occurences: -n 'genpwd' -- "$@")
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hsnule:L:o: --long \
|
||||
help,nosymbols,nonumbers,noup,nolow,extracars:,length:,occurences:,occurrences: \
|
||||
-n 'genpwd' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then return 1; fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "genpwd: Generate secure random password(s).\n\n"
|
||||
printf "genpwd: Generate random password(s).\n\n"
|
||||
printf "Usage: genpwd [options] [nb_passwd]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
@@ -75,9 +76,9 @@ local PARSED
|
||||
printf "\t-n, --nonumbers\t\tExclude numbers\n"
|
||||
printf "\t-u, --noup\t\tExclude uppercase letters\n"
|
||||
printf "\t-l, --nolow\t\tExclude lowercase letters\n"
|
||||
printf "\t-e, --extracars <c>\tAdd characters to list\n"
|
||||
printf "\t-e, --extracars <c>\tAdd characters to the pool\n"
|
||||
printf "\t-L, --length <n>\tSet password length (default: 16)\n"
|
||||
printf "\t-o, --occurences <n>\tMax occurences per character (default: 2)\n"
|
||||
printf "\t-o, --occurences <n>\tMax occurrences per character (default: 2)\n"
|
||||
return 0
|
||||
;;
|
||||
-s|--nosymbols)
|
||||
@@ -102,22 +103,209 @@ local PARSED
|
||||
;;
|
||||
-L|--length)
|
||||
length="$2"
|
||||
if ! [[ $length =~ ^[0-9]+$ ]]; then
|
||||
disp E "The --length parameter requires a number."
|
||||
if ! [[ $length =~ ^[1-9][0-9]*$ ]]; then
|
||||
disp E "The --length parameter requires a positive integer."
|
||||
return 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
-o|--occurences)
|
||||
-o|--occurences|--occurrences)
|
||||
occurs="$2"
|
||||
if ! [[ $occurs =~ ^[1-9]+$ ]]; then
|
||||
disp E "The --occurs parameter requires a number from 1 to 9."
|
||||
if ! [[ $occurs =~ ^[1-9][0-9]*$ ]]; then
|
||||
disp E "The --occurences parameter requires a positive integer."
|
||||
return 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift; break
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"genpwd --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ $# -gt 1 ]]; then
|
||||
disp E "Too many positional arguments. Use only [nb_passwd]."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ $# -eq 1 ]]; then
|
||||
nbpwd="$1"
|
||||
if ! [[ $nbpwd =~ ^[1-9][0-9]*$ ]]; then
|
||||
disp E "The number of passwords to generate must be a positive integer."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local carset=""
|
||||
local unique_carset=""
|
||||
local ch=""
|
||||
local i=0
|
||||
local n=0
|
||||
local idx=0
|
||||
local attempts=0
|
||||
local count=0
|
||||
local max_attempts=0
|
||||
local set=""
|
||||
local char=""
|
||||
local -a required_sets=()
|
||||
declare -A seen_chars=()
|
||||
|
||||
(( symb )) && {
|
||||
required_sets+=('!.@#&%/^-_')
|
||||
carset+='!.@#&%/^-_'
|
||||
}
|
||||
(( numb )) && {
|
||||
required_sets+=('0123456789')
|
||||
carset+='0123456789'
|
||||
}
|
||||
(( maj )) && {
|
||||
required_sets+=('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||
carset+='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
}
|
||||
(( min )) && {
|
||||
required_sets+=('abcdefghijklmnopqrstuvwxyz')
|
||||
carset+='abcdefghijklmnopqrstuvwxyz'
|
||||
}
|
||||
if [[ -n $extcar ]]; then
|
||||
required_sets+=("$extcar")
|
||||
carset+="$extcar"
|
||||
fi
|
||||
|
||||
if [[ -z $carset ]]; then
|
||||
disp E "No characters are available. Re-enable at least one character class."
|
||||
return 1
|
||||
fi
|
||||
|
||||
for (( i=0; i<${#carset}; i++ )); do
|
||||
ch=${carset:i:1}
|
||||
if [[ -z ${seen_chars["$ch"]+x} ]]; then
|
||||
seen_chars["$ch"]=1
|
||||
unique_carset+="$ch"
|
||||
fi
|
||||
done
|
||||
unset seen_chars
|
||||
carset="$unique_carset"
|
||||
|
||||
if (( ${#required_sets[@]} > length )); then
|
||||
disp E "The selected character classes require a longer password."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if (( length > ${#carset} * occurs )); then
|
||||
disp E "The occurrence limit is too strict for the selected length."
|
||||
disp E "Please allow more characters or increase --occurences."
|
||||
return 1
|
||||
fi
|
||||
|
||||
disp I "Generating $nbpwd password(s), please wait..."
|
||||
for (( n=1; n<=nbpwd; n++ )); do
|
||||
local -a password_chars=()
|
||||
local -A char_count=()
|
||||
max_attempts=$(( ${#carset} * (occurs + 1) + 32 ))
|
||||
|
||||
for set in "${required_sets[@]}"; do
|
||||
attempts=0
|
||||
while :; do
|
||||
if (( attempts >= max_attempts )); then
|
||||
disp E "Unable to satisfy the occurrence limit with the current settings."
|
||||
return 1
|
||||
fi
|
||||
|
||||
idx=$(( RANDOM % ${#set} ))
|
||||
char=${set:idx:1}
|
||||
count=${char_count["$char"]:-0}
|
||||
|
||||
if (( count < occurs )); then
|
||||
char_count["$char"]=$(( count + 1 ))
|
||||
password_chars+=("$char")
|
||||
break
|
||||
fi
|
||||
|
||||
((attempts++))
|
||||
done
|
||||
done
|
||||
|
||||
while (( ${#password_chars[@]} < length )); do
|
||||
attempts=0
|
||||
while :; do
|
||||
if (( attempts >= max_attempts )); then
|
||||
disp E "Unable to satisfy the occurrence limit with the current settings."
|
||||
return 1
|
||||
fi
|
||||
|
||||
idx=$(( RANDOM % ${#carset} ))
|
||||
char=${carset:idx:1}
|
||||
count=${char_count["$char"]:-0}
|
||||
|
||||
if (( count < occurs )); then
|
||||
char_count["$char"]=$(( count + 1 ))
|
||||
password_chars+=("$char")
|
||||
break
|
||||
fi
|
||||
|
||||
((attempts++))
|
||||
done
|
||||
done
|
||||
|
||||
for (( i=${#password_chars[@]} - 1; i>0; i-- )); do
|
||||
idx=$(( RANDOM % (i + 1) ))
|
||||
char=${password_chars[i]}
|
||||
password_chars[i]=${password_chars[idx]}
|
||||
password_chars[idx]=$char
|
||||
done
|
||||
|
||||
printf '%s' "${password_chars[@]}"
|
||||
printf '\n'
|
||||
done
|
||||
}
|
||||
export -f genpwd
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# pwdscore : score a password quality from 1 to 100
|
||||
# Usage: pwdscore [options] <password>
|
||||
pwdscore()
|
||||
{
|
||||
local verbose=0
|
||||
local read_stdin=0
|
||||
local password=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "pwdscore: Score a password from 1 to 100.\n\n"
|
||||
printf "Usage: pwdscore [options] <password>\n"
|
||||
printf " pwdscore [options] --stdin\n"
|
||||
printf " pwdscore [options] # prompt on terminal\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "\t-v, --verbose\t\tShow details about the computed score\n"
|
||||
printf "\t-i, --stdin\t\tRead the password from standard input\n\n"
|
||||
printf "Note:\n"
|
||||
printf " Passwords containing '!' should be quoted, or passed via --stdin.\n"
|
||||
return 0
|
||||
;;
|
||||
-v|--verbose)
|
||||
verbose=1
|
||||
shift
|
||||
;;
|
||||
-i|--stdin)
|
||||
read_stdin=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
disp E "Invalid option '$1'. Use \"pwdscore --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
break
|
||||
@@ -125,78 +313,164 @@ local PARSED
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -n "$1" ]]; then
|
||||
nbpwd="$1"
|
||||
if ! [[ $nbpwd =~ ^[0-9]+$ ]]; then
|
||||
disp E "The number of password to generate must be a number."
|
||||
if (( read_stdin )); then
|
||||
[[ $# -eq 0 ]] || {
|
||||
disp E "Do not pass a positional password when using --stdin."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Function selecting a random caracter from the list in parameter
|
||||
pickcar() {
|
||||
# When a character is picked we check if it's not appearing already twice
|
||||
# elsewhere, we choose an other char, to compensate weak bash randomizer
|
||||
while [[ -z $char ]]; do
|
||||
local char="${1:RANDOM%${#1}:1} $RANDOM"
|
||||
if [[ $(awk -F"$char" '{print NF-1}' <<<"$picked") -gt $occurs ]]; then
|
||||
unset char
|
||||
fi
|
||||
done
|
||||
picked+="$char"
|
||||
echo "$char"
|
||||
}
|
||||
|
||||
disp I "Generating $nbpwd passwords, please wait..."
|
||||
for (( n=1; n<=nbpwd; n++ )); do
|
||||
{
|
||||
local carset='' # store final caracter set to use
|
||||
local picked='' # store already used caracter
|
||||
local rlength=0 # store already assigned length of caracters
|
||||
|
||||
# ?, *, $ and \ impossible to use to my knowledge as it would be interpreted
|
||||
if [[ $symb == 1 ]]; then
|
||||
pickcar '!.@#&%/^-_'
|
||||
carset+='!.@#&%/^-_'
|
||||
((rlength++))
|
||||
IFS= read -r password || true
|
||||
elif [[ $# -eq 0 ]]; then
|
||||
if [[ -t 0 ]]; then
|
||||
read -r -s -p 'Password: ' password < /dev/tty || true
|
||||
printf '\n' > /dev/tty
|
||||
else
|
||||
IFS= read -r password || true
|
||||
fi
|
||||
if [[ $numb == 1 ]]; then
|
||||
pickcar '0123456789'
|
||||
carset+='0123456789'
|
||||
((rlength++))
|
||||
fi
|
||||
if [[ $maj == 1 ]]; then
|
||||
pickcar 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
carset+='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
((rlength++))
|
||||
fi
|
||||
if [[ $min == 1 ]]; then
|
||||
pickcar 'abcdefghijklmnopqrstuvwxyz'
|
||||
carset+='abcdefghijklmnopqrstuvwxyz'
|
||||
((rlength++))
|
||||
fi
|
||||
if [[ -n $extcar ]]; then
|
||||
pickcar "$extcar"
|
||||
carset+=$extcar
|
||||
((rlength++))
|
||||
fi
|
||||
|
||||
# Check if we have enough car to have something viable
|
||||
if [[ ${#carset} -lt $length ]]; then
|
||||
disp E 'Not enought caracters are authorised for the password length.'
|
||||
disp E 'Please allow more caracter (preferably) or reduce password lentgh.'
|
||||
else
|
||||
[[ $# -eq 1 ]] || {
|
||||
disp E "Please provide exactly one password to score."
|
||||
return 1
|
||||
}
|
||||
password="$1"
|
||||
fi
|
||||
|
||||
for i in $(seq 1 $(($length - $rlength))); do
|
||||
pickcar "$carset"
|
||||
local lower=${password,,}
|
||||
local length=${#password}
|
||||
local score=0
|
||||
local rating="very weak"
|
||||
local unique_count=0
|
||||
local i=0 idx=0
|
||||
local c1=0 c2=0 c3=0
|
||||
local ch=""
|
||||
local has_lower=0 has_upper=0 has_digit=0 has_symbol=0
|
||||
local pool_size=0
|
||||
local entropy_bits="0.0"
|
||||
local entropy_score=0
|
||||
local -A seen=()
|
||||
|
||||
if [[ -z $password ]]; then
|
||||
printf '1\n'
|
||||
return 0
|
||||
fi
|
||||
|
||||
if (( length >= 20 )); then
|
||||
score=40
|
||||
elif (( length >= 16 )); then
|
||||
score=34
|
||||
elif (( length >= 12 )); then
|
||||
score=28
|
||||
elif (( length >= 8 )); then
|
||||
score=18
|
||||
else
|
||||
score=$(( length * 2 ))
|
||||
fi
|
||||
|
||||
if [[ $password =~ [a-z] ]]; then
|
||||
has_lower=1
|
||||
pool_size=$(( pool_size + 26 ))
|
||||
score=$(( score + 12 ))
|
||||
fi
|
||||
if [[ $password =~ [A-Z] ]]; then
|
||||
has_upper=1
|
||||
pool_size=$(( pool_size + 26 ))
|
||||
score=$(( score + 12 ))
|
||||
fi
|
||||
if [[ $password =~ [0-9] ]]; then
|
||||
has_digit=1
|
||||
pool_size=$(( pool_size + 10 ))
|
||||
score=$(( score + 12 ))
|
||||
fi
|
||||
if [[ $password =~ [^[:alnum:]] ]]; then
|
||||
has_symbol=1
|
||||
pool_size=$(( pool_size + 33 ))
|
||||
score=$(( score + 14 ))
|
||||
fi
|
||||
|
||||
for (( i=0; i<length; i++ )); do
|
||||
ch=${password:i:1}
|
||||
if [[ -z ${seen["$ch"]+x} ]]; then
|
||||
seen["$ch"]=1
|
||||
unique_count=$(( unique_count + 1 ))
|
||||
fi
|
||||
done
|
||||
} | sort -R | awk '{printf "%s", $1}'
|
||||
unset picked carset rlength
|
||||
echo
|
||||
score=$(( score + (unique_count * 10) / length ))
|
||||
|
||||
if (( pool_size > 1 )); then
|
||||
entropy_bits=$(awk -v len="$length" -v pool="$pool_size" \
|
||||
'BEGIN { printf "%.1f", len * (log(pool) / log(2)) }')
|
||||
|
||||
entropy_score=$(awk -v bits="$entropy_bits" 'BEGIN {
|
||||
if (bits < 28) print -35;
|
||||
else if (bits < 36) print -25;
|
||||
else if (bits < 60) print -10;
|
||||
else if (bits < 80) print 0;
|
||||
else if (bits < 100) print 5;
|
||||
else print 10;
|
||||
}')
|
||||
score=$(( score + entropy_score ))
|
||||
fi
|
||||
|
||||
if [[ $lower =~ (password|admin|root|qwerty|azerty|welcome|letmein|secret|changeme) ]]; then
|
||||
score=$(( score - 25 ))
|
||||
fi
|
||||
if [[ $lower =~ (1234|abcd|qwer|0000|1111|aaaa) ]]; then
|
||||
score=$(( score - 15 ))
|
||||
fi
|
||||
if [[ $password =~ (.)\1\1 ]]; then
|
||||
score=$(( score - 10 ))
|
||||
fi
|
||||
if (( length < 8 )); then
|
||||
score=$(( score - 10 ))
|
||||
fi
|
||||
if (( unique_count * 2 < length )); then
|
||||
score=$(( score - 10 ))
|
||||
fi
|
||||
|
||||
for (( idx=0; idx<length-2; idx++ )); do
|
||||
printf -v c1 '%d' "'${lower:idx:1}"
|
||||
printf -v c2 '%d' "'${lower:idx+1:1}"
|
||||
printf -v c3 '%d' "'${lower:idx+2:1}"
|
||||
if (( (c2 == c1 + 1 && c3 == c2 + 1) || \
|
||||
(c2 == c1 - 1 && c3 == c2 - 1) )); then
|
||||
score=$(( score - 10 ))
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if (( score < 1 )); then
|
||||
score=1
|
||||
elif (( score > 100 )); then
|
||||
score=100
|
||||
fi
|
||||
|
||||
if (( score >= 90 )); then
|
||||
rating='excellent'
|
||||
elif (( score >= 75 )); then
|
||||
rating='strong'
|
||||
elif (( score >= 60 )); then
|
||||
rating='good'
|
||||
elif (( score >= 40 )); then
|
||||
rating='fair'
|
||||
elif (( score >= 20 )); then
|
||||
rating='weak'
|
||||
fi
|
||||
|
||||
if (( verbose )); then
|
||||
printf 'Score: %d/100\n' "$score"
|
||||
printf 'Rating: %s\n' "$rating"
|
||||
printf 'Length: %d\n' "$length"
|
||||
printf 'Lowercase: %s\n' "$([[ $has_lower -eq 1 ]] && echo yes || echo no)"
|
||||
printf 'Uppercase: %s\n' "$([[ $has_upper -eq 1 ]] && echo yes || echo no)"
|
||||
printf 'Digits: %s\n' "$([[ $has_digit -eq 1 ]] && echo yes || echo no)"
|
||||
printf 'Symbols: %s\n' "$([[ $has_symbol -eq 1 ]] && echo yes || echo no)"
|
||||
printf 'Unique chars: %d\n' "$unique_count"
|
||||
printf 'Entropy: ~%s bits\n' "$entropy_bits"
|
||||
printf 'Entropy modifier: %+d\n' "$entropy_score"
|
||||
else
|
||||
printf '%d\n' "$score"
|
||||
fi
|
||||
}
|
||||
export -f genpwd
|
||||
export -f pwdscore
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
142
profile.d/ssh.sh
142
profile.d/ssh.sh
@@ -35,74 +35,118 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Remove host from know_host (name and IP) for the active user
|
||||
# Remove host entries (name and IP) from ~/.ssh/known_hosts for the active user
|
||||
# Usage: rmhost <hostname|ip> [hostname2|ip2 [...]]
|
||||
rmhost()
|
||||
{
|
||||
local PARSED
|
||||
PARSED=$(getopt -o h --long help -n 'rmhost' -- "$@")
|
||||
local all_users=0
|
||||
local -a known_hosts_files=()
|
||||
|
||||
PARSED=$(getopt -o ha --long help,all-users -n 'rmhost' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then return 1; fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "rmhost: Remove host/IP from ~/.ssh/known_hosts.\n\n"
|
||||
printf "Usage: rmhost <hostname|ip> [hostname2|ip2 ...]\n\n"
|
||||
printf "rmhost: Remove host/IP from known_hosts files.\n\n"
|
||||
printf "Usage: rmhost [--all-users] <hostname|ip> [hostname2|ip2 ...]\n\n"
|
||||
printf "Options:\n"
|
||||
printf " -a, --all-users Remove entries from all local users when run as root\n"
|
||||
printf " -h, --help Display this help screen\n"
|
||||
return 0
|
||||
;;
|
||||
-a|--all-users)
|
||||
all_users=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"rmhost --help\" to display usage."
|
||||
break
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validation: Ensure at least one argument remains
|
||||
if [[ $# -eq 0 ]]; then
|
||||
[[ $# -eq 0 ]] && {
|
||||
disp E "Missing argument. Use 'rmhost --help' for usage."
|
||||
return 1
|
||||
}
|
||||
|
||||
command -v ssh-keygen >/dev/null 2>&1 || {
|
||||
disp E "ssh-keygen is not installed."
|
||||
return 127
|
||||
}
|
||||
|
||||
if (( all_users )); then
|
||||
[[ ${EUID:-$(id -u)} -eq 0 ]] || {
|
||||
disp E "Option --all-users is only available when run as root."
|
||||
return 1
|
||||
}
|
||||
|
||||
while IFS=: read -r _ _ _ _ _ home _; do
|
||||
[[ -n $home && -f $home/.ssh/known_hosts ]] || continue
|
||||
known_hosts_files+=("$home/.ssh/known_hosts")
|
||||
done < /etc/passwd
|
||||
|
||||
[[ -f /etc/ssh/ssh_known_hosts ]] && \
|
||||
known_hosts_files+=("/etc/ssh/ssh_known_hosts")
|
||||
|
||||
[[ ${#known_hosts_files[@]} -gt 0 ]] || {
|
||||
disp W "No known_hosts files found for local users."
|
||||
return 0
|
||||
}
|
||||
else
|
||||
known_hosts_files=("${HOME}/.ssh/known_hosts")
|
||||
fi
|
||||
|
||||
for target in "$@"; do
|
||||
local hst=$target
|
||||
isipv4 "$hst" >/dev/null
|
||||
local v4=$?
|
||||
isipv6 "$hst" >/dev/null
|
||||
local v6=$?
|
||||
local hst="$target"
|
||||
local ip=""
|
||||
local v4=1
|
||||
local v6=1
|
||||
|
||||
isipv4 "$hst" >/dev/null 2>&1; v4=$?
|
||||
isipv6 "$hst" >/dev/null 2>&1; v6=$?
|
||||
|
||||
if [[ $v4 -eq 0 || $v6 -eq 0 ]]; then
|
||||
local ip=$hst
|
||||
unset hst
|
||||
fi
|
||||
unset v4 v6
|
||||
|
||||
if [[ ! $ip && $hst ]]; then
|
||||
if ! ip=$(host "$hst" 2>/dev/null | awk '/has address/ {print $NF; exit}'); then
|
||||
disp E "Impossible to extract IP from hostname." &&
|
||||
return 1
|
||||
fi
|
||||
[[ -z $ip ]] && {
|
||||
disp E "Impossible to extract IP from hostname."
|
||||
return 1;
|
||||
}
|
||||
ip="$hst"
|
||||
hst=""
|
||||
fi
|
||||
|
||||
if [[ $hst ]]; then
|
||||
disp I "Removing host $hst from ssh known_host..."
|
||||
ssh-keygen -R $hst >/dev/null
|
||||
if [[ -z ${ip:-} && -n ${hst:-} ]]; then
|
||||
if command -v host >/dev/null 2>&1; then
|
||||
ip=$(host "$hst" 2>/dev/null |
|
||||
awk '/has address|has IPv6 address/ {print $NF; exit}')
|
||||
elif command -v getent >/dev/null 2>&1; then
|
||||
ip=$(getent ahosts "$hst" 2>/dev/null | awk 'NR == 1 {print $1; exit}')
|
||||
else
|
||||
disp W "No resolver tool found; removing hostname only for '$hst'."
|
||||
fi
|
||||
if [[ $ip ]]; then
|
||||
disp I "Removing IP $ip from ssh known_host..."
|
||||
ssh-keygen -R $ip >/dev/null
|
||||
|
||||
[[ -z ${ip:-} ]] && \
|
||||
disp W "Could not resolve IP for '$hst'; removing hostname only."
|
||||
fi
|
||||
unset hst ip
|
||||
|
||||
local known_hosts_file=""
|
||||
for known_hosts_file in "${known_hosts_files[@]}"; do
|
||||
if [[ -n ${hst:-} ]]; then
|
||||
disp I "Removing host $hst from $known_hosts_file..."
|
||||
if ! ssh-keygen -R "$hst" -f "$known_hosts_file" >/dev/null 2>&1; then
|
||||
disp W "No known_hosts entry found for '$hst' in '$known_hosts_file'."
|
||||
fi
|
||||
fi
|
||||
if [[ -n ${ip:-} ]]; then
|
||||
disp I "Removing IP $ip from $known_hosts_file..."
|
||||
if ! ssh-keygen -R "$ip" -f "$known_hosts_file" >/dev/null 2>&1; then
|
||||
disp W "No known_hosts entry found for '$ip' in '$known_hosts_file'."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
export -f rmhost
|
||||
@@ -114,41 +158,33 @@ export -f rmhost
|
||||
# Usage: ssr <server [ssh options]>
|
||||
ssr()
|
||||
{
|
||||
local PARSED
|
||||
PARSED=$(getopt -o h --long help -n 'ssr' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then return 1; fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
case "${1:-}" in
|
||||
-h|--help)
|
||||
printf "ssr: SSH into a server as root.\n\n"
|
||||
printf "Usage: ssr <server> [ssh_options...]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "Notes:\n"
|
||||
printf " The first argument is the target server.\n"
|
||||
printf " All remaining arguments are passed directly to ssh.\n\n"
|
||||
printf "Examples:\n"
|
||||
printf " ssr srv01\n"
|
||||
printf " ssr srv01 -p 2222\n"
|
||||
printf " ssr srv01 -i ~/.ssh/id_ed25519 -J bastion\n"
|
||||
return 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"ssr --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
command -v ssh >/dev/null 2>&1 || {
|
||||
disp E "ssh is not installed."
|
||||
return 127
|
||||
}
|
||||
[[ ! $1 ]] && {
|
||||
|
||||
[[ $# -eq 0 || -z ${1:-} ]] && {
|
||||
disp E "Please specify the server you want to log in."
|
||||
return 1
|
||||
}
|
||||
|
||||
local srv=$1 && shift
|
||||
local srv=$1
|
||||
shift
|
||||
|
||||
ssh -Y root@"$srv" "$@"
|
||||
}
|
||||
|
||||
@@ -39,24 +39,27 @@ export UPDT_URL="$BASE_URL/raw/branch/master"
|
||||
export ARCH_URL="$BASE_URL/archive/master.tar.gz"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Check for profile updates
|
||||
# Check whether a newer profile version is available
|
||||
# Usage: check_updates [-q]
|
||||
# If -q is specified, the function will operate in quiet mode (internal use only)
|
||||
check_updates()
|
||||
{
|
||||
local quiet=0
|
||||
local PARSED=$(getopt -o hq --long help,quiet -n 'check_updates' -- "$@")
|
||||
local quiet=0 result=5 PARSED
|
||||
local vfile="" lastver=""
|
||||
|
||||
PARSED=$(getopt -o hq --long help,quiet -n 'check_updates' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"check_updates --help\" to display usage."
|
||||
return 1
|
||||
return 2
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "check_updates: Check for new versions.\n\n"
|
||||
printf "Usage: check_updates\n"
|
||||
printf "check_updates: Check whether a newer profile version is available.\n\n"
|
||||
printf "Usage: check_updates [-q|--quiet]\n"
|
||||
printf "This command only checks availability; it does not modify the installation.\n"
|
||||
return 0
|
||||
;;
|
||||
-q|--quiet)
|
||||
@@ -73,28 +76,35 @@ check_updates()
|
||||
esac
|
||||
done
|
||||
|
||||
(( $quiet != 1 )) && disp I "Checking for updates..."
|
||||
local vfile="/tmp/version"
|
||||
wget "$UPDT_URL/version" -O $vfile >/dev/null 2>&1 || {
|
||||
disp E "Can't download version file, impossible to proceed!"
|
||||
(( quiet != 1 )) && disp I "Checking for updates..."
|
||||
|
||||
vfile=$(mktemp /tmp/profile_version.XXXXXX) || {
|
||||
disp E "Failed to create a temporary file."
|
||||
return 4
|
||||
}
|
||||
|
||||
dwl "$UPDT_URL/version" "$vfile" >/dev/null 2>&1 || {
|
||||
rm -f "$vfile"
|
||||
disp E "Cannot download version file; unable to continue."
|
||||
return 5
|
||||
}
|
||||
|
||||
if [[ -s $vfile ]]; then
|
||||
local lastver=$(cat $vfile)
|
||||
if [[ $lastver != $PROFVERSION ]]; then
|
||||
disp I "You have version $PROFVERSION installed. Version $lastver is available."
|
||||
(( $quiet != 1 )) && disp I "You should upgrade to last version when possible."
|
||||
lastver=$(<"$vfile")
|
||||
if [[ "$lastver" != "$PROFVERSION" ]]; then
|
||||
disp I "Installed: $PROFVERSION. Available: $lastver."
|
||||
(( quiet != 1 )) && disp I "You should upgrade when possible."
|
||||
result=1
|
||||
else
|
||||
(( $quiet != 1 )) && disp I "Your version is up-to-date."
|
||||
(( quiet != 1 )) && disp I "Your version is up-to-date."
|
||||
result=0
|
||||
fi
|
||||
rm -f $vfile
|
||||
rm -f "$vfile"
|
||||
else
|
||||
disp E "Impossible to read temporary file, impossible to proceed."
|
||||
rm -f "$vfile"
|
||||
disp E "Temporary file is unreadable; unable to continue."
|
||||
fi
|
||||
unset lastver vfile
|
||||
|
||||
return $result
|
||||
}
|
||||
export -f check_updates
|
||||
@@ -102,23 +112,63 @@ export -f check_updates
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Apply update to profile
|
||||
# Usage: profile_upgrade
|
||||
# Apply the available profile upgrade
|
||||
# Usage: profile_upgrade [options]
|
||||
profile_upgrade()
|
||||
{
|
||||
local PARSED=$(getopt -o h --long help -n 'profile_upgrade' -- "$@")
|
||||
local PARSED
|
||||
local check_rc=0 dry_run=0 force_git=0 switch_to_git=0
|
||||
local archive_file="" tmpbase="" use_archive=0 branch=""
|
||||
local tmpdir="" archive="" extracted_root=""
|
||||
|
||||
PARSED=$(getopt -o hf:t:nFb:g --long help,file:,tmpdir:,dry-run,force,branch:,switch-to-git -n 'profile_upgrade' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
printf "Invalid options, use \"profile_upgrade --help\" to display usage."
|
||||
return 1
|
||||
disp E "Invalid options, use \"profile_upgrade --help\" to display usage."
|
||||
return 2
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "profile_upgrade: Upgrade the profile to the latest version.\n\n"
|
||||
printf "Usage: profile_upgrade\n"
|
||||
printf "profile_upgrade: Apply the available profile upgrade.\n\n"
|
||||
printf "Usage: profile_upgrade [options]\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "\t-f, --file ARCHIVE\tUse a local archive file for the upgrade\n"
|
||||
printf "\t-t, --tmpdir DIR\tCreate the temporary working directory under DIR\n"
|
||||
printf "\t-b, --branch NAME\tUse NAME as the target Git branch\n"
|
||||
printf "\t-g, --switch-to-git\tReplace current install with a fresh Git clone\n"
|
||||
printf "\t-n, --dry-run\t\tDisplay what would be done without changing anything\n"
|
||||
printf "\t-F, --force\t\tDiscard local changes before upgrading\n\n"
|
||||
printf "If the profile is installed from Git, the upgrade uses 'git pull'.\n"
|
||||
printf "Otherwise, it downloads or applies an archive and refreshes the files.\n"
|
||||
return 0
|
||||
;;
|
||||
-f|--file)
|
||||
archive_file="$2"
|
||||
use_archive=1
|
||||
shift 2
|
||||
;;
|
||||
-t|--tmpdir)
|
||||
tmpbase="$2"
|
||||
shift 2
|
||||
;;
|
||||
-b|--branch)
|
||||
branch="$2"
|
||||
shift 2
|
||||
;;
|
||||
-g|--switch-to-git)
|
||||
switch_to_git=1
|
||||
shift
|
||||
;;
|
||||
-n|--dry-run)
|
||||
dry_run=1
|
||||
shift
|
||||
;;
|
||||
-F|--force)
|
||||
force_git=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
@@ -130,59 +180,229 @@ profile_upgrade()
|
||||
esac
|
||||
done
|
||||
|
||||
if check_updates -q; then
|
||||
disp "No update available."
|
||||
if (( ! use_archive && ! switch_to_git )); then
|
||||
check_updates -q
|
||||
check_rc=$?
|
||||
if (( check_rc == 0 )); then
|
||||
disp I "No update available."
|
||||
return 0
|
||||
elif (( check_rc > 1 )); then
|
||||
disp E "Unable to check whether an update is available."
|
||||
return "$check_rc"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -s $MYPATH/profile.sh ]]; then
|
||||
disp E "Installation path detection failed, cannot upgrade automatically."
|
||||
if [[ ! -s $MYPATH/profile.sh ]]; then
|
||||
disp E "Install path detection failed; cannot upgrade automatically."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -d $MYPATH/.git ]] && (( use_archive )) && (( ! force_git )); then
|
||||
disp E "Refusing archive upgrade on a Git install without --force."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if (( switch_to_git )); then
|
||||
command -v git >/dev/null 2>&1 || {
|
||||
disp E "Git is required to switch this install to a Git clone."
|
||||
return 3
|
||||
}
|
||||
if (( dry_run )); then
|
||||
disp I "[dry-run] rm -rf \"$MYPATH\"/.git"
|
||||
disp I "[dry-run] git clone "$BASE_URL" \"$MYPATH\""
|
||||
[[ -n "$branch" ]] && disp I "[dry-run] git -C \"$MYPATH\" checkout "$branch""
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -d $MYPATH/.git ]]; then
|
||||
disp W "Git repository already present; no switch is needed."
|
||||
else
|
||||
local backup_dir="${MYPATH}.pre-git.$$.bak"
|
||||
mv "$MYPATH" "$backup_dir" || {
|
||||
disp E "Failed to move current install out of the way."
|
||||
return 3
|
||||
}
|
||||
git clone "$BASE_URL" "$MYPATH" || {
|
||||
disp E "Git clone failed; previous install kept in $backup_dir."
|
||||
mv "$backup_dir" "$MYPATH" 2>/dev/null || true
|
||||
return 3
|
||||
}
|
||||
[[ -n "$branch" ]] && (
|
||||
cd "$MYPATH" && git checkout "$branch"
|
||||
) || true
|
||||
disp I "Switched installation to Git source."
|
||||
disp I "Previous install kept in $backup_dir."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -d $MYPATH/.git ]] && (( ! use_archive )); then
|
||||
disp I "Git installation detected, applying git pull."
|
||||
pushd "$MYPATH" || {
|
||||
command -v git >/dev/null 2>&1 || {
|
||||
disp E "Git is required for this upgrade but is not available."
|
||||
return 3
|
||||
}
|
||||
pushd "$MYPATH" >/dev/null || {
|
||||
disp E "Failed to change directory to $MYPATH."
|
||||
return 3
|
||||
}
|
||||
git pull || {
|
||||
disp E "Git pull failed, upgrade not applyed."
|
||||
popd
|
||||
return 2
|
||||
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || {
|
||||
disp E "Install directory is not a valid Git working tree."
|
||||
popd >/dev/null || return 1
|
||||
return 3
|
||||
}
|
||||
disp I "Successfully upgraded using git."
|
||||
popd
|
||||
if ! git diff --quiet || ! git diff --cached --quiet || [[ -n $(git ls-files --others --exclude-standard) ]]; then
|
||||
if (( force_git )); then
|
||||
disp W "Force mode: local Git changes and untracked files will be lost."
|
||||
if (( dry_run )); then
|
||||
disp I "[dry-run] git fetch --all --prune"
|
||||
disp I "[dry-run] git reset --hard HEAD"
|
||||
disp I "[dry-run] git clean -fd"
|
||||
else
|
||||
disp I "No Git detected. Downloading and applying upgrade from archive..."
|
||||
local tmpdir="/tmp/profile_upg.$$"
|
||||
mkdir -p "$tmpdir" || {
|
||||
disp E "Failed to create temporary directory."
|
||||
git fetch --all --prune || {
|
||||
disp E "Git fetch failed, upgrade not applied."
|
||||
popd >/dev/null || return 1
|
||||
return 4
|
||||
}
|
||||
git reset --hard HEAD || {
|
||||
disp E "Git reset failed, upgrade not applied."
|
||||
popd >/dev/null || return 1
|
||||
return 4
|
||||
}
|
||||
git clean -fd || {
|
||||
disp E "Git clean failed, upgrade not applied."
|
||||
popd >/dev/null || return 1
|
||||
return 4
|
||||
}
|
||||
fi
|
||||
else
|
||||
disp W "The Git working tree contains local changes."
|
||||
disp W "Consider committing or stashing them before upgrading, or use --force."
|
||||
disp W "Upgrade may fail if the changes conflict with the upgrade."
|
||||
fi
|
||||
fi
|
||||
if [[ -n "$branch" ]]; then
|
||||
if (( dry_run )); then
|
||||
disp I "[dry-run] git fetch origin $branch"
|
||||
disp I "[dry-run] git checkout $branch"
|
||||
else
|
||||
git fetch origin "$branch" || {
|
||||
disp E "Git fetch failed for branch $branch."
|
||||
popd >/dev/null || return 1
|
||||
return 2
|
||||
}
|
||||
git checkout "$branch" || {
|
||||
disp E "Git checkout failed for branch $branch."
|
||||
popd >/dev/null || return 1
|
||||
return 2
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
local archive="$tmpdir/profile.tar.gz"
|
||||
wget -q "$ARCH_URL" -O "$archive" || {
|
||||
disp E "Failed to download archive."
|
||||
rm -rf "$tmpdir"
|
||||
if (( dry_run )); then
|
||||
if [[ -n "$branch" ]]; then
|
||||
disp I "[dry-run] git pull origin $branch"
|
||||
else
|
||||
disp I "[dry-run] git pull"
|
||||
fi
|
||||
else
|
||||
if [[ -n "$branch" ]]; then
|
||||
git pull origin "$branch" || {
|
||||
disp E "Git pull failed, upgrade not applied."
|
||||
popd >/dev/null || return 1
|
||||
return 2
|
||||
}
|
||||
else
|
||||
git pull || {
|
||||
disp E "Git pull failed, upgrade not applied."
|
||||
popd >/dev/null || return 1
|
||||
return 2
|
||||
}
|
||||
fi
|
||||
disp I "Successfully upgraded using git."
|
||||
fi
|
||||
popd >/dev/null || return 1
|
||||
else
|
||||
if (( use_archive )); then
|
||||
[[ -r "$archive_file" ]] || {
|
||||
disp E "Local archive '$archive_file' is missing or unreadable."
|
||||
return 4
|
||||
}
|
||||
disp I "Using local archive $archive_file."
|
||||
else
|
||||
disp W "No Git repo found. Git is the recommended source."
|
||||
disp I "Applying upgrade from archive..."
|
||||
fi
|
||||
|
||||
if [[ -n "$tmpbase" ]]; then
|
||||
if (( dry_run )); then
|
||||
disp I "[dry-run] mkdir -p \"$tmpbase\""
|
||||
disp I "[dry-run] mktemp -d \"$tmpbase/profile_upg.XXXXXX\""
|
||||
tmpdir="$tmpbase/profile_upg.DRYRUN"
|
||||
else
|
||||
mkdir -p "$tmpbase" || {
|
||||
disp E "Failed to create temporary directory base $tmpbase."
|
||||
return 5
|
||||
}
|
||||
tmpdir=$(mktemp -d "$tmpbase/profile_upg.XXXXXX") || {
|
||||
disp E "Failed to create temp working directory under $tmpbase."
|
||||
return 5
|
||||
}
|
||||
fi
|
||||
else
|
||||
if (( dry_run )); then
|
||||
disp I "[dry-run] mktemp -d /tmp/profile_upg.XXXXXX"
|
||||
tmpdir="/tmp/profile_upg.DRYRUN"
|
||||
else
|
||||
tmpdir=$(mktemp -d /tmp/profile_upg.XXXXXX) || {
|
||||
disp E "Failed to create temporary directory."
|
||||
return 5
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
tar -xzf "$archive" -C "$tmpdir" || {
|
||||
disp E "Archive extraction failed."
|
||||
if (( use_archive )); then
|
||||
archive="$archive_file"
|
||||
else
|
||||
archive="$tmpdir/profile.tar.gz"
|
||||
if (( dry_run )); then
|
||||
disp I "[dry-run] dwl \"$ARCH_URL\" \"$archive\""
|
||||
else
|
||||
dwl "$ARCH_URL" "$archive" || {
|
||||
disp E "Failed to download archive."
|
||||
rm -rf "$tmpdir"
|
||||
return 6
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
disp I "Installing new version..."
|
||||
cp -r "$tmpdir"/profile/* "$MYPATH"/ || {
|
||||
disp E "Failed to copy new files to $MYPATH."
|
||||
if (( dry_run )); then
|
||||
disp I "[dry-run] tar -xzf \"$archive\" -C \"$tmpdir\""
|
||||
disp I "[dry-run] cp -a <extracted_profile>/. \"$MYPATH\"/"
|
||||
else
|
||||
tar -xzf "$archive" -C "$tmpdir" || {
|
||||
disp E "Archive extraction failed."
|
||||
rm -rf "$tmpdir"
|
||||
return 7
|
||||
}
|
||||
|
||||
disp I "Upgrade complete. You should now logout and login again."
|
||||
extracted_root=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d ! -name '.*' | head -n 1)
|
||||
if [[ -z "$extracted_root" ]]; then
|
||||
disp E "Could not find extracted profile files."
|
||||
rm -rf "$tmpdir"
|
||||
return 8
|
||||
fi
|
||||
|
||||
disp I "Installing new version..."
|
||||
cp -a "$extracted_root"/. "$MYPATH"/ || {
|
||||
disp E "Failed to copy new files into $MYPATH."
|
||||
rm -rf "$tmpdir"
|
||||
return 9
|
||||
}
|
||||
|
||||
disp I "Upgrade complete. Please log out and log in again."
|
||||
rm -rf "$tmpdir"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
export -f profile_upgrade
|
||||
|
||||
Reference in New Issue
Block a user