Score:2

Custom modt script prevents me from logging in on server. Am I doing something wrong?

ru flag

I am running Ubuntu 22.04 LTS Server on an old computer I have, and I would like to have a custom script be run when I login to print useful information.

I have the script (linked below), placed it in /etc/profile.d/motd.sh so it runs at login, and ran sudo chmod -x /etc/update-motd.d/* so the default Ubuntu motd isn't executed. But upon logging in, it logs me out immediately. (both via SSH and physically) I had to boot into a live USB on the machine to remove my custom script to be able to login on the server again.

Can't find anything wrong with the script either. If I run it on the server it works as intended (screenshot below), but it hangs when executed as motd...

So I have two questions:

  1. How can I make it so the script doesn't prevent me from logging in? What am I doing wrong?

  2. Is it possible to disable the login for just one user? So in case it ever hangs again for the default user, I can just login to a secondary user that has motd disabled? Thereby avoiding the need for physical access to the server.


This is the output of the script:

enter image description here

It works flawlessly if I run it on the server:

This is the content of the script:

#!/bin/bash


# ---::: Colors :::--- 


RED='\e[38;2;212;51;83m'
GREEN='\e[38;5;2m'
ZGREEN='\e[38;2;186;241;221m'
BLUE='\e[38;5;4m'
PINK='\e[38;2;255;175;255m'
LILAC='\e[38;2;218;186;255m'
EOC='\e[0m' # End of color


# ---::: Global Variables :::--- 


arch=$(uname -m)
distribution=$(lsb_release -s -d)
platform=$(uname -o)
kernel=$(uname -r)
lip=$(ip addr show enp2s0f1 | grep 'inet '| awk '{print $2}' | cut -f1 -d'/')
system_uptime=$(uptime -p | cut -d ' ' -f 2-)
cpu=$(</sys/class/thermal/thermal_zone0/temp)
temperature="$(printf %.1f "$(echo "${cpu}" | awk '{print $1 / 1000}')")°C"

processes=`ps -eo user=|sort|uniq -c | awk '{ print $2 " " $1 }'`
process_all=`echo "$processes"| awk {'print $2'} | awk '{ SUM += $1} END { print SUM }'`
process_root=`echo "$processes"| grep root | awk {'print $2'}`
process_user=`echo "$processes"| grep -v root | awk {'print $2'} | awk '{ SUM += $1} END { print SUM }'`

upgradable=$(apt list --upgradable 2> /dev/null | grep -c upgradable)
security_updates=$(apt list --upgradable 2>/dev/null | grep "\-security" | wc -l)

barWidth=20


# ---::: Logic CPU :::--- 


cpuBarContent=""

percent_cpu=$(awk '{u=$2+$4; t=$2+$4+$5; if (NR==1){u1=u; t1=t;} else print ($2+$4-u1) * 100 / (t-t1) " "; }' <(grep -w "cpu" /proc/stat) <(sleep 0.5;grep -w "cpu" /proc/stat))
percent_cpu=$(echo ${percent_cpu%.*})

usedCPUBarWidth=$((($percent_cpu*$barWidth)/100))

# Color when $percent_cpu is 0-49
cpuColor="$ZGREEN"

if [[ "${percent_cpu}" -ge 65 && "${percent_cpu}" -lt 85 ]]; then
  cpuColor="$LILAC"
elif [[ "${percent_cpu}" -ge 85 && "${percent_cpu}" -le 100 ]]; then
  cpuColor="$RED"
fi

for sep in $(seq 1 $usedCPUBarWidth); do
  cpuBarContent="${cpuBarContent}${cpuColor}■$EOC"
done
cpuBarContent="${cpuBarContent}"
for sep in $(seq 1 $(($barWidth-$usedCPUBarWidth))); do
  cpuBarContent="${cpuBarContent}-"
done
cpuBar="[${cpuBarContent}] $percent_cpu%"


# ---::: Logic RAM :::--- 


used_ram=" " read USED <<<$(free -htm | grep "Mem" | awk {'print $3'} | cut -f1 -d'i')
total_ram=" " read TOTAL <<<$(free -htm | grep "Mem" | awk {'print $2'} | cut -f1 -d'i')
percent_ram=$(vmstat -s | awk ' $0 ~ /total memory/ {total=$1 } $0 ~/free memory/ {free=$1} $0 ~/buffer memory/ {buffer=$1} $0 ~/cache/ {cache=$1} END{print (total-free-buffer-cache)/total*100}')
percent_ram=`echo ${percent_ram%.*}`

ramBarContent=""
usedRAMBarWidth=$((($percent_ram*$barWidth)/100))

# Color when $percent_ram is 0-49
ramColor="$ZGREEN" 

if [[ "${percent_ram}" -ge 65 && "${percent_ram}" -lt 85 ]]; then
    ramColor="$LILAC"
elif [[ "${percent_ram}" -ge 85 && "${percent_ram}" -le 100 ]]; then
    ramColor="$RED"
fi

for sep in $(seq 1 $usedRAMBarWidth); do
    ramBarContent="${ramBarContent}${ramColor}■$EOC"
done

ramBarContent="${ramBarContent}"
for sep in $(seq 1 $(($barWidth-$usedRAMBarWidth))); do
    ramBarContent="${ramBarContent}-"
done
ramBar="[${ramBarContent}]"


# ---::: Logic Storage :::--- 


mountpoints=('/')

storage=$(df -h / | grep '/dev/sda2' | awk '{print $3" / "$2" - "}')
storage_percent=$(df -h / | grep '/dev/sda2' | awk '{print $5}')

for point in "${mountpoints[@]}"; do
    line=$(df -h "${point}")
    percent_hd=$(echo "$line"|tail -n1|awk '{print $5;}'|sed 's/%//')
    usedBarWidth=$(((percent_hd*barWidth)/100))
    hdBarContent=""
    # Color when $percent_hd is 0-49
    hdColor="$ZGREEN"

    if [[ "${percent_hd}" -ge 65 && "${percent_hd}" -lt 85 ]]; then
        hdColor="$LILAC"
    elif [[ "${percent_hd}" -ge 85 && "${percent_hd}" -le 100 ]]; then
        hdColor="$RED"
    fi
    
    hdBarContent="${hdCcolor}"
    for sep in $(seq 1 $usedBarWidth); do
        hdBarContent="${hdBarContent}${hdColor}■$EOC"
    done
    hdBarContent="${hdBarContent}"
    for sep in $(seq 1 $(($barWidth-$usedBarWidth))); do
        hdBarContent="${hdBarContent}-"
    done
    hdBar="[${hdBarContent}]"
done


# ---::: Logic Docker Services :::--- 


export LANG='en_US.UTF-8'
# set column width
COLUMNS=2

length=13

mapfile -t containers < <( docker ps --format "{{.Names}} {{.Status}}" -a | awk '{ print $1,$2 }' | sed '/^\s*$/d' | tail -n +1)

IFS=$'\n' containers=($(sort <<<"${containers[*]}"))
unset IFS

serviceCount=`echo ${#containers[@]}`

services=""
for i in "${!containers[@]}"; do
    IFS=" " read serviceName status <<< ${containers[i]}

    # add ... to service name
    count=`echo -n "$serviceName" | wc -c`
    remaining=`expr $length - $count`
    for j in $(seq $remaining); do 
        serviceName+="."
    done
    
    if [[ "${status}" == "Up" ]]; then
        services+=" $PINK-$EOC ${serviceName}: ${GREEN}running$EOC  "
    else
        services+=" $PINK-$EOC ${serviceName}: ${RED}stopped$EOC    "
    fi
    # insert \n every $COLUMNS column
    if [ $((($i+1) % $COLUMNS)) -eq 0 ] && [[ $i+1 -lt $serviceCount ]]; then
        services+="\n"
    fi
done
#services+="\n"

outServices=`echo "$services"`


# ---::: Printed Elements :::--- 


echo -e "╔═══════════════════════════════ஓ๏⊙๏ஓ═════════════════════════════╗
                             WELCOME
╚═══════════════════════════════ஓ๏⊙๏ஓ═════════════════════════════╝

$BLUE===================================================================$EOC
 $PINK-$EOC Local IP.....: ${GREEN}${lip}$EOC
 $PINK-$EOC Processes....: ${GREEN}${process_all}$EOC (total), ${GREEN}${process_user}$EOC (user), ${GREEN}${process_root}$EOC (root)
 $PINK-$EOC Uptime.......: ${GREEN}${system_uptime}$EOC
$BLUE===================================================================$EOC
 $PINK-$EOC CPU usage....: $cpuBar - ${GREEN}${temperature}$EOC      
 $PINK-$EOC RAM used.....: $ramBar $USED / $TOTAL - ${GREEN}$percent_ram%$EOC
 $PINK-$EOC Disk Space...: $hdBar $storage${GREEN}$storage_percent$EOF
$BLUE===================================================================$EOC
$outServices
$BLUE===================================================================$EOC
$distribution ($platform $kernel $arch)"


# check if there are updates available

stamp="/var/lib/update-notifier/updates-available"

[ ! -r "$stamp" ] || cat "$stamp"

find $stamp -newermt 'now-7 days' 2> /dev/null | grep -q -m 1 '.' || /usr/share/update-notifier/notify-updates-outdated


# check if there are firmware updates
 
if [ -f /run/motd.d/85-fwupd ]; then
    cat /run/motd.d/85-fwupd
fi


# Unattended Upgrades

if [ -x /usr/share/unattended-upgrades/update-motd-unattended-upgrades ]; then
    exec /usr/share/unattended-upgrades/update-motd-unattended-upgrades
fi


# check if there are release upgrades

if [ -x /usr/lib/ubuntu-release-upgrader/release-upgrade-motd ]; then
    exec /usr/lib/ubuntu-release-upgrader/release-upgrade-motd
fi


# checks if reboot is required

if [ -x /usr/lib/update-notifier/update-motd-reboot-required ]; then
    exec /usr/lib/update-notifier/update-motd-reboot-required
fi

user535733 avatar
cn flag
Review your logs to determine why you cannot login. Since you have access to the hardware but cannot login, you might need to use a LiveUSB's "Try Ubuntu" environment to access the logs.
hr flag
At least with the default Ubuntu `/etc/profile`, files in `/etc/profile.d/` are *sourced* rather than simply run - your script is then using `exec`, which *replaces* the current process - i.e. your login shell
Raffa avatar
jp flag
... In particular, you're replacing your login shell with a non-shell e.g. `exec /usr/share/unattended-upgrades/update-motd-unattended-upgrades` ... That has similar effect of e.g. `exec /bin/test` which will log you out (*terminate your session*) as well if you are at $SHLVL 1
Raffa avatar
jp flag
@steeldriver Your comment looks pretty much like an answer to me and it probably should be.
hr flag
... fundamentally, `/etc/profile.d/` is the wrong place for a dynamic motd script - you already know the right place (`/etc/update-motd.d/`) so I don't understand why you are not using that location?
Raffa avatar
jp flag
... *"It works flawlessly if I run it on the server:"* ... That's because you're executing it which will run it in a subshell and the subshell is the one getting replaced by `exec` i.e. a shell one level deep from your current shell ... But try to run it in the current shell instead e.g. with `source scriptfile` and it will log you out.
dazzmos avatar
ru flag
@steeldriver @Raffa Thanks guys. I have switched `exec` to `sh`, as those are sh scripts. I followed a guide on youtube and it said to put it in profile.d. I will put it in update-motd.d tomorrow and test it all out. Will update here once I do. Thanks for the info!
hr flag
... when you do that, make sure the file name obeys the conventions listed under `BEST PRACTICES` in `man update-motd`
dazzmos avatar
ru flag
@steeldriver Thank you, it worked!
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.