#!/usr/bin/env bash set -euo pipefail source ./lib.sh log "MOTD installieren …" install -d /usr/local/bin cat >/usr/local/bin/mw-motd <<'SH' #!/usr/bin/env bash # MOTD – MailWolt # bewusst KEIN "set -e" und KEIN pipefail; MOTD darf nie hart abbrechen set -u # ---------- Farben ---------- NC="\033[0m"; WH="\033[1;37m"; CY="\033[1;36m"; GY="\033[0;90m" GR="\033[1;32m"; YE="\033[1;33m"; RD="\033[1;31m" # ---------- Breite / Zentrierung ---------- W=110 term_cols=$(tput cols 2>/dev/null || echo $W) [ "$term_cols" -gt "$W" ] && pad=$(( (term_cols - W)/2 )) || pad=0 sp(){ [ "$1" -gt 0 ] && printf "%${1}s" " " || true; } center() { local s="$1"; local n=$(( (W - ${#s})/2 )); sp $((pad+n)); printf "%s\n" "$s"; } rule(){ sp "$pad"; printf "%0.s=" $(seq 1 "$W"); printf "\n"; } title(){ sp "$pad"; local t="$1"; local lf=$(( (W - ${#t} - 2)/2 )); local rf=$(( W - ${#t} - 2 - lf )); \ printf "%s" "$(printf '─%.0s' $(seq 1 $lf))"; printf " %s " "$t"; printf "%s\n" "$(printf '─%.0s' $(seq 1 $rf))"; } kv(){ sp "$pad"; printf "%-12s: %s\n" "$1" "$2"; } # ---------- Installer-/App-Variablen ---------- UI_HOST=""; WEBMAIL_HOST=""; MAIL_HOSTNAME="" [ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env || true # ---------- Systemdaten ---------- now="$(date '+%Y-%m-%d %H:%M:%S %Z' 2>/dev/null || echo '-')" upt="$(uptime -p 2>/dev/null || echo '-')" cores="$(nproc 2>/dev/null || echo 1)" load_raw="$(awk '{printf "%s / %s / %s",$1,$2,$3}' /proc/loadavg 2>/dev/null || echo '0.00 / 0.00 / 0.00')" load1="$(awk '{print $1}' /proc/loadavg 2>/dev/null || echo 0)" # RAM/SWAP mem_total="$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo 0)" mem_avail="$(awk '/MemAvailable/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo 0)" mem_used=$(( mem_total - mem_avail )) swap_total="$(awk '/SwapTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo 0)" swap_free="$(awk '/SwapFree/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo 0)" swap_used=$(( swap_total - swap_free )) pct(){ local u="$1" t="$2"; [ "$t" -gt 0 ] || { echo 0; return; }; awk -v u="$u" -v t="$t" 'BEGIN{printf "%d",(u*100)/t}' ; } ram_pct=$(pct "$mem_used" "$mem_total") swap_pct=$(pct "$swap_used" "$swap_total") # Disks df_line(){ df -hP "$1" 2>/dev/null | awk 'NR==2{printf "%s / %s (%s)",$3,$2,$5}'; } df_pct(){ df -P "$1" 2>/dev/null | awk 'NR==2{gsub("%","",$5);print $5+0}'; } disk_root="$(df_line /)"; pct_root="$(df_pct /)" disk_var="$(df_line /var 2>/dev/null)"; [ -n "$disk_var" ] || disk_var="-" pct_var="$(df_pct /var 2>/dev/null)"; [ -n "$pct_var" ] || pct_var=0 # IPs (int/ext) ipv4_int="$(hostname -I 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i!~/:/){print $i;exit}}')" ipv6_int="$(hostname -I 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i~/:/){print $i;exit}}')" ipv4_ext="$(curl -4fsS --max-time 1 https://ifconfig.me 2>/dev/null || true)" ipv6_ext="$(curl -6fsS --max-time 1 https://ifconfig.me 2>/dev/null || true)" # ---------- Status-Farben ---------- mark(){ # value thresholdY thresholdR local v="$1" y="$2" r="$3" if [ "$v" -ge "$r" ]; then printf "${RD}[HIGH]${NC}" elif [ "$v" -ge "$y" ]; then printf "${YE}[WARN]${NC}" else printf "${GR}[OK]${NC}" fi } # Load/CPU-Schwellen (pro Core) load_pct=$(awk -v l="$load1" -v c="$cores" 'BEGIN{if(c<1)c=1; printf "%d", (l/c)*100}') m_load="$(mark "$load_pct" 70 100)" m_ram="$(mark "$ram_pct" 75 90)" m_swap="$(mark "$swap_pct" 10 50)" m_root="$(mark "$pct_root" 75 90)" m_var="$(mark "$pct_var" 75 90)" # ---------- Header ---------- rule center "" center ":::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: :::::::::::" center ":+:+:+ :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: " center ":+: +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ " center "+#+ +:+ +#+ +#++:++#++: +#+ +#+ +#+ +:+ +#+ +#+ +:+ +#+ +#+ " center "+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+ " center "#+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+# " center "### ### ### ### ########### ########## ### ### ######## ########## ### " center "" rule # ---------- System ---------- kv "Date / Time" "${YE}${now}${NC}" sp "$pad"; printf "%-12s: int %-40s ext %s\n" "IPv4" "${ipv4_int:--}" "${ipv4_ext:--}" sp "$pad"; printf "%-12s: int %-40s ext %s\n" "IPv6" "${ipv6_int:--}" "${ipv6_ext:--}" kv "Uptime" "$upt" sp "$pad"; printf "%-12s: %s cores, load %s %b\n" "CPU" "$cores" "$load_raw" "$m_load" sp "$pad"; printf "%-12s: %s MiB / %s MiB (%d%%) %b %-5s %s MiB / %s MiB (%d%%) %b\n" \ "RAM" "$mem_used" "$mem_total" "$ram_pct" "$m_ram" "SWAP:" "$swap_used" "$swap_total" "$swap_pct" "$m_swap" sp "$pad"; printf "%-12s: / %s %b %-5s %s %b\n" \ "Disk" "$disk_root" "$m_root" "/var:" "$disk_var" "$m_var" echo # ---------- Domains ---------- title "Domains" [ -n "${UI_HOST:-}" ] && kv "UI" "${UI_HOST}" [ -n "${WEBMAIL_HOST:-}" ] && kv "Webmail" "${WEBMAIL_HOST}" [ -n "${MAIL_HOSTNAME:-}" ]&& kv "MX" "${MAIL_HOSTNAME}" echo # ---------- Services (4 Spalten, bündig) ---------- title "Services" svc_state(){ systemctl is-active --quiet "$1" && printf "${GR}[OK]${NC}" || printf "${RD}[FAIL]${NC}"; } SVC=( nginx mariadb redis-server postfix dovecot rspamd opendkim opendmarc clamav-daemon fail2ban mailwolt-ws mailwolt-queue mailwolt-schedule ) i=0; line="" for s in "${SVC[@]}"; do st="$(svc_state "$s")" seg="$(printf "%-18s %-7s" "$s" "$st")" line="$line$seg" i=$((i+1)) if [ $((i%4)) -eq 0 ]; then sp "$pad"; echo "$line"; line=""; else line="$line "; fi done [ -n "$line" ] && { sp "$pad"; echo "$line"; } echo exit 0 SH chmod 755 /usr/local/bin/mw-motd # update-motd Hook if [[ -d /etc/update-motd.d ]]; then cat >/etc/update-motd.d/10-mailwolt <<'SH' #!/usr/bin/env bash /usr/local/bin/mw-motd SH chmod +x /etc/update-motd.d/10-mailwolt [[ -f /etc/update-motd.d/50-motd-news ]] && chmod -x /etc/update-motd.d/50-motd-news || true else # Fallback für Systeme ohne dynamic MOTD cat >/etc/profile.d/10-mailwolt-motd.sh <<'SH' case "$-" in *i*) /usr/local/bin/mw-motd ;; esac SH fi : > /etc/motd 2>/dev/null || true log "[✓] MOTD installiert."