VM NOTES

PARROT OS VIRTUALBOX BASIC SETUP

Small commands I reuse when setting up or maintaining a VM.

UPDATE THE VM

Refresh the package list and install available updates.

sudo apt update
sudo apt full-upgrade -y

VIRTUALBOX GUEST TOOLS

Install the VirtualBox guest packages, then restart the VM.

sudo apt install -y virtualbox-guest-utils virtualbox-guest-x11
sudo reboot

INSTALL ZSH

Install Zsh and make it the current user's default shell.

sudo apt install -y zsh
chsh -s "$(command -v zsh)" "$USER"
exec zsh

Check the configured login shell.

getent passwd "$USER" | cut -d: -f7

SHOW USER@HOST

Show User@Host in the prompt.

PROMPT='┌─[%n@%m]─[%~]
└──╼ %# '

Reload the configuration.

source "$HOME/.zshrc"

CLEAN DAILY COMMAND/OUTPUT LOGGER

Add this block to $HOME/.zshrc. It records commands, output, exit status, and duration in one daily log.

# ── Clean daily command/output logger ──────────────────────────

DAILY_LOG_DIR="$HOME/daily"
mkdir -p "$DAILY_LOG_DIR"
chmod 700 "$DAILY_LOG_DIR"

autoload -Uz add-zsh-hook
zmodload zsh/datetime

# Save the real terminal FDs once only.
# Re-sourcing .zshrc must NOT save an already-redirected tee pipe.
if [[ -z "${DAILY_LOGGER_FDS_READY:-}" ]]; then
    typeset -g DAILY_LOGGER_FDS_READY=1
    exec {DAILY_TTY_OUT}>&1
    exec {DAILY_TTY_ERR}>&2
fi

_daily_preexec() {
    local cmd="$1"
    local logfile="$DAILY_LOG_DIR/$(date '+%Y-%m-%d').log"
    local firstcmd="${${(z)cmd}[1]}"

    typeset -g DAILY_COMMAND_ACTIVE=1
    typeset -g DAILY_COMMAND_CAPTURE=0
    typeset -g DAILY_CURRENT_LOG="$logfile"
    typeset -g DAILY_START_TIME="${EPOCHREALTIME:-$(date '+%s.%N')}"

    printf '\n[%s] COMMAND: %s\n' \
        "$(date '+%Y-%m-%d %H:%M:%S')" \
        "$cmd" >> "$logfile"

    # Don't capture programs that redraw the terminal, or shell
    # reload/replacement commands that can mutate logger state.
    case "$firstcmd" in
        less|more|vim|nvim|nano|top|htop|watch|man|tmux|screen|source|.|exec)
            printf '[interactive/shell output not captured]\n' >> "$logfile"
            ;;
        *)
            typeset -g DAILY_COMMAND_CAPTURE=1

            exec > >(tee -a "$logfile" >&$DAILY_TTY_OUT) \
                 2> >(tee -a "$logfile" >&$DAILY_TTY_ERR)
            ;;
    esac
}

_daily_precmd() {
    local exit_code=$?
    local end_time
    local -F 3 duration

    [[ "${DAILY_COMMAND_ACTIVE:-0}" == "1" ]] || return

    # Restore the real terminal BEFORE the next prompt/ZLE redraw.
    if [[ "${DAILY_COMMAND_CAPTURE:-0}" == "1" ]]; then
        exec 1>&$DAILY_TTY_OUT 2>&$DAILY_TTY_ERR
    fi

    end_time="${EPOCHREALTIME:-$(date '+%s.%N')}"
    duration=$(( end_time - DAILY_START_TIME ))

    printf '[%s] exit=%d duration=%.1fs\n' \
        "$(date '+%Y-%m-%d %H:%M:%S')" \
        "$exit_code" \
        "$duration" >> "$DAILY_CURRENT_LOG"

    unset DAILY_COMMAND_ACTIVE
    unset DAILY_COMMAND_CAPTURE
    unset DAILY_CURRENT_LOG
    unset DAILY_START_TIME
}

# Make re-sourcing .zshrc idempotent: replace, don't stack, hooks.
add-zsh-hook -d preexec _daily_preexec 2>/dev/null
add-zsh-hook -d precmd _daily_precmd 2>/dev/null
add-zsh-hook preexec _daily_preexec
add-zsh-hook precmd _daily_precmd

Reload Zsh after saving the file.

exec zsh

NOTE: If you are hacking the logger SHOULD contain passwords, tokens, hashes, cookies, client data, and command output. Treat the output as sensitive.

QUICK HEALTH CHECKS

Check the host, network, disk, memory, and failed services.

hostnamectl
ip addr
df -h
free -h
systemctl --failed

CLEAN UP PACKAGES

Remove packages that are no longer needed and clear downloaded package files.

sudo apt autoremove --purge -y
sudo apt clean
← ROOT