VMware has an option to create virtual serial ports. The “Named Pipe” used under Linux is actually a UNIX domain socket, which is not easily accessed by most tools. My goal was to be able to connect to the virtual serial port using minicom the same way I would connect to a physical device with a real serial port.
The solution is to use socat along with Unix98 pseudo-terminals (/dev/pts/*).
I set up the Virtual Machine to “Use named pipe”, “This end is the client”, “The other end is an application”, and “Yield CPU on poll”. I put the pipe in /export/vmware/DUT.serial0.
At host startup I run the following socat command using start-stop-daemon:
# start-stop-daemon --start --pidfile /var/run/socat.DUT.pid \
--background --make-pidfile \
--exec /usr/bin/socat -- \
-ly -d -lpsocat:DUT \
PTY,b115200,raw,link=/dev/ttyDUTSerial0,group=uucp,mode=660 \
UNIX-LISTEN:/export/vmware/DUT.serial0,fork,owner=frank,group=frank,mode=755
DUT is a placeholder for the virtual machine’s name.
I can then make a minicom config using /dev/ttyDUTSerial0 for the serial port and work as usual.
The above is actually wrapped up in some Gentoo init scripts.
In /etc/conf.d/socat I have:
# socat configuration
# add dependencies to socat_use, socat_need, socat_before, and socat_after
socat_use="net"
# Common args used for all invocations. This is an Array.
#
# -ly : log to syslog
socat_args=( -ly -d )
# Configurations to auto-start. This is an Array.
socat_autostart=( WCBSerial0 )
# Lists of arguments for each configuration. These are arrays to better support
# embedded spaces in arguments.
socat_WCBSerial0=(
"PTY,b115200,raw,link=/dev/ttyWCBSerial0,group=uucp,mode=660"
"UNIX-LISTEN:/export/vmware/WCB.serial0,fork,owner=frank,group=frank,mode=755"
)
socat_WCBSerial1=(
"PTY,b115200,raw,link=/dev/ttyWCBSerial1,group=uucp,mode=660"
"UNIX-LISTEN:/var/run/vmware/WCB.serial1,fork,group=uucp,mode=755"
)
and in /etc/init.d/socat I have:
#!/sbin/runscript
# Copyright 2008 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo-x86/sys-libs/gpm/files/gpm.rc6,v 1.12 2004/07/15 01:02:02 agriffis Exp $
#NB: Config is in /etc/conf.d/socat
autostart_count=${#socat_autostart[@]}
socat=${socat:-/usr/bin/socat}
depend() {
local t a
for t in $deptypes $ordtypes ; do
a="socat_${t}"
a="${!a}"
[ -n "$a" ] && $t $a
done
}
checkconfig() {
local i a n name
for (( i=0; i< $autostart_count; i++ )) ; do
name=${socat_autostart[$i]}
a="socat_${name}[@]"
a=( "${!a}" )
n=${#a[@]}
if [ $n -lt 2 ] ; then
eerror "Too few args ($n) for socat.$name (${a[*]})"
return 1
fi
done
}
start() {
checkconfig || return 1
local i a n name extra
for (( i=0; i<$autostart_count; i++ )); do
let n=i+1
name=${socat_autostart[$i]}
a="socat_${name}[@]"
a=( "${!a}" )
ebegin "Starting socat config $name ($n of $autostart_count)"
#echo $socat "${socat_args[@]}" -lpsocat:$name "${a[@]}"
start-stop-daemon --start --pidfile /var/run/socat.$name.pid \
--background --make-pidfile \
--exec $socat -- \
"${socat_args[@]}" -lpsocat:$name "${a[@]}" \
< /dev/null
eend ${?}
done
}
stop() {
local i n name
for (( i=0; i<$autostart_count; i++ )); do
let n=i+1
name=${socat_autostart[$i]}
ebegin "Stopping socat config $name ($n of $autostart_count)"
start-stop-daemon --stop --pidfile /var/run/socat.$name.pid \
--exec $socat
eend ${?}
done
}