Ejemplo n.º 1
0
    def verifyIsDMG(myClass, identifier, checksumDMG=False):
        '''Confirm with hdiutil that the object identified is a dmg, optionally checksumming it'''

        if not hasattr(identifier, 'capitalize'):
            raise ValueError(
                'verifyIsDMG requires a path, bsd name, or a dev path. Got: ' +
                str(identifier))

        if not checksumDMG in [True, False]:
            raise ValueError(
                'The option checksumDMG given to verifyIsDMG must be either True or False. Got: '
                + str(checksumDMG))

        command = ['/usr/bin/hdiutil', 'imageinfo', str(identifier)]
        try:
            process = managedSubprocess(command)
        except RuntimeError:
            return False

        if checksumDMG is True:
            command = ['/usr/bin/hdiutil', 'verify', str(identifier)]
            try:
                process = managedSubprocess(command)
            except RuntimeError:
                return False

        return True
Ejemplo n.º 2
0
	def test_failingCommand(self):
		'''Calling a command that results in a failing return code should throw a RuntimeError'''
		
		command = ['/bin/ls', '/this-should-not-exist']
		self.assertRaises(RuntimeError, managedSubprocess, command)
		
		# again, but this time catch the output
		try:
			managedSubprocess(command)
		except RuntimeError, e:
			expectedString = 'The process "/bin/ls /this-should-not-exist" failed with error: 1\nStderr: ls: /this-should-not-exist: No such file or directory'
			self.assertEqual(str(e), expectedString, 'Calling a failing command (%s) and expected:\n%s\nBut got:\n%s' % (" ".join(command), expectedString, str(e)))
Ejemplo n.º 3
0
def unmountVolume(targetPath):
	'''Unmount a volume or dmg mounted at the path given'''
	
	if not os.path.ismount(targetPath):
		raise ValueError('unmountVolume valled on a path that was not a mount point: ' + targetPath)
	
	targetPath = pathHelpers.normalizePath(targetPath)
	
	# check to see if this is a disk image
	isMountedDMG = False
	command = ['/usr/bin/hdiutil', 'info', '-plist']
	process = managedSubprocess(command, processAsPlist=True)
	plistData = process.getPlistObject()
	
	if not hasattr(plistData, 'has_key') or not plistData.has_key('images') or not hasattr(plistData['images'], '__iter__'):
		raise RuntimeError('The "%s" output does not have an "images" array as expected. Output was:\n%s' % (' '.join(command), output))
	
	for thisImage in plistData['images']:
	
		if not hasattr(thisImage, '__iter__') or not thisImage.has_key('system-entities') or not hasattr(thisImage['system-entities'], '__iter__'):
			raise RuntimeError('The "%s" output had an image entry that was not formed as expected. Output was:\n%s' % (' '.join(command), output))
		
		for thisEntry in thisImage['system-entities']:
			if thisEntry.has_key('mount-point') and os.path.samefile(thisEntry['mount-point'], targetPath):
				isMountedDMG = True
				break
		if isMountedDMG is True: break
	
	if isMountedDMG is True:
		# ToDo: log this
		command = ['/usr/bin/hdiutil', 'eject', targetPath]
		process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
		
		if process.wait() != 0 and os.path.ismount(targetPath):
			# try again with a bit more force
			# ToDo: log this
			
			command = ['/usr/bin/hdiutil', 'eject', '-force', targetPath]
			managedSubprocess(command)
	
	else:
		# a non dmg mount point
		# ToDo: log this
		command = ['/usr/sbin/diskutil', 'unmount', targetPath]
		process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
		
		if process.wait() != 0 and os.path.ismount(targetPath):
			# try again with a bit more force
			# ToDo: log this
			
			command = ['/usr/sbin/diskutil', 'unmount', 'force', targetPath]
			managedSubprocess(command)
Ejemplo n.º 4
0
    def test_failingCommand(self):
        '''Calling a command that results in a failing return code should throw a RuntimeError'''

        command = ['/bin/ls', '/this-should-not-exist']
        self.assertRaises(RuntimeError, managedSubprocess, command)

        # again, but this time catch the output
        try:
            managedSubprocess(command)
        except RuntimeError, e:
            expectedString = 'The process "/bin/ls /this-should-not-exist" failed with error: 1\nStderr: ls: /this-should-not-exist: No such file or directory'
            self.assertEqual(
                str(e), expectedString,
                'Calling a failing command (%s) and expected:\n%s\nBut got:\n%s'
                % (" ".join(command), expectedString, str(e)))
Ejemplo n.º 5
0
def getMountedVolumes(excludeRoot=True):

    diskutilArguments = ['/usr/sbin/diskutil', 'list', '-plist']
    diskutilProcess = managedSubprocess(diskutilArguments, processAsPlist=True)
    diskutilOutput = diskutilProcess.getPlistObject()

    if not "AllDisks" in diskutilOutput or not hasattr(
            diskutilOutput["AllDisks"], '__iter__'):
        raise RuntimeError(
            'Error: The output from diksutil list does not look right:\n%s\n' %
            str(diskutilOutput))

    mountedVolumes = []

    for thisVolume in diskutilOutput["AllDisks"]:

        # get the mount
        thisVolumeInfo = getDiskutilInfo(str(thisVolume))

        # exclude whole disks
        if thisVolumeInfo['bsdName'] == thisVolumeInfo['diskBsdName']:
            continue

        # exclude unmounted disks
        if not 'mountPath' in thisVolumeInfo or thisVolumeInfo[
                'mountPath'] in [None, '']:
            continue
        # exclude the root mount if it is not requested
        elif thisVolumeInfo['mountPath'] == '/' and excludeRoot == True:
            continue

        mountedVolumes.append(str(thisVolumeInfo['mountPath']))

    return mountedVolumes
Ejemplo n.º 6
0
    def test_stderr(self):
        '''Make sure that stderr is being properly returned'''

        # setup a folder to then test on (so things are predictable)
        outerFolder = tempFolderManager.getNewTempFolder()
        testFile = open(os.path.join(outerFolder, "testItem"), "w")
        testFile.close()

        command = ["/bin/ls " + outerFolder + " 1>&2"]
        process = managedSubprocess(command, shell=True)

        self.assertTrue(
            hasattr(process, 'stderr') and process.stderr is not None,
            'managedSubprocess did not have a stderr item when it should have')
        result = process.stderr.read()
        expectedResult = "testItem\n"
        self.assertTrue(
            isinstance(process.stderrLen, int),
            'managedSubprocess should have had an integer value for stderrLen, rather it had: '
            + str(process.stderrLen))
        self.assertEqual(
            len(expectedResult), process.stderrLen,
            'managedSubprocess should have had a length of %i for stdoutLen, rather it had a length of %i: %s'
            % (len(expectedResult), process.stderrLen, result))
        self.assertEqual(
            result, expectedResult,
            'managedSubprocess did not return the correct stderr for process "%s". Got "%s" rather than "%s"'
            % (" ".join(command), result, expectedResult))
Ejemplo n.º 7
0
    def getDMGMountPoints(myClass, dmgFilePath):

        if not os.path.exists(dmgFilePath):
            raise ValueError(
                'getDMGMountPoint called with a dmgFilePath that does not exist: '
                + dmgFilePath)

        hdiutilArguments = ['/usr/bin/hdiutil', 'info', '-plist']
        hdiutilProcess = managedSubprocess(hdiutilArguments,
                                           processAsPlist=True)
        hdiutilOutput = hdiutilProcess.getPlistObject()

        if 'images' in hdiutilOutput:
            for thisDMG in hdiutilOutput['images']:
                if os.path.samefile(thisDMG['image-path'], dmgFilePath):
                    mountPoints = []

                    for thisEntry in thisDMG['system-entities']:
                        if 'mount-point' in thisEntry:
                            mountPoints.append(str(thisEntry['mount-point']))

                    if len(mountPoints) > 0:
                        return mountPoints

                    break

        return None
Ejemplo n.º 8
0
def getMountedVolumes(excludeRoot=True):
		
	diskutilArguments = ['/usr/sbin/diskutil', 'list', '-plist']
	diskutilProcess = managedSubprocess(diskutilArguments, processAsPlist=True)
	diskutilOutput = diskutilProcess.getPlistObject()
	
	if not "AllDisks" in diskutilOutput or not hasattr(diskutilOutput["AllDisks"], '__iter__'):
		raise RuntimeError('Error: The output from diksutil list does not look right:\n%s\n' % str(diskutilOutput))  
	
	mountedVolumes = []
	
	for thisVolume in diskutilOutput["AllDisks"]:
		
		# get the mount
		thisVolumeInfo = getDiskutilInfo(str(thisVolume))
		
		# exclude whole disks
		if thisVolumeInfo['bsdName'] == thisVolumeInfo['diskBsdName']:
			continue
		
		# exclude unmounted disks
		if not 'mountPath' in thisVolumeInfo or thisVolumeInfo['mountPath'] in [None, '']:
			continue
		# exclude the root mount if it is not requested
		elif thisVolumeInfo['mountPath'] == '/' and excludeRoot == True:
			continue
		
		mountedVolumes.append(str(thisVolumeInfo['mountPath']))
	
	return mountedVolumes
Ejemplo n.º 9
0
	def test_processAsPlist(self):
		'''Make sure that correct plists get returned properly'''
		
		command = ['/usr/bin/hdiutil', 'info', '-plist']
		process = managedSubprocess(command, processAsPlist=True)
		
		self.assertTrue(not hasattr(process, 'stdout') or process.stdout is None, 'When called with processAsPlist=True managedSubprocess should not have a useable stdout attribute')
		self.assertTrue(not hasattr(process, 'stderr') or process.stderr is None, 'When called with processAsPlist=True managedSubprocess should not have a useable stderr attribute')
		
		plistData = process.getPlistObject()
		self.assertTrue(hasattr(plistData, 'has_key') and plistData.has_key('images'), 'The plist data returned form the command "%s" was not a hash with a "images" key as expected' % " ".join(command))
Ejemplo n.º 10
0
def getDiskutilInfo(identifier):
	'''Return the following information about the mount point, bsd name, or dev path provided: mountPath, volumeName, bsdPath, volumeFormat, diskType, bsdName, diskBsdName, volumeSizeInBytes, volumeUuid'''
	
	if not hasattr(identifier, 'capitalize'):
		raise ValueError('getVolumeInfo requires a path, bsd name, or a dev path. Got: ' + str(identifier))
	
	command = ['/usr/sbin/diskutil', 'info', '-plist', str(identifier)]
	try:
		process = managedSubprocess(command, processAsPlist=True)
	except RuntimeError, error:
		raise ValueError('The input to getVolumeInfo does not look like it was valid: ' + str(identifier) + "\nError:\n" + str(error))
Ejemplo n.º 11
0
    def test_commandLine(self):

        pathToCommandLine = os.path.join(os.path.dirname(__file__), "findInstallerDisc.py")
        buildsInfo = self.getAllowedBuildsFromVanilla("10.6")

        process = managedSubprocess.managedSubprocess(
            [pathToCommandLine, "--allowed-builds", ", ".join(buildsInfo), "--supress-return"]
        )
        results = process.stdout.read().split("\n")

        self.assertTrue(
            os.path.exists(results[0]),
            "The first line returned by the command-line version is not a path to a valid item: " + str(results[0]),
        )
Ejemplo n.º 12
0
	def verifyIsDMG(myClass, identifier, checksumDMG=False):
		'''Confirm with hdiutil that the object identified is a dmg, optionally checksumming it'''
		
		if not hasattr(identifier, 'capitalize'):
			raise ValueError('verifyIsDMG requires a path, bsd name, or a dev path. Got: ' + str(identifier))
		
		if not checksumDMG in [True, False]:
			raise ValueError('The option checksumDMG given to verifyIsDMG must be either True or False. Got: ' + str(checksumDMG))
		
		command = ['/usr/bin/hdiutil', 'imageinfo', str(identifier)]
		try:
			process = managedSubprocess(command)
		except RuntimeError:
			return False
		
		if checksumDMG is True:
			command = ['/usr/bin/hdiutil', 'verify', str(identifier)]
			try:
				process = managedSubprocess(command)
			except RuntimeError:
				return False
		
		return True
Ejemplo n.º 13
0
def getDiskutilInfo(identifier):
    '''Return the following information about the mount point, bsd name, or dev path provided: mountPath, volumeName, bsdPath, volumeFormat, diskType, bsdName, diskBsdName, volumeSizeInBytes, volumeUuid'''

    if not hasattr(identifier, 'capitalize'):
        raise ValueError(
            'getVolumeInfo requires a path, bsd name, or a dev path. Got: ' +
            str(identifier))

    command = ['/usr/sbin/diskutil', 'info', '-plist', str(identifier)]
    try:
        process = managedSubprocess(command, processAsPlist=True)
    except RuntimeError, error:
        raise ValueError(
            'The input to getVolumeInfo does not look like it was valid: ' +
            str(identifier) + "\nError:\n" + str(error))
Ejemplo n.º 14
0
    def test_commandLine(self):

        pathToCommandLine = os.path.join(os.path.dirname(__file__),
                                         'findInstallerDisc.py')
        buildsInfo = self.getAllowedBuildsFromVanilla('10.6')

        process = managedSubprocess.managedSubprocess([
            pathToCommandLine, '--allowed-builds', ", ".join(buildsInfo),
            '--supress-return'
        ])
        results = process.stdout.read().split('\n')

        self.assertTrue(
            os.path.exists(results[0]),
            'The first line returned by the command-line version is not a path to a valid item: '
            + str(results[0]))
Ejemplo n.º 15
0
	def test_stderr(self):
		'''Make sure that stderr is being properly returned'''
		
		# setup a folder to then test on (so things are predictable)
		outerFolder = tempFolderManager.getNewTempFolder()
		testFile = open(os.path.join(outerFolder, "testItem"), "w")
		testFile.close()
		
		command = ["/bin/ls " + outerFolder + " 1>&2"]
		process = managedSubprocess(command, shell=True)
		
		self.assertTrue(hasattr(process, 'stderr') and process.stderr is not None, 'managedSubprocess did not have a stderr item when it should have')
		result = process.stderr.read()
		expectedResult = "testItem\n"
		self.assertTrue(isinstance(process.stderrLen, int), 'managedSubprocess should have had an integer value for stderrLen, rather it had: ' + str(process.stderrLen))
		self.assertEqual(len(expectedResult), process.stderrLen, 'managedSubprocess should have had a length of %i for stdoutLen, rather it had a length of %i: %s' % (len(expectedResult), process.stderrLen, result))
		self.assertEqual(result, expectedResult, 'managedSubprocess did not return the correct stderr for process "%s". Got "%s" rather than "%s"' % (" ".join(command), result, expectedResult))
Ejemplo n.º 16
0
    def test_processAsPlist(self):
        '''Make sure that correct plists get returned properly'''

        command = ['/usr/bin/hdiutil', 'info', '-plist']
        process = managedSubprocess(command, processAsPlist=True)

        self.assertTrue(
            not hasattr(process, 'stdout') or process.stdout is None,
            'When called with processAsPlist=True managedSubprocess should not have a useable stdout attribute'
        )
        self.assertTrue(
            not hasattr(process, 'stderr') or process.stderr is None,
            'When called with processAsPlist=True managedSubprocess should not have a useable stderr attribute'
        )

        plistData = process.getPlistObject()
        self.assertTrue(
            hasattr(plistData, 'has_key') and plistData.has_key('images'),
            'The plist data returned form the command "%s" was not a hash with a "images" key as expected'
            % " ".join(command))
Ejemplo n.º 17
0
	def getDMGMountPoints(myClass, dmgFilePath):
		
		if not os.path.exists(dmgFilePath):
			raise ValueError('getDMGMountPoint called with a dmgFilePath that does not exist: ' + dmgFilePath)
		
		hdiutilArguments = ['/usr/bin/hdiutil', 'info', '-plist']
		hdiutilProcess = managedSubprocess(hdiutilArguments, processAsPlist=True)
		hdiutilOutput = hdiutilProcess.getPlistObject()
		
		if 'images' in hdiutilOutput:
			for thisDMG in hdiutilOutput['images']:
				if os.path.samefile(thisDMG['image-path'], dmgFilePath):
					mountPoints = []
					
					for thisEntry in thisDMG['system-entities']:
						if 'mount-point' in thisEntry:
							mountPoints.append(str(thisEntry['mount-point']))
					
					if len(mountPoints) > 0:
						return mountPoints
					
					break
		
		return None
Ejemplo n.º 18
0
	def test_getPlistObjectWithoutAPlist(self):
		'''Confirm that a RuntimeError is called if getPlistObject is called on a non-plist object'''
		
		command = ['/bin/ls']
		process = managedSubprocess(command)
		self.assertRaises(RuntimeError, process.getPlistObject)
Ejemplo n.º 19
0
    def getVolumeInfo(myClass, identifier):
        '''Get the following information for a volume (if avalible) and return it as a hash:
			filePath, dmgFormat, writeable, dmg-checksum-type, dmg-checksum-value
		Additionally, provide information from the superclass if it is mounted:
			volumeName, mount-points, bsd-label
		'''

        if not hasattr(identifier, 'capitalize'):
            raise ValueError(
                'getVolumeInfo requires a path, bsd name, or a dev path. Got: '
                + str(identifier))

        result = None
        # look to see if this is a mount path, bsd name, or a dev path that diskutil can work with
        try:
            result = super(self.__class__, self).getVolumeInfo(identifier)

            if result['diskType'] is not 'Disk Image':
                raise ValueError(
                    "%s's getVolumeInfo method requires a disk image as the argument. Got a %s as the argument: %s"
                    % (myClass.__name__, result['diskType'], identifier))

            # if we are here, then the identifier must be the mounted path, or something in it
            identifier = result['mountPath']

        except ValueError:
            # this might be a pointer to the dmg file
            result = {}

        # try for information on this as a dmg
        command = ['/usr/bin/hdiutil', 'imageinfo', '-plist', str(identifier)]
        try:
            process = managedSubprocess(command, processAsPlist=True)
        except RuntimeError:
            raise ValueError('The item given does not seem to be a DMG: ' +
                             str(identifier))
        dmgProperties = process.getPlistObject()

        # filePath
        result['filePath'] = dmgProperties['Backing Store Information']['URL']
        if result['filePath'].startswith('file://localhost'):
            result['filePath'] = result['filePath'][len('file://localhost'):]
        elif result['filePath'].startswith('file://'):
            result['filePath'] = result['filePath'][len('file://'):]

        # dmgFormat
        result['dmgFormat'] = dmgProperties['Format']

        # writable
        if dmgProperties['Format'] in ['UDRW', 'UDSP', 'UDSB', 'RdWr']:
            result['writeable'] = True
        else:
            result['writeable'] = False

        # dmg-checksum-type
        if 'Checksum Type' in dmgProperties:
            result['dmgChecksumType'] = dmgProperties['Checksum Type']
        else:
            result['dmgChecksumType'] = None  # just in case we ever re-do this

        # dmg-checksum-value
        if 'Checksum Value' in dmgProperties:
            result['dmgChecksumValue'] = dmgProperties['Checksum Value']
        else:
            result[
                'dmgChecksumValue'] = None  # just in case we ever re-do this

        return result
Ejemplo n.º 20
0
    def mountImage(myClass,
                   dmgFile,
                   mountPoint=None,
                   mountInFolder=None,
                   mountReadWrite=None,
                   shadowFile=None,
                   paranoidMode=False):
        '''Mount an image'''

        # -- validate input

        # dmgFile
        if dmgFile is None or not os.path.exists(dmgFile) or os.path.ismount(
                dmgFile):
            raise ValueError(
                'mountImage requires dmgFile be a path to a file, got: ' +
                dmgFile)
        dmgFile = pathHelpers.normalizePath(dmgFile, followSymlink=True)

        # mountPoint/mountInFolder
        if mountPoint is not None and mountInFolder is not None:
            raise ValueError(
                'mountImage can only be called with mountPoint or mountInFolder, not both'
            )

        elif mountPoint is not None and os.path.ismount(mountPoint):
            raise ValueError(
                'mountImage called with a mountPoint that is already a mount point: '
                + mountPoint)

        elif mountPoint is not None and os.path.isdir(mountPoint):
            if len(os.listdir(mountPoint)) != 0:
                raise ValueError(
                    'mountImage called with a mountPoint that already has contents: %s (%s)'
                    % (mountPoint, str(os.listdir(mountPoint))))

        elif mountPoint is not None and os.path.exists(mountPoint):
            raise ValueError(
                'mountImage called with a mountPoint that already exists and is not a folder: '
                + mountPoint)

        elif mountPoint is not None:
            tempFolderManager.add

        elif mountInFolder is not None and not os.path.isdir(mountInFolder):
            raise ValueError(
                'mountImage called with a mountInFolder path that is not a folder: '
                + mountInFolder)

        elif mountInFolder is not None:
            mountPoint = tempFolderManager.getNewMountPoint()

        else:
            # create a default mount point
            mountPoint = tempFolderManager.getNewMountPoint()
        mountPoint = pathHelpers.normalizePath(mountPoint, followSymlink=True)

        # mountReadWrite
        if mountReadWrite not in [None, True, False]:
            raise ValueError(
                'The only valid options for mountReadWrite are True or False')

        # shadowFile
        if shadowFile is True:
            # generate a temporary one
            shadowFile = tempFolderManager.getNewTempFile(suffix='.shadow')

        elif shadowFile is not None:
            shadowFile = pathHelpers.normalizePath(shadowFile,
                                                   followSymlink=True)

            if os.path.isfile(shadowFile):  # work here
                pass  # just use the file

            elif os.path.isdir(shadowFile):
                # a directory to put the shadow file in
                shadowFile = tempFolderManager.getNewTempFile(
                    parentFolder=shadowFile, suffix='.shadow')

            elif os.path.isdir(os.path.dirname(shadowFile)):
                # the path does not exist, but the directory it is in looks good
                pass

            else:
                # not valid
                raise ValueError(
                    'The path given for the shadow file does not look valid: '
                    + str(shadowFile))

        # paranoidMode
        if paranoidMode not in [True, False]:
            raise ValueError(
                'checksumImage must be either True, or False. Got: ' +
                str(paranoidMode))

        # -- check to see if it is already mounted

        existingMountPoints = myClass.getDMGMountPoints(dmgFile)
        if existingMountPoints is not None:
            raise RuntimeError('The image (%s) was already mounted: %s' %
                               (dmgFile, ", ".join(existingMountPoints)))

        # -- construct the command

        command = [
            '/usr/bin/hdiutil', 'attach', dmgFile, '-plist', '-mountpoint',
            mountPoint, '-nobrowse', '-owners', 'on'
        ]

        if mountReadWrite is True and shadowFile is None and self.writeable is False:
            shadowFile = tempFolderManager.getNewTempFile(suffix='.shadow')
        elif mountReadWrite is False and shadowFile is None:
            command += ['-readonly']

        if paranoidMode is False:
            command += ['-noverify', '-noautofsck']
        else:
            command += ['-verify', '-autofsck']

        if shadowFile is not None:
            command += ['-shadow', shadowFile]

        # -- run the command

        process = managedSubprocess(command, processAsPlist=True)
        mountInfo = process.getPlistObject()

        actualMountedPath = None

        for thisEntry in mountInfo['system-entities']:
            if 'mount-point' in thisEntry:
                if actualMountedPath != None and os.path.ismount(
                        actualMountedPath):
                    # ToDo: think all of this through, prefereabley before it is needed
                    raise Exception(
                        'This item (%s) seems to be mounted at two places , this is possible, but now that it is happening larkost needs to work on this'
                        % self.filePath)

                actualMountedPath = thisEntry[
                    'mount-point']  # ToDo: make sure that this is the mount point we requested
                break  # assume that there is only one mountable item... otherwise we are hosed already

        if actualMountedPath is None:
            raise RuntimeError('Error: image could not be mounted')

        return actualMountedPath
Ejemplo n.º 21
0
    def test_getPlistObjectWithoutAPlist(self):
        '''Confirm that a RuntimeError is called if getPlistObject is called on a non-plist object'''

        command = ['/bin/ls']
        process = managedSubprocess(command)
        self.assertRaises(RuntimeError, process.getPlistObject)
Ejemplo n.º 22
0
def unmountVolume(targetPath):
    '''Unmount a volume or dmg mounted at the path given'''

    if not os.path.ismount(targetPath):
        raise ValueError(
            'unmountVolume valled on a path that was not a mount point: ' +
            targetPath)

    targetPath = pathHelpers.normalizePath(targetPath)

    # check to see if this is a disk image
    isMountedDMG = False
    command = ['/usr/bin/hdiutil', 'info', '-plist']
    process = managedSubprocess(command, processAsPlist=True)
    plistData = process.getPlistObject()

    if not hasattr(plistData, 'has_key') or not plistData.has_key(
            'images') or not hasattr(plistData['images'], '__iter__'):
        raise RuntimeError(
            'The "%s" output does not have an "images" array as expected. Output was:\n%s'
            % (' '.join(command), output))

    for thisImage in plistData['images']:

        if not hasattr(thisImage, '__iter__') or not thisImage.has_key(
                'system-entities') or not hasattr(thisImage['system-entities'],
                                                  '__iter__'):
            raise RuntimeError(
                'The "%s" output had an image entry that was not formed as expected. Output was:\n%s'
                % (' '.join(command), output))

        for thisEntry in thisImage['system-entities']:
            if thisEntry.has_key('mount-point') and os.path.samefile(
                    thisEntry['mount-point'], targetPath):
                isMountedDMG = True
                break
        if isMountedDMG is True: break

    if isMountedDMG is True:
        # ToDo: log this
        command = ['/usr/bin/hdiutil', 'eject', targetPath]
        process = subprocess.Popen(command,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)

        if process.wait() != 0 and os.path.ismount(targetPath):
            # try again with a bit more force
            # ToDo: log this

            command = ['/usr/bin/hdiutil', 'eject', '-force', targetPath]
            managedSubprocess(command)

    else:
        # a non dmg mount point
        # ToDo: log this
        command = ['/usr/sbin/diskutil', 'unmount', targetPath]
        process = subprocess.Popen(command,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)

        if process.wait() != 0 and os.path.ismount(targetPath):
            # try again with a bit more force
            # ToDo: log this

            command = ['/usr/sbin/diskutil', 'unmount', 'force', targetPath]
            managedSubprocess(command)
Ejemplo n.º 23
0
	def mountImage(myClass, dmgFile, mountPoint=None, mountInFolder=None, mountReadWrite=None, shadowFile=None, paranoidMode=False):
		'''Mount an image'''
		
		# -- validate input
		
		# dmgFile
		if dmgFile is None or not os.path.exists(dmgFile) or os.path.ismount(dmgFile):
			raise ValueError('mountImage requires dmgFile be a path to a file, got: ' + dmgFile)
		dmgFile = pathHelpers.normalizePath(dmgFile, followSymlink=True)
		
		# mountPoint/mountInFolder
		if mountPoint is not None and mountInFolder is not None:
			raise ValueError('mountImage can only be called with mountPoint or mountInFolder, not both')
		
		elif mountPoint is not None and os.path.ismount(mountPoint):
			raise ValueError('mountImage called with a mountPoint that is already a mount point: ' + mountPoint)
		
		elif mountPoint is not None and os.path.isdir(mountPoint):
			if len(os.listdir(mountPoint)) != 0:
				raise ValueError('mountImage called with a mountPoint that already has contents: %s (%s)' % (mountPoint, str(os.listdir(mountPoint))))
		
		elif mountPoint is not None and os.path.exists(mountPoint):
			raise ValueError('mountImage called with a mountPoint that already exists and is not a folder: ' + mountPoint)
		
		elif mountPoint is not None:
			tempFolderManager.add
		
		elif mountInFolder is not None and not os.path.isdir(mountInFolder):
			raise ValueError('mountImage called with a mountInFolder path that is not a folder: ' + mountInFolder)
		
		elif mountInFolder is not None:
			mountPoint = tempFolderManager.getNewMountPoint()
		
		else:
			# create a default mount point
			mountPoint = tempFolderManager.getNewMountPoint()
		mountPoint = pathHelpers.normalizePath(mountPoint, followSymlink=True)
		
		# mountReadWrite
		if mountReadWrite not in [None, True, False]:
			raise ValueError('The only valid options for mountReadWrite are True or False')
		
		# shadowFile
		if shadowFile is True:
			# generate a temporary one
			shadowFile = tempFolderManager.getNewTempFile(suffix='.shadow')
			
		elif shadowFile is not None:
			shadowFile = pathHelpers.normalizePath(shadowFile, followSymlink=True)
			
			if os.path.isfile(shadowFile): # work here
				pass # just use the file
			
			elif os.path.isdir(shadowFile):
				# a directory to put the shadow file in
				shadowFile = tempFolderManager.getNewTempFile(parentFolder=shadowFile, suffix='.shadow')
			
			elif os.path.isdir(os.path.dirname(shadowFile)):
				# the path does not exist, but the directory it is in looks good
				pass
			
			else:
				# not valid
				raise ValueError('The path given for the shadow file does not look valid: ' + str(shadowFile))
		
		# paranoidMode
		if paranoidMode not in [True, False]:
			raise ValueError('checksumImage must be either True, or False. Got: ' + str(paranoidMode))		
		
		# -- check to see if it is already mounted
		
		existingMountPoints = myClass.getDMGMountPoints(dmgFile)
		if existingMountPoints is not None:
			raise RuntimeError('The image (%s) was already mounted: %s' % (dmgFile, ", ".join(existingMountPoints)))
		
		# -- construct the command
		
		command = ['/usr/bin/hdiutil', 'attach', dmgFile, '-plist', '-mountpoint', mountPoint, '-nobrowse', '-owners', 'on']
		
		if mountReadWrite is True and shadowFile is None and self.writeable is False:
			shadowFile = tempFolderManager.getNewTempFile(suffix='.shadow')
		elif mountReadWrite is False and shadowFile is None:
			command += ['-readonly']
		
		if paranoidMode is False:
			command += ['-noverify', '-noautofsck']
		else:
			command += ['-verify', '-autofsck']
		
		if shadowFile is not None:
			command += ['-shadow', shadowFile]
		
		# -- run the command
		
		process = managedSubprocess(command, processAsPlist=True)
		mountInfo = process.getPlistObject()
		
		actualMountedPath = None
		
		for thisEntry in mountInfo['system-entities']:
			if 'mount-point' in thisEntry:
				if actualMountedPath != None and os.path.ismount(actualMountedPath):
					# ToDo: think all of this through, prefereabley before it is needed
					raise Exception('This item (%s) seems to be mounted at two places , this is possible, but now that it is happening larkost needs to work on this' % self.filePath)
				
				actualMountedPath = thisEntry['mount-point'] # ToDo: make sure that this is the mount point we requested
				break # assume that there is only one mountable item... otherwise we are hosed already
		
		if actualMountedPath is None:
			raise RuntimeError('Error: image could not be mounted')
		
		return actualMountedPath
Ejemplo n.º 24
0
	def getVolumeInfo(myClass, identifier):
		'''Get the following information for a volume (if avalible) and return it as a hash:
			filePath, dmgFormat, writeable, dmg-checksum-type, dmg-checksum-value
		Additionally, provide information from the superclass if it is mounted:
			volumeName, mount-points, bsd-label
		'''
		
		if not hasattr(identifier, 'capitalize'):
			raise ValueError('getVolumeInfo requires a path, bsd name, or a dev path. Got: ' + str(identifier))
		
		result = None
		# look to see if this is a mount path, bsd name, or a dev path that diskutil can work with
		try:
			result = super(self.__class__, self).getVolumeInfo(identifier)
			
			if result['diskType'] is not 'Disk Image':
				raise ValueError("%s's getVolumeInfo method requires a disk image as the argument. Got a %s as the argument: %s" % (myClass.__name__, result['diskType'], identifier))
			
			# if we are here, then the identifier must be the mounted path, or something in it
			identifier = result['mountPath']
			
		except ValueError:
			# this might be a pointer to the dmg file 
			result = {}
		
		# try for information on this as a dmg
		command = ['/usr/bin/hdiutil', 'imageinfo', '-plist', str(identifier)]
		try:
			process = managedSubprocess(command, processAsPlist=True)
		except RuntimeError:
			raise ValueError('The item given does not seem to be a DMG: ' + str(identifier))
		dmgProperties = process.getPlistObject()
		
		# filePath
		result['filePath'] = dmgProperties['Backing Store Information']['URL']
		if result['filePath'].startswith('file://localhost'):
			result['filePath'] = result['filePath'][len('file://localhost'):]
		elif result['filePath'].startswith('file://'):
			result['filePath'] = result['filePath'][len('file://'):]
		
		# dmgFormat
		result['dmgFormat'] = dmgProperties['Format']
		
		# writable
		if dmgProperties['Format'] in ['UDRW', 'UDSP', 'UDSB', 'RdWr']:
			result['writeable'] = True
		else:
			result['writeable'] = False
		
		# dmg-checksum-type
		if 'Checksum Type' in dmgProperties:
			result['dmgChecksumType'] = dmgProperties['Checksum Type']
		else:
			result['dmgChecksumType'] = None # just in case we ever re-do this
		
		# dmg-checksum-value
		if 'Checksum Value' in dmgProperties:
			result['dmgChecksumValue'] = dmgProperties['Checksum Value']
		else:
			result['dmgChecksumValue'] = None # just in case we ever re-do this
		
		return result
Ejemplo n.º 25
0
	def isValidInstaller(myClass, pkgPath, chrootPath=None, installerChoicesFilePath=None):
		'''Use installer to check if a target looks like a valid pkg/mpkg'''
		
		pathToInstaller = '/usr/sbin/installer'
		
		# ---- validate and normalize input
		
		# pkg path
		
		if pkgPath is None:
			raise ValueError('The pkgPath given to isValidInstaller can not be none')
		elif not os.path.isdir(pkgPath) and not os.path.isfile(pkgPath):
			raise ValueError('The pkgPath given to isValidInstaller does not look correct: ' + str(pkgPath))
		pkgPath = pathHelpers.normalizePath(pkgPath, followSymlink=True)
		
		# chroot path
		
		if chrootPath is not None and not os.path.ismount(chrootPath):
			raise ValueError('The chrootPath given to isValidInstaller must be a mount point, this was not: ' + str(chrootPath))
		
		if chrootPath is not None:
			chrootPath = pathHelpers.normalizePath(chrootPath, followSymlink=True)
		
		# installer choices
		
		if installerChoicesFilePath is not None and not os.path.isfile(installerChoicesFilePath):
			raise ValueError('The installerChoicesFilePath given to isValidInstaller must be a file, this was not: ' + str(installerChoicesFilePath))
		installerChoicesFilePath = pathHelpers.normalizePath(installerChoicesFilePath, followSymlink=True)
		
		# ---- validate that the installer command is avalible
		
		if chrootPath is None and not os.access(pathToInstaller, os.F_OK | os.X_OK):
			raise RuntimeError('The installer command was not avalible where it was expected to be, or was not useable: ' + pathToInstaller)
		elif chrootPath is not None and not os.access(os.path.join(chrootPath, pathToInstaller[1:]), os.F_OK | os.X_OK):
			raise RuntimeError('The installer command was not avalible where it was expected to be, or was not useable: ' + os.path.join(chrootPath, pathToInstaller[1:]))
		
		# ---- build the command
		
		command = []
		
		if chrootPath is not None:
			command += ['/usr/sbin/chroot', chrootPath]
		
		command += [pathToInstaller, '-pkginfo']
		
		if installerChoicesFilePath is not None:
			command += ['-applyChoiceChangesXML', installerChoicesFilePath]
		
		command += ['-pkg', pkgPath, '-target', '.']
		
		# ---- run the command
		
		process = None
		try:
			if chrootPath is None:
				process = managedSubprocess(command)
			else:
				process = managedSubprocess(command, cwd=chrootPath)
		except:
			return False
		
		# if installer did not have a problem, then it is very probably good
		return True