diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f793e4c..e730314c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. Project website: https://github.com/mviereck/x11docker ## [Unreleased] +### Changed + - Adjustments to support [MSYS2/CYGWIN/MINGW](https://www.msys2.org/). + [(#55)](https://github.com/mviereck/x11docker/issues/55) ### Fixed - `--xpra`: Support of outdated xpra version v0.17.6 that is still distributed in debian stretch and buster. - `--pw gksu`, `--pw gksudo`: Disable keyboard grabbing to avoid issues with Gnome 3 Wayland session. - `--xpra`: Check if `xhost` is available if xpra version 2.3.1 has cookie - issue. [(#57)](https://github.com/mviereck/x11docker/issues/53) + issue. [(#57)](https://github.com/mviereck/x11docker/issues/57) - `--xpra-xwayland`: Set Weston `--fullscreen` to get Xwayland resolution matching host display. Weston v4.0.0 seems to interpret screen size settings in `weston.ini` different than before. diff --git a/x11docker b/x11docker index 501d0d9e..c9082164 100755 --- a/x11docker +++ b/x11docker @@ -429,7 +429,7 @@ logentry() { # write into logfile [ "$Logfile" ] && echo "$*" >>$Logfile ||: } killpid() { # kill PID $1 with codename $2 [and process name $3] - verbose -d "Terminating ${1:-} (${2:-}) ${3:-}: $(ps --no-headers -p ${1:-})" + verbose -d "Terminating ${1:-} (${2:-}) ${3:-}: $(pspid ${1:-})" ps -p ${1:-} >/dev/null && { [ "${3:-}" ] && { ps -p ${1:-} | grep -q -E "${3:-}" && kill ${1:-} 2>/dev/null @@ -451,7 +451,7 @@ finish() { # trap EXIT routine to clean up background processes and verbose -d "Terminating x11docker." checkpid $Pid1pid && verbose -d "Process tree of container: -$(pstree -p $Pid1pid ||:)" +$(pstree -p $Pid1pid 2>&1 ||:)" debugnote "List of stored background processes: $(cat $Bgpidfile 2>/dev/null)" @@ -463,7 +463,7 @@ $(cat $Bgpidfile 2>/dev/null)" while read -r Line ; do Pid=$(echo $Line | awk '{print $1}') Name=$(echo $Line | awk '{print $2}') - debugnote "Checking: $Pid ($Name): $(ps -p $Pid --no-headers ||:)" + debugnote "Checking: $Pid ($Name): $(pspid $Pid ||:)" checkpid $Pid && { case $Name in xinit) killpid $Pid $Name xinit ;; @@ -484,8 +484,8 @@ $(cat $Bgpidfile 2>/dev/null)" Pid= # Send TERM to PID1 of container checkpid $Pid1pid 2>&1 && { - verbose -d "Sending TERM to PID 1 of container ($(ps --no-headers -p $Pid1pid))" - killpid $Pid1pid 2>/dev/null || note "Could not terminate PID 1 of container: $(ps --no-headers -p $Pid1pid)" + verbose -d "Sending TERM to PID 1 of container ($(pspid $Pid1pid))" + killpid $Pid1pid 2>/dev/null || note "Could not terminate PID 1 of container: $(pspid $Pid1pid)" # Give container a bit time for graceful shutdown for Count in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0; do checkpid $Pid1pid || break @@ -507,7 +507,7 @@ $(ps -p $Pid)" esac checkpid $Pid && { sleep 1 - checkpid $Pid && debugnote "Issue terminating $Line: $(ps -p --no-headers $Pid)" && kill -s KILL $Pid + checkpid $Pid && debugnote "Issue terminating $Line: $(pspid $Pid)" && kill -s KILL $Pid } } done < <(tac $Bgpidfile) @@ -567,7 +567,7 @@ saygoodbye() { # create file signaling watching processes to terminate verbose -d "time to say goodbye ($*)" [ -e "$Sharefolder" ] && { echo timetosaygoodbye >> $Timetosaygoodbye - echo timetosaygoodbye >&8 + echo timetosaygoodbye >> $Timetosaygoodbyefifo } } mywatch() { # repeat $1 untils its output changes @@ -596,7 +596,9 @@ watchpidlist() { # watch list of important pids read -t1 Pid <&9 ||: [ "$Pid" ] && { Watchpidlist="$Watchpidlist $Pid" - debugnote "Watching $(ps --no-headers -p $Pid)" + debugnote "Watching $(pspid $Pid)" + } || { + [ "$Cygwin" ] && sleep 1 } for Pid in $Watchpidlist; do [ -e /proc/$Pid ] || { @@ -608,14 +610,16 @@ watchpidlist() { # watch list of important pids saygoodbye "watchpidlist" } setonwatchpidlist() { # add PID $1 to watchpidlist() - echo ${1:-} >&9 + #echo ${1:-} >&9 + echo ${1:-} >>$Watchpidfifo } watchmessagefifo() { # watch for messages out of container or dockerrc # message in fifo must end with :$Messagetype local Line= Message= Messagetype= while rocknroll ; do + [ "$Line" ] || sleep 1 IFS= read -r Line <&6 ||: - Message="$Message + [ "$Line" ] && Message="$Message $Line" grep -q -E ":WARNING|:NOTE|:DEBUGNOTE|:VERBOSE|:ERROR|:STDOUT" <<< "$Line" && { Messagetype=":$(echo $Line | rev | cut -d: -f1 | rev)" @@ -740,7 +744,10 @@ storepid () { # store pid $1 and name $2 of background process in file disown ${1:-} 2>/dev/null ||: } checkpid() { # check if PID $1 is active - ps -p ${1:-0} >/dev/null 2>&1 + ps -p ${1:-} >/dev/null 2>&1 +} +pspid() { # ps -p --no-headers $1 + ps -p ${1:-} | tail -n+2 } no_xhost() { # remove any access to X server granted by xhost local Line= @@ -1147,11 +1154,6 @@ export IFS=$' \n\t' # set IFS to default exec 3>&2 # stderr channel for warning() and error() exec 4>&2 # stderr channel for --stderr -pstree -ps $$ | grep -q sshd && Ssh="yes" || Ssh="no" # check if running over SSH ### FIXME pstree is not available everywhere -tty | grep -q tty && Tty="yes" || Tty="no" # check if running on X or on tty -Ttyinuse= -XDG_VTNR=${XDG_VTNR:-} - export PATH="$PATH:/usr/games:/usr/local/bin" # may miss for root, but can be needed for --exe and --xfishtank export PATH="$PATH:/usr/sbin:/sbin" # may miss for unprivileged users, but can be needed for `ip` @@ -1262,11 +1264,16 @@ Hostdisplaynumber="$(echo $Hostdisplay | cut -d: -f2 | cut -d. -f1)" Hostxauthority="Xauthority-$Hostdisplaynumber" # file to store copy of $XAUTHORITY [ -n "$Hostdisplay" ] && Hostxsocket="/tmp/.X11-unix/X$Hostdisplaynumber" || Hostxsocket="" # X socket from host, needed for --hostdisplay [ -e "$Hostxsocket" ] || Hostxsocket="" # can miss in SSH session +Hostxenv="" # collection of host X environment variables Hostlibc="unknown" # check libc:glibc, musl or others. Needed to eventually provide time zone file. ldd --version 2>&1 | grep -q 'musl libc' && Hostlibc='musl' ldd --version 2>&1 | grep -q -E 'GLIBC|GNU libc' && Hostlibc='glibc' Hostlocaltime="$(realpath /etc/localtime)" # find time zone file in /usr/share/zoneinfo Hostutctime=$(date +%:::z) ; [ "$(cut -c1 <<< "$Hostutctime")" = "+" ] && Hostutctime="UTC-$(cut -c2- <<< "$Hostutctime")" || Hostutctime="UTC+$(cut -c2- <<< "$Hostutctime")" # offset of UTC if time zone file cannot be provided +[ "${MSYSTEM:-}${CYGWIN:-}" ] && Cygwin="yes" || Cygwin="no" # Running on Cygwin/MSYS2 ? +Ssh="" +Tty="" +Ttyinuse="" # X server settings Xserver="" # X server option to use @@ -1434,23 +1441,23 @@ Wm_all="$Wm_recommended_nodesktop_light $Wm_recommended_nodesktop_heavy $Wm_rec Messagefifofuncs=' warning() { - echo "$*:WARNING" >&3 + echo "$*:WARNING" >>$Messagefile } note() { - echo "$*:NOTE" >&3 + echo "$*:NOTE" >>$Messagefile } verbose() { - echo "$*:VERBOSE" >&3 + echo "$*:VERBOSE" >>$Messagefile } debugnote() { - echo "$*:DEBUGNOTE" >&3 + echo "$*:DEBUGNOTE" >>$Messagefile } error() { - echo "$*:ERROR" >&3 + echo "$*:ERROR" >>$Messagefile exit 1 } stdout() { - echo "$*:STDOUT" >&3 + echo "$*:STDOUT" >>$Messagefile }' } @@ -1747,7 +1754,7 @@ $Customenvironment" ; shift ;; # set custom environm https://github.com/mviereck/x11docker" verbose "x11docker version $Version -docker version: $(docker --version) +docker version: $(docker --version 2>&1) Host system: $(source /etc/os-release 2>/dev/null; echo "$PRETTY_NAME") Command: $0 $X11dockerargs Parsed options: $Parsedoptions" @@ -1762,6 +1769,15 @@ $(cowsay "$Wisdom" 2>/dev/null || echo "Wanda the fish says: $Wisdom")" trap 'traperror $? $LINENO $BASH_LINENO "$BASH_COMMAND" $(printf "::%s" ${FUNCNAME[@]})' ERR } + # Check ssh and tty + pstree -ps $$ 2>/dev/null | grep -q sshd && Ssh="yes" || Ssh="no" # check if running over SSH ### FIXME pstree is not available everywhere + command -v pstree >/dev/null || { + [ "${SSH_CLIENT:-}" ] && Ssh="yes" || warning "Could not check whether x11docker is running over ssh. + Please install pstree." + } + tty | grep -q tty && Tty="yes" || Tty="no" # check if running on X or on tty + XDG_VTNR=${XDG_VTNR:-} + [ "$Cachebasefolder" != "$(echo $Cachebasefolder | sed -e 's/ *//g')" ] && error "Cache root folder must not contain whitespaces. $Cachebasefolder" @@ -1825,7 +1841,7 @@ $(cowsay "$Wisdom" 2>/dev/null || echo "Wanda the fish says: $Wisdom")" Hostexe="sleep infinity" Imagename="" Imagecommand="" - Hostexebasename="xonly" + Hostexebasename="" X11dockermode="exe" ;; esac @@ -1838,7 +1854,7 @@ $(cowsay "$Wisdom" 2>/dev/null || echo "Wanda the fish says: $Wisdom")" [ "$Gpu" = "yes" ] && Xserver="--xpra-xwayland" [ "$Xfishtank" = "yes" ] && Xserver="--xephyr" [ "$Desktopmode" = "yes" ] && Xserver="--xephyr" - [ -z "$Imagename" ] && { Xserver="--xephyr" ; Desktopmode="yes" ; } + [ -z "$Imagename$Hostexebasename" ] && { Xserver="--xephyr" ; Desktopmode="yes" ; } [ "$Xserver" = "--xephyr" ] && { depends --xephyr || Xserver="--weston-xwayland" ; } [ "$Gpu" = "yes" ] && [ "$Xserver" = "--xephyr" ] && Xserver="--weston-xwayland" [ "$Outputcount" != "1" ] && Xserver="--weston-xwayland" @@ -2460,47 +2476,44 @@ $(cowsay "$Wisdom" 2>/dev/null || echo "Wanda the fish says: $Wisdom")" ;; esac - Timetosaygoodbyefifo="$Sharefolder/$Timetosaygoodbyefifo" && $Mksu "mkfifo $Timetosaygoodbyefifo" - Timetosaygoodbye="$Sharefolder/$Timetosaygoodbye" && mkfile $Timetosaygoodbye - Watchpidfifo="$Cachefolder/$Watchpidfifo" && $Mksu "mkfifo $Watchpidfifo" - Messagefifo="$Sharefolder/$Messagefifo" && $Mksu "mkfifo $Messagefifo && chmod 666 $Messagefifo" - Xinitrc="$Cachefolder/$Xinitrc" && mkfile $Xinitrc - Xinitlogfile="$Cachefolder/$Xinitlogfile" && mkfile $Xinitlogfile - Xtermrc="$Cachefolder/$Xtermrc" && mkfile $Xtermrc - Pullrc="$Cachefolder/$Pullrc" && mkfile $Pullrc - Containerlogfile="$Cachefolder/$Containerlogfile" && mkfile $Containerlogfile - Containerpidfile="$Cachefolder/$Containerpidfile" && mkfile $Containerpidfile - Containeridfile="$Cachefolder/$Containeridfile" && mkfile $Containeridfile - Containerpid1pidfile="$Cachefolder/$Containerpid1pidfile" && mkfile $Containerpid1pidfile - Dockerrc="$Cachefolder/$Dockerrc" && mkfile $Dockerrc - Containerrootsetupscript="$Sharefolder/$Containerrootsetupscript" && mkfile $Containerrootsetupscript - Containeripfile="$Cachefolder/$Containeripfile" && mkfile $Containeripfile - Xservercookie="$Cachefolder/$Xservercookie" && mkfile $Xservercookie - Xclientcookie="$Sharefolder/$Xclientcookie" && mkfile $Xclientcookie - Hostxauthority="$Cachefolder/$Hostxauthority" && mkfile $Hostxauthority - Xpraserverlogfile="$Cachefolder/$Xpraserverlogfile" && mkfile $Xpraserverlogfile - Xpraclientlogfile="$Cachefolder/$Xpraclientlogfile" && mkfile $Xpraclientlogfile - Compositorlogfile="$Cachefolder/$Compositorlogfile" && mkfile $Compositorlogfile - Compositorpidfile="$Cachefolder/$Compositorpidfile" && mkfile $Compositorpidfile - Pulseaudioconf="$Cachefolder/$Pulseaudioconf" && mkfile $Pulseaudioconf - Bgpidfile="$Cachefolder/$Bgpidfile" && mkfile $Bgpidfile - Imagecommandscript="$Sharefolder/$Imagecommandscript" && mkfile $Imagecommandscript - Shareclipboardscript="$Cachefolder/$Shareclipboardscript" && mkfile $Shareclipboardscript - Westonini="$Cachefolder/$Westonini" && mkfile $Westonini - Xdummyconf="$Cachefolder/$Xdummyconf" && mkfile $Xdummyconf - Xorgwrapper="$Cachefolder/$Xorgwrapper" && mkfile $Xorgwrapper - Xkbkeymapfile="$Cachefolder/$Xkbkeymapfile" && mkfile $Xkbkeymapfile + Timetosaygoodbye="$Sharefolder/$Timetosaygoodbye" && mkfile $Timetosaygoodbye + Xinitrc="$Cachefolder/$Xinitrc" && mkfile $Xinitrc + Xinitlogfile="$Cachefolder/$Xinitlogfile" && mkfile $Xinitlogfile + Xtermrc="$Cachefolder/$Xtermrc" && mkfile $Xtermrc + Pullrc="$Cachefolder/$Pullrc" && mkfile $Pullrc + Containerlogfile="$Cachefolder/$Containerlogfile" && mkfile $Containerlogfile + Containerpidfile="$Cachefolder/$Containerpidfile" && mkfile $Containerpidfile + Containeridfile="$Cachefolder/$Containeridfile" && mkfile $Containeridfile + Containerpid1pidfile="$Cachefolder/$Containerpid1pidfile" && mkfile $Containerpid1pidfile + Dockerrc="$Cachefolder/$Dockerrc" && mkfile $Dockerrc + Containerrootsetupscript="$Sharefolder/$Containerrootsetupscript" && mkfile $Containerrootsetupscript + Containeripfile="$Cachefolder/$Containeripfile" && mkfile $Containeripfile + Xservercookie="$Cachefolder/$Xservercookie" && mkfile $Xservercookie + Xclientcookie="$Sharefolder/$Xclientcookie" && mkfile $Xclientcookie + Hostxauthority="$Cachefolder/$Hostxauthority" && mkfile $Hostxauthority + Xpraserverlogfile="$Cachefolder/$Xpraserverlogfile" && mkfile $Xpraserverlogfile + Xpraclientlogfile="$Cachefolder/$Xpraclientlogfile" && mkfile $Xpraclientlogfile + Compositorlogfile="$Cachefolder/$Compositorlogfile" && mkfile $Compositorlogfile + Compositorpidfile="$Cachefolder/$Compositorpidfile" && mkfile $Compositorpidfile + Pulseaudioconf="$Cachefolder/$Pulseaudioconf" && mkfile $Pulseaudioconf + Bgpidfile="$Cachefolder/$Bgpidfile" && mkfile $Bgpidfile + Imagecommandscript="$Sharefolder/$Imagecommandscript" && mkfile $Imagecommandscript + Shareclipboardscript="$Cachefolder/$Shareclipboardscript" && mkfile $Shareclipboardscript + Westonini="$Cachefolder/$Westonini" && mkfile $Westonini + Xdummyconf="$Cachefolder/$Xdummyconf" && mkfile $Xdummyconf + Xorgwrapper="$Cachefolder/$Xorgwrapper" && mkfile $Xorgwrapper + Xkbkeymapfile="$Cachefolder/$Xkbkeymapfile" && mkfile $Xkbkeymapfile mv $Logfile $Sharefolder/x11docker.log Logfile="$Sharefolder/x11docker.log" # Cache folder for x11docker-gui. Created here to store image list in dockerrc for x11docker-gui mkdir -p $Cachebasefolder/x11docker-gui && chown $Hostuser $Cachebasefolder/x11docker-gui - + # standard streams for container - Cmdstdinfile="$Sharefolder/$Cmdstdinfile" && $Mksu "mkfifo $Cmdstdinfile" - Cmdstdoutlogfile="$Sharefolder/$Cmdstdoutlogfile" && mkfile $Cmdstdoutlogfile 666 - Cmdstderrlogfile="$Sharefolder/$Cmdstderrlogfile" && mkfile $Cmdstderrlogfile 666 + Cmdstdinfile="$Sharefolder/$Cmdstdinfile" && $Mksu "mkfifo $Cmdstdinfile" + Cmdstdoutlogfile="$Sharefolder/$Cmdstdoutlogfile" && mkfile $Cmdstdoutlogfile 666 + Cmdstderrlogfile="$Sharefolder/$Cmdstderrlogfile" && mkfile $Cmdstderrlogfile 666 mkfile "$Sharefolder/environment" } @@ -4253,10 +4266,9 @@ DefaultEnvironment=DISPLAY=$Newdisplay XAUTHORITY=$Cshare/Xclientcookie $(IFS=$' echo "Hostusergid=$Hostusergid" echo "Timetosaygoodbye=$Timetosaygoodbye" echo "$Messagefifofuncs" - echo "exec 3<>$Sharefolder/message.fifo" + echo "Messagefile=$Messagefifo" echo "" echo "verbose -d 'Running dockerrc'" - [ "$Debugmode" = "yes" ] && { echo "PS4='$DebugPS4'" #echo "set -x" @@ -4274,7 +4286,7 @@ DefaultEnvironment=DISPLAY=$Newdisplay XAUTHORITY=$Cshare/Xclientcookie $(IFS=$' Is docker daemon running at all? Try to start docker daemon with: systemctl start docker - + Last lines of log: \$(tail $Containerlogfile)\"" echo "mkfile $Cachebasefolder/x11docker-gui/images.list" @@ -4364,7 +4376,7 @@ DefaultEnvironment=DISPLAY=$Newdisplay XAUTHORITY=$Cshare/Xclientcookie $(IFS=$' echo " echo '# runs as unprivileged user in container'" echo " echo '$Messagefifofuncs'" - echo " echo 'exec 3<>$Cshare/message.fifo'" + echo " echo 'Messagefile=$Cshare/message.fifo'" echo " echo ''" echo " echo '# wait for container setup script do be ready'" @@ -4590,7 +4602,7 @@ DefaultEnvironment=DISPLAY=$Newdisplay XAUTHORITY=$Cshare/Xclientcookie $(IFS=$' echo "" echo "$Messagefifofuncs" - echo "exec 3<>$Cshare/message.fifo" + echo "Messagefile=$Cshare/message.fifo" echo "" echo "verbose -d 'Running setup as root in container'" @@ -5088,7 +5100,7 @@ exit 0' >> /etc/rc.local" declare -f no_xhost echo "$Messagefifofuncs" - echo "exec 3<>$Messagefifo" + echo "Messagefile=$Messagefifo" echo "" echo "verbose -d 'Running xinitrc'" @@ -5374,7 +5386,8 @@ exit 0' >> /etc/rc.local" Terminal for password frontend: $Passwordterminal Terminal to show docker pull progress: $Pullterminal Running on console: $Tty - Running over SSH: $Ssh" + Running over SSH: $Ssh + Running on CYGWIN: $Cygwin" case $X11dockermode in run) verbose "Generated container.rootsetup.sh: @@ -5456,6 +5469,19 @@ Keywords=docker x11docker $(echo $Name | tr -c '[:alpha:][:digit:][:blank:]' ' ' cat <&0 >$Cmdstdinfile & storepid $! catstdin } + case $Cygwin in + no) + Watchpidfifo="$Cachefolder/$Watchpidfifo" && $Mksu "mkfifo $Watchpidfifo" + Messagefifo="$Sharefolder/$Messagefifo" && $Mksu "mkfifo $Messagefifo && chmod 666 $Messagefifo" + Timetosaygoodbyefifo="$Sharefolder/$Timetosaygoodbyefifo" && $Mksu "mkfifo $Timetosaygoodbyefifo" + ;; + yes) + Watchpidfifo="$Cachefolder/$Watchpidfifo" && mkfile $Watchpidfifo + Messagefifo="$Sharefolder/$Messagefifo" && mkfile $Messagefifo && chmod 666 $Messagefifo + Timetosaygoodbyefifo="$Sharefolder/$Timetosaygoodbyefifo" && mkfile $Timetosaygoodbyefifo && chmod 666 $Timetosaygoodbyefifo + ;; + esac + # used by waitfortheend() exec 8<>$Timetosaygoodbyefifo @@ -5568,7 +5594,7 @@ $(tail $Xpraserverlogfile)" [ -n "$Xpraclientpid" ] && note "Restarting Xpra client." $Mksu "env $Hostxenv XPRA_PADDING_COLORS='0,0.2,1' $Xpraclientcommand" >> $Xpraclientlogfile 2>&1 & Xpraclientpid=$! && storepid $Xpraclientpid xpraclient - checkpid $Xpraclientpid && mywatch "ps --no-headers -p $Xpraserverpid -o pid ; ps --no-headers -p $Xpraclientpid -o pid #xpra" + checkpid $Xpraclientpid && mywatch "ps -p $Xpraserverpid -o pid ; ps -p $Xpraclientpid -o pid #xpra" tail $Xpraserverlogfile | grep -q "client ping timeout" || saygoodbye xpraclient done & storepid $! xpraloop ;; @@ -5604,7 +5630,7 @@ $(tail $Xpraserverlogfile)" storepid $Containerpid container setonwatchpidlist $(cat $Containerpid1pidfile) verbose -d "Process tree of container (maybe not complete yet): -$(pstree -cp $(cat $Containerpid1pidfile))" +$(pstree -cp $(cat $Containerpid1pidfile) 2>&1)" } || { [ "$Xserver" = "--nothing" ] && saygoodbye "--nothing" || { error "Container startup seems to have failed! @@ -5659,7 +5685,7 @@ $(tail $Logfile)" echo $Hostexepid >>$Containerpid1pidfile debugnote "Process tree of $Hostexe: -$(pstree -p $Hostexepid)" +$(pstree -p $Hostexepid 2>&1)" storepid $Hostexepid hostexe setonwatchpidlist $Hostexepid @@ -5668,7 +5694,7 @@ $(pstree -p $Hostexepid)" } debugnote "Process tree of x11docker: -$(pstree -p $$)" +$(pstree -p $$ 2>&1)" } & storepid $! containershell #### { #### part: start Compositor