first commit
This commit is contained in:
commit
d102b513e2
121
00-motdfetch
Executable file
121
00-motdfetch
Executable file
|
@ -0,0 +1,121 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# MOTDfetch is a modular and dynamic MOTD replacement
|
||||||
|
# and a very nice command line information tool for Debian/Ubuntu systems.
|
||||||
|
#
|
||||||
|
# repository: https://git.tkapias.net/tkapias/MOTDfetch
|
||||||
|
# author: Tomasz Kapias
|
||||||
|
# email: tomasz@tkapias.net
|
||||||
|
#
|
||||||
|
# modules path: ./motdfetch.d/
|
||||||
|
# config paths: $HOME/.config/motdfetch/motdfetch.conf
|
||||||
|
# /etc/motdfetch/motdfetch.conf
|
||||||
|
#
|
||||||
|
# requirements (modules apart): sudo apt install coreutils bc
|
||||||
|
|
||||||
|
# locale env
|
||||||
|
unset LC_ALL
|
||||||
|
export LC_MESSAGES=C
|
||||||
|
|
||||||
|
# GLOBAL COLORS ######################################################
|
||||||
|
|
||||||
|
c_txt="39"
|
||||||
|
c_txt_emphase="35"
|
||||||
|
c_txt_deco="97"
|
||||||
|
c_txt_invert="30"
|
||||||
|
c_bg="47"
|
||||||
|
c_danger="31"
|
||||||
|
c_warning="33"
|
||||||
|
c_success="32"
|
||||||
|
c_title="${c_bg};1;${c_txt_invert}m"
|
||||||
|
|
||||||
|
# RUN OPTIONS #######################################################
|
||||||
|
|
||||||
|
# MODTfetch directory path
|
||||||
|
SCRIPT_DIR=$(dirname "$(realpath "$0")")
|
||||||
|
|
||||||
|
Help()
|
||||||
|
{
|
||||||
|
echo -e "\e[1;${c_txt_emphase}mMOTDfetch\e[1;${c_txt}m is a modular and dynamic MOTD replacement and a very"
|
||||||
|
echo -e "nice command line information tool for Debian/Ubuntu systems.\e[0m"
|
||||||
|
echo
|
||||||
|
echo "Syntax: bash $SCRIPT_DIR/00-motdfetch [-h] [-f] [-t ARG] [-l]"
|
||||||
|
echo
|
||||||
|
echo "options: -h Print this Help"
|
||||||
|
echo " -f force execution under heavy load"
|
||||||
|
echo " -t execute a standalone module with internal sample conf"
|
||||||
|
echo " -l list available modules files names"
|
||||||
|
}
|
||||||
|
|
||||||
|
unset option_force_load
|
||||||
|
|
||||||
|
# command options and arguments
|
||||||
|
while getopts "hft:l" option; do
|
||||||
|
case $option in
|
||||||
|
h) Help
|
||||||
|
exit ;;
|
||||||
|
f) option_force_load=1;;
|
||||||
|
t) # standalone module option
|
||||||
|
if [[ -f "$SCRIPT_DIR/motdfetch.d/$OPTARG" ]]; then
|
||||||
|
(. "$SCRIPT_DIR/motdfetch.d/$OPTARG")
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo -e "\e[1;${c_danger}mError\e[0m: Invalid module filename, check the -l option.\n"
|
||||||
|
Help
|
||||||
|
exit 1
|
||||||
|
fi;;
|
||||||
|
l) # List modules option
|
||||||
|
for file in $SCRIPT_DIR/motdfetch.d/*
|
||||||
|
do
|
||||||
|
echo -e "$(basename $file) $(head -3 $file|tail -1)"
|
||||||
|
done | column -t -s '#'
|
||||||
|
exit 0;;
|
||||||
|
\?) # Invalid option
|
||||||
|
echo -e "\e[1;${c_danger}mError\e[0m: Invalid option"
|
||||||
|
Help
|
||||||
|
exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# CONFIG LOADING ###################################################
|
||||||
|
|
||||||
|
userconf="$HOME/.config/motdfetch/motdfetch.conf"
|
||||||
|
sysconf="/etc/motdfetch/motdfetch.conf"
|
||||||
|
|
||||||
|
if [[ -f "$userconf" ]];then
|
||||||
|
. "$userconf"
|
||||||
|
elif [[ -f "$sysconf" ]];then
|
||||||
|
. "$sysconf"
|
||||||
|
else
|
||||||
|
echo -e "\e[1;${c_danger}mError\e[0m: no configuration available.\n"
|
||||||
|
Help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# EXECUTION #########################################################
|
||||||
|
|
||||||
|
## load check
|
||||||
|
cores=$(/usr/bin/grep -ioPc 'processor\t:' /proc/cpuinfo 2>/dev/null)
|
||||||
|
if [[ "$cores" -eq "0" ]]; then
|
||||||
|
cores=1
|
||||||
|
fi
|
||||||
|
threshold="${cores:-1}.5"
|
||||||
|
|
||||||
|
echo -e "\n\e[${c_title} MOTDFETCH \e[0m\n"
|
||||||
|
if [[ $(echo "`cut -f1 -d ' ' /proc/loadavg` < $threshold" | /usr/bin/bc) -eq 1 || $option_force_load -eq 1 ]]; then
|
||||||
|
### output modules
|
||||||
|
for file in $SCRIPT_DIR/motdfetch.d/*
|
||||||
|
do
|
||||||
|
(. "$file")
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
### too much load for modules, run only 00 & 99 + msg
|
||||||
|
module_header_disable=0
|
||||||
|
(. $SCRIPT_DIR/motdfetch.d/00-*)
|
||||||
|
module_userslog_disable=0
|
||||||
|
(. $SCRIPT_DIR/motdfetch.d/99-*)
|
||||||
|
echo -e "\n\e[${c_title} WE SKIPPED SOME MODULES \e[0m\n"
|
||||||
|
echo -e " MOTDfetch skipped some modules because of\n this \e[1;${c_danger}msystem load\e[0m being higher than \e[1;${c_danger}m$threshold\e[0;${c_warning}m.\e[0m\n"
|
||||||
|
echo -e " \e[1;${c_txt}mBAD ADVICE\e[0m: you can force execution with the option [-f]:\n # bash $SCRIPT_DIR/00-motdfetch -f\n"
|
||||||
|
fi
|
BIN
docs/img/preview.jpg
Normal file
BIN
docs/img/preview.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 116 KiB |
157
install.sh
Executable file
157
install.sh
Executable file
|
@ -0,0 +1,157 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# installation script for MOTDfetch
|
||||||
|
# repository: https://git.tkapias.net/tkapias/MOTDfetch
|
||||||
|
# author: Tomasz Kapias
|
||||||
|
# email: tomasz@tkapias.net
|
||||||
|
#
|
||||||
|
# run with sudo or as root user, or directly from the repository:
|
||||||
|
# sudo wget -q https://git.tkapias.net/tkapias/MOTDfetch/raw/master/install.sh -O - | sudo bash
|
||||||
|
|
||||||
|
|
||||||
|
# locale
|
||||||
|
export LC_ALL="C.UTF-8"
|
||||||
|
export GREP_COLORS="ms=01;32:mc=01;32:sl=:cx=:fn=35:ln=31:bn=31:se=36"
|
||||||
|
|
||||||
|
N="\e[0m"
|
||||||
|
T="\e[1;35m"
|
||||||
|
S="\e[0;32m"
|
||||||
|
W="\e[0;33m"
|
||||||
|
E="\e[0;31m"
|
||||||
|
|
||||||
|
# check if executed by root or sudo
|
||||||
|
if (( ! `id -u` == 0 )); then
|
||||||
|
echo -e "${E}Please do run as root or with sudo${N}"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check if the user uses Bash
|
||||||
|
if [[ ! $BASH_VERSION ]]; then
|
||||||
|
echo -e "\n\e[1;33mThis tool is written for Bash, its compatibility is not tested with other shells.\e[0m"
|
||||||
|
echo -e "You are currently using \e[1;31m $SHELL\e[0m, do you want to continue? [\e[1;32mY\e[0m/\e[1;31mn\e[0m]\n"
|
||||||
|
read -n 1 -r
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ERRORCOUNT=0
|
||||||
|
|
||||||
|
if [[ -f "/etc/ssh/sshd_config" ]]; then
|
||||||
|
echo -e "${T}# setup ssh server (/etc/ssh/sshd_config) to not print MOTD or LASTLOGIN${N}"
|
||||||
|
sed -ri 's/^(\#?)(PrintMotd|PrintLastLog)([[:space:]]+)(yes|no)/\2\3no/' /etc/ssh/sshd_config
|
||||||
|
resultsshno=$(/usr/bin/grep -E "PrintMotd\s+(no)?|\PrintLastLog\s+(no)?" /etc/ssh/sshd_config 2>/dev/null)
|
||||||
|
if [[ $resultsshno == "" ]]; then
|
||||||
|
echo -e "${E}FAIL - check manually \"PrintMotd no\" & \"PrintLastLog no\"${N}\n"
|
||||||
|
((ERRORCOUNT++))
|
||||||
|
else
|
||||||
|
echo -e "$resultsshno" | /usr/bin/grep --color=auto "no"
|
||||||
|
echo -e "${S}DONE${N}\n"
|
||||||
|
fi
|
||||||
|
echo -e "${T}# setup ssh server (/etc/ssh/sshd_config) to accept custom SSH_MOTD env variable${N}"
|
||||||
|
sed -ri '/SSH_MOTD/! s/^(\#?)(AcceptEnv)(.+)/\2\3 SSH_MOTD/' /etc/ssh/sshd_config
|
||||||
|
resultsshmotd=$(/usr/bin/grep -E "^AcceptEnv.+SSH_MOTD" /etc/ssh/sshd_config 2>/dev/null)
|
||||||
|
if [[ $resultsshmotd == "" ]]; then
|
||||||
|
echo -e "${E}FAIL - check manually \"AcceptEnv SSH_MOTD\"${N}\n"
|
||||||
|
((ERRORCOUNT++))
|
||||||
|
else
|
||||||
|
echo -e "$resultsshmotd" | /usr/bin/grep --color=auto "SSH_MOTD"
|
||||||
|
echo -e "${S}DONE${N}\n"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${E}/etc/ssh/sshd_config DOES NOT EXIST${N}\n"
|
||||||
|
((ERRORCOUNT++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${T}# setup PAM's sshd (/etc/pam.d/sshd) to not print MOTD and MAIL${N}"
|
||||||
|
if [[ -f "/etc/pam.d/sshd" ]]; then
|
||||||
|
sed -ri 's/^(\#?)(session[[:space:]]+optional[[:space:]]+)(pam_motd.so|pam_mail.so)(.+)/#\2\3\4/' /etc/pam.d/sshd
|
||||||
|
resultpamcom=$(/usr/bin/grep -E "^\#.+pam_motd.so|^\#.+pam_mail.so" /etc/pam.d/sshd 2>/dev/null)
|
||||||
|
if [[ $resultpamcom == "" ]]; then
|
||||||
|
echo -e "${E}FAIL - comment manually lines with \"pam_motd.so\" & \"pam_mail.so\"${N}\n"
|
||||||
|
((ERRORCOUNT++))
|
||||||
|
else
|
||||||
|
echo -e "$resultpamcom" | /usr/bin/grep --color=auto -E "^\#"
|
||||||
|
echo -e "${S}DONE${N}\n"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${E}FAIL - /etc/pam.d/sshd DOES NOT EXIST${N}\n"
|
||||||
|
((ERRORCOUNT++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${T}# restart ssh server if it's active${N}"
|
||||||
|
if [[ $(systemctl is-active ssh 2>/dev/null) == "active" ]]; then
|
||||||
|
systemctl restart ssh.service
|
||||||
|
echo -e "${S}DONE${N}\n"
|
||||||
|
else
|
||||||
|
echo -e "${E}SSHD NOT ACTIVE${N}\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${T}# install minimal dependencies${N}"
|
||||||
|
apt install -f figlet coreutils bc wget nano dnsutils openssl s-nail
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${T}# install ANSI_Shadow figlet font${N}"
|
||||||
|
downloadfigletfont=$(wget -nv -O "/usr/share/figlet/ANSI Shadow.flf" https://raw.githubusercontent.com/xero/figlet-fonts/master/ANSI%20Shadow.flf)
|
||||||
|
if $downloadfigletfont ; then
|
||||||
|
echo -e "${S}DONE${N}\n"
|
||||||
|
else
|
||||||
|
echo -e "${E}FAIL${N}\n"
|
||||||
|
((ERRORCOUNT++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${T}# check directories & backup old & obsolete files${N}"
|
||||||
|
if [[ ! -d "/etc/update-motd.d/backup" ]]; then
|
||||||
|
mkdir -vp /etc/update-motd.d/backup
|
||||||
|
fi
|
||||||
|
if [[ ! -d "/etc/motdfetch" ]]; then
|
||||||
|
mkdir -vp /etc/motdfetch
|
||||||
|
fi
|
||||||
|
chmod -v 755 /etc/update-motd.d/ /etc/update-motd.d/backup/ 2>/dev/null
|
||||||
|
echo -e "${S}CHMOD DONE${N}\n"
|
||||||
|
if [[ -d "/etc/update-motd.d/motdfetch.d" ]]; then
|
||||||
|
cp -p -Rv /etc/update-motd.d/*motdfetch* /etc/update-motd.d/backup/ 2>/dev/null
|
||||||
|
echo -e "${S}MOTDfetch BACKUP DONE${N}"
|
||||||
|
fi
|
||||||
|
if [[ -d "/etc/motd" ]]; then
|
||||||
|
mkdir -vp /etc/update-motd.d/backup/etc
|
||||||
|
mv -vf /etc/motd /etc/update-motd.d/backup/etc/motd 2>/dev/null
|
||||||
|
echo -e "${S}Static MOTD BACKUP DONE${N}"
|
||||||
|
fi
|
||||||
|
if [[ -d "/etc/update-motd.d/10-uname" ]]; then
|
||||||
|
mv -vf /etc/update-motd.d/10-uname /etc/update-motd.d/backup/10-uname 2>/dev/null
|
||||||
|
echo -e "${S}Debian uname MOTD BACKUP DONE${N}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${T}# install/update MOTDfetch${N}"
|
||||||
|
downloadmotd=$(wget -c -nv https://git.tkapias.net/tkapias/MOTDfetch/archive/master.tar.gz -O - \
|
||||||
|
| tar -xz --strip-components=1 -C /etc/update-motd.d/ MOTDfetch-master/motdfetch.d/ MOTDfetch-master/00-motdfetch MOTDfetch-master/motdfetch.sample.conf 2>/dev/null)
|
||||||
|
if $downloadmotd ; then
|
||||||
|
mv -vf /etc/update-motd.d/motdfetch.sample.conf /etc/motdfetch/motdfetch.sample.conf
|
||||||
|
if [[ -f "/etc/motdfetch/motdfetch.conf" ]]; then
|
||||||
|
echo -e "${S}SUCCESSFUL UPDATE${N}\n"
|
||||||
|
else
|
||||||
|
cp -p -Rv /etc/motdfetch/motdfetch.sample.conf /etc/motdfetch/motdfetch.conf
|
||||||
|
echo -e "${S}SUCCESSFUL INSTALLATION${N}\n"
|
||||||
|
fi
|
||||||
|
if (( $ERRORCOUNT == 1 )); then
|
||||||
|
echo -e "${W}But CAUTION, $ERRORCOUNT configuration steps have failed.${N} Please check if you need to adjust manually.\n"
|
||||||
|
elif (( $ERRORCOUNT > 1 )); then
|
||||||
|
echo -e "${W}But CAUTION, $ERRORCOUNT configuration step has failed.${N} Please check if you need to adjust manually.\n"
|
||||||
|
fi
|
||||||
|
echo -e " - ${S}edit the config file${N}:
|
||||||
|
# sudo nano /etc/motdfetch/motdfetch.conf
|
||||||
|
${S}or create a new user config${N}:
|
||||||
|
# userdir=~/.config/motdfetch \\
|
||||||
|
&& mkdir \$userdir \\
|
||||||
|
&& cp /etc/motdfetch/motdfetch.sample.conf \$userdir/motdfetch.conf \\
|
||||||
|
&& nano \$userdir/motdfetch.conf\n"
|
||||||
|
echo -e " - ${S}add an alias \"motd\" command to your .bashrc${N}:\n alias motd='/etc/update-motd.d/00-motdfetch'\n"
|
||||||
|
echo -e " - ${S}how to use MOTDfetch as an alternative MOTD for SSH sessions${N}:
|
||||||
|
+ ${S}on the ssh server, add the new \"motd\" alias at the end of the ssh user .bashrc${N}:
|
||||||
|
if [[ -n \$SSH_CONNECTION ]]; then\n motd\n fi
|
||||||
|
+ ${S}on the ssh client, add an alias \"sshmotd\" to your .bashrc${N}:\n alias sshmotd='ssh -o SetEnv=SSH_MOTD=1'\n"
|
||||||
|
else
|
||||||
|
echo -e "${E}INSTALLATION FAILED - please retry${N}\n"
|
||||||
|
fi
|
81
motdfetch.d/00-header
Normal file
81
motdfetch.d/00-header
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# display a custom decorative text (default to username)
|
||||||
|
# + welcome the username + date, time and timezone
|
||||||
|
# + inform of mail presence for user (if s-nail is installed)
|
||||||
|
#
|
||||||
|
# requirements: sudo apt install figlet
|
||||||
|
# sudo wget --no-check-certificate -O "/usr/share/figlet/ansi-shadow.flf" https://raw.githubusercontent.com/xero/figlet-fonts/master/ANSI%20Shadow.flf
|
||||||
|
# optionnal: sudo apt install s-nail
|
||||||
|
|
||||||
|
# GENERAL ###########################################################
|
||||||
|
|
||||||
|
# locale env
|
||||||
|
unset LC_ALL
|
||||||
|
export LC_MESSAGES=C
|
||||||
|
|
||||||
|
# check if module was disabled
|
||||||
|
module_disable=${module_header_disable:=0}
|
||||||
|
if (($module_disable == 1)); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# colors
|
||||||
|
c_txt=${c_txt:="39"}
|
||||||
|
c_txt_emphase=${c_txt_emphase:="35"}
|
||||||
|
c_txt_deco=${c_txt_deco:="97"}
|
||||||
|
c_txt_invert=${c_txt_invert:="30"}
|
||||||
|
c_bg=${c_bg_sec:="47"}
|
||||||
|
c_danger=${c_danger:="31"}
|
||||||
|
c_warning=${c_warning:="33"}
|
||||||
|
c_success=${c_success:="32"}
|
||||||
|
c_title=${c_title:="${c_bg};1;${c_txt_invert}m"}
|
||||||
|
|
||||||
|
# OPTIONS ###########################################################
|
||||||
|
|
||||||
|
# banner custom text or username
|
||||||
|
username=$(/usr/bin/id -un)
|
||||||
|
header_text=${module_header_text:="$username"}
|
||||||
|
|
||||||
|
# PREPARATIONS ######################################################
|
||||||
|
|
||||||
|
# check if s-nail is available and if you have mail
|
||||||
|
if command -v s-nail 1>/dev/null; then
|
||||||
|
# check mail for user
|
||||||
|
if /usr/bin/s-nail -e; then
|
||||||
|
hasmail=$(echo -e " You have \e[1;${c_success}mmessages\e[0m.")
|
||||||
|
|
||||||
|
else
|
||||||
|
hasmail=$(echo -e " You have no messages.")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
hasmail=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# trim banner text
|
||||||
|
header_text_width=${#header_text}
|
||||||
|
figlet_width=$(/usr/bin/env figlet -f "ANSI Shadow" "$header_text" | wc -L)
|
||||||
|
while [[ $figlet_width -ge 73 ]]; do
|
||||||
|
let "header_text_width-=1"
|
||||||
|
header_text=$(echo -e "${header_text:0:$header_text_width}...")
|
||||||
|
figlet_width=$(/usr/bin/env figlet -f "ANSI Shadow" "$header_text" | wc -L)
|
||||||
|
done
|
||||||
|
|
||||||
|
# OUTPUT ############################################################
|
||||||
|
|
||||||
|
if [[ $module_header_text != "$username" ]]; then
|
||||||
|
/usr/bin/env figlet -f "ANSI Shadow" "$header_text" \
|
||||||
|
| sed "$d" \
|
||||||
|
| sed "s/^/ /" \
|
||||||
|
| echo -e "$(sed "1 s/^/\\\e[${c_txt_emphase}m/")" \
|
||||||
|
| echo -e "$(sed "$ s/$/\\\e[0m/")"
|
||||||
|
echo -e " \e[1;${c_txt}mWelcome \e[${c_txt_emphase}m${username}\e[${c_txt}m, it is \e[${c_txt_emphase}m$(date +"%Y-%m-%d %H:%M:%S %z")\e[${c_txt}m.\e[0m\n${hasmail}"
|
||||||
|
else
|
||||||
|
echo -e " Welcome"
|
||||||
|
/usr/bin/env figlet -f "ANSI Shadow" "$header_text" \
|
||||||
|
| sed "$d" \
|
||||||
|
| sed "s/^/ /" \
|
||||||
|
| echo -e "$(sed "1 s/^/\\\e[${c_txt_emphase}m/")" \
|
||||||
|
| echo -e "$(sed "$ s/$/\\\e[0m/")"
|
||||||
|
echo -e " \e[1;${c_txt}mIt is \e[${c_txt_emphase}m$(date +"%Y-%m-%d %H:%M:%S %z")\e[${c_txt}m.\e[0m\n${hasmail}"
|
||||||
|
fi
|
149
motdfetch.d/01-sysinfo
Normal file
149
motdfetch.d/01-sysinfo
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# display a list of system informations
|
||||||
|
# + dig and curl have shorts timeouts to not hang the script
|
||||||
|
#
|
||||||
|
# requirements: sudo apt install dnsutils
|
||||||
|
|
||||||
|
# GENERAL ###########################################################
|
||||||
|
|
||||||
|
# locale env
|
||||||
|
unset LC_ALL
|
||||||
|
export LC_MESSAGES=C
|
||||||
|
|
||||||
|
# check if module was disabled
|
||||||
|
module_disable=${module_sysinfo_disable:=0}
|
||||||
|
if (($module_disable == 1)); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# colors
|
||||||
|
c_txt=${c_txt:="39"}
|
||||||
|
c_txt_emphase=${c_txt_emphase:="35"}
|
||||||
|
c_txt_deco=${c_txt_deco:="97"}
|
||||||
|
c_txt_invert=${c_txt_invert:="30"}
|
||||||
|
c_bg=${c_bg_sec:="47"}
|
||||||
|
c_danger=${c_danger:="31"}
|
||||||
|
c_warning=${c_warning:="33"}
|
||||||
|
c_success=${c_success:="32"}
|
||||||
|
c_title=${c_title:="${c_bg};1;${c_txt_invert}m"}
|
||||||
|
|
||||||
|
# api website name for plain public IP4/6 check
|
||||||
|
publicip_api=${global_publicip_api:="icanhazip.com"}
|
||||||
|
|
||||||
|
# PREPARATIONS ######################################################
|
||||||
|
|
||||||
|
# output header
|
||||||
|
echo -e "\nWaiting for DNS and IP checks\e[5m...\e[0m"
|
||||||
|
|
||||||
|
# get hostname
|
||||||
|
HOSTNAME=`hostname -f`
|
||||||
|
# get distribution name
|
||||||
|
DISTRO=`/usr/bin/cat /etc/*release | /usr/bin/grep "PRETTY_NAME" | cut -d "=" -f 2- | sed 's/"//g'`
|
||||||
|
# get name of main interface with a route for internet
|
||||||
|
INTERNETIFACE="$(ip -o route get 8/32 2>/dev/null)"
|
||||||
|
if [[ "$INTERNETIFACE" ]]; then
|
||||||
|
INTERNETIFACE=`echo -e "$INTERNETIFACE" | sed -e 's/.*dev //' -e 's/ .*//'`
|
||||||
|
else
|
||||||
|
INTERNETIFACE="\e[1;${c_warning}mno interface with a route to 8/32\e[0;${c_txt}m"
|
||||||
|
fi
|
||||||
|
# get DNS servers ips from resolv.conf
|
||||||
|
DNSSERVERS=`/usr/bin/grep '^nameserver' /etc/resolv.conf | cut -d' ' -f2 | paste -sd ','`
|
||||||
|
if [[ ! $DNSSERVERS ]];then
|
||||||
|
DNSSERVERS="\e[1;${c_warning}mno ns in resolv.conf\e[0;${c_txt}m"
|
||||||
|
fi
|
||||||
|
# get current output public IPs and their revers DNS record
|
||||||
|
PUBLICIP4=`timeout 6 curl -s -4 $publicip_api 2>/dev/null`
|
||||||
|
if [[ $PUBLICIP4 ]];then
|
||||||
|
IP4PTR=`timeout 4 dig +short -x $PUBLICIP4 @1.1.1.1 2>/dev/null`
|
||||||
|
if [[ ! $IP4PTR ]];then
|
||||||
|
IP4PTR="\e[0;${c_txt}mno data"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
IP4PTR="\e[0;${c_txt}mno data"
|
||||||
|
PUBLICIP4="\e[1;5;${c_warning}mno IPv4 internet\e[0;${c_txt}m"
|
||||||
|
INTERNET_IP4=0
|
||||||
|
fi
|
||||||
|
PUBLICIP6=`timeout 6 curl -s -6 $publicip_api 2>/dev/null`
|
||||||
|
if [[ $PUBLICIP6 ]];then
|
||||||
|
IP6PTR=`timeout 4 dig +short -x $PUBLICIP6 @1.1.1.1 2>/dev/null`
|
||||||
|
if [[ ! $IP6PTR ]];then
|
||||||
|
IP6PTR="\e[0;${c_txt}mno data"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
IP6PTR="\e[0;${c_txt}mno data"
|
||||||
|
PUBLICIP6="\e[1;${c_warning}mno ipv6 internet\e[0;${c_txt}m"
|
||||||
|
INTERNET_IP6=0
|
||||||
|
fi
|
||||||
|
INTERNET_OUT=0
|
||||||
|
if [[ $INTERNET_IP4 && $INTERNET_IP6 ]]; then
|
||||||
|
INTERNET_OUT=1
|
||||||
|
fi
|
||||||
|
# get DNS records of the FQDN
|
||||||
|
HOSTNAMEIP4=`timeout 4 dig +short A $HOSTNAME @1.1.1.1 2>/dev/null`
|
||||||
|
if [[ ! $HOSTNAMEIP4 ]];then
|
||||||
|
HOSTNAMEIP4="\e[0;${c_txt}mno data"
|
||||||
|
fi
|
||||||
|
HOSTNAMEIP6=`timeout 4 dig +short AAAA $HOSTNAME @1.1.1.1 2>/dev/null`
|
||||||
|
if [[ ! $HOSTNAMEIP6 ]];then
|
||||||
|
HOSTNAMEIP6="\e[0;${c_txt}mno data"
|
||||||
|
fi
|
||||||
|
# get processes
|
||||||
|
PROCESS=`/usr/bin/ps -eo user= | sort | uniq -c | awk '{ print $2 " " $1 }'`
|
||||||
|
PROCESS_ALL=`echo "$PROCESS" | awk {'print $2'} | awk '{ SUM += $1} END { print SUM }'`
|
||||||
|
PROCESS_ROOT=`echo "$PROCESS" | /usr/bin/grep root | awk {'print $2'}`
|
||||||
|
PROCESS_USER=`echo "$PROCESS" | /usr/bin/grep -v root | awk {'print $2'} | awk '{ SUM += $1} END { print SUM }'`
|
||||||
|
# get processors
|
||||||
|
PROCESSOR_NAME=`/usr/bin/grep "model name" /proc/cpuinfo | cut -d ' ' -f3- | awk {'print $0'} | head -1 | sed -e 's/([^()]*)/ /g' -e 's/\s\+/ /g'`
|
||||||
|
PROCESSOR_COUNT=`/usr/bin/grep -ioPc 'processor\t:' /proc/cpuinfo 2>/dev/null`
|
||||||
|
# get load averages
|
||||||
|
IFS=" " read LOAD1 LOAD5 LOAD15 <<<$(cat /proc/loadavg | awk '{ print $1,$2,$3 }')
|
||||||
|
if [[ $(echo "$LOAD1 > $(echo "$PROCESSOR_COUNT + ($PROCESSOR_COUNT / 3)" | bc -l )" | bc) == 1 ]]; then
|
||||||
|
LOAD1="\e[1;5;${c_danger}m$LOAD1\e[0;${c_txt}m"
|
||||||
|
elif [[ $(echo "$LOAD1 > $(echo "$PROCESSOR_COUNT - ($PROCESSOR_COUNT / 3)" | bc -l )" | bc) == 1 ]]; then
|
||||||
|
LOAD1="\e[1;5;${c_warning}m$LOAD1\e[0;${c_txt}m"
|
||||||
|
fi
|
||||||
|
if [[ $(echo "$LOAD5 > $(echo "$PROCESSOR_COUNT * 2" | bc -l )" | bc) == 1 ]]; then
|
||||||
|
LOAD2="\e[1;5;${c_warning}m$LOAD5\e[0;${c_txt}m"
|
||||||
|
fi
|
||||||
|
if [[ $(echo "$LOAD15 > $(echo "$PROCESSOR_COUNT * 2" | bc -l )" | bc) == 1 ]]; then
|
||||||
|
LOAD3="\e[1;5;${c_warning}m$LOAD15\e[0;${c_txt}m"
|
||||||
|
fi
|
||||||
|
# get free memory
|
||||||
|
IFS=" " read USED AVAIL TOTAL <<<$(free -htm | /usr/bin/grep "Mem" | awk {'print $3,$7,$2'})
|
||||||
|
# get free swap
|
||||||
|
IFS=" " read SUSED SAVAIL STOTAL <<<$(free -htm | /usr/bin/grep "Swap" | awk {'print $3,$4,$2'})
|
||||||
|
|
||||||
|
# OUTPUT ############################################################
|
||||||
|
|
||||||
|
W="\e[0;${c_txt}m"
|
||||||
|
X="\e[1;${c_txt}m"
|
||||||
|
G="\e[1;${c_txt_emphase}m"
|
||||||
|
N="\e[0m"
|
||||||
|
echo -e "\e[1A\e[${c_title} System information $N
|
||||||
|
|
||||||
|
$X Distro$W..........: $DISTRO
|
||||||
|
$X Kernel$W..........: `uname -sr`
|
||||||
|
$X Uptime$W..........: $G`uptime -p`$W
|
||||||
|
|
||||||
|
$X CPU$W.............: $PROCESSOR_NAME
|
||||||
|
$X CPU cores$W.......: $G$PROCESSOR_COUNT$W
|
||||||
|
$X Load$W............: $G$LOAD1$W (1m), $G$LOAD5$W (5m), $G$LOAD15$W (15m)
|
||||||
|
$X Processes$W.......: $G$PROCESS_ROOT$W (root), $G$PROCESS_USER$W (user), $G$PROCESS_ALL$W (total)
|
||||||
|
$X Memory$W..........: $G$USED$W used, $G$AVAIL$W avail, $G$TOTAL$W total$N"
|
||||||
|
if [[ ${SUSED} ]]; then
|
||||||
|
echo -e "$X Swap$W............: $G$SUSED$W used, $G$SAVAIL$W avail, $G$STOTAL$W total$W"
|
||||||
|
else
|
||||||
|
echo -e "$X Swap$W............: \e[1;${c_warning}mno Swap$W"
|
||||||
|
fi
|
||||||
|
echo -e "
|
||||||
|
$X Hostname/FQDN$W...: $G$(hostname)$W / $G$(hostname -f)$W
|
||||||
|
$X Internet Iface$W..: $G$INTERNETIFACE$W
|
||||||
|
$X DNS servers$W.....: $G$(echo -e "${DNSSERVERS}" | sed "s/,/\\\e[0m, \\\e[1;${c_txt_emphase}m/g")$N"
|
||||||
|
if [[ ${INTERNET_OUT} == 0 ]]; then
|
||||||
|
echo -e "$X Public IP4/IP6$W..: $G$PUBLICIP4$W / $G$PUBLICIP6$N"
|
||||||
|
else
|
||||||
|
echo -e "$X Public IP4/IP6$W..: \e[1;${c_warning}mno internet or "${publicip_api}" timeout$N"
|
||||||
|
fi
|
||||||
|
echo -e "$X PTR IP4/IP6$W.....: $G$IP4PTR$W / $G$IP6PTR$W
|
||||||
|
$X FQDN A/AAAA$W.....: $G$HOSTNAMEIP4$W / $G$HOSTNAMEIP6$N"
|
143
motdfetch.d/02-services
Normal file
143
motdfetch.d/02-services
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# check status of a list of systemd service units
|
||||||
|
# + accept service name with or without extension (.service)
|
||||||
|
# + default to system wide services but accept --user services with the :uid
|
||||||
|
# + alarm by bullet coloration and blinking
|
||||||
|
#
|
||||||
|
# requirements: systemd
|
||||||
|
|
||||||
|
# GENERAL ###########################################################
|
||||||
|
|
||||||
|
# locale env
|
||||||
|
unset LC_ALL
|
||||||
|
export LC_MESSAGES=C
|
||||||
|
|
||||||
|
# check if module was disabled
|
||||||
|
module_disable=${module_services_disable:=0}
|
||||||
|
if (($module_disable == 1)); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# colors
|
||||||
|
c_txt=${c_txt:="39"}
|
||||||
|
c_txt_emphase=${c_txt_emphase:="35"}
|
||||||
|
c_txt_deco=${c_txt_deco:="97"}
|
||||||
|
c_txt_invert=${c_txt_invert:="30"}
|
||||||
|
c_bg=${c_bg_sec:="47"}
|
||||||
|
c_danger=${c_danger:="31"}
|
||||||
|
c_warning=${c_warning:="33"}
|
||||||
|
c_success=${c_success:="32"}
|
||||||
|
c_title=${c_title:="${c_bg};1;${c_txt_invert}m"}
|
||||||
|
|
||||||
|
# OPTIONS ###########################################################
|
||||||
|
|
||||||
|
# array of services
|
||||||
|
if [[ $module_services ]]; then
|
||||||
|
services=(${module_services[@]})
|
||||||
|
else
|
||||||
|
services=("cron.service" "dbus.service:1000" "user2service:1002")
|
||||||
|
fi
|
||||||
|
IFS=$'\n' services=($(sort <<<"${services[*]}"))
|
||||||
|
unset IFS
|
||||||
|
|
||||||
|
# column max-width
|
||||||
|
width=${module_services_width:="80"}
|
||||||
|
|
||||||
|
# PREPARATIONS ######################################################
|
||||||
|
|
||||||
|
# get status
|
||||||
|
# + dim status if the service does not exist or if the user is not root and the service has another uid
|
||||||
|
serviceStatus=()
|
||||||
|
for service in "${services[@]}"; do
|
||||||
|
uid=${service/*:/}
|
||||||
|
# script executed as root and the service to check is from a user
|
||||||
|
if [[ $service = *:* ]] && [[ "$(id -u)" == "0" ]]; then
|
||||||
|
service=${service/.service/}
|
||||||
|
service=${service/:[0-9]*/}
|
||||||
|
serviceexist=$(machinectl -q shell --uid="$uid" .host /usr/bin/systemctl list-units --user -q --plain --no-pager --full --all -t service 2>/dev/null \
|
||||||
|
| awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }' \
|
||||||
|
| /usr/bin/grep "$service")
|
||||||
|
if [[ "$serviceexist" ]] ;then
|
||||||
|
status=$(machinectl -q shell --uid="$uid" .host /usr/bin/systemctl is-active --user "$service")
|
||||||
|
if [[ $status = inactive* ]]; then
|
||||||
|
serviceStatus+=("inactive")
|
||||||
|
elif [[ $status = active* ]]; then
|
||||||
|
serviceStatus+=("active")
|
||||||
|
else
|
||||||
|
serviceStatus+=("hidden")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
serviceStatus+=("hidden")
|
||||||
|
fi
|
||||||
|
# script executed by the same user as the service user
|
||||||
|
elif [[ $service = *:* ]] && [[ "$(id -u)" == "$uid" ]]; then
|
||||||
|
service=${service/.service/}
|
||||||
|
service=${service/:[0-9]*/}
|
||||||
|
serviceexist=$(/usr/bin/systemctl list-units --user -q --plain --no-pager --full --all -t service 2>/dev/null \
|
||||||
|
| awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }' \
|
||||||
|
| /usr/bin/grep "$service")
|
||||||
|
if [[ "$serviceexist" ]] ;then
|
||||||
|
serviceStatus+=($(/usr/bin/systemctl --user is-active "$service"))
|
||||||
|
else
|
||||||
|
serviceStatus+=("hidden")
|
||||||
|
fi
|
||||||
|
# script executed by another user than root and than the service user
|
||||||
|
elif [[ $service = *:* ]]; then
|
||||||
|
serviceStatus+=("hidden")
|
||||||
|
# system service
|
||||||
|
else
|
||||||
|
service=${service/.service/}
|
||||||
|
service=${service/:[0-9]*/}
|
||||||
|
serviceexist=$(/usr/bin/systemctl list-units -q --plain --no-pager --full --all -t service 2>/dev/null \
|
||||||
|
| awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }' \
|
||||||
|
| /usr/bin/grep "$service")
|
||||||
|
if [[ "$serviceexist" ]] ;then
|
||||||
|
serviceStatus+=($(/usr/bin/systemctl is-active "$service"))
|
||||||
|
else
|
||||||
|
serviceStatus+=("hidden")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# OUTPUT ############################################################
|
||||||
|
|
||||||
|
# output header
|
||||||
|
echo -e "\n\e[${c_title} Services checks \e[0m\n"
|
||||||
|
|
||||||
|
# output checklist
|
||||||
|
line=" "
|
||||||
|
lineLen=1
|
||||||
|
for i in "${!serviceStatus[@]}"
|
||||||
|
do
|
||||||
|
service=${services[$i]/.service/}
|
||||||
|
service=${service^}
|
||||||
|
|
||||||
|
# Next line and next line length
|
||||||
|
next=" $service "
|
||||||
|
nextLen=$((1+${#next}))
|
||||||
|
|
||||||
|
# If the current line will exceed the max column with then echo and start a new line
|
||||||
|
if [[ $((lineLen+nextLen)) -gt $width ]]; then
|
||||||
|
echo -e "$line"
|
||||||
|
lineLen=1
|
||||||
|
line=" "
|
||||||
|
fi
|
||||||
|
|
||||||
|
lineLen=$((lineLen+nextLen))
|
||||||
|
|
||||||
|
# Color the next line green if it's active, red if inactive, else orange
|
||||||
|
if [[ "${serviceStatus[$i]}" == "active" ]]
|
||||||
|
then
|
||||||
|
line+=" \e[${c_success}m●\e[0m \e[${c_txt}m$service\e[0m "
|
||||||
|
elif [[ "${serviceStatus[$i]}" == "inactive" ]]
|
||||||
|
then
|
||||||
|
line+=" \e[1;5;${c_danger}m▲\e[0m \e[1;${c_txt}m$service\e[0m "
|
||||||
|
else
|
||||||
|
line+=" \e[1;2;${c_warning}m▲\e[0m \e[1;2;${c_txt}m$service\e[0m "
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# echo what is left
|
||||||
|
echo -e "$line"
|
||||||
|
|
227
motdfetch.d/03-filesystem
Normal file
227
motdfetch.d/03-filesystem
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# status of mounted filesystems in 2 steps
|
||||||
|
# 1. use "df" for general fs except zfs, squashfs, tmpfs, devtmpfs and overlay
|
||||||
|
# 2. use "zpool" for ZFS pools
|
||||||
|
# + displays name, filesystem type, used blocks and inodes or pool health when relevant
|
||||||
|
# + custom warn threshold for blocks
|
||||||
|
# + warn threshold for inodes (80%), flashing danger threshold for health, blocks (95%) and inodes (90%)
|
||||||
|
#
|
||||||
|
# requirements: sudo apt install coreutils
|
||||||
|
# optionnal: sudo apt install zfsutils-linux
|
||||||
|
|
||||||
|
# GENERAL ###########################################################
|
||||||
|
|
||||||
|
# locale env
|
||||||
|
unset LC_ALL
|
||||||
|
export LC_MESSAGES=C
|
||||||
|
|
||||||
|
# check if module was disabled
|
||||||
|
module_disable=${module_filesystem_disable:=0}
|
||||||
|
if (($module_disable == 1)); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# colors
|
||||||
|
c_txt=${c_txt:="39"}
|
||||||
|
c_txt_emphase=${c_txt_emphase:="35"}
|
||||||
|
c_txt_deco=${c_txt_deco:="97"}
|
||||||
|
c_txt_invert=${c_txt_invert:="30"}
|
||||||
|
c_bg=${c_bg_sec:="47"}
|
||||||
|
c_danger=${c_danger:="31"}
|
||||||
|
c_warning=${c_warning:="33"}
|
||||||
|
c_success=${c_success:="32"}
|
||||||
|
c_title=${c_title:="${c_bg};1;${c_txt_invert}m"}
|
||||||
|
|
||||||
|
# OPTIONS ###########################################################
|
||||||
|
|
||||||
|
# max usage warning threshold
|
||||||
|
max_usage=${module_filesystem_max_usage:="85"}
|
||||||
|
|
||||||
|
# disable ZFS section
|
||||||
|
zfs_disable=${module_filesystem_zfs_disable:=0}
|
||||||
|
|
||||||
|
# PREPARATIONS ######################################################
|
||||||
|
|
||||||
|
# disk usage: ignore zfs, squashfs & tmpfs, standard error output because of a bug with /run/user/1000/doc
|
||||||
|
dfcmd=$(/usr/bin/df -H -x zfs -x squashfs -x tmpfs -x devtmpfs -x overlay --output 2>/dev/null)
|
||||||
|
mapfile -t dfoutput < <(echo "$dfcmd" | tail -n+2)
|
||||||
|
|
||||||
|
# determine best width for the bar
|
||||||
|
largesttarget=$(echo "$dfcmd" | awk '{if (length ($12)>max) max=length($12)} END {print max}')
|
||||||
|
if [[ $((largesttarget+30)) -gt 50 ]]; then
|
||||||
|
bar_width=$((largesttarget+30))
|
||||||
|
else
|
||||||
|
bar_width="50"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# OUTPUT ############################################################
|
||||||
|
|
||||||
|
# general filesystems
|
||||||
|
linecounter=0
|
||||||
|
if [[ "${dfoutput[@]}" ]]; then
|
||||||
|
# output header
|
||||||
|
echo -e "\n\e[${c_title} Filesystem usage \e[0m\n"
|
||||||
|
# output filesystem status except ZFS
|
||||||
|
for line in "${dfoutput[@]}"; do
|
||||||
|
# parse df output
|
||||||
|
diskid=$(echo "$line" | awk '{print $12}')
|
||||||
|
diskused=$(echo "$line" | awk '{print $10}'| sed 's/%//')
|
||||||
|
disktotal=$(echo "$line" | awk '{print $7}')
|
||||||
|
fsformat=$(echo "$line" | awk '{print $2}')
|
||||||
|
inodesused=$(echo "$line" | awk '{print $6}'| sed 's/%//')
|
||||||
|
inodestotal=$(echo "$line" | awk '{print $3}')
|
||||||
|
|
||||||
|
# bar & blocks coloration, danger red above 95%
|
||||||
|
if [[ "${diskused}" -ge "95" ]]; then
|
||||||
|
barcolor="\e[1;${c_danger}m"
|
||||||
|
blockscolor="\e[1;${c_danger}m"
|
||||||
|
flashing="\e[5m"
|
||||||
|
elif [ "${diskused}" -ge "${max_usage}" ]; then
|
||||||
|
barcolor="\e[1;${c_warning}m"
|
||||||
|
blockscolor="\e[1;${c_warning}m"
|
||||||
|
flashing=""
|
||||||
|
else
|
||||||
|
barcolor="\e[1;${c_success}m"
|
||||||
|
blockscolor="\e[${c_txt}m"
|
||||||
|
flashing=""
|
||||||
|
fi
|
||||||
|
# print colored bar until used_width
|
||||||
|
used_width=$(((diskused*$bar_width)/100))
|
||||||
|
bar="[${barcolor}"
|
||||||
|
for ((i=0; i<$used_width; i++)); do
|
||||||
|
bar+="="
|
||||||
|
done
|
||||||
|
# print dimmmed bar until end
|
||||||
|
bar+="\e[${c_txt}m\e[0m"
|
||||||
|
for ((i=$used_width; i<$bar_width; i++)); do
|
||||||
|
bar+="="
|
||||||
|
done
|
||||||
|
bar+="\e[0m]"
|
||||||
|
|
||||||
|
# print blocks usage line & bar
|
||||||
|
padding=$((bar_width-28))
|
||||||
|
if [[ $linecounter -ge 1 ]]
|
||||||
|
then
|
||||||
|
echo -e "\n"
|
||||||
|
fi
|
||||||
|
echo "${line}" | printf "\e[1;${c_txt_emphase}m%-${padding}s\e[0m${blockscolor}%+3s%% used ${flashing}blocks\e[0m out of %+4s\n" $diskid $diskused $disktotal | sed 's/^/ /'
|
||||||
|
echo -e "${bar}" | sed 's/^/ /'
|
||||||
|
|
||||||
|
# print filesystem type & inodes usage line
|
||||||
|
if [[ ! "$inodesused" == "-" ]]
|
||||||
|
then
|
||||||
|
padding=$((bar_width-34))
|
||||||
|
# inodes coloration, danger red above 90%
|
||||||
|
if [[ "${inodesused}" -ge "90" ]]; then
|
||||||
|
inodescolor="\e[1;${c_danger}m"
|
||||||
|
flashing="\e[5m"
|
||||||
|
elif [[ "${inodesused}" -ge "80" ]]; then
|
||||||
|
inodescolor="\e[1;${c_warning}m"
|
||||||
|
flashing=""
|
||||||
|
else
|
||||||
|
inodescolor="\e[${c_txt}m"
|
||||||
|
flashing=""
|
||||||
|
fi
|
||||||
|
echo "${line}" | printf "Type: %-${padding}s${inodescolor}%+3s%% used ${flashing}inodes\e[0m out of %+4s\n" $fsformat $inodesused $inodestotal | sed 's/^/ /'
|
||||||
|
else
|
||||||
|
echo "${line}" | printf "Type: %-10s\n" $fsformat | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
linecounter=$((linecounter+1))
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo " no general filesystem available, ZFS expected in next section"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check if ZFS section was disabled
|
||||||
|
if [[ $zfs_disable == 1 ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# output ZFS header
|
||||||
|
echo -e "\n\e[${c_title} Zpool usage \e[0m\n"
|
||||||
|
|
||||||
|
# check if zpool is available
|
||||||
|
if ! command -v zpool 1> /dev/null; then
|
||||||
|
echo " no ZFS tools available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ZFS zpool usage & health status
|
||||||
|
zlistcmd=$(zpool list -o name,cap,size,health 2> /dev/null)
|
||||||
|
if [[ $zlistcmd == "no pools available" ]]; then
|
||||||
|
echo " no ZFS pool available"
|
||||||
|
else
|
||||||
|
mapfile -t zpools < <(echo "$zlistcmd" | tail -n+2)
|
||||||
|
|
||||||
|
# determine best width for the bar
|
||||||
|
largesttarget=$(echo "zlistcmd" | awk '{if (length ($1)>max) max=length($1)} END {print max}')
|
||||||
|
if [[ $((largesttarget+30)) -gt 50 ]]; then
|
||||||
|
bar_width=$((largesttarget+30))
|
||||||
|
else
|
||||||
|
bar_width="50"
|
||||||
|
fi
|
||||||
|
|
||||||
|
linecounter=0
|
||||||
|
for line in "${zpools[@]}"; do
|
||||||
|
# parse zpool list output
|
||||||
|
poolid=$(echo "$line" | awk '{print $1}')
|
||||||
|
poolused=$(echo "$line" | awk '{print $2}'| sed 's/%//')
|
||||||
|
pooltotal=$(echo "$line" | awk '{print $3}')
|
||||||
|
poolhealth=$(echo "$line" | awk '{print $4}')
|
||||||
|
|
||||||
|
# bar & pools coloration, danger red above 95%
|
||||||
|
if [[ "${poolused}" -ge "95" ]]; then
|
||||||
|
barcolor="\e[1;${c_danger}m"
|
||||||
|
poolscolor="\e[1;${c_danger}m"
|
||||||
|
flashing="\e[5m"
|
||||||
|
elif [[ "${poolused}" -ge "${max_usage}" ]]; then
|
||||||
|
barcolor="\e[1;${c_warning}m"
|
||||||
|
poolscolor="\e[1;${c_warning}m"
|
||||||
|
flashing=""
|
||||||
|
else
|
||||||
|
barcolor="\e[1;${c_success}m"
|
||||||
|
poolscolor="\e[${c_txt}m"
|
||||||
|
flashing=""
|
||||||
|
fi
|
||||||
|
# print colored bar until used_width
|
||||||
|
used_width=$(((poolused*$bar_width)/100))
|
||||||
|
bar="[${barcolor}"
|
||||||
|
for ((i=0; i<$used_width; i++)); do
|
||||||
|
bar+="="
|
||||||
|
done
|
||||||
|
# print dimmmed bar until end
|
||||||
|
bar+="\e[${c_txt}m\e[0m"
|
||||||
|
for ((i=$used_width; i<$bar_width; i++)); do
|
||||||
|
bar+="="
|
||||||
|
done
|
||||||
|
bar+="\e[0m]"
|
||||||
|
|
||||||
|
# print pool usage line & bar
|
||||||
|
padding=$((bar_width-29))
|
||||||
|
if [[ $linecounter -ge 1 ]]
|
||||||
|
then
|
||||||
|
echo -e "\n"
|
||||||
|
fi
|
||||||
|
echo "${line}" | printf "\e[1;${c_txt_emphase}m%-${padding}s\e[0m${poolscolor}%+3s%% used ${flashing}blocks\e[0m out of %+5s\n" $poolid $poolused $pooltotal | sed 's/^/ /'
|
||||||
|
echo -e "${bar}" | sed 's/^/ /'
|
||||||
|
|
||||||
|
# print pool health line
|
||||||
|
padding=$((bar_width-34))
|
||||||
|
# health coloration, danger red for FAULTED
|
||||||
|
if [[ "${poolhealth}" == "FAULTED" ]]; then
|
||||||
|
healthcolor="\e[1;${c_danger}m"
|
||||||
|
flashing="\e[5m"
|
||||||
|
elif [[ "${poolhealth}" == "OFFLINE" ]] || [[ "${poolhealth}" == "UNAVAIL" ]] || [[ "${poolhealth}" == "REMOVED" ]] || [[ "${poolhealth}" == "DEGRADED" ]]; then
|
||||||
|
healthcolor="\e[1;${c_warning}m"
|
||||||
|
flashing=""
|
||||||
|
else
|
||||||
|
healthcolor="\e[${c_txt}m"
|
||||||
|
flashing=""
|
||||||
|
fi
|
||||||
|
padding=$((bar_width-17))
|
||||||
|
text="health"
|
||||||
|
echo "${line}" | printf "%+${padding}s status: ${healthcolor}${flashing}%+8s\e[0m\n" $text ${poolhealth,,} | sed 's/^/ /'
|
||||||
|
linecounter=$((linecounter+1))
|
||||||
|
done
|
||||||
|
fi
|
119
motdfetch.d/04-tls
Normal file
119
motdfetch.d/04-tls
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# check X.509 cert for a domain:port with openssl, for correspondance and expiration
|
||||||
|
# + by default the port is 443
|
||||||
|
# + there is a timeout of 6 sec and is there is no connectivity the check is skipped
|
||||||
|
#
|
||||||
|
# requirements: sudo apt install openssl
|
||||||
|
|
||||||
|
# GENERAL ###########################################################
|
||||||
|
|
||||||
|
# locale env
|
||||||
|
unset LC_ALL
|
||||||
|
export LC_MESSAGES=C
|
||||||
|
|
||||||
|
# check if module was disabled
|
||||||
|
module_disable=${module_tls_disable:=0}
|
||||||
|
if (($module_disable == 1)); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# colors
|
||||||
|
c_txt=${c_txt:="39"}
|
||||||
|
c_txt_emphase=${c_txt_emphase:="35"}
|
||||||
|
c_txt_deco=${c_txt_deco:="97"}
|
||||||
|
c_txt_invert=${c_txt_invert:="30"}
|
||||||
|
c_bg=${c_bg_sec:="47"}
|
||||||
|
c_danger=${c_danger:="31"}
|
||||||
|
c_warning=${c_warning:="33"}
|
||||||
|
c_success=${c_success:="32"}
|
||||||
|
c_title=${c_title:="${c_bg};1;${c_txt_invert}m"}
|
||||||
|
|
||||||
|
# api website name for plain public IP4/6 check
|
||||||
|
publicip_api=${global_publicip_api:="icanhazip.com"}
|
||||||
|
|
||||||
|
# OPTIONS ###########################################################
|
||||||
|
|
||||||
|
# domains:ports input
|
||||||
|
if [[ $module_tls_domains ]]
|
||||||
|
then
|
||||||
|
tls_domains=(${module_tls_domains[@]})
|
||||||
|
else
|
||||||
|
tls_domains=("www.google.com" "smtp.gmail.com:465")
|
||||||
|
fi
|
||||||
|
IFS=$'\n' tls_domains=($(sort <<<"${tls_domains[*]}"))
|
||||||
|
unset IFS
|
||||||
|
|
||||||
|
# PREPARATIONS ######################################################
|
||||||
|
|
||||||
|
# print loading message
|
||||||
|
echo -e "\nWaiting for TLS checks\e[5m...\e[0m"
|
||||||
|
|
||||||
|
# parse output
|
||||||
|
output=" \e[1;4;${c_txt}mDomain\e[24m|\e[4mPort\e[24m|\e[4mValid until\e[0m"
|
||||||
|
currentTime=$(date +%s)
|
||||||
|
|
||||||
|
# check if there is internet connectivity
|
||||||
|
INTERNET_OUT=0
|
||||||
|
PUBLICIP="$(timeout 6 curl -s $publicip_api 2>/dev/null)"
|
||||||
|
if [[ ! $PUBLICIP ]]; then
|
||||||
|
INTERNET_OUT=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# OUTPUT ############################################################
|
||||||
|
|
||||||
|
for domain in "${tls_domains[@]}"
|
||||||
|
do
|
||||||
|
if [[ $domain == *:* ]]
|
||||||
|
then
|
||||||
|
port=${domain/*:/}
|
||||||
|
domain=${domain/:*/}
|
||||||
|
else
|
||||||
|
port="443"
|
||||||
|
fi
|
||||||
|
if [[ $INTERNET_OUT == 0 ]]; then
|
||||||
|
# fetch cert
|
||||||
|
cert=""
|
||||||
|
cert=$(timeout 6 openssl s_client -servername ${domain} -connect ${domain}:${port} < /dev/null 2>/dev/null)
|
||||||
|
# fetch subject name with a 3 sec timeout
|
||||||
|
certSubj=$(echo -e "$cert" | openssl x509 -noout -subject 2>/dev/null)
|
||||||
|
# fetch expiration time
|
||||||
|
certTime=$(echo -e "$cert" | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
|
||||||
|
certLineTime=$(date -d "${certTime}" +"%F")
|
||||||
|
certTimestamp=$(date -d "${certTime}" +%s)
|
||||||
|
port="\e[${c_txt}m${port}\e[0m"
|
||||||
|
# check subject name with a 3 sec timeout
|
||||||
|
if [[ $certSubj == *${domain} ]]
|
||||||
|
then
|
||||||
|
domain="\e[${c_txt}m${domain}\e[0m"
|
||||||
|
# check expiration time - 3 days
|
||||||
|
if [[ "$((${certTimestamp} - 259200 ))" -ge "${currentTime}" ]]
|
||||||
|
then
|
||||||
|
sign="\e[${c_success}m●\e[0m"
|
||||||
|
result="\e[1;${c_success}m$certLineTime\e[0m"
|
||||||
|
# check expiration time today
|
||||||
|
elif [[ "${certTimestamp}" -ge "${currentTime}" ]]
|
||||||
|
then
|
||||||
|
sign="\e[1;${c_warning}m▲\e[0m"
|
||||||
|
result="\e[1;${c_warning}m${certLineTime}\e[0m"
|
||||||
|
else
|
||||||
|
sign="\e[1;5;${c_danger}m▲\e[0m"
|
||||||
|
result="\e[1;${c_danger}m$certLineTime\e[0m"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
domain="\e[${c_txt}m${domain}\e[0m"
|
||||||
|
sign="\e[1;2;${c_warning}m\U25B2\e[0m"
|
||||||
|
result="\e[1;2;${c_warning}mtimeout or misnamed\e[0m"
|
||||||
|
fi
|
||||||
|
elif [[ $INTERNET_OUT == 1 ]]; then
|
||||||
|
domain="\e[${c_txt}m${domain}\e[0m"
|
||||||
|
sign="\e[1;2;${c_txt}m▲\e[0m"
|
||||||
|
result="\e[1;2;${c_txt}mno internet, skipped\e[0m"
|
||||||
|
fi
|
||||||
|
output+="\n ${sign} ${domain}|${port}|$result"
|
||||||
|
done
|
||||||
|
|
||||||
|
# output header and table content
|
||||||
|
echo -e "\e[1A\e[${c_title} TLS checks \e[0m "
|
||||||
|
echo -e
|
||||||
|
echo -e "$output" | column -t -s '|'
|
74
motdfetch.d/05-postqueue
Normal file
74
motdfetch.d/05-postqueue
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# check if there is some mails in the deferred queue of postfix
|
||||||
|
# + danger color if >= 100 messages
|
||||||
|
# + warning color if >= 1 messages
|
||||||
|
#
|
||||||
|
# requirements: sudo apt install postfix
|
||||||
|
|
||||||
|
# GENERAL ###########################################################
|
||||||
|
|
||||||
|
# locale env
|
||||||
|
unset LC_ALL
|
||||||
|
export LC_MESSAGES=C
|
||||||
|
|
||||||
|
# check if module was disabled
|
||||||
|
module_disable=${module_postqueue_disable:=0}
|
||||||
|
if (($module_disable == 1)); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# colors
|
||||||
|
c_txt=${c_txt:="39"}
|
||||||
|
c_txt_emphase=${c_txt_emphase:="35"}
|
||||||
|
c_txt_deco=${c_txt_deco:="97"}
|
||||||
|
c_txt_invert=${c_txt_invert:="30"}
|
||||||
|
c_bg=${c_bg_sec:="47"}
|
||||||
|
c_danger=${c_danger:="31"}
|
||||||
|
c_warning=${c_warning:="33"}
|
||||||
|
c_success=${c_success:="32"}
|
||||||
|
c_title=${c_title:="${c_bg};1;${c_txt_invert}m"}
|
||||||
|
|
||||||
|
# PREPARATIONS ######################################################
|
||||||
|
|
||||||
|
# print loading message
|
||||||
|
echo -e "\nWaiting for Postqueue checks\e[5m...\e[0m"
|
||||||
|
|
||||||
|
# check if postfix is available, with qshape
|
||||||
|
if ! command -v qshape 1>/dev/null; then
|
||||||
|
# output module header
|
||||||
|
echo -e "\e[1A\e[${c_title} Postfix deferred queue status \e[0m\n"
|
||||||
|
echo -e " no Postfix server available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# parse deferred messages qty with qshape
|
||||||
|
deferredcmd=$(timeout 5 qshape -b 6 deferred 2>/dev/null)
|
||||||
|
|
||||||
|
# OUTPUT ############################################################
|
||||||
|
|
||||||
|
# if qshape timeout 5sec
|
||||||
|
if [[ "$deferredcmd" == "" ]]; then
|
||||||
|
# output module header
|
||||||
|
echo -e "\e[1A\e[${c_title} Postfix deferred \e[0m\n"
|
||||||
|
echo -e " \e[1;${c_warning}mqshape needs more than 5 sec to parse the deferred Mails list,\n you should investigate!\e[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if total deferred is 0
|
||||||
|
deferredtotal=$(echo -e "$deferredcmd" | grep TOTAL | awk '{print $2}')
|
||||||
|
if [[ "$deferredtotal" == "0" ]]; then
|
||||||
|
# output module header
|
||||||
|
echo -e "\e[1A\e[${c_title} Postfix deferred queue status \e[0m\n"
|
||||||
|
echo -e " There is \e[1;${c_success}m${deferredtotal}\e[0m deferred Mails."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# else print qshape output
|
||||||
|
# output module header
|
||||||
|
echo -e "\e[1A\e[${c_title} Postfix deferred queue status \e[0m\n"
|
||||||
|
if [[ "$deferredtotal" -gt 100 ]]; then
|
||||||
|
echo -e " There is \e[1;${c_danger}m${deferredtotal}\e[0m deferred Mails in queue."
|
||||||
|
else
|
||||||
|
echo -e " There is \e[1;${c_warning}m${deferredtotal}\e[0m deferred Mails in queue."
|
||||||
|
fi
|
77
motdfetch.d/06-fail2ban
Normal file
77
motdfetch.d/06-fail2ban
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# parse Fail2ban jail status, display failed and banned counts
|
||||||
|
# + Warning if currently more than 0
|
||||||
|
# + Danger if currently more than 20
|
||||||
|
#
|
||||||
|
# /!\ need root to display status, display warning for other user
|
||||||
|
#
|
||||||
|
# requirements: sudo apt install fail2ban
|
||||||
|
|
||||||
|
# GENERAL ###########################################################
|
||||||
|
|
||||||
|
# locale env
|
||||||
|
unset LC_ALL
|
||||||
|
export LC_MESSAGES=C
|
||||||
|
|
||||||
|
# check if module was disabled
|
||||||
|
module_disable=${module_fail2ban_disable:=0}
|
||||||
|
if (($module_disable == 1)); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# colors
|
||||||
|
c_txt=${c_txt:="39"}
|
||||||
|
c_txt_emphase=${c_txt_emphase:="35"}
|
||||||
|
c_txt_deco=${c_txt_deco:="97"}
|
||||||
|
c_txt_invert=${c_txt_invert:="30"}
|
||||||
|
c_bg=${c_bg_sec:="47"}
|
||||||
|
c_danger=${c_danger:="31"}
|
||||||
|
c_warning=${c_warning:="33"}
|
||||||
|
c_success=${c_success:="32"}
|
||||||
|
c_title=${c_title:="${c_bg};1;${c_txt_invert}m"}
|
||||||
|
|
||||||
|
# PREPARATIONS ######################################################
|
||||||
|
|
||||||
|
# check if fail2ban is available
|
||||||
|
if ! command -v fail2ban-client 1>/dev/null; then
|
||||||
|
# output module header
|
||||||
|
echo -e "\n\e[${c_title} Fail2Ban status \e[0m\n"
|
||||||
|
echo -e " no Fail2Ban server available"
|
||||||
|
exit 1
|
||||||
|
elif [[ ! `id -un` == "root" ]]; then
|
||||||
|
echo -e "\n\e[${c_title} Fail2Ban status \e[0m\n"
|
||||||
|
echo -e " you must be root to get Fail2Ban status"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# OUTPUT ############################################################
|
||||||
|
|
||||||
|
echo -e "\n\e[${c_title} Fail2Ban status \e[0m\n"
|
||||||
|
|
||||||
|
# fail2ban-client status to get all jails, takes about ~70ms
|
||||||
|
jails=($(fail2ban-client status | grep "Jail list:" | sed "s/ //g" | awk '{split($2,a,",");for(i in a) print a[i]}'))
|
||||||
|
|
||||||
|
out="\e[1;4;${c_txt}mJail name\e[24m,\e[4mFailed\e[24m,\e[4mTotal\e[24m,\e[4mBanned\e[24m,\e[4mTotal\e[24m\n"
|
||||||
|
|
||||||
|
for jail in ${jails[@]}; do
|
||||||
|
# slow because fail2ban-client has to be called for every jail (~70ms per jail)
|
||||||
|
status=$(fail2ban-client status ${jail})
|
||||||
|
failed=$(echo "$status" | grep -ioP '(?<=Currently failed:\t)[[:digit:]]+')
|
||||||
|
if [[ $failed -ge 20 ]]; then
|
||||||
|
failed="\e[1;5;${c_danger}m${failed}\e[0m"
|
||||||
|
elif [[ $failed -ge 1 ]]; then
|
||||||
|
failed="\e[1;${c_warning}m${failed}\e[0m"
|
||||||
|
fi
|
||||||
|
totalfailed=$(echo "$status" | grep -ioP '(?<=Total failed:\t)[[:digit:]]+')
|
||||||
|
banned=$(echo "$status" | grep -ioP '(?<=Currently banned:\t)[[:digit:]]+')
|
||||||
|
if [[ $banned -ge 20 ]]; then
|
||||||
|
banned="\e[1;5;${c_danger}m${banned}\e[0m"
|
||||||
|
elif [[ $banned -ge 1 ]]; then
|
||||||
|
banned="\e[1;${c_warning}m${banned}\e[0m"
|
||||||
|
fi
|
||||||
|
totalbanned=$(echo "$status" | grep -ioP '(?<=Total banned:\t)[[:digit:]]+')
|
||||||
|
out+="\e[1;${c_txt_emphase}m${jail}\e[0m,$failed,$totalfailed,$banned,$totalbanned\n"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo -e "$out" | column -ts $',' | sed 's/^/ /'
|
77
motdfetch.d/99-userslog
Normal file
77
motdfetch.d/99-userslog
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# check last user logged in (with host ip and period) and currently logged in users
|
||||||
|
# + if the last logged in is not the current user, add a section about the last login of the curent user
|
||||||
|
|
||||||
|
# GENERAL ###########################################################
|
||||||
|
|
||||||
|
# locale env
|
||||||
|
unset LC_ALL
|
||||||
|
export LC_MESSAGES=C
|
||||||
|
|
||||||
|
# check if module was disabled
|
||||||
|
module_disable=${module_userslog_disable:=0}
|
||||||
|
if (($module_disable == 1)); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# colors
|
||||||
|
c_txt=${c_txt:="39"}
|
||||||
|
c_txt_emphase=${c_txt_emphase:="35"}
|
||||||
|
c_txt_deco=${c_txt_deco:="97"}
|
||||||
|
c_txt_invert=${c_txt_invert:="30"}
|
||||||
|
c_bg=${c_bg_sec:="47"}
|
||||||
|
c_danger=${c_danger:="31"}
|
||||||
|
c_warning=${c_warning:="33"}
|
||||||
|
c_success=${c_success:="32"}
|
||||||
|
c_title=${c_title:="${c_bg};1;${c_txt_invert}m"}
|
||||||
|
|
||||||
|
# PREPARATIONS ######################################################
|
||||||
|
|
||||||
|
lastuserlog=$(last -i -F -n 2 | head -2 | tail -1)
|
||||||
|
lastusername=$(echo -e "$lastuserlog" | awk '{print $1}')
|
||||||
|
lastuserhost=$(echo -e "$lastuserlog" | awk '{print $3}')
|
||||||
|
if [[ "$lastuserhost" == "0.0.0.0" ]]; then
|
||||||
|
lastuserhost="localhost"
|
||||||
|
fi
|
||||||
|
lastusertime=$(echo -e "$lastuserlog" | awk '{$1=$2=$3=""; print $0}' | sed 's/^ //')
|
||||||
|
|
||||||
|
lastcurrentuserlog=$(last $(id -un) -i -F -n 2 | head -2 | tail -1)
|
||||||
|
lastcurrentusername=$(echo -e "$lastcurrentuserlog" | awk '{print $1}')
|
||||||
|
lastcurrentuserhost=$(echo -e "$lastcurrentuserlog" | awk '{print $3}')
|
||||||
|
if [[ "$lastcurrentuserhost" == "0.0.0.0" ]]; then
|
||||||
|
lastcurrentuserhost="localhost"
|
||||||
|
fi
|
||||||
|
lastcurrentusertime=$(echo -e "$lastcurrentuserlog" | awk '{$1=$2=$3=""; print $0}' | sed 's/^ //')
|
||||||
|
|
||||||
|
loggedusers=$(last -i -F -p now | /usr/bin/grep "logged in" | awk '{print $1}')
|
||||||
|
loggedusersnames=$(echo -e "$loggedusers" | uniq -c | sed 's/^\s\+/|/' | tr ' ' '|')
|
||||||
|
loggeduserscount=$(echo -e "$loggedusers" | wc -l)
|
||||||
|
|
||||||
|
# OUTPUT ############################################################
|
||||||
|
|
||||||
|
# header
|
||||||
|
echo -e "\n\e[${c_title} Users log \e[0m\n"
|
||||||
|
|
||||||
|
W="\e[0;${c_txt}m"
|
||||||
|
X="\e[1;${c_txt}m"
|
||||||
|
F="\e[0;${c_txt_emphase}m"
|
||||||
|
G="\e[1;${c_txt_emphase}m"
|
||||||
|
S="\e[1;4;${c_txt}m"
|
||||||
|
N="\e[0m"
|
||||||
|
|
||||||
|
# last logins
|
||||||
|
if [[ "$lastusername" == "$lastcurrentusername" ]]; then
|
||||||
|
echo -e "$X Last user logged in$W: $G$lastcurrentusername$W, from $F$lastcurrentuserhost$W
|
||||||
|
$X | Login - out$W (duration): $F$lastcurrentusertime$N"
|
||||||
|
else
|
||||||
|
echo -e "$X Last user logged in$W: $G$lastusername$W, from $F$lastuserhost$W
|
||||||
|
$X | Login - out$W (duration): $F$lastusertime$W
|
||||||
|
|
||||||
|
$X Last time$W $G$lastcurrentusername$W$X logged in$W, was from $F$lastcurrentuserhost$W
|
||||||
|
$X | Login - out$W (duration): $F$lastcurrentusertime$N"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# logged users
|
||||||
|
echo
|
||||||
|
echo -e "$G"$loggeduserscount"$W ${X}session$W(s)$X are logged in$W:|${S}Session(s)${W}|${S}User$W${G}\n`echo -e "$loggedusersnames"`$N" | column -t -s '|' | sed 's/^/ /'
|
70
motdfetch.sample.conf
Normal file
70
motdfetch.sample.conf
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# user configuration file for MOTDfetch
|
||||||
|
|
||||||
|
# GLOBAL COLORS ######################################################
|
||||||
|
|
||||||
|
c_txt="39"
|
||||||
|
c_txt_emphase="35"
|
||||||
|
c_txt_deco="97"
|
||||||
|
c_txt_invert="30"
|
||||||
|
c_bg="47"
|
||||||
|
c_danger="31"
|
||||||
|
c_warning="33"
|
||||||
|
c_success="32"
|
||||||
|
c_title="${c_bg};1;${c_txt_invert}m"
|
||||||
|
|
||||||
|
# GLOBAL OPTIONS ####################################################
|
||||||
|
|
||||||
|
## api website name for plain public IP4/6 check
|
||||||
|
global_publicip_api="icanhazip.com"
|
||||||
|
|
||||||
|
# MODULES OPTIONS ####################################################
|
||||||
|
|
||||||
|
## HEADER module
|
||||||
|
module_header_disable=0
|
||||||
|
### custom text (comment to use username, trim > 80 char)
|
||||||
|
module_header_text="BANNER"
|
||||||
|
|
||||||
|
## SYSINFO module
|
||||||
|
module_sysinfo_disable=0
|
||||||
|
|
||||||
|
## SERVICES module
|
||||||
|
module_services_disable=0
|
||||||
|
### services to check
|
||||||
|
### + lookup system & current user services running with these 2 commands:
|
||||||
|
### systemctl --type=service --no-pager -q --state running
|
||||||
|
### systemctl --type=service --user --no-pager -q --state running
|
||||||
|
### + to add user services you need to provide the uid of the user ("service:uid"), find the uid with:
|
||||||
|
### id -u
|
||||||
|
module_services=(
|
||||||
|
"cron"
|
||||||
|
"unattended-upgrades.service"
|
||||||
|
"dbus:1000"
|
||||||
|
)
|
||||||
|
### column max-width
|
||||||
|
module_services_width="80"
|
||||||
|
|
||||||
|
## FILESYSTEM module
|
||||||
|
module_filesystem_disable=0
|
||||||
|
### disable the ZFS section of the module
|
||||||
|
module_filesystem_zfs_disable=0
|
||||||
|
### max blocks usage percentage warning threshold
|
||||||
|
module_filesystem_max_usage="85"
|
||||||
|
|
||||||
|
## TLS module
|
||||||
|
module_tls_disable=0
|
||||||
|
### Domains and ports (default:433) for TLS certification check
|
||||||
|
module_tls_domains=(
|
||||||
|
"www.google.com"
|
||||||
|
"w.fakedomain.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
## POSTQUEUE module
|
||||||
|
module_postqueue_disable=0
|
||||||
|
|
||||||
|
## FAIL2BAN module
|
||||||
|
module_fail2ban_disable=0
|
||||||
|
|
||||||
|
## USERLOG module
|
||||||
|
module_userslog_disable=0
|
112
readme.md
Normal file
112
readme.md
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
# [MOTDfetch][motdfetch_repo]
|
||||||
|
|
||||||
|
![Bash](https://img.shields.io/badge/bash-1f425f.svg?style=for-the-badge&logo=image%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw%2FeHBhY2tldCBiZWdpbj0i77u%2FIiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8%2BIDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkE3MDg2QTAyQUZCMzExRTVBMkQxRDMzMkJDMUQ4RDk3IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkE3MDg2QTAzQUZCMzExRTVBMkQxRDMzMkJDMUQ4RDk3Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTcwODZBMDBBRkIzMTFFNUEyRDFEMzMyQkMxRDhEOTciIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QTcwODZBMDFBRkIzMTFFNUEyRDFEMzMyQkMxRDhEOTciLz4gPC9yZGY6RGVzY3JpcHRpb24%2BIDwvcmRmOlJERj4gPC94OnhtcG1ldGE%2BIDw%2FeHBhY2tldCBlbmQ9InIiPz6lm45hAAADkklEQVR42qyVa0yTVxzGn7d9Wy03MS2ii8s%2BeokYNQSVhCzOjXZOFNF4jx%2BMRmPUMEUEqVG36jo2thizLSQSMd4N8ZoQ8RKjJtooaCpK6ZoCtRXKpRempbTv5ey83bhkAUphz8fznvP8znn%2B%2F3NeEEJgNBoRRSmz0ub%2FfuxEacBg%2FDmYtiCjgo5NG2mBXq%2BH5I1ogMRk9Zbd%2BQU2e1ML6VPLOyf5tvBQ8yT1lG10imxsABm7SLs898GTpyYynEzP60hO3trHDKvMigUwdeaceacqzp7nOI4n0SSIIjl36ao4Z356OV07fSQAk6xJ3XGg%2BLCr1d1OYlVHp4eUHPnerU79ZA%2F1kuv1JQMAg%2BE4O2P23EumF3VkvHprsZKMzKwbRUXFEyTvSIEmTVbrysp%2BWr8wfQHGK6WChVa3bKUmdWou%2BjpArdGkzZ41c1zG%2Fu5uGH4swzd561F%2BuhIT4%2BLnSuPsv9%2BJKIpjNr9dXYOyk7%2FBZrcjIT4eCnoKgedJP4BEqhG77E3NKP31FO7cfQA5K0dSYuLgz2TwCWJSOBzG6crzKK%2BohNfni%2Bx6OMUMMNe%2Fgf7ocbw0v0acKg6J8Ql0q%2BT%2FAXR5PNi5dz9c71upuQqCKFAD%2BYhrZLEAmpodaHO3Qy6TI3NhBpbrshGtOWKOSMYwYGQM8nJzoFJNxP2HjyIQho4PewK6hBktoDcUwtIln4PjOWzflQ%2Be5yl0yCCYgYikTclGlxadio%2BBQCSiW1UXoVGrKYwH4RgMrjU1HAB4vR6LzWYfFUCKxfS8Ftk5qxHoCUQAUkRJaSEokkV6Y%2F%2BJUOC4hn6A39NVXVBYeNP8piH6HeA4fPbpdBQV5KOx0QaL1YppX3Jgk0TwH2Vg6S3u%2BdB91%2B%2FpuNYPYFl5uP5V7ZqvsrX7jxqMXR6ff3gCQSTzFI0a1TX3wIs8ul%2Bq4HuWAAiM39vhOuR1O1fQ2gT%2F26Z8Z5vrl2OHi9OXZn995nLV9aFfS6UC9JeJPfuK0NBohWpCHMSAAsFe74WWP%2BvT25wtP9Bpob6uGqqyDnOtaeumjRu%2ByFu36VntK%2FPA5umTJeUtPWZSU9BCgud661odVp3DZtkc7AnYR33RRC708PrVi1larW7XwZIjLnd7R6SgSqWSNjU1B3F72pz5TZbXmX5vV81Yb7Lg7XT%2FUXriu8XLVqw6c6XqWnBKiiYU%2BMt3wWF7u7i91XlSEITwSAZ%2FCzAAHsJVbwXYFFEAAAAASUVORK5CYII%3D)
|
||||||
|
![Debian](https://img.shields.io/badge/Debian-D70A53?style=for-the-badge&logo=debian&logoColor=white)
|
||||||
|
![Ubuntu](https://img.shields.io/badge/Ubuntu-E95420?style=for-the-badge&logo=ubuntu&logoColor=white)
|
||||||
|
|
||||||
|
**MOTDfetch** is a modular & dynamic **MOTD replacement** written in Bash and a nice **command line information tool** for Debian/Ubuntu systems.
|
||||||
|
|
||||||
|
>*MOTD - "message of the day"
|
||||||
|
>Feature used on Unix-like CLI systems to send a common message to all users after a successful login, and just before it executes the login shell.
|
||||||
|
>Newer Unix-like systems may generate the message dynamically when the host boots or a user logs in.*
|
||||||
|
|
||||||
|
**Drawbacks** with the current implementation of **MOTD with PAM on Debian and Ubuntu** are at least 3:
|
||||||
|
1. The **SSH client does not decide** whether to activate the MOTD.
|
||||||
|
As it is loaded before the shell login is opened:
|
||||||
|
2. User has to **wait blindly** for the end of the execution if there is a dynamic script.
|
||||||
|
3. Scripts **can not check the user sessions** status.
|
||||||
|
|
||||||
|
MOTDfetch **avoids** and partially **disable the original MOTD implementation**, but **remains compatible** with it for PAM login.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
>###### Table of contents
|
||||||
|
>**[FEATURES](#features)**
|
||||||
|
>**[INSTALLATION](#installation)**
|
||||||
|
>**[USAGE](#usage)**
|
||||||
|
|
||||||
|
[![Preview of MOTDfetch][preview_image]][preview_image_url]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Usable as a **command**, a **login MOTD** or **SSH MOTD**.
|
||||||
|
- **[8 Core modules](#8_core_modules)**.
|
||||||
|
- Uniform and **easily customizable**.
|
||||||
|
- **Emphasis** of important elements and status by **colors, symbols or flashing**.
|
||||||
|
- **Notice message** upon missing dependencies
|
||||||
|
- **Reduced operation mode fot high load** (enforceable).
|
||||||
|
- Separate **system and users configuration** files.
|
||||||
|
- **Scripted installation** and updates.
|
||||||
|
- **Modules or sections can be disabled**.
|
||||||
|
- Standalone **executable modules**.
|
||||||
|
|
||||||
|
### 8 Core modules
|
||||||
|
|
||||||
|
#### **HEADER module**
|
||||||
|
|
||||||
|
- decorative banner (custom text or username)
|
||||||
|
- welcome message with username, date and time
|
||||||
|
- user mail inbox status
|
||||||
|
|
||||||
|
#### **SYSYINFO module**
|
||||||
|
|
||||||
|
- distribution name, kernel version, uptime
|
||||||
|
- CPU, cores, load, processes, memory, swap
|
||||||
|
- hostname, network interface, DNS servers, public IPs/DNS/rDNS records
|
||||||
|
- custom external API for public IP check
|
||||||
|
- skip connectivity related tests if the API check fail
|
||||||
|
- short timeout on dig & curl commands to keep the script snappy
|
||||||
|
|
||||||
|
#### **SERVICES module**
|
||||||
|
|
||||||
|
- check systemd services status
|
||||||
|
- by service name and user UID if not system
|
||||||
|
- :warning: user cannot check other user's services
|
||||||
|
|
||||||
|
#### **FILESYSTEM module**
|
||||||
|
|
||||||
|
- 2 sections: general filesystems, ZFS filesystems
|
||||||
|
- name, fs type, usage and size of disk or ZFS pool
|
||||||
|
- inodes usage and size when relevant
|
||||||
|
- health status for ZFS
|
||||||
|
- custom usage threshold for warning hints
|
||||||
|
|
||||||
|
#### **TLS module**
|
||||||
|
|
||||||
|
- check X.509 certificates status with openssl
|
||||||
|
- accept domain and optional port (443 by default)
|
||||||
|
- validate name correspondence and expiration date
|
||||||
|
- skip the test if there is no internet connectivity
|
||||||
|
- short timeout on openssl command to keep the script snappy
|
||||||
|
|
||||||
|
#### **POSTQUEUE module**
|
||||||
|
|
||||||
|
- postfix deferred queue status
|
||||||
|
- short timeout on the parsing to keep the script snappy if there is thousands of mails
|
||||||
|
|
||||||
|
#### **FAIL2BAN module**
|
||||||
|
|
||||||
|
- display fail2ban jails status
|
||||||
|
- :warning: need to be executed with root or sudo
|
||||||
|
|
||||||
|
#### **USERSLOG module**
|
||||||
|
|
||||||
|
- display last user logged in
|
||||||
|
- name, IP and connection range
|
||||||
|
- if the current user is different, display his last log too
|
||||||
|
- display currently logged sessions with usernames
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[//]: # (LINKS)
|
||||||
|
[motdfetch_repo]: https://git.tkapias.net/tkapias/MOTDfetch
|
||||||
|
[preview_image]: docs/img/preview.jpg "Preview of MOTDfetch"
|
||||||
|
[preview_image_url]: https://git.tkapias.net/tkapias/MOTDfetch/raw/master/docs/img/preview.jpg
|
Loading…
Reference in a new issue