Skip to content

Commit 6501fae

Browse files
committed
fix cookiebaker() (missing subfunctions); use telnet to check if port is free
1 parent 6a857bb commit 6501fae

File tree

2 files changed

+92
-76
lines changed

2 files changed

+92
-76
lines changed

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ For similar functionality on native Linux systems use [x11docker](https://github
3434
Installation in general:
3535
- Install an X server, *VcXsrv* or *XWin*.
3636
- Copy `runx` into folder `/usr/local/bin` and make it executeable with `chmod +x /usr/local/bin/runx`.
37-
- Install dependency `xauth` if available.
37+
- Install Linux dependency `xauth` if available.
38+
- Install Linux dependency `telnet`.
3839

3940
### Installation of X server
4041
`runx` needs an [X server](https://en.wikipedia.org/wiki/X_Window_System). Install on MS Windows one or both of:
@@ -52,11 +53,11 @@ Installation in general:
5253
sudo wget https://raw.githubusercontent.com/mviereck/runx/master/runx -O /usr/local/bin/runx
5354
sudo chmod +x /usr/local/bin/runx
5455
sudo apt update
55-
sudo apt install xauth
56+
sudo apt install xauth telnet
5657
```
5758

5859
### Installation in Cygwin
59-
- Run the Cygwin installer and install packages `xinit`, `xauth` and `wget`.
60+
- Run the Cygwin installer and install packages `xinit`, `xauth`, `wget` and `inetutils`.
6061
- In Cygwin terminal run the commands:
6162
```
6263
wget https://raw.githubusercontent.com/mviereck/runx/master/runx -O /usr/local/bin/runx
@@ -70,8 +71,7 @@ Installation in general:
7071
wget https://raw.githubusercontent.com/mviereck/runx/master/runx -O /usr/local/bin/runx
7172
chmod +x /usr/local/bin/runx
7273
```
73-
- Constraints in MSYS2:
74-
- In MSYS2 `runx` only supports X server *VcXsrv*, but not *XWin*.
74+
- Constraint in MSYS2: `runx` only supports X server *VcXsrv*, but not *XWin*.
7575

7676
## GPU hardware acceleration
7777
`runx` supports GPU hardware accelerated graphics with option `--gpu`.

runx

+87-71
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#! /bin/bash
22
# runx: Provide an X server in Cygwin, MSYS2 or WSL.
33

4-
Version="v0.4.3"
4+
Version="v0.4.4"
55

66
usage() { # Usage information (--help)
77
echo "runx - Run Linux GUI applications on MS Windows.
@@ -20,7 +20,8 @@ Options:
2020
--xwin Use X server XWin.
2121
--clipboard [=yes|no] Enable clipboard sharing yes/no. Default: yes.
2222
--display N Use display number N for new X server.
23-
Default: random number in range of 100...3376.
23+
If the display number is already in use, runx will
24+
only provide the likely access credentials.
2425
--ip ADRESS IP adress to use. Default: First found 192.168.*
2526
--no-auth Disable X cookie authentication. Discouraged.
2627
--cleanup Stop all X servers and delete cookies.
@@ -67,14 +68,14 @@ runx version $Version
6768
Please report issues and get help at: https://github.com/mviereck/runx
6869
" >&2
6970
}
70-
7171
finish() { # Clean up and terminate
7272
verbose "Exitcode: ${1:-0}"
7373
case "$Sourced" in
7474
yes)
7575
unset -f usage finish
7676
unset -f error warning note verbose
7777
unset -f rmcr getwslpath escapestring convertpath
78+
unset -f check_display check_displayport cookiebaker makecookie strlenhex
7879
unset -f check_host check_dependency check_dependencies setup_cookie generate_xcommand
7980
unset -f cleanup
8081
unset -f declare_variables parse_options main
@@ -98,26 +99,22 @@ finish() { # Clean up and terminate
9899
;;
99100
esac
100101
}
101-
102102
error() { # Show error message and exit
103103
echo -e "${Colredbg}runx ERROR:${Colnorm} $*
104104
" >&2
105105
Exitcode=1
106106
return 0
107107
}
108-
109108
warning() { # Show warning messages
110109
echo "${Colyellow}runx WARNING:${Colnorm} $*
111110
" >&2
112111
return 0
113112
}
114-
115113
note() { # Show notice messages
116-
echo "${Colgreen}runx note:${Colnorm} $*
114+
[ "$Sourced" = "no" ] && echo "${Colgreen}runx note:${Colnorm} $*
117115
" >&2
118116
return 0
119117
}
120-
121118
verbose() { # Show verbose message (--verbose)
122119
[ "$Verbose" = "yes" ] && note "$*"
123120
return 0
@@ -132,7 +129,6 @@ rmcr() { # Remove carriage return to translate DOS/Window
132129
*) sed -i "s/$(printf "\r")//g" "${1:-}"
133130
esac
134131
}
135-
136132
getwslpath() { # get path to currently running WSL system
137133
# Fork from https://github.com/Microsoft/WSL/issues/2578#issuecomment-354010141
138134
local RUN_ID= BASE_PATH=
@@ -166,12 +162,10 @@ getwslpath() { # get path to currently running WSL system
166162
rm "${RUN_ID}"
167163
return 0
168164
}
169-
170165
escapestring() { # Escape special chars of $1
171166
# escape all characters except those described in [^a-zA-Z0-9,._+@=:/-]
172167
echo "${1:-}" | LC_ALL=C sed -e 's/[^a-zA-Z0-9,._+@=:/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
173168
}
174-
175169
convertpath() { # convert unix and windows pathes
176170
# $1: Mode:
177171
# windows echo Windows path - result: c:/path
@@ -289,9 +283,27 @@ convertpath() { # convert unix and windows pathes
289283

290284
return 0
291285
}
286+
makecookie() { # bake a cookie
287+
mcookie 2>/dev/null || echo $RANDOM$RANDOM$RANDOM$RANDOM$RANDOM$RANDOM | cut -b1-32
288+
}
289+
strlenhex() { # print byte length of string $1 as hex value
290+
printf '%x' "$(printf "%s" "${1:-}" | wc -c)"
291+
}
292292

293293
#### setup
294-
294+
check_displayport() { # return 0 if display number $1 is in use
295+
echo "quit" | env LC_ALL=C telnet "$Hostip" "$((6000+${1:-}))" 2>&1 | grep -q "Connected"
296+
}
297+
check_display() { # find unused display number
298+
local Displaynumber
299+
for Displaynumber in $(seq 999 | shuf); do
300+
check_displayport "$Displaynumber" || {
301+
echo "$Displaynumber"
302+
return 0
303+
}
304+
done
305+
return 1
306+
}
295307
check_host() { # Check host environment
296308

297309
# Check for MS Windows subsystem
@@ -337,7 +349,6 @@ check_host() { # Check host environment
337349

338350
return 0
339351
}
340-
341352
check_dependency() { # Check for single command
342353
[ "${1:-}" ] || return 1
343354
command -v "${1:-}" >/dev/null || {
@@ -346,7 +357,6 @@ check_dependency() { # Check for single command
346357
}
347358
return 0
348359
}
349-
350360
check_dependencies() { # Check all dependencies
351361
local Line
352362

@@ -408,8 +418,13 @@ check_dependencies() { # Check all dependencies
408418
for Line in cmd.exe ipconfig.exe powershell.exe tasklist.exe taskkill.exe; do
409419
check_dependency "$Line" || error "Did not find Windows command: $Line"
410420
done
411-
}
412421

422+
# Linux commands
423+
for Line in telnet; do
424+
check_dependency "$Line" || error "Did not find Linux command: $Line
425+
Please install $Line"
426+
done
427+
}
413428
cookiebaker() { # create an X cookie without xauth
414429
# $1 DISPLAY
415430
# Write directly to file, bash cannot store nullbytes in a string.
@@ -465,13 +480,9 @@ cookiebaker() { # create an X cookie without xauth
465480
printf \"${Code}\"
466481
}"
467482
}
468-
469483
setup_cookie() { # Generate X authentication cookie
470484
local Cookie
471485

472-
Xclientcookie="$(convertpath subsystem "~/runx_Xauthority")"
473-
Xservercookie="$(convertpath subsystem "$(MSYS2_ARG_CONV_EXCL='*' cmd.exe /C "echo %userprofile%")" | rmcr)/runx_Xauthority"
474-
475486
verbose "Cookies:
476487
$Xservercookie
477488
$Xclientcookie"
@@ -507,7 +518,6 @@ $(xauth -v -f "$Xservercookie" list)"
507518
rm $Xclientcookie.tmp
508519
}
509520
}
510-
511521
generate_xcommand() { # Generate command to start X server VcXsrv
512522

513523
Xcommand="$(escapestring "$Xserverexe") :$Newdisplaynumber -listen tcp -retro -lesspointer"
@@ -561,7 +571,6 @@ generate_xcommand() { # Generate command to start X server VcXsrv
561571
}
562572

563573
#### special jobs
564-
565574
cleanup() { # --cleanup: Terminate X servers, delete cookies.
566575
# kill all instances of VcXsrv and remove cookies
567576
MSYS2_ARG_CONV_EXCL='*' tasklist.exe | rmcr | grep -E 'vcxsrv.exe|XWin.exe'
@@ -574,7 +583,6 @@ cleanup() { # --cleanup: Terminate X servers, delete cookies
574583
}
575584

576585
#### main
577-
578586
declare_variables() {
579587
# Default values
580588
Desktopmode="no"
@@ -611,7 +619,6 @@ declare_variables() {
611619
Xserverpid=""
612620
Xwinexe=""
613621
}
614-
615622
parse_options() {
616623
local Shortoptions Longoptions Parsererror
617624

@@ -645,22 +652,26 @@ parse_options() {
645652
shift
646653
done
647654
}
648-
649655
main() {
650-
local Waiting Tasklistold Tasklistnew
651-
652-
[ "$Newdisplaynumber" ] || {
653-
Newdisplaynumber="$((RANDOM / 10))"
654-
Newdisplaynumber="$((Newdisplaynumber + 100))"
655-
note "Using random X display number :$Newdisplaynumber.
656-
If this display number is already in use, X server startup will fail.
657-
You can specify a display number N with option '--display N'."
656+
local Waiting Tasklistold Tasklistnew Xalreadyrunning
657+
658+
Xclientcookie="$(convertpath subsystem "~/runx_Xauthority")"
659+
Xservercookie="$(convertpath subsystem "$(MSYS2_ARG_CONV_EXCL='*' cmd.exe /C "echo %userprofile%")" | rmcr)/runx_Xauthority"
660+
661+
Xalreadyrunning="no"
662+
[ -n "$Newdisplaynumber" ] && {
663+
check_displayport "$Newdisplaynumber" && {
664+
note "Option --display: Display number $Newdisplaynumber seems
665+
to be in use already. runx will try to provide access to it."
666+
Xalreadyrunning="yes"
667+
}
658668
}
659669

660-
[ "$Xauthentication" = "yes" ] && setup_cookie
661-
generate_xcommand
670+
[ -z "$Newdisplaynumber" ] && {
671+
Newdisplaynumber="$(check_display)" || error "runx: Did not find a free display number."
672+
}
662673

663-
[ "$Sourced" = "no" ] && note "Windows firewall settings can forbid application access
674+
note "Windows firewall settings can forbid application access
664675
to the X server. If no application window appears, but no obvious error
665676
is shown, please check your firewall settings.
666677
Compare: https://github.com/mviereck/x11docker/issues/108"
@@ -688,49 +699,54 @@ main() {
688699
;;
689700
esac
690701

691-
case "$Verbose" in
692-
yes) Xcommand="$Xcommand 1>&2" ;;
693-
no) Xcommand="$Xcommand >/dev/null 2>&1" ;;
694-
esac
702+
[ "$Xalreadyrunning" = "no" ] && {
703+
[ "$Xauthentication" = "yes" ] && setup_cookie
704+
generate_xcommand
695705

696-
# Run X in background?
697-
{ [ "$Hostcommand" ] || [ "$Sourced" = "yes" ] ; } && Xcommand="$Xcommand & Xserverpid=\$!"
706+
case "$Verbose" in
707+
yes) Xcommand="$Xcommand 1>&2" ;;
708+
no) Xcommand="$Xcommand >/dev/null 2>&1" ;;
709+
esac
698710

699-
# Store Windows PID list
700-
case $Winsubsystem in
701-
WSL1|WSL2) Tasklistold="$(tasklist.exe | rmcr | grep -i ${Xserver}.exe | awk '{print $2}')" ;;
702-
esac
711+
# Run X in background?
712+
{ [ "$Hostcommand" ] || [ "$Sourced" = "yes" ] ; } && Xcommand="$Xcommand & Xserverpid=\$!"
703713

704-
# Run X server
705-
eval $Xcommand
714+
# Store Windows PID list
715+
case $Winsubsystem in
716+
WSL1|WSL2) Tasklistold="$(tasklist.exe | rmcr | grep -i ${Xserver}.exe | awk '{print $2}')" ;;
717+
esac
706718

707-
# Find Windows PID of X server
708-
case $Winsubsystem in
709-
WSL1|WSL2)
710-
Tasklistnew="$(tasklist.exe | rmcr | grep -i ${Xserver}.exe | awk '{print $2}')"
711-
Xserverwinpid="$(echo "$Tasklistold
712-
$Tasklistnew" | sort | uniq -u | sed '/^$/d')"
713-
verbose "Windows PID of X server: $Xserverwinpid"
714-
;;
715-
esac
719+
# Run X server
720+
eval $Xcommand
716721

717-
# Check for successfull startup
718-
[ "$Xserverpid" ] && {
719-
verbose "Linux PID of X server: $Xserverpid
720-
$(ps -p "$Xserverpid")"
721-
case "$Xserver" in
722-
xwin)
723-
for Waiting in 1 2 3 4 5 6 7 8 9 10; do
724-
[ -e "$(dirname "$Xwinexe")/../../tmp/.X11-unix/X$Newdisplaynumber" ] && Xready="yes"
725-
[ -e "$(dirname "$Xwinexe")/../tmp/.X11-unix/X$Newdisplaynumber" ] && Xready="yes"
726-
sleep 1
727-
[ "$Xready" ] && break
728-
verbose "Waiting since ${Waiting}s for XWin to be ready."
729-
done
730-
[ "$Xready" ] && verbose "X server XWin ready after ${Waiting}s." || error "X server XWin not ready after ${Waiting}s."
722+
# Find Windows PID of X server
723+
case $Winsubsystem in
724+
WSL1|WSL2)
725+
Tasklistnew="$(tasklist.exe | rmcr | grep -i ${Xserver}.exe | awk '{print $2}')"
726+
Xserverwinpid="$(echo "$Tasklistold
727+
$Tasklistnew" | sort | uniq -u | sed '/^$/d')"
728+
verbose "Windows PID of X server: $Xserverwinpid"
731729
;;
732-
vcxsrv) sleep 1 ;;
733730
esac
731+
732+
# Check for successfull startup
733+
[ "$Xserverpid" ] && {
734+
verbose "Linux PID of X server: $Xserverpid
735+
$(ps -p "$Xserverpid")"
736+
case "$Xserver" in
737+
xwin)
738+
for Waiting in 1 2 3 4 5 6 7 8 9 10; do
739+
[ -e "$(dirname "$Xwinexe")/../../tmp/.X11-unix/X$Newdisplaynumber" ] && Xready="yes"
740+
[ -e "$(dirname "$Xwinexe")/../tmp/.X11-unix/X$Newdisplaynumber" ] && Xready="yes"
741+
sleep 1
742+
[ "$Xready" ] && break
743+
verbose "Waiting since ${Waiting}s for XWin to be ready."
744+
done
745+
[ "$Xready" ] && verbose "X server XWin ready after ${Waiting}s." || error "X server XWin not ready after ${Waiting}s."
746+
;;
747+
vcxsrv) sleep 1 ;;
748+
esac
749+
}
734750
}
735751

736752
# Run host command

0 commit comments

Comments
 (0)