feat(tools): add welcome message (MOTD) management tool

- add `tools/welcome-message.sh` with view, set, and reset actions
- register `lxs tool welcome|motd` command in `lxs.sh`
- add option 7 to interactive tools menu in `tools/index.sh`
- document `lxs tool welcome` in README
This commit is contained in:
2026-05-12 21:44:05 -04:00
parent c3002ef274
commit cdcd89b5b2
4 changed files with 211 additions and 3 deletions
+3 -1
View File
@@ -53,6 +53,7 @@ lxs help # Show help
| `lxs tool root-password` | Change the root password (interactive or generated) |
| `lxs tool update` | Update the server (apt update + upgrade + autoremove + autoclean) |
| `lxs tool root-ssh-login` | Enable or disable root login over SSH with a password |
| `lxs tool welcome` | View, edit, or reset the SSH welcome message (MOTD) |
## Project structure
@@ -76,7 +77,8 @@ lxs/
├── harden.sh
├── root-password.sh
├── update-server.sh
── root-ssh-login.sh
── root-ssh-login.sh
└── welcome-message.sh
```
After `lxs setup`, the full tree lives in `/usr/local/share/lxs/` and sub-scripts execute from disk. If `lxs.sh` is run without being installed (the one-liner mode), it falls back to downloading sub-scripts on demand.
+1
View File
@@ -290,6 +290,7 @@ cmd_tool() {
root-password) download_and_run "tools/root-password.sh" "$@" ;;
update) download_and_run "tools/update-server.sh" "$@" ;;
root-ssh-login) download_and_run "tools/root-ssh-login.sh" "$@" ;;
welcome|motd) download_and_run "tools/welcome-message.sh" "$@" ;;
"") echo -e "${RED}[✗] Missing tool name. Try: lxs help${NC}"; return 1 ;;
*) echo -e "${RED}[✗] Unknown tool: $tool. Try: lxs help${NC}"; return 1 ;;
esac
+4 -2
View File
@@ -63,9 +63,10 @@ menu_tools() {
echo -e " ${GREEN}[4]${NC} Change Root Password"
echo -e " ${CYAN}[5]${NC} Update Server"
echo -e " ${YELLOW}[6]${NC} Root SSH Password Login"
echo -e " ${PURPLE}[7]${NC} Welcome Message (MOTD)"
echo -e " ${RED}[0]${NC} Back"
echo ""
echo -e -n "${BOLD}Choice [0-6]: ${NC}"
echo -e -n "${BOLD}Choice [0-7]: ${NC}"
read -r choice
case $choice in
@@ -75,8 +76,9 @@ menu_tools() {
4) run_sibling "tools/root-password.sh" ;;
5) run_sibling "tools/update-server.sh" ;;
6) run_sibling "tools/root-ssh-login.sh" ;;
7) run_sibling "tools/welcome-message.sh" ;;
0) return ;;
*) echo -e "${RED}[✗] Invalid option. Please select 0-6.${NC}"; sleep 1; continue ;;
*) echo -e "${RED}[✗] Invalid option. Please select 0-7.${NC}"; sleep 1; continue ;;
esac
if [ "$choice" != "0" ]; then
+203
View File
@@ -0,0 +1,203 @@
#!/bin/bash
# LXS - Welcome message (MOTD)
# Description: View, edit, or reset the SSH login welcome message (/etc/motd)
# Author: LXS
# Date: 2025
# Load LXS common library (colors, separator, run_spinner, loggers, helpers)
LXS_RAW_BASE="${LXS_RAW_BASE:-https://git.hyko.cx/hykocx/lxs/raw/branch/main}"
_lib=$(curl -fsSL "${LXS_RAW_BASE}/lib/common.sh") || { echo "Failed to fetch lib/common.sh" >&2; exit 1; }
eval "$_lib"
unset _lib
export LXS_LOG_FILE="/tmp/lxs_welcome_message.log"
require_root "$0" "$@"
set -u
MOTD_FILE="/etc/motd"
BACKUP_FILE="/etc/motd.lxs.bak"
DYNAMIC_DIR="/etc/update-motd.d"
# ═══════════════════════════════════════════════════════════════════════════
# Arguments
# ═══════════════════════════════════════════════════════════════════════════
ACTION=""
TEXT=""
FROM_FILE=""
while [ $# -gt 0 ]; do
case "$1" in
view|--view|show|--show) ACTION="view" ;;
set|--set|edit|--edit) ACTION="set" ;;
reset|--reset) ACTION="reset" ;;
--text) shift; TEXT=${1:-} ;;
--text=*) TEXT="${1#*=}" ;;
--from-file) shift; FROM_FILE=${1:-} ;;
--from-file=*) FROM_FILE="${1#*=}" ;;
-h|--help)
cat <<EOF
Usage: welcome-message.sh [action] [options]
Actions:
view Show the current welcome message
set Set a new welcome message (see source options below)
reset Clear the welcome message (a backup is kept)
Source options for 'set' (mutually exclusive):
--text "..." Use the given string as the new message
--from-file PATH Read the new message from PATH
(none) Open an interactive editor (\$EDITOR or nano/vi)
-h, --help Show this help
With no action, an interactive menu is shown.
The welcome message lives in ${MOTD_FILE}.
On Ubuntu, dynamic MOTD scripts in ${DYNAMIC_DIR} also contribute to the
banner shown at login — those are not modified by this tool.
EOF
exit 0
;;
*)
echo -e "${RED}Unknown option: $1${NC}" >&2
exit 1
;;
esac
shift
done
if [ -n "$TEXT" ] && [ -n "$FROM_FILE" ]; then
err "--text and --from-file are mutually exclusive"
exit 1
fi
# ═══════════════════════════════════════════════════════════════════════════
# Helpers
# ═══════════════════════════════════════════════════════════════════════════
view_motd() {
echo -e "${WHITE}${BOLD}Current welcome message${NC} ${GRAY}(${MOTD_FILE})${NC}"
show_separator
if [ ! -s "$MOTD_FILE" ]; then
echo -e "${GRAY}(empty)${NC}"
else
cat "$MOTD_FILE"
fi
show_separator
if [ -d "$DYNAMIC_DIR" ] && compgen -G "${DYNAMIC_DIR}/*" >/dev/null; then
echo ""
warn "Dynamic MOTD scripts are present in ${DYNAMIC_DIR}:"
find "$DYNAMIC_DIR" -maxdepth 1 -type f -executable -printf ' • %f\n' | sort
echo -e "${GRAY}These run at login and add to the banner.${NC}"
fi
}
backup_motd() {
[ -f "$MOTD_FILE" ] || return 0
cp -a "$MOTD_FILE" "$BACKUP_FILE"
info "Previous message backed up to ${BACKUP_FILE}"
}
write_motd() {
local src=$1
backup_motd
install -m 644 "$src" "$MOTD_FILE"
ok "Welcome message updated"
echo ""
view_motd
}
set_from_text() {
local tmp
tmp=$(mktemp /tmp/lxs.motd.XXXXXX) || { err "mktemp failed"; return 1; }
# Preserve embedded newlines; ensure a trailing newline.
printf '%s\n' "$1" > "$tmp"
write_motd "$tmp"
rm -f "$tmp"
}
set_from_file() {
local src=$1
if [ ! -r "$src" ]; then
err "Cannot read file: ${src}"
return 1
fi
write_motd "$src"
}
set_interactive() {
local editor=${EDITOR:-}
if [ -z "$editor" ]; then
if command -v nano >/dev/null 2>&1; then editor="nano"
elif command -v vi >/dev/null 2>&1; then editor="vi"
else
err "No editor found (\$EDITOR unset; nano/vi missing). Use --text or --from-file."
return 1
fi
fi
local tmp
tmp=$(mktemp /tmp/lxs.motd.XXXXXX) || { err "mktemp failed"; return 1; }
[ -s "$MOTD_FILE" ] && cat "$MOTD_FILE" > "$tmp"
info "Opening ${editor}... save and exit to apply, leave empty to cancel."
"$editor" "$tmp"
if [ ! -s "$tmp" ]; then
warn "Empty content — change cancelled."
rm -f "$tmp"
return 0
fi
write_motd "$tmp"
rm -f "$tmp"
}
reset_motd() {
if [ ! -s "$MOTD_FILE" ]; then
info "Welcome message is already empty."
return 0
fi
backup_motd
: > "$MOTD_FILE"
chmod 644 "$MOTD_FILE"
ok "Welcome message cleared"
}
# ═══════════════════════════════════════════════════════════════════════════
# Menu (when no action is given on the CLI)
# ═══════════════════════════════════════════════════════════════════════════
if [ -z "$ACTION" ]; then
echo -e "${WHITE}${BOLD}LXS - Welcome message${NC}"
show_separator
echo -e " ${CYAN}[1]${NC} View current message"
echo -e " ${GREEN}[2]${NC} Set a new message"
echo -e " ${YELLOW}[3]${NC} Reset (clear) the message"
echo -e " ${RED}[0]${NC} Cancel"
echo ""
echo -e -n "${BOLD}Choice [0-3]: ${NC}"
read -r choice
case "$choice" in
1) ACTION="view" ;;
2) ACTION="set" ;;
3) ACTION="reset" ;;
0|"") info "Cancelled."; exit 0 ;;
*) err "Invalid option."; exit 1 ;;
esac
fi
case "$ACTION" in
view) view_motd ;;
set)
if [ -n "$TEXT" ]; then set_from_text "$TEXT"
elif [ -n "$FROM_FILE" ]; then set_from_file "$FROM_FILE"
else set_interactive
fi
;;
reset) reset_motd ;;
esac