Skip to content

Commit

Permalink
Recover advanced synced folders in Linux.
Browse files Browse the repository at this point in the history
Now it should works fine, pretty close to the 'virtualbox' provider approach:
- Possibility to set mount options [GH-100] [GH-103]
- Shared folders aren't missed after suspend/resume, [GH-102] is fixed
- It is possible to share single folder to the some mount points, [GH-105] is fixed
  • Loading branch information
legal90 committed Jun 24, 2014
1 parent 9972054 commit b819d55
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 23 deletions.
100 changes: 78 additions & 22 deletions lib/vagrant-parallels/guest_cap/linux/mount_parallels_shared_folder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,98 @@ module VagrantPlugins
module Parallels
module GuestLinuxCap
class MountParallelsSharedFolder

def self.mount_parallels_shared_folder(machine, name, guestpath, options)
# Expand the guest path so we can handle things like "~/vagrant"
expanded_guest_path = machine.guest.capability(
:shell_expand_guest_path, guestpath)

machine.communicate.tap do |comm|
# clear prior symlink
if comm.test("test -L \"#{expanded_guest_path}\"", :sudo => true)
comm.sudo("rm \"#{expanded_guest_path}\"")
end
mount_commands = []

# clear prior directory if exists
if comm.test("test -d \"#{expanded_guest_path}\"", :sudo => true)
comm.sudo("rm -Rf \"#{expanded_guest_path}\"")
end
if options[:owner].is_a? Integer
mount_uid = options[:owner]
else
mount_uid = "`id -u #{options[:owner]}`"
end

if options[:group].is_a? Integer
mount_gid = options[:group]
mount_gid_old = options[:group]
else
mount_gid = "`getent group #{options[:group]} | cut -d: -f3`"
mount_gid_old = "`id -g #{options[:group]}`"
end

# First mount command uses getent to get the group
mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}"
mount_options += ",#{options[:mount_options].join(",")}" if options[:mount_options]
mount_commands << "mount -t prl_fs #{mount_options} #{name} #{expanded_guest_path}"

# Second mount command uses the old style `id -g`
mount_options = "-o uid=#{mount_uid},gid=#{mount_gid_old}"
mount_options += ",#{options[:mount_options].join(",")}" if options[:mount_options]
mount_commands << "mount -t prl_fs #{mount_options} #{name} #{expanded_guest_path}"

# Clear prior symlink if exists
if machine.communicate.test("test -L #{expanded_guest_path}")
machine.communicate.sudo("rm #{expanded_guest_path}")
end

# Create the guest path if it doesn't exist
machine.communicate.sudo("mkdir -p #{expanded_guest_path}")

# create intermediate directories if needed
intermediate_dir = File.dirname(expanded_guest_path)
if !comm.test("test -d \"#{intermediate_dir}\"", :sudo => true)
comm.sudo("mkdir -p \"#{intermediate_dir}\"")
# Attempt to mount the folder. We retry here a few times because
# it can fail early on.
attempts = 0
while true
success = true

mount_commands.each do |command|
no_such_device = false
status = machine.communicate.sudo(command, error_check: false) do |type, data|
no_such_device = true if type == :stderr && data =~ /No such device/i
end

success = status == 0 && !no_such_device
break if success
end

# finally make the symlink
comm.sudo("ln -s \"/media/psf/#{name}\" \"#{expanded_guest_path}\"")
break if success

# Emit an upstart event if we can
if comm.test("test -x /sbin/initctl")
comm.sudo(
"/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{expanded_guest_path}")
attempts += 1
if attempts > 10
raise Vagrant::Errors::LinuxMountFailed,
command: mount_commands.join("\n")
end

sleep 2
end

# Emit an upstart event if we can
if machine.communicate.test("test -x /sbin/initctl")
machine.communicate.sudo(
"/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{expanded_guest_path}")
end
end

def self.unmount_parallels_shared_folder(machine, guestpath, options)
machine.communicate.sudo("rm #{guestpath}", error_check: false)
result = machine.communicate.sudo(
"umount #{guestpath}", error_check: false)
if result == 0
machine.communicate.sudo("rmdir #{guestpath}", error_check: false)
end
end

def self.prepare_psf_services(machine)
# Parallels Tools for Linux includes native auto-mount script,
# which causes loosing some of Vagrant-relative shared folders.
# So, we should to disable this behavior. [GH-102]

auto_mount_script = '/usr/bin/prlfsmountd'
if machine.communicate.test("test -f #{auto_mount_script}")
machine.communicate.sudo(
"echo -e '#!/bin/sh\n'" +
'# Shared folders auto-mount is disabled by Vagrant ' +
"> #{auto_mount_script}")
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/vagrant-parallels/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class Plugin < Vagrant.plugin("2")
GuestLinuxCap::MountParallelsSharedFolder
end

guest_capability(:linux, :prepare_psf_services) do
require_relative "guest_cap/linux/mount_parallels_shared_folder"
GuestLinuxCap::MountParallelsSharedFolder
end

guest_capability(:linux, :install_parallels_tools) do
require_relative "guest_cap/linux/install_parallels_tools"
GuestLinuxCap::InstallParallelsTools
Expand Down
7 changes: 6 additions & 1 deletion lib/vagrant-parallels/synced_folder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def enable(machine, folders, _opts)
hostpath = Vagrant::Util::Platform.cygwin_windows_path(hostpath)
end


defs << {
name: os_friendly_id(id),
hostpath: hostpath.to_s,
Expand All @@ -42,6 +41,12 @@ def enable(machine, folders, _opts)

shf_config = driver(machine).read_shared_folders

# Parallels Shared Folder services can override Vagrant synced folder
# configuration. These services should be pre-configured.
if machine.guest.capability?(:prepare_psf_services)
machine.guest.capability(:prepare_psf_services)
end

# Go through each folder and mount
machine.ui.output(I18n.t("vagrant.actions.vm.share_folders.mounting"))
folders.each do |_ , data|
Expand Down

0 comments on commit b819d55

Please sign in to comment.