#!/bin/sh # shellcheck disable=SC2164,SC2181,SC2009,SC2034,SC2154 # . ./medley_header.sh # shellcheck shell=sh ############################################################################### # # medley.sh - script for running Medley Interlisp on # Linux/WSL/Cygwin/MacOS. On all platforms it just sets # up directories and environment variables and then calls # maiko with the right arguments. On WSL, there is an option to # run without or around X Windows by using the XVnc and a VNC viewer # on the Windows side. This script will start this VNC viewer # on the Windows side. # # NOTE: This script is "compiled" using compile.sh (and inline.sh) from the # component scripts (medley_*.sh). The top-level component is # medley_main.sh. The other components are sourced (directly or # indirectly) from medley_main.sh. # # Do not edit this script directly. Edit the component scripts and # then recompile to get this "combined" script. You can also run # the scripts by exec-ing the medley_main.sh script. This will allow # testing of component modifications without having to compile. # # 2023-01-12 Frank Halasz # 2024-04-29 Frank Halasz: Major overhaul # # Copyright 2023-2024 Interlisp.org # ############################################################################### ############################################################################### # # medley_main.sh - "main" script for running Medley Interlisp on # Linux/WSL/Cygwin/MacOS. On all platforms it just sets # up directories and environment variables and then calls # maiko with the right arguments. On WSL, there is an option to # run without or around X Windows by using the XVnc and a VNC viewer # on the Windows side. This script will start this VNC viewer # on the Windows side. # # 2023-01-12 Frank Halasz # 2024-04-29 Frank Halasz: Major overhaul # # Copyright 2023-2024 Interlisp.org # ############################################################################### #set -x # # # Start off with some functions to determine what directory this script is being executed from # # get_abs_filename() { # $1 : relative filename echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" } # This function taken from # https://stackoverflow.com/questions/29832037/how-to-get-script-directory-in-posix-sh rreadlink() ( # Execute this function in a *subshell* to localize variables and the effect of `cd`. target=$1 fname= targetDir= CDPATH= # Try to make the execution environment as predictable as possible: # All commands below are invoked via `command`, so we must make sure that `command` # itself is not redefined as an alias or shell function. # (Note that command is too inconsistent across shells, so we don't use it.) # `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not even have # an external utility version of it (e.g, Ubuntu). # `command` bypasses aliases and shell functions and also finds builtins # in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for that # to happen. { \unalias command; \unset -f command; } >/dev/null 2>&1 [ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too. while :; do # Resolve potential symlinks until the ultimate target is found. [ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; } command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path. fname=$(command basename -- "$target") # Extract filename. [ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/' if [ -L "$fname" ]; then # Extract [next] target path, which may be defined # *relative* to the symlink's own directory. # Note: We parse `ls -l` output to find the symlink target # which is the only POSIX-compliant, albeit somewhat fragile, way. target=$(command ls -l "$fname") target=${target#* -> } continue # Resolve [next] symlink target. fi break # Ultimate target reached. done targetDir=$(command pwd -P) # Get canonical dir. path # Output the ultimate target's canonical path. # Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path. if [ "$fname" = '.' ]; then command printf '%s\n' "${targetDir%/}" elif [ "$fname" = '..' ]; then # Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied # AFTER canonicalization. command printf '%s\n' "$(command dirname -- "${targetDir}")" else command printf '%s\n' "${targetDir%/}/$fname" fi ) get_script_dir() { # call this with $0 (from main script) as its (only) parameter # if you need to preserve cwd, run this is a subshell since # it can change cwd # set -x local_SCRIPT_PATH="$( get_abs_filename "$1" )"; while [ -h "$local_SCRIPT_PATH" ]; do cd "$( dirname -- "$local_SCRIPT_PATH"; )"; local_SCRIPT_PATH="$( rreadlink "$local_SCRIPT_PATH" )"; done cd "$( dirname -- "$local_SCRIPT_PATH"; )" > '/dev/null'; local_SCRIPT_PATH="$( pwd; )"; # set +x echo "${local_SCRIPT_PATH}" } # end of script directory functions ############################################################################### # figure out the script dir SCRIPTDIR="$(get_script_dir "$0")" # Define some generally useful functions # shellcheck source=./medley_utils.sh # . "${SCRIPTDIR}/medley_utils.sh" # shellcheck shell=sh ############################################################################### # # medley_utils.sh - script containing various useful functions for medley.sh script. # # !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. # !!!! It should not be run as a standlone script. # # 2023-01-23 Frank Halasz # # Copyright 2023 Interlisp.org # ############################################################################### is_tput="$(which tput)" output_error_msg() { local_oem_file="${TMPDIR:-/tmp}"/oem_$$ echo "$1" >"${local_oem_file}" while read -r line do if [ -n "${is_tput}" ]; then echo "$(${is_tput} setab 1)$(${is_tput} setaf 7)${line}$(${is_tput} sgr0)" else echo "$1" fi done <"${local_oem_file}" rm -f "${local_oem_file}" } check_for_dash_or_end() { local_err_msg=""; if [ -z "$2" ] || [ "$2" = "--" ] then local_err_msg="Error: the flag \"$1\" requires a value. Value is missing." usage "${local_err_msg}" else case "$2" in -*) local_err_msg="Error: either the value for flag \"${1}\" is missing OR the value begins with a \"-\", which is not allowed." usage "${local_err_msg}" ;; esac fi } check_file_writeable_or_creatable() { local_msg_core="\"$2\" given as the value of the \"$1\" flag" local_err_msg="" if [ -e "$2" ] then if [ ! -f "$2" ] then local_err_msg="Error: File ${local_msg_core} is not a regular file. It is either a directory or a device file of some sort. Exiting" output_error_msg "${local_err_msg}" exit 1 elif [ ! -w "$2" ] then local_err_msg="Error: File ${local_msg_core} exists but is not writeable Exiting" output_error_msg "${local_err_msg}" exit 1 fi else if [ ! -w "$(dirname -- "$2")" ] then local_err_msg="Error: File ${local_msg_core} cannot be created because its directory either doen't exist or is not writeable. Exiting" output_error_msg "${local_err_msg}" exit 1 fi fi } check_dir_writeable_or_creatable() { local_msg_core="\"$2\" given as the value of the \"$1\" flag" local_err_msg="" if [ -e "$2" ] then if [ ! -d "$2" ] then local_err_msg="Error: ${local_msg_core} exists but is not a directory. Exiting" output_error_msg "${local_err_msg}" exit 1 elif [ ! -w "$2" ] then local_err_msg="Error: Directory ${local_msg_core} exists but is not writeable Exiting" output_error_msg "${local_err_msg}" exit 1 fi else if [ ! -w "$(dirname -- "$2")" ] then local_err_msg="Error: Directory ${local_msg_core} cannot be created because its directory either doesn't exist or is not writeable. Exiting" output_error_msg "${local_err_msg}" exit 1 fi fi } check_file_readable() { local_msg_core="\"$2\" given as the value of the \"$1\" flag" if [ ! -r "$2" ] then local_err_msg="Error: File ${local_msg_core} either doesn't exist or is not readable. Exiting" output_error_msg "${local_err_msg}" exit 1 fi } check_dir_exists() { local_msg_core="\"$2\" given as the value of the \"$1\" flag" if [ -e "$2" ] then if [ ! -d "$2" ] then local_err_msg="Error: Pathname ${local_msg_core} exists but is not a directory. Exiting" output_error_msg "${local_err_msg}" exit 1 elif [ ! -r "$2" ] then local_err_msg="Error: Directory ${local_msg_core} exists but is not readable. Exiting" output_error_msg "${local_err_msg}" exit 1 fi fi } parse_nethub_data() { nh_host="" nh_port="" nh_mac="" nh_debug="" # x="${1%:}:" nh_host="${x%%:*}" x="${x#"${nh_host}":*}" nh_port="${x%%:*}" if [ "${nh_port}" = "${x}" ]; then nh_port=""; return 0; fi x="${x#"${nh_port}":*}" nh_mac="${x%%:*}" if [ "${nh_mac}" = "${x}" ]; then nh_mac=""; return 0; fi nh_debug="${x#"${nh_mac}":*}" if [ "${nh_debug}" = "${x}" ]; then nh_debug=""; return 0; fi nh_debug="${nh_debug%:}" return 0 } MEDLEYDIR="$(cd "${SCRIPTDIR}/../.."; pwd)" export MEDLEYDIR IL_DIR="$(cd "${MEDLEYDIR}/.."; pwd)" # Are we running under WSL or Darwin or Cygwin? # wsl=false darwin=false cygwin=false linux=false platform=unknown if [ "$(uname)" = "Darwin" ] then darwin=true platform=darwin elif [ "$(uname -s | head --bytes 6)" = "CYGWIN" ] then cygwin=true platform=cgwin elif [ -e "/proc/version" ] && grep --ignore-case --quiet Microsoft /proc/version then platform=wsl wsl=true wsl_ver=0 # WSL2 grep --ignore-case --quiet wsl /proc/sys/kernel/osrelease if [ $? -eq 0 ]; then wsl_ver=2 else # WSL1 grep --ignore-case --quiet microsoft /proc/sys/kernel/osrelease if [ $? -eq 0 ] then if [ "$(uname -m)" = "x86_64" ] then wsl_ver=1 else err_msg="ERROR: Running Medley on WSL1 requires an x86_64-based PC. This is not an x86_64-based PC. Exiting" output_error_msg "${err_msg}" exit 23 fi fi fi else linux=true platform=linux fi #################### TEST CODE #################### #wsl=false #darwin=false #cygwin=false #linux=true #platform=linux #################### TEST CODE #################### # process config file and args # shellcheck source=./medley_configfile.sh # . "${SCRIPTDIR}/medley_configfile.sh" # shellcheck shell=sh ############################################################################### # # medley_configfile.sh - script for processing the config file for the # medley.sh script. # # !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. # !!!! It should not be run as a standlone script. # # 2024-04-20 Frank Halasz # # Copyright 2024 Interlisp.org # ############################################################################### config_file="" # look thru args looking to see if a config file was specified j=1 jmax=$# while [ "$j" -le "$jmax" ] do if [ "$(eval "printf %s \${${j}}")" = "-c" ] || [ "$(eval "printf %s \${${j}}")" = "--config" ] then k=$(( j + 1 )) config_file="$(eval "printf %s \${${k}}")" if [ ! "${config_file}" = "-" ] && [ ! -f "${config_file}" ] then echo "Error: specified config file \"${config_file}\" not found." echo "Exiting." exit 52 fi j=$(( j + 1 )) fi j=$(( j + 1 )) done # if no config file specified, use the defaults (if they exist) if [ -z "${config_file}" ] then for f in "${HOME}/.medley_config" "${MEDLEYDIR}/.medley_config" do if [ -f "$f" ] then config_file="$f" fi done fi # add marker to separate config file args from command line args set -- "--start_cl_args" "--start_cl_args" "$@" # if there is a config file and its not been suppressed with "-", # read the config file (in reverse order) and add the first two items on each line # to the arguments array if [ -n "${config_file}" ] && [ ! "${config_file}" = "-" ] then rev_config_file="${TMPDIR:-/tmp}"/.medley_config_$$ # reverse order of lines in medley config file sed '1!x;H;1h;$!d;g' < "${config_file}" >"${rev_config_file}" while read -r arg1 arg2 do if [ -n "${arg2}" ] then arg2="$(echo "${arg2}" | sed s/\"//g)" set -- "${arg2}" "$@" fi if [ -n "${arg1}" ] then set -- "${arg1}" "$@" fi done < "${rev_config_file}" rm -f "${rev_config_file}" fi # shellcheck source=./medley_args.sh # . "${SCRIPTDIR}/medley_args.sh" # shellcheck shell=sh # shellcheck disable=SC2034,SC2154,SC2164 ############################################################################### # # medley_args.sh - script for processing the args to medley.sh script. # # !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. # !!!! It should not be run as a standlone script. # # 2023-01-12 Frank Halasz # # Copyright 2023 Interlisp.org # ############################################################################### # load usage function # shellcheck source=./medley_usage.sh # . "${SCRIPTDIR}/medley_usage.sh" # shellcheck shell=sh # shellcheck disable=SC2154 ############################################################################### # # medley_useage.sh - script defining the "usage" for medley.sh script. # # !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. # !!!! It should not be run as a standlone script. # # 2023-01-21 Frank Halasz # # Copyright 2023 Interlisp.org # ############################################################################### PAGER=$( if [ -n "$(which more)" ]; then echo "more"; else echo "cat"; fi) usage() { usage_msg_path=/tmp/msg-$$ if [ "${wsl}" = true ]; then wsl_incl="+w" wsl_excl="-w" else wsl_incl="-w" wsl_excl="+w" fi if [ "${docker}" = true ]; then docker_incl="+d" docker_excl="-d" else docker_incl="-d" docker_excl="+d" fi if [ "${windows}" = true ]; then windows_incl="+W" windows_excl="-W" else windows_incl="-W" windows_excl="+W" fi if [ $# -ne 0 ]; then full_msg="In ${args_stage}: $1" { echo; output_error_msg "${full_msg}"; echo; } >> "${usage_msg_path}" else touch "${usage_msg_path}" fi cat "${usage_msg_path}" - <\" argument to give this new instance a different id. Exiting" output_error_msg "${err_msg}" exit 3 fi else matching=$( \ ps ax | \ sed -e "/ldex.*-id ${run_id_base}[0-9]/s/^.*-id ${run_id_base}\([0-9]*\).*$/\\1/p" \ -e "/ldesdl.*-id ${run_id_base}[0-9]/s/^.*-id ${run_id_base}\([0-9]*\).*$/\\1/p" \ -e d \ ) max=0 for n in $matching do if [ "$n" -gt "$max" ]; then max=$n; fi done max=$(( max + 1 )) run_id="${run_id_base}${max}" fi # Run medley # shellcheck source=./medley_run.sh # . "${SCRIPTDIR}/medley_run.sh" # shellcheck shell=sh # shellcheck disable=SC2154,SC2164,SC2086 ############################################################################### # # medley_run.sh - script for processing actually running maiko/medley # for the medley.sh script. # # !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. # !!!! It should not be run as a standlone script. # # 2024-04-21 Frank Halasz # # Copyright 2024 Interlisp.org # ############################################################################### # Figure out LOGINDIR situation if [ -z "${logindir_arg}" ] then LOGINDIR="${HOME}/il" else LOGINDIR="${logindir_arg}" fi export LOGINDIR if [ ! -e "${LOGINDIR}" ]; then mkdir -p "${LOGINDIR}" elif [ ! -d "${LOGINDIR}" ]; then echo "ERROR: Medley requires a directory named ${LOGINDIR}." echo "But ${LOGINDIR} exists but appears not be a directory." echo "Exiting" exit 2 fi mkdir -p "${LOGINDIR}"/vmem # Set LDEDESTSYSOUT env variable based on id # if LDEDESRTSYSOUT has not already been set # during arg processing if [ -z "${vmem_arg}" ] then if [ "${run_id}" = "default" ] then LDEDESTSYSOUT="${LOGINDIR}/vmem/lisp.virtualmem" else LDEDESTSYSOUT="${LOGINDIR}/vmem/lisp_${run_id}.virtualmem" fi else LDEDESTSYSOUT="${vmem_arg}" fi export LDEDESTSYSOUT # Figure out the sysout situation loadups_dir="${MEDLEYDIR}/loadups" if [ -z "${sysout_arg}" ] then if [ -f "${LDEDESTSYSOUT}" ] then src_sysout="${LDEDESTSYSOUT}" else src_sysout="${loadups_dir}/full.sysout" fi else case "${sysout_arg}" in lisp | full | apps) if [ ! -d "${loadups_dir}" ] then err_msg="Error: The sysout argument --${sysout_arg} was specified in ${sysout_stage}, but the directory \"${loadups_dir}\" where ${sysout_arg}.sysout is supposed to be located cannot be found. Exiting." output_error_msg "${err_msg}" exit 62 fi src_sysout="${loadups_dir}/${sysout_arg}.sysout" ;; *) src_sysout="${sysout_arg}" ;; esac fi if [ ! -f "${src_sysout}" ] then err_msg="Error: Cannot find the specified sysout file \"${src_sysout}\". Exiting." output_error_msg "${err_msg}" fi # Figure out screensize and geometry based on arguments # shellcheck source=./medley_geometry.sh # . "${SCRIPTDIR}/medley_geometry.sh" # shellcheck shell=sh # shellcheck disable=SC2154,SC2269 ############################################################################### # # medley_geometry.sh - script for computing the geometry and screensize # parameters for a medley session # # !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. # !!!! It should not be run as a standlone script. # # 2023-01-17 Frank Halasz # # Copyright 2023 Interlisp.org # ############################################################################### if [ "${noscroll}" = false ]; then scroll=22 else scroll=0 fi if [ -n "${geometry}" ] && [ -n "${screensize}" ] then gw=$(expr "${geometry}" : "\([0-9]*\)x[0-9]*$") gh=$(expr "${geometry}" : "[0-9]*x\([0-9]*\)$") if [ -z "${gw}" ] || [ -z "${gh}" ] then err_msg="Error: Improperly formed -geometry or -dimension argument: ${geometry}" usage "${err_msg}" fi geometry="${geometry}" # sw=$(expr "${screensize}" : "\([0-9]*\)x[0-9]*$") sh=$(expr "${screensize}" : "[0-9]*x\([0-9]*\)$") if [ -z "${sw}" ] || [ -z "${sh}" ] then err_msg="Error: Improperly formed -screensize argument: ${screensize}" usage "${err_msg}" fi screensize="${screensize}" elif [ -n "${geometry}" ] then gw=$(expr "${geometry}" : "\([0-9]*\)x[0-9]*$") gh=$(expr "${geometry}" : "[0-9]*x\([0-9]*\)$") if [ -n "${gw}" ] && [ -n "${gh}" ] then sw=$(( (((31+gw)/32)*32)-scroll )) sh=$(( gh - scroll )) geometry="${gw}x${gh}" screensize="${sw}x${sh}" else err_msg="Error: Improperly formed -geometry or -dimension argument: ${geometry}" usage "${err_msg}" fi elif [ -n "${screensize}" ] then sw=$(expr "${screensize}" : "\([0-9]*\)x[0-9]*$") sh=$(expr "${screensize}" : "[0-9]*x\([0-9]*\)$") if [ -n "${sw}" ] && [ -n "${sh}" ] then sw=$(( (31+sw)/32*32 )) gw=$(( scroll+sw )) gh=$(( scroll+sh )) geometry="${gw}x${gh}" screensize="${sw}x${sh}" else err_msg="Error: Improperly formed -screensize argument: ${screensize}" usage "${err_msg}" fi else screensize="1440x900" if [ "${noscroll}" = false ]; then geometry="1462x922" else geometry="1440x900" fi fi # Figure out border width situation borderwidth_flag="" borderwidth_value="" if [ -n "${borderwidth_arg}" ] then borderwidth_flag="-bw" borderwidth_value="${borderwidth_arg}" fi # Figure out pixelscale situation pixelscale_flag="" pixelscale_value="" if [ -n "${pixelscale_arg}" ] then pixelscale_flag="-pixelscale" pixelscale_value="${pixelscale_arg}" fi # figure out greet files situation if [ -z "${greet_arg}" ] then if [ "${sysout_arg}" = "apps" ] then LDEINIT="${MEDLEYDIR}/greetfiles/APPS-INIT.LCOM" else LDEINIT="${MEDLEYDIR}/greetfiles/MEDLEYDIR-INIT.LCOM" fi else if [ "${greet_arg}" = "--nogreet--" ] then LDEINIT="${MEDLEYDIR}/greetfiles/NOGREET" else LDEINIT="${greet_arg}" fi fi export LDEINIT # figure out noscroll situation noscroll_arg="" if [ "${noscroll}" = true ] then noscroll_arg="-noscroll" fi # figure out -m situatiom mem_flag="" mem_value="" if [ -n "${mem_arg}" ] then mem_flag="-m" mem_value="${mem_arg}" fi # figure out the nethub situation nh_host_flag="" nh_host_value="" nh_port_flag="" nh_port_value="" nh_mac_flag="" nh_mac_value="" nh_debug_flag="" nh_debug_value="" if [ -n "${nh_host_arg}" ] then nh_host_flag="-nh-host" nh_host_value="${nh_host_arg}" if [ -n "${nh_port_arg}" ] then nh_port_flag="-nh-port" nh_port_value="${nh_port_arg}" fi if [ -n "${nh_mac_arg}" ] then nh_mac_flag="-nh-mac" nh_mac_value="${nh_mac_arg}" fi if [ -n "${nh_debug_arg}" ] then nh_debug_flag="-nh-loglevel" nh_debug_value="${nh_debug_arg}" fi fi # figure out the keyboard type if [ -z "${LDEKBDTYPE}" ]; then export LDEKBDTYPE="X" fi # figure out title situation if [ -z "${title}" ] then title="Medley Interlisp %i" fi if [ ! "${run_id}" = default ] then title="$(printf %s "${title}" | sed -e "s/%i/:: ${run_id}/")" else title="$(printf %s "${title}" | sed -e "s/%i//")" fi # Figure out the maiko executable name # used for loadups (ldeinit) if [ -z "${maikoprog_arg}" ] then maikoprog_arg="lde" fi # Figure out the maiko directory maiko check_if_maiko_dir () { if [ -d "$1" ] \ && [ -d "$1/bin" ] \ && [ -x "$1/bin/osversion" ] \ && [ -x "$1/bin/machinetype" ] then maiko_exe_subdir="$("$1/bin/osversion").$("$1/bin/machinetype")" return 0 fi return 1 } check_for_maiko_exe () { if ! check_if_maiko_dir "$1" then return 1 fi maiko_exe="$1/${maiko_exe_subdir}/${maikoprog_arg}" if [ -x "${maiko_exe}" ] then return 0 else maiko_exe="" return 1 fi } if [ -z "${maikodir_arg}" ] then if check_for_maiko_exe "${MEDLEYDIR}/maiko" then maikodir_arg="${MEDLEYDIR}/maiko" elif check_for_maiko_exe "${MEDLEYDIR}/../maiko" then maikodir_arg="$(cd "${MEDLEYDIR}/../maiko"; pwd)" else if ! check_if_maiko_dir "${MEDLEYDIR}/maiko" && ! check_if_maiko_dir "${MEDLEYDIR}/../maiko" then err_msg="ERROR: Cannot find the Maiko directory at either \"${MEDLEYDIR}/maiko\" or \"${MEDLEYDIR}/../maiko\". You can use the --maikodir argument to specify the Maiko directory. Exiting." output_error_msg "${err_msg}" exit 53 else err_msg="ERROR: Cannot find the Maiko executable (${maiko_exe_subdir}/${maikoprog_arg}) in either \"${MEDLEYDIR}/maiko\" or \"${MEDLEYDIR}/../maiko\". Exiting." output_error_msg "${err_msg}" exit 54 fi fi elif ! check_if_maiko_dir "${maikodir_arg}" || ! check_for_maiko_exe "${maikodir_arg}" then err_msg="In ${maikodir_stage}: ERROR: The value of the --maikodir argument is not in fact a directory containing the Maiko emulator (${maiko_exe_subdir}/${maikoprog_arg}). Exiting." output_error_msg "${err_msg}" exit 53 fi maiko="${maiko_exe}" # Define function to start up maiko given all arguments # Arg to this function should be "$@", the main args # array that at this point should just include the pass-on args start_maiko() { echo \ \"${maiko}\" \"${src_sysout}\" \ -id \"${run_id}\" \ -title \"${title}\" \ -g ${geometry} \ -sc ${screensize} \ ${borderwidth_flag} ${borderwidth_value} \ ${pixelscale_flag} ${pixelscale_value} \ ${noscroll_arg} \ ${mem_flag} ${mem_value} \ ${nh_host_flag} ${nh_host_value} \ ${nh_port_flag} ${nh_port_value} \ ${nh_mac_flag} ${nh_mac_value} \ ${nh_debug_flag} ${nh_debug_value} \ ${nofork_arg} \ "$@" ; echo "MEDLEYDIR: \"${MEDLEYDIR}\"" echo "LOGINDIR: \"${LOGINDIR}\"" echo "GREET FILE: \"${LDEINIT}\"" echo "VMEM FILE: \"${LDEDESTSYSOUT}\"" # # Temp workaround for issues in Maiko sysout arg # processing. See Issue #1702. FGH 2024-05-09 # LDESOURCESYSOUT="${src_sysout}" export LDESOURCESYSOUT # # End work around # "${maiko}" "${src_sysout}" \ -id "${run_id}" \ -title "${title}" \ -g "${geometry}" \ -sc "${screensize}" \ ${borderwidth_flag} ${borderwidth_value} \ ${pixelscale_flag} ${pixelscale_value} \ ${noscroll_arg} \ ${mem_flag} ${mem_value} \ ${nh_host_flag} ${nh_host_value} \ ${nh_port_flag} ${nh_port_value} \ ${nh_mac_flag} ${nh_mac_value} \ ${nh_debug_flag} ${nh_debug_value} \ ${nofork_arg} \ "$@" ; exit_code=$? } # temp fix for cygwin to workaround issue #1685 # 2024-04-29 if [ "${cygwin}" = true ] then MEDLEYDIR="${MEDLEYDIR}/" fi # Run maiko either directly or with vnc if [ "${use_vnc}" = true ] then # do the vnc thing - if called for # shellcheck source=./medley_vnc.sh # . "${SCRIPTDIR}/medley_vnc.sh" # shellcheck shell=sh # shellcheck disable=SC2154,SC2162 ############################################################################### # # medley_vnc.sh - script for running Medley Interlisp on WSL using Xvnc # on the Linux side and a vncviewer on the Windows side. # This script run under Linux will start the right apps # on both the Linux and Windows sides. # # !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. # !!!! It should not be run as a standlone script. # # 2023-01-12 Frank Halasz # # Copyright 2023 Interlisp.org # ############################################################################### #set -x ip_addr() { if [ "${wsl}" = true ] then ip -4 -br address show dev eth0 | awk '{print $3}' | sed 's-/.*$--' else echo "127.0.0.1" fi } find_open_display() { local_ctr=1 local_result=-1 while [ ${local_ctr} -lt 64 ]; do if [ ! -e /tmp/.X${local_ctr}-lock ]; then local_result=${local_ctr} break else local_ctr=$(( local_ctr+1 )) fi done echo ${local_result} } find_open_port() { local_ctr=5900 local_result=-1 while [ ${local_ctr} -lt 6000 ]; do if [ "${wsl}" = true ] && [ "${wsl_ver}" -eq 1 ] then netstat.exe -a -n | awk '{ print $2 }' | grep -q ":${local_ctr}\$" else ss -a | grep -q "LISTEN.*:${local_ctr}[^0-9]" fi if [ $? -eq 1 ]; then local_result=${local_ctr} break else local_ctr=$(( local_ctr+1 )) fi done echo ${local_result} } # # Make sure prequisites for vnc support are in place # if [ -z "$(which Xtigervnc)" ] then echo "Error: The -v or --vnc flag was set." echo "But it appears that the TigerVNC server (Xtigervnc) has not been installed." echo "Please install the TigerVNC server and try again. On Debian and Ubuntu, use:" echo "\"sudo apt install tigervnc-standalone-server\". On most other Linux distros, use the" echo "distro's package manager to install the \"tigervnc-server\" package." echo "Exiting." exit 4 fi if [ "${linux}" = "true" ] then if [ -z "$(which xtigervncviewer)" ] then echo "Error: The -v or --vnc flag was set." echo "But it appears that that the TigerVNC viewer (xtigervncviewer) is not installed on your system." echo "Please install the TigerVNC viewer and try again. On Debian and Ubuntu, use:" echo "\"sudo apt install tigervnc-viewer\". On most other Linux distros, use the" echo "the distro's package manager to install the \"tigervnc-viewer\" (or sometimes just \"tigervnc\")" echo "package." echo "Exiting." exit 5 else vncviewer="$(which xtigervncviewer)" fi elif [ "${wsl}" = "true" ] then win_userprofile="$(cmd.exe /c "/dev/null)" vnc_dir="$(wslpath "${win_userprofile}")/AppData/Local/Interlisp" vnc_exe="vncviewer64-1.12.0.exe" if [ ! -e "${vnc_dir}/${vnc_exe}" ]; then if [ -e "${IL_DIR}/wsl/${vnc_exe}" ]; then # make sure TigerVNC viewer is in a Windows (not Linux) directory. If its in a Linux directory # there will be a long delay when it starts up mkdir -p "${vnc_dir}" cp -p "${IL_DIR}/wsl/${vnc_exe}" "${vnc_dir}/${vnc_exe}" else loop_done=false while [ "${loop_done}" = "false" ] do echo "TigerVnc viewer is required by the -vnc option but is not installed." echo "Ok to download from SourceForge? [y, Y, n or N, default n] " read resp if [ -z "${resp}" ]; then resp=n; fi case "${resp}" in n* | N* ) echo "Ok. You can download the Tiger VNC viewer (v1.12.0) .exe yourself and " echo "place it in ${vnc_dir}/${vnc_exe}. Then retry." echo "Exiting." exit 5 ;; y* | Y* ) wget -P "${vnc_dir}" https://sourceforge.net/projects/tigervnc/files/stable/1.12.0/vncviewer64-1.12.0.exe loop_done=true ;; * ) echo "Answer not one of Y, y, N, or n. Retry." ;; esac done fi fi vncviewer="${vnc_dir}/${vnc_exe}" fi # # Start the log file so we can trace any issues with vnc, etc # LOG="${LOGINDIR}/logs/medley_${run_id}.log" mkdir -p "$(dirname -- "${LOG}")" echo "START" >"${LOG}" # # #set -x # are we running in background - used for pretty-fying the echos case $(ps -o stat= -p $$) in *+*) bg=false ;; *) bg=true ;; esac # # find an unused display and an available port # #set -x ORIGINAL_DISPLAY="${DISPLAY}" OPEN_DISPLAY="$(find_open_display)" if [ "${OPEN_DISPLAY}" -eq -1 ]; then echo "Error: cannot find an unused DISPLAY between 1 and 63" echo "Exiting" exit 33 else if [ "${bg}" = true ]; then echo; fi echo "Using DISPLAY=:${OPEN_DISPLAY}" fi DISPLAY=":${OPEN_DISPLAY}" export DISPLAY VNC_PORT="$(find_open_port)" export VNC_PORT if [ "${VNC_PORT}" -eq -1 ]; then echo "Error: cannot find an unused port between 5900 and 5999" echo "Exiting" exit 33 else echo "Using VNC_PORT=${VNC_PORT}" fi # # Start the Xvnc server # mkdir -p "${LOGINDIR}"/logs Xvnc "${DISPLAY}" \ -rfbport "${VNC_PORT}" \ -geometry "${geometry}" \ -SecurityTypes None \ -NeverShared \ -DisconnectClients=0 \ -desktop "${title}" \ --MaxDisconnectionTime=10 \ >> "${LOG}" 2>&1 & sleep .5 # # Run Maiko in background, handing over the pass-on args which are all thats left in the main args array # { start_maiko "$@" if [ -n "$(pgrep -f "${vnc_exe}.*:${VNC_PORT}")" ]; then vncconfig -disconnect; fi } & # # Start the vncviewer # # First give medley time to startup # sleep .25 # Sleep appears not to be needed, but faster/slower machines ???? # FGH 2023-02-08 # Then start vnc viewer vncv_loc=$(( OPEN_DISPLAY * 50 )) start_time=$(date +%s) export DISPLAY="${ORIGINAL_DISPLAY}" "${vncviewer}" -geometry "+${vncv_loc}+${vncv_loc}" \ −AlertOnFatalError=0 \ -ReconnectOnError=0 \ "$(ip_addr)":"${VNC_PORT}" \ >>"${LOG}" 2>&1 & wait $! if [ $(( $(date +%s) - start_time )) -lt 5 ] then if [ -z "$(pgrep -f "Xvnc ${DISPLAY}")" ] then echo "Xvnc server failed to start." echo "See log file at ${LOG}" echo "Exiting" exit 3 else echo "VNC viewer failed to start."; echo "See log file at ${LOG}"; echo "Exiting" ; exit 4; fi fi # # Done, "Go back" to medley_run.sh # true ####################################### else # If not using vnc, just exec maiko directly # handing over the pass-on args which are all thats left in the main args array start_maiko "$@" fi exit ${exit_code}