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
}