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:
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Executable
+203
@@ -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
|
||||
Reference in New Issue
Block a user