1
1
#! /bin/bash
2
2
# runx: Provide an X server in Cygwin, MSYS2 or WSL.
3
3
4
- Version=" v0.4.3 "
4
+ Version=" v0.4.4 "
5
5
6
6
usage () { # Usage information (--help)
7
7
echo " runx - Run Linux GUI applications on MS Windows.
@@ -20,7 +20,8 @@ Options:
20
20
--xwin Use X server XWin.
21
21
--clipboard [=yes|no] Enable clipboard sharing yes/no. Default: yes.
22
22
--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.
24
25
--ip ADRESS IP adress to use. Default: First found 192.168.*
25
26
--no-auth Disable X cookie authentication. Discouraged.
26
27
--cleanup Stop all X servers and delete cookies.
@@ -67,14 +68,14 @@ runx version $Version
67
68
Please report issues and get help at: https://github.com/mviereck/runx
68
69
" >&2
69
70
}
70
-
71
71
finish () { # Clean up and terminate
72
72
verbose " Exitcode: ${1:- 0} "
73
73
case " $Sourced " in
74
74
yes)
75
75
unset -f usage finish
76
76
unset -f error warning note verbose
77
77
unset -f rmcr getwslpath escapestring convertpath
78
+ unset -f check_display check_displayport cookiebaker makecookie strlenhex
78
79
unset -f check_host check_dependency check_dependencies setup_cookie generate_xcommand
79
80
unset -f cleanup
80
81
unset -f declare_variables parse_options main
@@ -98,26 +99,22 @@ finish() { # Clean up and terminate
98
99
;;
99
100
esac
100
101
}
101
-
102
102
error () { # Show error message and exit
103
103
echo -e " ${Colredbg} runx ERROR:${Colnorm} $*
104
104
" >&2
105
105
Exitcode=1
106
106
return 0
107
107
}
108
-
109
108
warning () { # Show warning messages
110
109
echo " ${Colyellow} runx WARNING:${Colnorm} $*
111
110
" >&2
112
111
return 0
113
112
}
114
-
115
113
note () { # Show notice messages
116
- echo " ${Colgreen} runx note:${Colnorm} $*
114
+ [ " $Sourced " = " no " ] && echo " ${Colgreen} runx note:${Colnorm} $*
117
115
" >&2
118
116
return 0
119
117
}
120
-
121
118
verbose () { # Show verbose message (--verbose)
122
119
[ " $Verbose " = " yes" ] && note " $* "
123
120
return 0
@@ -132,7 +129,6 @@ rmcr() { # Remove carriage return to translate DOS/Window
132
129
* ) sed -i " s/$( printf " \r" ) //g" " ${1:- } "
133
130
esac
134
131
}
135
-
136
132
getwslpath () { # get path to currently running WSL system
137
133
# Fork from https://github.com/Microsoft/WSL/issues/2578#issuecomment-354010141
138
134
local RUN_ID= BASE_PATH=
@@ -166,12 +162,10 @@ getwslpath() { # get path to currently running WSL system
166
162
rm " ${RUN_ID} "
167
163
return 0
168
164
}
169
-
170
165
escapestring () { # Escape special chars of $1
171
166
# escape all characters except those described in [^a-zA-Z0-9,._+@=:/-]
172
167
echo " ${1:- } " | LC_ALL=C sed -e ' s/[^a-zA-Z0-9,._+@=:/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
173
168
}
174
-
175
169
convertpath () { # convert unix and windows pathes
176
170
# $1: Mode:
177
171
# windows echo Windows path - result: c:/path
@@ -289,9 +283,27 @@ convertpath() { # convert unix and windows pathes
289
283
290
284
return 0
291
285
}
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
+ }
292
292
293
293
# ### 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
+ }
295
307
check_host () { # Check host environment
296
308
297
309
# Check for MS Windows subsystem
@@ -337,7 +349,6 @@ check_host() { # Check host environment
337
349
338
350
return 0
339
351
}
340
-
341
352
check_dependency () { # Check for single command
342
353
[ " ${1:- } " ] || return 1
343
354
command -v " ${1:- } " > /dev/null || {
@@ -346,7 +357,6 @@ check_dependency() { # Check for single command
346
357
}
347
358
return 0
348
359
}
349
-
350
360
check_dependencies () { # Check all dependencies
351
361
local Line
352
362
@@ -408,8 +418,13 @@ check_dependencies() { # Check all dependencies
408
418
for Line in cmd.exe ipconfig.exe powershell.exe tasklist.exe taskkill.exe; do
409
419
check_dependency " $Line " || error " Did not find Windows command: $Line "
410
420
done
411
- }
412
421
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
+ }
413
428
cookiebaker () { # create an X cookie without xauth
414
429
# $1 DISPLAY
415
430
# Write directly to file, bash cannot store nullbytes in a string.
@@ -465,13 +480,9 @@ cookiebaker() { # create an X cookie without xauth
465
480
printf \" ${Code} \"
466
481
}"
467
482
}
468
-
469
483
setup_cookie () { # Generate X authentication cookie
470
484
local Cookie
471
485
472
- Xclientcookie=" $( convertpath subsystem " ~/runx_Xauthority" ) "
473
- Xservercookie=" $( convertpath subsystem " $( MSYS2_ARG_CONV_EXCL=' *' cmd.exe /C " echo %userprofile%" ) " | rmcr) /runx_Xauthority"
474
-
475
486
verbose " Cookies:
476
487
$Xservercookie
477
488
$Xclientcookie "
@@ -507,7 +518,6 @@ $(xauth -v -f "$Xservercookie" list)"
507
518
rm $Xclientcookie .tmp
508
519
}
509
520
}
510
-
511
521
generate_xcommand () { # Generate command to start X server VcXsrv
512
522
513
523
Xcommand=" $( escapestring " $Xserverexe " ) :$Newdisplaynumber -listen tcp -retro -lesspointer"
@@ -561,7 +571,6 @@ generate_xcommand() { # Generate command to start X server VcXsrv
561
571
}
562
572
563
573
# ### special jobs
564
-
565
574
cleanup () { # --cleanup: Terminate X servers, delete cookies.
566
575
# kill all instances of VcXsrv and remove cookies
567
576
MSYS2_ARG_CONV_EXCL=' *' tasklist.exe | rmcr | grep -E ' vcxsrv.exe|XWin.exe'
@@ -574,7 +583,6 @@ cleanup() { # --cleanup: Terminate X servers, delete cookies
574
583
}
575
584
576
585
# ### main
577
-
578
586
declare_variables () {
579
587
# Default values
580
588
Desktopmode=" no"
@@ -611,7 +619,6 @@ declare_variables() {
611
619
Xserverpid=" "
612
620
Xwinexe=" "
613
621
}
614
-
615
622
parse_options () {
616
623
local Shortoptions Longoptions Parsererror
617
624
@@ -645,22 +652,26 @@ parse_options() {
645
652
shift
646
653
done
647
654
}
648
-
649
655
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
+ }
658
668
}
659
669
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
+ }
662
673
663
- [ " $Sourced " = " no " ] && note " Windows firewall settings can forbid application access
674
+ note " Windows firewall settings can forbid application access
664
675
to the X server. If no application window appears, but no obvious error
665
676
is shown, please check your firewall settings.
666
677
Compare: https://github.com/mviereck/x11docker/issues/108"
@@ -688,49 +699,54 @@ main() {
688
699
;;
689
700
esac
690
701
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
695
705
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
698
710
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=\$ !"
703
713
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
706
718
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
716
721
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 "
731
729
;;
732
- vcxsrv) sleep 1 ;;
733
730
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
+ }
734
750
}
735
751
736
752
# Run host command
0 commit comments