summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2020-03-31 09:39:11 +0000
committerAlyssa Ross <hi@alyssa.is>2020-06-15 09:37:25 +0000
commita201fd46bd0549655b85bcd6e609fdabd1add837 (patch)
tree1f51d7e5e54fb7f715cdcc45451ff114ab597f94
parent89f45363b3c902edaa137e5bc0ada605c604d854 (diff)
downloadcrosvm-a201fd46bd0549655b85bcd6e609fdabd1add837.tar
crosvm-a201fd46bd0549655b85bcd6e609fdabd1add837.tar.gz
crosvm-a201fd46bd0549655b85bcd6e609fdabd1add837.tar.bz2
crosvm-a201fd46bd0549655b85bcd6e609fdabd1add837.tar.lz
crosvm-a201fd46bd0549655b85bcd6e609fdabd1add837.tar.xz
crosvm-a201fd46bd0549655b85bcd6e609fdabd1add837.tar.zst
crosvm-a201fd46bd0549655b85bcd6e609fdabd1add837.zip
make remote wayland device optional
-rw-r--r--devices/src/virtio/controller.rs2
-rw-r--r--devices/src/virtio/wl.rs6
-rw-r--r--src/crosvm.rs2
-rw-r--r--src/linux.rs156
-rw-r--r--src/main.rs18
-rw-r--r--src/wl.rs15
6 files changed, 112 insertions, 87 deletions
diff --git a/devices/src/virtio/controller.rs b/devices/src/virtio/controller.rs
index be7228a..7500164 100644
--- a/devices/src/virtio/controller.rs
+++ b/devices/src/virtio/controller.rs
@@ -668,6 +668,8 @@ pub struct Controller {
 }
 
 impl Controller {
+    /// Construct a controller, and initialize (but don't activate)
+    /// the remote device.
     pub fn create(
         device_params: Params,
         memory_params: MemoryParams,
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
index 6671693..6a412f9 100644
--- a/devices/src/virtio/wl.rs
+++ b/devices/src/virtio/wl.rs
@@ -30,7 +30,7 @@
 
 use std::collections::btree_map::Entry;
 use std::collections::{BTreeMap as Map, BTreeSet as Set, VecDeque};
-use std::convert::From;
+use std::convert::{From, Infallible};
 use std::error::Error as StdError;
 use std::fmt::{self, Display};
 use std::fs::File;
@@ -1628,9 +1628,9 @@ impl<'de> DeserializeWithFds<'de> for Params {
 
 impl VirtioDeviceNew for Wl {
     type Params = Params;
-    type Error = ();
+    type Error = Infallible;
 
-    fn new(params: Params) -> Result<Self, ()> {
+    fn new(params: Params) -> Result<Self, Self::Error> {
         let Params {
             wayland_paths,
             vm_socket,
diff --git a/src/crosvm.rs b/src/crosvm.rs
index 1ea7e0d..e6e7268 100644
--- a/src/crosvm.rs
+++ b/src/crosvm.rs
@@ -181,6 +181,7 @@ pub struct Config {
     pub tap_fd: Vec<RawFd>,
     pub cid: Option<u64>,
     pub wayland_socket_paths: BTreeMap<String, PathBuf>,
+    pub remote_wayland_device_socket_path: Option<PathBuf>,
     pub wayland_dmabuf: bool,
     pub x_display: Option<String>,
     pub shared_dirs: Vec<SharedDir>,
@@ -235,6 +236,7 @@ impl Default for Config {
             gpu_parameters: None,
             software_tpm: false,
             wayland_socket_paths: BTreeMap::new(),
+            remote_wayland_device_socket_path: None,
             wayland_dmabuf: false,
             x_display: None,
             display_window_keyboard: false,
diff --git a/src/linux.rs b/src/linux.rs
index a416a3e..ce177e0 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -31,7 +31,7 @@ use acpi_tables::sdt::SDT;
 
 #[cfg(feature = "gpu")]
 use devices::virtio::EventDevice;
-use devices::virtio::{self, Console, Params, VirtioDevice};
+use devices::virtio::{self, Console, Params, VirtioDevice, VirtioDeviceNew};
 use devices::{
     self, Ac97Backend, Ac97Dev, Bus, HostBackendDeviceProvider, PciDevice, VfioContainer,
     VfioDevice, VfioPciDevice, VirtioPciDevice, XhciController,
@@ -87,9 +87,10 @@ pub enum Error {
     BuildVm(<Arch as LinuxArch>::Error),
     ChownTpmStorage(sys_util::Error),
     CloneEventFd(sys_util::Error),
-    ControllerCreate(msg_socket2::Error),
+    ConnectRemoteDevice(io::Error),
     CreateAc97(devices::PciDeviceError),
     CreateConsole(arch::serial::Error),
+    CreateController(msg_socket2::Error),
     CreateDiskError(disk::Error),
     CreateEventFd(sys_util::Error),
     CreatePollContext(sys_util::Error),
@@ -152,7 +153,6 @@ pub enum Error {
     VhostNetDeviceNew(virtio::vhost::Error),
     VhostVsockDeviceNew(virtio::vhost::Error),
     VirtioPciDev(sys_util::Error),
-    WaylandDeviceNew(sys_util::Error),
 }
 
 impl Display for Error {
@@ -174,9 +174,10 @@ impl Display for Error {
             BuildVm(e) => write!(f, "The architecture failed to build the vm: {}", e),
             ChownTpmStorage(e) => write!(f, "failed to chown tpm storage: {}", e),
             CloneEventFd(e) => write!(f, "failed to clone eventfd: {}", e),
-            ControllerCreate(e) => write!(f, "failed to create device controller: {}", e),
+            ConnectRemoteDevice(e) => write!(f, "failed to connect to remote device socket: {}", e),
             CreateAc97(e) => write!(f, "failed to create ac97 device: {}", e),
             CreateConsole(e) => write!(f, "failed to create console device: {}", e),
+            CreateController(e) => write!(f, "failed to create device controller: {}", e),
             CreateDiskError(e) => write!(f, "failed to create virtual disk: {}", e),
             CreateEventFd(e) => write!(f, "failed to create eventfd: {}", e),
             CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
@@ -248,7 +249,6 @@ impl Display for Error {
             VhostNetDeviceNew(e) => write!(f, "failed to set up vhost networking: {}", e),
             VhostVsockDeviceNew(e) => write!(f, "failed to set up virtual socket device: {}", e),
             VirtioPciDev(e) => write!(f, "failed to create virtio pci dev: {}", e),
-            WaylandDeviceNew(e) => write!(f, "failed to create wayland device: {}", e),
         }
     }
 }
@@ -411,7 +411,7 @@ type DeviceResult<T = VirtioDeviceStub> = std::result::Result<T, Error>;
 fn create_block_device(
     cfg: &Config,
     disk: &DiskOption,
-    disk_device_socket: DiskControlResponseSocket,
+    disk_device_control_socket: DiskControlResponseSocket,
 ) -> DeviceResult {
     // Special case '/proc/self/fd/*' paths. The FD is already open, just use it.
     let raw_image: File = if disk.path.parent() == Some(Path::new("/proc/self/fd")) {
@@ -438,7 +438,7 @@ fn create_block_device(
         disk.read_only,
         disk.sparse,
         disk.block_size,
-        Some(disk_device_socket),
+        Some(disk_device_control_socket),
     )
     .map_err(Error::BlockDeviceNew)?;
 
@@ -652,7 +652,7 @@ fn create_net_device(
 fn create_gpu_device(
     cfg: &Config,
     exit_evt: &EventFd,
-    gpu_device_socket: VmMemoryControlRequestSocket,
+    gpu_device_control_socket: VmMemoryControlRequestSocket,
     gpu_sockets: Vec<virtio::resource_bridge::ResourceResponseSocket>,
     wayland_socket_path: Option<&PathBuf>,
     x_display: Option<String>,
@@ -678,7 +678,7 @@ fn create_gpu_device(
 
     let dev = virtio::Gpu::new(
         exit_evt.try_clone().map_err(Error::CloneEventFd)?,
-        Some(gpu_device_socket),
+        Some(gpu_device_control_socket),
         NonZeroU8::new(1).unwrap(), // number of scanouts
         gpu_sockets,
         display_backends,
@@ -756,7 +756,7 @@ fn create_gpu_device(
 
 fn create_wayland_device(
     cfg: &Config,
-    socket: VmMemoryControlRequestSocket,
+    vm_socket: VmMemoryControlRequestSocket,
     resource_bridge: Option<virtio::resource_bridge::ResourceRequestSocket>,
     memory_params: MemoryParams,
 ) -> DeviceResult {
@@ -767,20 +767,23 @@ fn create_wayland_device(
         .collect::<Option<Vec<_>>>()
         .ok_or(Error::InvalidWaylandPath)?;
 
-    let mut path = std::env::var("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR missing");
-    path.push_str("/crosvm-wl.sock");
-    let seq_socket = UnixSeqpacket::connect(&path).expect("connect failed");
-    let msg_socket = msg_socket2::Socket::new(seq_socket);
-    let dev = virtio::Controller::create(
-        Params {
-            wayland_paths: cfg.wayland_socket_paths.clone(),
-            vm_socket: socket,
-            resource_bridge,
-        },
-        memory_params,
-        msg_socket,
-    )
-    .map_err(Error::ControllerCreate)?;
+    let params = Params {
+        wayland_paths: cfg.wayland_socket_paths.clone(),
+        vm_socket,
+        resource_bridge,
+    };
+
+    let dev: Box<dyn VirtioDevice> = match cfg.remote_wayland_device_socket_path {
+        Some(ref socket_path) => {
+            let socket = UnixSeqpacket::connect(socket_path).map_err(Error::ConnectRemoteDevice)?;
+            let msg_socket = msg_socket2::Socket::new(socket);
+            let controller = virtio::Controller::create(params, memory_params, msg_socket)
+                .map_err(Error::CreateController)?;
+            Box::new(controller)
+        }
+
+        None => Box::new(virtio::Wl::new(params).unwrap()),
+    };
 
     let jail = match simple_jail(&cfg, "wl_device")? {
         Some(mut jail) => {
@@ -808,10 +811,7 @@ fn create_wayland_device(
         None => None,
     };
 
-    Ok(VirtioDeviceStub {
-        dev: Box::new(dev),
-        jail,
-    })
+    Ok(VirtioDeviceStub { dev, jail })
 }
 
 #[cfg(any(feature = "video-decoder", feature = "video-encoder"))]
@@ -1066,7 +1066,7 @@ fn create_console_device(cfg: &Config, param: &SerialParameters) -> DeviceResult
     })
 }
 
-// gpu_device_socket is not used when GPU support is disabled.
+// gpu_device_control_socket is not used when GPU support is disabled.
 #[cfg_attr(not(feature = "gpu"), allow(unused_variables))]
 fn create_virtio_devices(
     cfg: &Config,
@@ -1075,11 +1075,11 @@ fn create_virtio_devices(
     vm: &mut Vm,
     resources: &mut SystemAllocator,
     _exit_evt: &EventFd,
-    wayland_device_socket: VmMemoryControlRequestSocket,
-    gpu_device_socket: VmMemoryControlRequestSocket,
-    balloon_device_socket: BalloonControlResponseSocket,
-    disk_device_sockets: &mut Vec<DiskControlResponseSocket>,
-    pmem_device_sockets: &mut Vec<VmMsyncRequestSocket>,
+    wayland_device_control_socket: VmMemoryControlRequestSocket,
+    gpu_device_control_socket: VmMemoryControlRequestSocket,
+    balloon_device_control_socket: BalloonControlResponseSocket,
+    disk_device_control_sockets: &mut Vec<DiskControlResponseSocket>,
+    pmem_device_control_sockets: &mut Vec<VmMsyncRequestSocket>,
 ) -> DeviceResult<Vec<VirtioDeviceStub>> {
     let mut devs = Vec::new();
 
@@ -1093,19 +1093,19 @@ fn create_virtio_devices(
     }
 
     for disk in &cfg.disks {
-        let disk_device_socket = disk_device_sockets.remove(0);
-        devs.push(create_block_device(cfg, disk, disk_device_socket)?);
+        let disk_device_control_socket = disk_device_control_sockets.remove(0);
+        devs.push(create_block_device(cfg, disk, disk_device_control_socket)?);
     }
 
     for (index, pmem_disk) in cfg.pmem_devices.iter().enumerate() {
-        let pmem_device_socket = pmem_device_sockets.remove(0);
+        let pmem_device_control_socket = pmem_device_control_sockets.remove(0);
         devs.push(create_pmem_device(
             cfg,
             vm,
             resources,
             pmem_disk,
             index,
-            pmem_device_socket,
+            pmem_device_control_socket,
         )?);
     }
 
@@ -1138,7 +1138,7 @@ fn create_virtio_devices(
         devs.push(create_vinput_device(cfg, dev_path)?);
     }
 
-    devs.push(create_balloon_device(cfg, balloon_device_socket)?);
+    devs.push(create_balloon_device(cfg, balloon_device_control_socket)?);
 
     // We checked above that if the IP is defined, then the netmask is, too.
     for tap_fd in &cfg.tap_fd {
@@ -1154,7 +1154,7 @@ fn create_virtio_devices(
     #[cfg_attr(not(feature = "gpu"), allow(unused_mut))]
     let mut resource_bridges = Vec::<virtio::resource_bridge::ResourceResponseSocket>::new();
 
-    if !cfg.wayland_socket_paths.is_empty() {
+    if !cfg.wayland_socket_paths.is_empty() || cfg.remote_wayland_device_socket_path.is_some() {
         #[cfg_attr(not(feature = "gpu"), allow(unused_mut))]
         let mut wl_resource_bridge = None::<virtio::resource_bridge::ResourceRequestSocket>;
 
@@ -1170,7 +1170,7 @@ fn create_virtio_devices(
 
         devs.push(create_wayland_device(
             cfg,
-            wayland_device_socket,
+            wayland_device_control_socket,
             wl_resource_bridge,
             mem_params,
         )?);
@@ -1205,7 +1205,7 @@ fn create_virtio_devices(
         if let Some(gpu_parameters) = &cfg.gpu_parameters {
             let mut event_devices = Vec::new();
             if cfg.display_window_mouse {
-                let (event_device_socket, virtio_dev_socket) =
+                let (event_device_control_socket, virtio_dev_socket) =
                     UnixStream::pair().map_err(Error::CreateSocket)?;
                 let (single_touch_width, single_touch_height) = cfg
                     .virtio_single_touch
@@ -1222,22 +1222,22 @@ fn create_virtio_devices(
                     dev: Box::new(dev),
                     jail: simple_jail(&cfg, "input_device")?,
                 });
-                event_devices.push(EventDevice::touchscreen(event_device_socket));
+                event_devices.push(EventDevice::touchscreen(event_device_control_socket));
             }
             if cfg.display_window_keyboard {
-                let (event_device_socket, virtio_dev_socket) =
+                let (event_device_control_socket, virtio_dev_socket) =
                     UnixStream::pair().map_err(Error::CreateSocket)?;
                 let dev = virtio::new_keyboard(virtio_dev_socket).map_err(Error::InputDeviceNew)?;
                 devs.push(VirtioDeviceStub {
                     dev: Box::new(dev),
                     jail: simple_jail(&cfg, "input_device")?,
                 });
-                event_devices.push(EventDevice::keyboard(event_device_socket));
+                event_devices.push(EventDevice::keyboard(event_device_control_socket));
             }
             devs.push(create_gpu_device(
                 cfg,
                 _exit_evt,
-                gpu_device_socket,
+                gpu_device_control_socket,
                 resource_bridges,
                 // Use the unnamed socket for GPU display screens.
                 cfg.wayland_socket_paths.get(""),
@@ -1279,11 +1279,11 @@ fn create_devices(
     resources: &mut SystemAllocator,
     exit_evt: &EventFd,
     control_sockets: &mut Vec<TaggedControlSocket>,
-    wayland_device_socket: VmMemoryControlRequestSocket,
-    gpu_device_socket: VmMemoryControlRequestSocket,
-    balloon_device_socket: BalloonControlResponseSocket,
-    disk_device_sockets: &mut Vec<DiskControlResponseSocket>,
-    pmem_device_sockets: &mut Vec<VmMsyncRequestSocket>,
+    wayland_device_control_socket: VmMemoryControlRequestSocket,
+    gpu_device_control_socket: VmMemoryControlRequestSocket,
+    balloon_device_control_socket: BalloonControlResponseSocket,
+    disk_device_control_sockets: &mut Vec<DiskControlResponseSocket>,
+    pmem_device_control_sockets: &mut Vec<VmMsyncRequestSocket>,
     usb_provider: HostBackendDeviceProvider,
 ) -> DeviceResult<Vec<(Box<dyn PciDevice>, Option<Minijail>)>> {
     let stubs = create_virtio_devices(
@@ -1293,20 +1293,20 @@ fn create_devices(
         vm,
         resources,
         exit_evt,
-        wayland_device_socket,
-        gpu_device_socket,
-        balloon_device_socket,
-        disk_device_sockets,
-        pmem_device_sockets,
+        wayland_device_control_socket,
+        gpu_device_control_socket,
+        balloon_device_control_socket,
+        disk_device_control_sockets,
+        pmem_device_control_sockets,
     )?;
 
     let mut pci_devices = Vec::new();
 
     for stub in stubs {
-        let (msi_host_socket, msi_device_socket) =
+        let (msi_host_socket, msi_device_control_socket) =
             msg_socket::pair::<VmIrqResponse, VmIrqRequest>().map_err(Error::CreateSocket)?;
         control_sockets.push(TaggedControlSocket::VmIrq(msi_host_socket));
-        let dev = VirtioPciDevice::new(mem.clone(), stub.dev, msi_device_socket)
+        let dev = VirtioPciDevice::new(mem.clone(), stub.dev, msi_device_control_socket)
             .map_err(Error::VirtioPciDev)?;
         let dev = Box::new(dev) as Box<dyn PciDevice>;
         pci_devices.push((dev, stub.jail));
@@ -1332,11 +1332,11 @@ fn create_devices(
 
         for vfio_path in &cfg.vfio {
             // create one Irq and Mem request socket for each vfio device
-            let (vfio_host_socket_irq, vfio_device_socket_irq) =
+            let (vfio_host_socket_irq, vfio_device_control_socket_irq) =
                 msg_socket::pair::<VmIrqResponse, VmIrqRequest>().map_err(Error::CreateSocket)?;
             control_sockets.push(TaggedControlSocket::VmIrq(vfio_host_socket_irq));
 
-            let (vfio_host_socket_mem, vfio_device_socket_mem) =
+            let (vfio_host_socket_mem, vfio_device_control_socket_mem) =
                 msg_socket::pair::<VmMemoryResponse, VmMemoryRequest>()
                     .map_err(Error::CreateSocket)?;
             control_sockets.push(TaggedControlSocket::VmMemory(vfio_host_socket_mem));
@@ -1345,8 +1345,8 @@ fn create_devices(
                 .map_err(Error::CreateVfioDevice)?;
             let vfiopcidevice = Box::new(VfioPciDevice::new(
                 vfiodevice,
-                vfio_device_socket_irq,
-                vfio_device_socket_mem,
+                vfio_device_control_socket_irq,
+                vfio_device_control_socket_mem,
             ));
             pci_devices.push((vfiopcidevice, simple_jail(&cfg, "vfio_device")?));
         }
@@ -1792,40 +1792,40 @@ pub fn run_config(cfg: Config) -> Result<()> {
     };
 
     let mut control_sockets = Vec::new();
-    let (wayland_host_socket, wayland_device_socket) =
+    let (wayland_host_socket, wayland_device_control_socket) =
         msg_socket::pair::<VmMemoryResponse, VmMemoryRequest>().map_err(Error::CreateSocket)?;
     control_sockets.push(TaggedControlSocket::VmMemory(wayland_host_socket));
     // Balloon gets a special socket so balloon requests can be forwarded from the main process.
-    let (balloon_host_socket, balloon_device_socket) =
+    let (balloon_host_socket, balloon_device_control_socket) =
         msg_socket::pair::<BalloonControlCommand, BalloonControlResult>()
             .map_err(Error::CreateSocket)?;
 
     // Create one control socket per disk.
-    let mut disk_device_sockets = Vec::new();
+    let mut disk_device_control_sockets = Vec::new();
     let mut disk_host_sockets = Vec::new();
     let disk_count = cfg.disks.len();
     for _ in 0..disk_count {
-        let (disk_host_socket, disk_device_socket) =
+        let (disk_host_socket, disk_device_control_socket) =
             msg_socket::pair::<DiskControlCommand, DiskControlResult>()
                 .map_err(Error::CreateSocket)?;
         disk_host_sockets.push(disk_host_socket);
-        disk_device_sockets.push(disk_device_socket);
+        disk_device_control_sockets.push(disk_device_control_socket);
     }
 
-    let mut pmem_device_sockets = Vec::new();
+    let mut pmem_device_control_sockets = Vec::new();
     let pmem_count = cfg.pmem_devices.len();
     for _ in 0..pmem_count {
-        let (pmem_host_socket, pmem_device_socket) =
+        let (pmem_host_socket, pmem_device_control_socket) =
             msg_socket::pair::<VmMsyncResponse, VmMsyncRequest>().map_err(Error::CreateSocket)?;
-        pmem_device_sockets.push(pmem_device_socket);
+        pmem_device_control_sockets.push(pmem_device_control_socket);
         control_sockets.push(TaggedControlSocket::VmMsync(pmem_host_socket));
     }
 
-    let (gpu_host_socket, gpu_device_socket) =
+    let (gpu_host_socket, gpu_device_control_socket) =
         msg_socket::pair::<VmMemoryResponse, VmMemoryRequest>().map_err(Error::CreateSocket)?;
     control_sockets.push(TaggedControlSocket::VmMemory(gpu_host_socket));
 
-    let (ioapic_host_socket, ioapic_device_socket) =
+    let (ioapic_host_socket, ioapic_device_control_socket) =
         msg_socket::pair::<VmIrqResponse, VmIrqRequest>().map_err(Error::CreateSocket)?;
     control_sockets.push(TaggedControlSocket::VmIrq(ioapic_host_socket));
 
@@ -1833,7 +1833,7 @@ pub fn run_config(cfg: Config) -> Result<()> {
     let linux = Arch::build_vm(
         components,
         cfg.split_irqchip,
-        ioapic_device_socket,
+        ioapic_device_control_socket,
         &cfg.serial_parameters,
         simple_jail(&cfg, "serial")?,
         |mem, mem_params, vm, sys_allocator, exit_evt| {
@@ -1845,11 +1845,11 @@ pub fn run_config(cfg: Config) -> Result<()> {
                 sys_allocator,
                 exit_evt,
                 &mut control_sockets,
-                wayland_device_socket,
-                gpu_device_socket,
-                balloon_device_socket,
-                &mut disk_device_sockets,
-                &mut pmem_device_sockets,
+                wayland_device_control_socket,
+                gpu_device_control_socket,
+                balloon_device_control_socket,
+                &mut disk_device_control_sockets,
+                &mut pmem_device_control_sockets,
                 usb_provider,
             )
         },
diff --git a/src/main.rs b/src/main.rs
index 36f3881..7ea2e01 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -871,6 +871,15 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
             }
             cfg.wayland_socket_paths.insert(name.to_string(), path);
         }
+        "wayland-device-sock" => {
+            let path = PathBuf::from(value.unwrap());
+            if cfg.remote_wayland_device_socket_path.is_some() {
+                return Err(argument::Error::TooManyArguments(String::from(
+                    "wayland device socket already supplied",
+                )));
+            }
+            cfg.remote_wayland_device_socket_path = Some(path);
+        }
         #[cfg(feature = "wl-dmabuf")]
         "wayland-dmabuf" => cfg.wayland_dmabuf = true,
         "x-display" => {
@@ -1446,9 +1455,7 @@ Possible key values:
         Argument::value("x-display", "DISPLAY", "X11 display name to use."),
         Argument::flag(
             "display-window-keyboard",
-            "\
-Capture keyboard input from the display window.
-",
+            "Capture keyboard input from the display window.",
         ),
         Argument::flag(
             "display-window-mouse",
@@ -1470,6 +1477,11 @@ Path to the Wayland socket to use.  The unnamed one is used for displaying
 virtual screens.  Named ones are only for IPC.
 ",
         ),
+        Argument::value(
+            "wayland-device-sock",
+            "PATH",
+            "Path to a remote crosvm Wayland device to use.",
+        ),
         #[cfg(feature = "wl-dmabuf")]
         Argument::flag(
             "wayland-dmabuf",
diff --git a/src/wl.rs b/src/wl.rs
index bf8989e..1581b2c 100644
--- a/src/wl.rs
+++ b/src/wl.rs
@@ -6,6 +6,10 @@ use devices::virtio::{
 };
 use msg_socket::MsgSocket;
 use std::fs::remove_file;
+use std::io::prelude::*;
+use std::io::stdout;
+use std::os::unix::prelude::*;
+use std::process;
 use sys_util::{error, net::UnixSeqpacketListener, GuestMemory};
 use vm_control::MaybeOwnedFd;
 
@@ -20,11 +24,16 @@ fn main() {
     eprintln!("hello world");
 
     // Create and display the socket.
-    let mut path = std::env::var("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR missing");
-    path.push_str("/crosvm-wl.sock");
+    let mut path = std::env::var_os("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR missing");
+    path.push("/crosvm_wl-");
+    path.push(process::id().to_string());
+    path.push(".sock");
     let _ = remove_file(&path);
     let server = UnixSeqpacketListener::bind(&path).expect("failed to create control socket");
-    println!("{}", path);
+    match stdout().write_all(path.as_bytes()) {
+        Ok(()) => println!(),
+        Err(e) => eprintln!("{}", e),
+    }
 
     // Receive connection from crosvm.
     let conn = server.accept().expect("accept failed");