Tools/Linux_reinstall/Alpine/motd.sh

292 lines
9 KiB
Bash

#!/bin/sh
#
# Alpine ash/POSIX compatible MOTD
# Put this file in /etc/profile.d/motd.sh
# Authors:Leitbogioro
#
# ------------------ 0) helpers ------------------
have_cmd() { command -v "$1" >/dev/null 2>&1; }
# Do not "exit" in a sourced script; try return, fallback to true.
safe_return() { return 0 2>/dev/null || true; }
run_timeout() {
_t="$1"; shift
if have_cmd timeout; then
timeout "$_t" "$@" 2>/dev/null
else
"$@" 2>/dev/null
fi
}
# CPU usage: sample /proc/stat twice, output integer percent like "8%"
get_cpu_usage() {
# 1st sample
set -- $(head -n 1 /proc/stat 2>/dev/null)
[ "$1" = "cpu" ] || { echo "N/A"; return; }
user=${2:-0}
nice=${3:-0}
system=${4:-0}
idle=${5:-0}
iowait=${6:-0}
irq=${7:-0}
softirq=${8:-0}
steal=${9:-0}
idle_all1=$((idle + iowait))
total1=$((user + nice + system + idle + iowait + irq + softirq + steal))
# small interval; if fractional sleep unsupported, fallback to 1s
sleep 0.2 2>/dev/null || sleep 1
# 2nd sample
set -- $(head -n 1 /proc/stat 2>/dev/null)
[ "$1" = "cpu" ] || { echo "N/A"; return; }
user2=${2:-0}
nice2=${3:-0}
system2=${4:-0}
idle2=${5:-0}
iowait2=${6:-0}
irq2=${7:-0}
softirq2=${8:-0}
steal2=${9:-0}
idle_all2=$((idle2 + iowait2))
total2=$((user2 + nice2 + system2 + idle2 + iowait2 + irq2 + softirq2 + steal2))
dt=$((total2 - total1))
di=$((idle_all2 - idle_all1))
[ "$dt" -gt 0 ] 2>/dev/null || { echo "N/A"; return; }
awk -v dt="$dt" -v di="$di" 'BEGIN{printf "%d%%", ((dt-di)*100)/dt}'
}
# ------------------ 1) tweak vim defaults ------------------
sed -i 's/set mouse=a/set mouse-=a/g' /usr/share/vim/vim82/defaults.vim >/dev/null 2>&1
sed -i 's/set mouse=a/set mouse-=a/g' /usr/share/vim/vim90/defaults.vim >/dev/null 2>&1
# ------------------ 2) distro name ------------------
DISTRIB_DESCRIPTION="Alpine"
if [ -r /etc/os-release ]; then
_id="$(awk -F= 'tolower($1)=="id"{gsub(/"/,"",$2); print $2; exit}' /etc/os-release 2>/dev/null)"
if [ -n "$_id" ]; then
_id="$(printf "%s" "$_id" | tr '[:upper:]' '[:lower:]')"
DISTRIB_DESCRIPTION="$(printf "%s" "$_id" | awk '{printf toupper(substr($0,1,1)) substr($0,2)}')"
fi
fi
UNAME_O="$(uname -o 2>/dev/null)"
[ -z "$UNAME_O" ] && UNAME_O="$(uname -s 2>/dev/null)"
printf "Welcome to %s %s (%s)\n" "$DISTRIB_DESCRIPTION" "$UNAME_O" "$(uname -r 2>/dev/null) $(uname -m 2>/dev/null)"
printf "\n"
printf "The Alpine Wiki contains a large amount of how-to guides and general\n"
printf "information about administrating Alpine systems.\n"
printf "See <https://wiki.alpinelinux.org/>.\n"
printf "\n"
printf "You can setup the system with the command: setup-alpine\n"
printf "\n"
printf "You may change this message by editing /etc/profile.d/motd.sh\n"
printf "\n"
# ------------------ 3) system info ------------------
date_str="$(date 2>/dev/null)"
load="$(awk '{print $1}' /proc/loadavg 2>/dev/null)"
[ -z "$load" ] && load="0.00"
root_usage="$(df -h / 2>/dev/null | awk 'NR==2{print $5}')"
[ -z "$root_usage" ] && root_usage="N/A"
# memory usage: prefer /proc/meminfo (no free dependency)
mem_total_kb="$(awk '/^MemTotal:/{print $2; exit}' /proc/meminfo 2>/dev/null)"
mem_avail_kb="$(awk '/^MemAvailable:/{print $2; exit}' /proc/meminfo 2>/dev/null)"
if [ -n "$mem_total_kb" ] && [ -n "$mem_avail_kb" ] && [ "$mem_total_kb" -gt 0 ] 2>/dev/null; then
mem_used_kb=$((mem_total_kb - mem_avail_kb))
memory_usage="$(awk -v u="$mem_used_kb" -v t="$mem_total_kb" 'BEGIN{printf "%.1f%%", (u/t)*100}')"
else
if have_cmd free; then
memory_usage="$(free -m 2>/dev/null | awk '/Mem:/ { total=$2; used=$3 } END { if(total>0) printf("%.1f%%", used/total*100); else print "N/A"}')"
else
memory_usage="N/A"
fi
fi
# swap usage from /proc/meminfo
swap_total_kb="$(awk '/^SwapTotal:/{print $2; exit}' /proc/meminfo 2>/dev/null)"
swap_free_kb="$(awk '/^SwapFree:/{print $2; exit}' /proc/meminfo 2>/dev/null)"
if [ -n "$swap_total_kb" ] && [ "$swap_total_kb" -gt 0 ] 2>/dev/null; then
swap_used_kb=$((swap_total_kb - swap_free_kb))
swap_usage="$(awk -v u="$swap_used_kb" -v t="$swap_total_kb" 'BEGIN{printf "%.1f%%", (u/t)*100}')"
else
swap_usage="0.0%"
fi
# Users Logged In: prefer ssh established sessions (ss/netstat), fallback to who
usersnum="0"
if have_cmd ss; then
usersnum="$(ss -tnp 2>/dev/null | awk '/sshd/ && /ESTAB/{c++} END{print c+0}')"
elif have_cmd netstat; then
usersnum="$(netstat -tnp 2>/dev/null | awk '/sshd/ && /ESTABLISHED/{c++} END{print c+0}')"
elif have_cmd who; then
usersnum="$(who 2>/dev/null | wc -l | tr -d ' ')"
[ -z "$usersnum" ] && usersnum="0"
fi
# processes count
processes="$(ps aux 2>/dev/null | wc -l | tr -d ' ')"
case "$processes" in ""|0) processes="$(ps 2>/dev/null | wc -l | tr -d ' ')";; esac
[ -z "$processes" ] && processes="0"
# uptime: /proc/uptime seconds -> "Xd Yh" / "Xh Ymin" / "X min"
uptime_str="N/A"
uptime_s="$(cut -d. -f1 /proc/uptime 2>/dev/null)"
case "$uptime_s" in
""|*[!0-9]*) uptime_str="N/A" ;;
*)
days=$((uptime_s / 86400))
hrs=$(((uptime_s % 86400) / 3600))
mins=$(((uptime_s % 3600) / 60))
if [ "$days" -gt 0 ]; then
uptime_str="${days} days ${hrs} hours"
elif [ "$hrs" -gt 0 ]; then
uptime_str="${hrs} hours ${mins} min"
else
uptime_str="${mins} min"
fi
;;
esac
# ------------------ 4) local IP (improved) ------------------
localip=""
if have_cmd ip; then
# best: infer real source IP used to reach internet
localip="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '
{ for(i=1;i<=NF;i++){ if($i=="src"){print $(i+1); exit} } }')"
# fallback: first global ipv4
if [ -z "$localip" ]; then
localip="$(ip -4 addr show scope global 2>/dev/null | awk '/inet /{print $2; exit}' | cut -d/ -f1)"
fi
fi
# ------------------ 5) public IP ------------------
IPv4=""
IPv6=""
# Prefer dig (same as your original), fallback to curl/wget if present
if have_cmd dig; then
IPv4="$(run_timeout 1 dig -4 TXT +short o-o.myaddr.l.google.com @ns3.google.com | head -n 1 | tr -d '"')"
[ -z "$IPv4" ] && IPv4="$(run_timeout 1 dig -4 TXT CH +short whoami.cloudflare @1.0.0.3 | head -n 1 | tr -d '"')"
IPv6="$(run_timeout 1 dig -6 TXT +short o-o.myaddr.l.google.com @ns3.google.com | head -n 1 | tr -d '"')"
[ -z "$IPv6" ] && IPv6="$(run_timeout 1 dig -6 TXT CH +short whoami.cloudflare @2606:4700:4700::1003 | head -n 1 | tr -d '"')"
fi
if [ -z "$IPv4" ] && have_cmd curl; then
IPv4="$(run_timeout 2 curl -4 -fsS https://api.ipify.org | head -n 1)"
fi
if [ -z "$IPv6" ] && have_cmd curl; then
IPv6="$(run_timeout 2 curl -6 -fsS https://api64.ipify.org | head -n 1)"
fi
if [ -z "$IPv4" ] && have_cmd wget; then
IPv4="$(run_timeout 2 wget -T 2 -qO- https://api.ipify.org | head -n 1)"
fi
if [ -z "$IPv6" ] && have_cmd wget; then
IPv6="$(run_timeout 2 wget -T 2 -qO- https://api64.ipify.org | head -n 1)"
fi
# ---- IPv4 validate ----
is_ipv4="0"
if [ -n "$IPv4" ]; then
echo "$IPv4" | awk -F. '
NF==4 {
for(i=1;i<=4;i++){
if($i !~ /^[0-9]+$/) exit 1
if($i < 0 || $i > 255) exit 1
}
exit 0
}
{ exit 1 }
' >/dev/null 2>&1 && is_ipv4="1"
fi
[ "$is_ipv4" != "1" ] && IPv4="N/A"
# ---- IPv6 normalize (no bash substring) ----
if [ -n "$IPv6" ]; then
case "$IPv6" in
:*) IPv6="0$IPv6" ;;
esac
case "$IPv6" in
*:) IPv6="${IPv6}0" ;;
esac
fi
# ---- IPv6 validate (simple but practical) ----
is_ipv6="0"
if [ -n "$IPv6" ]; then
echo "$IPv6" | awk '
{
s=$0
if (index(s,":")==0) exit 1
if (s ~ /[^0-9A-Fa-f:]/) exit 1
if (s ~ /:::/) exit 1
tmp=s
n=gsub(/::/, "&", tmp)
if (n>1) exit 1
split(s, a, ":")
hext=0
for(i=1;i<=length(a);i++){
if (a[i]!=""){
if (length(a[i])>4) exit 1
if (a[i] ~ /[^0-9A-Fa-f]/) exit 1
hext++
}
}
if (n==0){
if (length(a)!=8) exit 1
} else {
if (hext>8) exit 1
}
exit 0
}
' >/dev/null 2>&1 && is_ipv6="1"
fi
[ "$is_ipv6" != "1" ] && IPv6="N/A"
# localip fallback rules: if empty / equals public ip / contains ":" => use localhost
if [ -z "$localip" ] || [ "$localip" = "$IPv4" ] || [ "$localip" = "$IPv6" ]; then
localip="$(awk '/localhost/{print $1; exit}' /etc/hosts 2>/dev/null)"
fi
case "$localip" in
*:*) localip="$(awk '/localhost/{print $1; exit}' /etc/hosts 2>/dev/null)" ;;
esac
[ -z "$localip" ] && localip="127.0.0.1"
# CPU usage (after IPs, before memory output)
cpu_usage="$(get_cpu_usage)"
# ------------------ 6) output ------------------
echo " System information as of $date_str"
echo
printf "%-30s%-15s\n" " System Load:" "$load"
printf "%-30s%-15s\n" " CPU Usage:" "$cpu_usage"
printf "%-30s%-15s\n" " Memory Usage:" "$memory_usage"
printf "%-30s%-15s\n" " Usage On /:" "$root_usage"
printf "%-30s%-15s\n" " Swap Usage:" "$swap_usage"
printf "%-30s%-15s\n" " Processes:" "$processes"
printf "%-30s%-15s\n" " Users Logged In:" "$usersnum"
printf "%-30s%-15s\n" " Private IP Address:" "$localip"
printf "%-30s%-15s\n" " Public IPv4 Address:" "$IPv4"
printf "%-30s%-15s\n" " Public IPv6 Address:" "$IPv6"
printf "%-30s%-15s\n" " System Uptime:" "$uptime_str"
echo
safe_return