Fork me on GitHub

This is an old revision of the document!


Mounting Attached Devices

This page is dedicated to the development of systems to mount attached devices. The hope is that this page will result in a variety of tools which will be able to assist pre and post action scripts.



Support for Mac OS X Devices



USB Device Support Tools

The script below supports mounting attached USB devices by name volume name. There is support for FireWire devices and non-removable drives commented out. This code should work. The script requires improvements in various areas. Improvements are welcomed via email.

The script below is a work in progress. Even though it works it is certainly not an ideal solution.

##!/usr/bin/env ruby
#
# (C)2009 Henri Shustak
# Released Under the GNU GPL
# Lucid Information Systems
# http://www.lucidsystems.org
#
# WARNING : This code is quite speggitfied. Assistance with tiding up it would be great.
#
# This is a script to detect attached but unmounted volumes by Volume name and mount them.
# Tested on the following versions of Mac OS X : 
#                         - 10.6.1  Intel Ruby version 1.8.7 
#                         - 10.4.4  PPC
#                         - 10.4.11 PPC
#
#
# Knowen Issues :  - If you rename the disk then somtimes the partition will not be detected.
#                    If this happens re-partition the disk and try again.
#
# Version 0.3.1
#
#
# Note : Using a (list of) UUID('s) is generally a good approach to mounting devices. 
#        That is not how this script works. This script mounts volumes via the volume name.
#        This approach allows you to add additional devices into a rotation set without
#        altering this script or the way you call this script. However, it is extremely 
#        important to be aware of the potential problems which may arise by using the
#        volume name to mount a device before you use this script in any kind
#        of production setting.
#


# Check we are running on Mac OS X
os_kind = `uname`
if os_kind.chomp != "Darwin" 
    puts "This script is designed to run on darwin."
    exit -1
end

# Load system profile data 
#
#   Note : it would be better to use xml - 
#          anyone care to make this work 
#          with the built in RUBy XML system.
#          It requires parsing a Mac OS X .plist  
#          Assistance with this is greatly appreciated.
#


# List of detachable drives
disks = []

# Build a list of detachable USB drives.
system_profiler_output = `system_profiler SPUSBDataType`

# Add detachable FireWire drives to the list
#system_profiler_output = system_profiler_output + `system_profiler SPFireWireDataType`

# Add ATA drives to the list.
#system_profiler_output = system_profiler_output + `system_profiler SPParallelATADataType`

# Add SATA dirves to the list
#system_profiler_output = system_profiler_output + `system_profiler SPSerialATADataType`

device = system_profiler_output.split("Volumes:")
device.each { |d|
    volume = d.split("Detachable Drive")
    volume.each { |v|
        #puts v.inspect
        disk_name = v.split(/: Yes\n\s{10,18}BSD Name: /)
        # uncomment the line below if you are only interested non removable drives
        #disk_name = disk_name + v.split(/: No\n\s{10,18}BSD Name: /)
        disk_name.each { |d|
            devname = d.split("\n")[0]
            if devname.to_s.include? "disk"
                disks << "/dev/" + devname
            end
        }
    }
}


# Generate a hash of all devices to Volumes names. Disks without volume names will be set to nil
#
#    Note : Any suggestions on how to improve this are greatly welcomed.
# 
$disk_hash = {}
disks.each { |d|
    partitions_list = `diskutil list #{d} | grep -e "disk*[0-9]s*[0-9]" | awk '{print $NF}'`
    partitions = partitions_list.split("\n")
    partitions.each { |p|
        major_system_version=`uname -v | awk -F "Version " '{print $2}' | awk -F "." '{print $1}'`
    	if major_system_version.to_i < 9 
    		# 10.4 or earlier
    	    volume_name = `diskutil info #{p.chomp} | grep "Volume Name:" | awk -F "Volume Name:        " '{print $2}'`
    	else
    		# 10.5 or later
	        volume_name = `diskutil info -plist #{p.chomp} | grep -A 1 "<key>VolumeName</key>" | tail -n 1 | awk -F "<string>" '{print $2}' | awk -F "</string>" '{print $1}'`       
	    end
        if volume_name.chomp.to_s.empty?
            new_partition = {"#{p.chomp}" => nil}
        else
            new_partition = {"#{p.chomp}" => "#{volume_name.chomp}"}
        end
        $disk_hash = $disk_hash.merge(new_partition)  
    }
}


# Find the device from the volume name (global varible)
def get_device
    if $disk_hash.has_value? $volume_name_to_mount
        device_to_mount = $disk_hash.index $volume_name_to_mount.to_s
        return device_to_mount
    else
        puts "Volume is not available."
        return nil
    end
end

# check if the device is mounted
def is_device_mounted (device_to_mount)
    # find the first disk containing a volume with a matching name
    mount_point = `diskutil info -plist #{device_to_mount[0]} | grep -A 1 -i MountPoint | tail -1 | awk -F "<string>" '{print $2}' | awk -F "</string>" '{print $1}'`
    if mount_point.chomp == "" then
        return false
    else
        return true
    end
end


# mount the device
def mount_first_volume_with_name
    device_to_mount = get_device
    if device_to_mount != nil 
        if ( (is_device_mounted(device_to_mount)) == false ) 
            device_mounted = `diskutil mount #{device_to_mount} 1>/dev/null 2>&1>/dev/null`
            if device_mounted.to_i == 0 
                # puts "device already mounted."
                return 0
            else
                return -1
            end
        end
    else
        return -1
    end
end

# Pull the name of the volume to mount from the command line
if ARGV.length == 1
    name_of_volume_to_mount = ARGV[0].to_s.chomp
else
    puts "Usage : /path/to/script/ \"<volume_name>\""
    exit -1
end

# Tell this system to mount the disk
$volume_name_to_mount=name_of_volume_to_mount
result = mount_first_volume_with_name
exit result