svarbox/scripts/dos-shell

304 lines
7.7 KiB
Text
Raw Normal View History

2025-10-18 11:05:20 +03:00
#!/bin/bash
# /usr/local/bin/dos-shell
2025-10-18 20:34:07 +03:00
# Prepare the SvarDOS environment and launch dosemu.
2025-10-18 11:05:20 +03:00
set -euo pipefail
ALLOWED_LIST="/etc/dos_allowed"
2025-10-18 20:34:07 +03:00
ALLOWED_REPO="/opt/allowed_repo"
2025-10-18 11:05:20 +03:00
ENV_DIR="/etc/dos_env"
AUTOEXEC_TEMPLATE="${ENV_DIR}/AUTOEXEC.BAT"
CONFIG_TEMPLATE="${ENV_DIR}/CONFIG.SYS"
2025-10-18 20:34:07 +03:00
SVARDOS_ROOT="${SVARDOS_ROOT:-/opt/svardos}"
SVARDOS_BASE="${SVARDOS_BASE:-${SVARDOS_ROOT}/base}"
ALLOW_MODE="${DOS_ALLOW_MODE:-all}"
DEFAULT_DOS_USER="dosuser"
2025-10-19 00:45:04 +03:00
INSTALL_SENTINEL_NAME=".svardos_installed"
2025-10-18 11:05:20 +03:00
2025-10-18 20:34:07 +03:00
if [ "$(id -u)" -eq 0 ]; then
DOS_USER="${DEFAULT_DOS_USER}"
DOS_HOME="$(getent passwd "${DOS_USER}" | cut -d: -f6)"
else
DOS_USER="$(id -un)"
DOS_HOME="${HOME}"
fi
if [ -z "${DOS_HOME}" ]; then
echo "Unable to determine home directory for ${DOS_USER}" >&2
exit 1
fi
DOSEMU_DIR="${DOS_HOME}/.dosemu"
C_DRIVE="${DOSEMU_DIR}/drive_c"
2025-10-19 00:45:04 +03:00
INSTALL_SENTINEL_PATH="${DOSEMU_DIR}/${INSTALL_SENTINEL_NAME}"
DOSEMU_ARGS=()
2025-10-18 23:29:41 +03:00
detect_dosemu_args() {
local mode="${DOS_TERMINAL_MODE:-auto}"
if [ "${mode}" = "auto" ]; then
if [ -n "${DISPLAY:-}" ]; then
mode="x"
else
mode="terminal"
fi
fi
case "${mode,,}" in
x|sdl|window|gui)
DOSEMU_ARGS=(-X -K "${C_DRIVE}")
;;
terminal|tty|text)
DOSEMU_ARGS=(-td -K "${C_DRIVE}")
;;
dumb)
DOSEMU_ARGS=(-dumb -K "${C_DRIVE}")
;;
*)
echo "Unknown DOS_TERMINAL_MODE '${mode}', defaulting to terminal mode." >&2
DOSEMU_ARGS=(-td -K "${C_DRIVE}")
;;
esac
}
2025-10-18 20:34:07 +03:00
allowed_entries=()
mkdir -p "${DOSEMU_DIR}" "${C_DRIVE}"
2025-10-18 11:05:20 +03:00
if [ "$(id -u)" -eq 0 ] && [ ! -d "${ENV_DIR}" ]; then
mkdir -p "${ENV_DIR}"
fi
2025-10-19 00:45:04 +03:00
reset_drive_c() {
2025-10-18 20:34:07 +03:00
if [ ! -d "${SVARDOS_BASE}" ] || [ -z "$(ls -A "${SVARDOS_BASE}")" ]; then
echo "SvarDOS base directory ${SVARDOS_BASE} is empty. Aborting." >&2
exit 1
fi
rm -rf "${C_DRIVE:?}/"*
2025-10-18 11:05:20 +03:00
2025-10-18 11:47:07 +03:00
cp -a "${SVARDOS_BASE}/." "${C_DRIVE}/"
2025-10-18 22:51:41 +03:00
if [ "$(id -u)" -eq 0 ]; then
chown -R "${DOS_USER}:${DOS_USER}" "${DOSEMU_DIR}"
fi
if [ -f "${DOS_HOME}/.dosemurc" ]; then
rm -f "${DOS_HOME}/.dosemurc"
fi
2025-10-18 20:34:07 +03:00
echo "SvarDOS base staged to ${C_DRIVE}"
}
2025-10-18 11:05:20 +03:00
2025-10-18 20:34:07 +03:00
sync_allowed_content() {
allowed_entries=()
local mode="${ALLOW_MODE}"
if [ "${mode}" = "all" ]; then
if [ -d "${ALLOWED_REPO}" ] && [ "$(ls -A "${ALLOWED_REPO}" 2>/dev/null)" ]; then
2025-10-18 11:47:07 +03:00
cp -a "${ALLOWED_REPO}/." "${C_DRIVE}/"
2025-10-18 20:34:07 +03:00
allowed_entries+=("ALL")
2025-10-18 11:47:07 +03:00
fi
2025-10-18 20:34:07 +03:00
return
fi
if [ "${mode}" != "list" ] && [ "${mode}" != "allowlist" ]; then
echo "Unknown DOS_ALLOW_MODE '${mode}', defaulting to allowlist mode." >&2
mode="list"
ALLOW_MODE="${mode}"
fi
2025-10-18 11:47:07 +03:00
if [ -f "${ALLOWED_LIST}" ]; then
while IFS= read -r line || [ -n "$line" ]; do
line="$(printf '%s' "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
case "$line" in
''|\#*) continue ;;
esac
allowed_entries+=("$line")
done < "${ALLOWED_LIST}"
2025-10-18 11:05:20 +03:00
fi
2025-10-18 11:47:07 +03:00
for entry in "${allowed_entries[@]}"; do
src="${ALLOWED_REPO}/${entry}"
if [ -e "$src" ]; then
dst_dir="$(dirname "${entry}")"
mkdir -p "${C_DRIVE}/${dst_dir}"
cp -a "$src" "${C_DRIVE}/${dst_dir}/"
else
echo "Warning: allowed file not found: $src" >&2
fi
done
2025-10-18 20:34:07 +03:00
}
2025-10-18 11:05:20 +03:00
2025-10-18 20:34:07 +03:00
apply_templates() {
if [ -f "${AUTOEXEC_TEMPLATE}" ]; then
cp "${AUTOEXEC_TEMPLATE}" "${C_DRIVE}/AUTOEXEC.BAT"
fi
if [ -f "${CONFIG_TEMPLATE}" ]; then
cp "${CONFIG_TEMPLATE}" "${C_DRIVE}/CONFIG.SYS"
fi
}
2025-10-18 11:05:20 +03:00
2025-10-19 00:45:04 +03:00
detect_dosemu_args
FORCE_CPU_EMULATION=0
detect_kvm_support() {
if [ ! -c /dev/kvm ]; then
return 1
fi
if [ "$(id -u)" -eq 0 ]; then
if command -v runuser >/dev/null 2>&1; then
runuser -u "${DOS_USER}" -- test -r /dev/kvm 2>/dev/null || return 1
return 0
fi
return 0
fi
[ -r /dev/kvm ]
}
if ! detect_kvm_support; then
echo "dos-shell: disabling KVM acceleration (no usable /dev/kvm)" >&2
FORCE_CPU_EMULATION=1
fi
should_disable_audio=0
audio_mode="${DOS_AUDIO_MODE:-auto}"
case "${audio_mode,,}" in
mute|off|disabled)
should_disable_audio=1
;;
force|on|enabled)
should_disable_audio=0
;;
auto)
if [ -n "${SSH_CONNECTION:-}" ]; then
if [ -z "${PULSE_SERVER:-}" ] && [ -z "${PIPEWIRE_REMOTE:-}" ]; then
should_disable_audio=1
fi
fi
;;
*)
echo "Unknown DOS_AUDIO_MODE '${audio_mode}', defaulting to auto." >&2
if [ -n "${SSH_CONNECTION:-}" ] && [ -z "${PULSE_SERVER:-}" ] && [ -z "${PIPEWIRE_REMOTE:-}" ]; then
should_disable_audio=1
fi
;;
esac
if [ "${should_disable_audio}" -eq 1 ]; then
echo "dos-shell: muting DOS audio for this session" >&2
export AO_DRIVER="${AO_DRIVER:-null}"
fi
detect_landlock_support() {
local header
for header in /usr/include/linux/landlock.h \
/usr/include/uapi/linux/landlock.h \
/usr/lib*/gcc/*/*/include/uapi/linux/landlock.h; do
if [ -f "$header" ] && grep -q 'LANDLOCK_ACCESS_FS_REFER' "$header" 2>/dev/null; then
return 0
fi
done
return 1
}
landlock_mode="${DOS_LANDLOCK_MODE:-auto}"
case "${landlock_mode,,}" in
auto)
if detect_landlock_support; then
:
else
echo "dos-shell: disabling Landlock sandbox (ABI mismatch detected)" >&2
DOSEMU_ARGS+=(-p)
fi
;;
off|disable|disabled)
echo "dos-shell: Landlock sandbox disabled by DOS_LANDLOCK_MODE" >&2
DOSEMU_ARGS+=(-p)
;;
force|on|enabled)
;;
*)
echo "Unknown DOS_LANDLOCK_MODE '${landlock_mode}', defaulting to auto." >&2
if detect_landlock_support; then
:
else
echo "dos-shell: disabling Landlock sandbox (ABI mismatch detected)" >&2
DOSEMU_ARGS+=(-p)
fi
;;
esac
write_autoconfig() {
local need_config=0
local conf_path="${DOSEMU_DIR}/dosemurc"
local legacy_conf="${DOS_HOME}/.dosemurc"
local managed_marker="# Managed by dos-shell for compatibility"
if [ "${FORCE_CPU_EMULATION}" -eq 1 ] || [ "${should_disable_audio}" -eq 1 ]; then
need_config=1
fi
if [ "${need_config}" -eq 1 ]; then
if [ -f "${legacy_conf}" ] && grep -qF "${managed_marker}" "${legacy_conf}" 2>/dev/null; then
rm -f "${legacy_conf}"
fi
local tmp_conf="${conf_path}.tmp"
{
echo "${managed_marker}"
echo "define parser_version_3"
if [ "${FORCE_CPU_EMULATION}" -eq 1 ]; then
echo '$_cpu_vm = "emulated"'
echo '$_cpu_vm_dpmi = "emulated"'
fi
if [ "${should_disable_audio}" -eq 1 ]; then
echo '$_sound = (off)'
echo '$_pcm_hpf = (off)'
fi
} > "${tmp_conf}"
mv "${tmp_conf}" "${conf_path}"
if [ "$(id -u)" -eq 0 ]; then
chown "${DOS_USER}:${DOS_USER}" "${conf_path}"
fi
echo "dos-shell: wrote ${conf_path} overrides" >&2
else
for candidate in "${conf_path}" "${legacy_conf}"; do
if [ -f "${candidate}" ] && grep -qF "${managed_marker}" "${candidate}" 2>/dev/null; then
rm -f "${candidate}"
echo "dos-shell: removed autogenerated ${candidate}" >&2
fi
done
fi
}
2025-10-19 00:45:04 +03:00
if [ "${DOS_FORCE_INSTALL:-0}" = "1" ] || [ ! -f "${INSTALL_SENTINEL_PATH}" ]; then
reset_drive_c
touch "${INSTALL_SENTINEL_PATH}"
if [ "$(id -u)" -eq 0 ]; then
chown "${DOS_USER}:${DOS_USER}" "${INSTALL_SENTINEL_PATH}"
2025-10-18 22:51:41 +03:00
fi
2025-10-19 00:45:04 +03:00
else
echo "Reusing existing SvarDOS installation on ${C_DRIVE}" >&2
2025-10-18 11:05:20 +03:00
fi
2025-10-18 20:34:07 +03:00
sync_allowed_content
apply_templates
write_autoconfig
2025-10-18 20:34:07 +03:00
if [ "$(id -u)" -eq 0 ]; then
chown -R "${DOS_USER}:${DOS_USER}" "${DOSEMU_DIR}"
2025-10-18 11:05:20 +03:00
fi
2025-10-18 20:34:07 +03:00
if [ "${ALLOW_MODE}" = "all" ] && [ "${#allowed_entries[@]}" -gt 0 ]; then
echo "All files in ${ALLOWED_REPO} are available on drive C:."
elif [ "${#allowed_entries[@]}" -gt 0 ]; then
echo "Allowlisted files copied to C: from ${ALLOWED_REPO}:"
for entry in "${allowed_entries[@]}"; do
echo " ${entry}"
done
2025-10-18 11:05:20 +03:00
fi
if [ "$(id -u)" -eq 0 ]; then
2025-10-18 20:34:07 +03:00
exec runuser -u "${DOS_USER}" -- dosemu "${DOSEMU_ARGS[@]}"
2025-10-18 11:05:20 +03:00
else
2025-10-18 20:34:07 +03:00
exec dosemu "${DOSEMU_ARGS[@]}"
2025-10-18 11:05:20 +03:00
fi