On Tue, Mar 08, 2011 at 03:16:32PM +0100, Zygmunt Krynicki wrote: > W dniu 08.03.2011 09:51, Shawn Guo pisze: > > >By looking the workaround on the hacking branch, I changed the sleep(1) > >to sleep(5) in /usr/share/pyshared/linaro_media_create/partitions.py, > >and almost made it, but sadly it still fails at the last step. > > You most likely missed another sleep (there should be two). > Could you please confirm that? > I only see one sleep in /usr/share/pyshared/linaro_media_create/partitions.py. You meant there is another one in partitions.py or other files?
I attached the /usr/share/pyshared/linaro_media_create/partitions.py for your checking. -- Regards, Shawn
# Copyright (C) 2010, 2011 Linaro # # Author: Guilherme Salgado <guilherme.salg...@linaro.org> # # This file is part of Linaro Image Tools. # # Linaro Image Tools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Linaro Image Tools is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Linaro Image Tools. If not, see <http://www.gnu.org/licenses/>. import atexit import glob import re import subprocess import time import dbus from parted import ( Device, Disk, ) from linaro_media_create import cmd_runner HEADS = 255 SECTORS = 63 SECTOR_SIZE = 512 # bytes CYLINDER_SIZE = HEADS * SECTORS * SECTOR_SIZE DBUS_PROPERTIES = 'org.freedesktop.DBus.Properties' UDISKS = "org.freedesktop.UDisks" # I wonder if it'd make sense to convert this into a small shim which calls # the appropriate function for the given type of device? I think it's still # small enough that there's not much benefit in doing that, but if it grows we # might want to do it. def setup_partitions(board_config, media, image_size, bootfs_label, rootfs_label, rootfs_type, should_create_partitions, should_format_bootfs, should_format_rootfs): """Make sure the given device is partitioned to boot the given board. :param board_config: A BoardConfig class. :param media: The Media we should partition. :param image_size: The size of the image file, in case we're setting up a QEMU image. :param should_create_partitions: Whether or not we should erase existing partitions and create new ones. """ cylinders = None if not media.is_block_device: image_size_in_bytes = convert_size_to_bytes(image_size) cylinders = image_size_in_bytes / CYLINDER_SIZE image_size_in_bytes = cylinders * CYLINDER_SIZE proc = cmd_runner.run( ['qemu-img', 'create', '-f', 'raw', media.path, image_size], stdout=open('/dev/null', 'w')) proc.wait() if should_create_partitions: create_partitions( board_config, media, HEADS, SECTORS, cylinders) if media.is_block_device: bootfs, rootfs = get_boot_and_root_partitions_for_media( media, board_config) # It looks like KDE somehow automounts the partitions after you # repartition a disk so we need to unmount them here to create the # filesystem. ensure_partition_is_not_mounted(bootfs) ensure_partition_is_not_mounted(rootfs) else: bootfs, rootfs = get_boot_and_root_loopback_devices(media.path) if should_format_bootfs: print "\nFormating boot partition\n" proc = cmd_runner.run( ['mkfs.vfat', '-F', str(board_config.fat_size), bootfs, '-n', bootfs_label], as_root=True) proc.wait() if should_format_rootfs: print "\nFormating root partition\n" mkfs = 'mkfs.%s' % rootfs_type proc = cmd_runner.run( [mkfs, rootfs, '-L', rootfs_label], as_root=True) proc.wait() return bootfs, rootfs def get_uuid(partition): """Find UUID of the given partition.""" proc = cmd_runner.run( ['blkid', '-o', 'udev', '-p', '-c', '/dev/null', partition], as_root=True, stdout=subprocess.PIPE) blkid_output, _ = proc.communicate() return _parse_blkid_output(blkid_output) def _parse_blkid_output(output): for line in output.splitlines(): uuid_match = re.match("ID_FS_UUID=(.*)", line) if uuid_match: return uuid_match.group(1) return None def ensure_partition_is_not_mounted(partition): """Ensure the given partition is not mounted, umounting if necessary.""" if is_partition_mounted(partition): cmd_runner.run(['umount', partition], as_root=True).wait() def is_partition_mounted(partition): """Is the given partition mounted?""" device_path = _get_udisks_device_path(partition) device = dbus.SystemBus().get_object(UDISKS, device_path) return device.Get( device_path, 'DeviceIsMounted', dbus_interface=DBUS_PROPERTIES) def get_boot_and_root_loopback_devices(image_file): """Return the boot and root loopback devices for the given image file. Register the loopback devices as well. """ vfat_size, vfat_offset, linux_size, linux_offset = ( calculate_partition_size_and_offset(image_file)) boot_device = register_loopback(image_file, vfat_offset, vfat_size) root_device = register_loopback(image_file, linux_offset, linux_size) return boot_device, root_device def register_loopback(image_file, offset, size): """Register a loopback device with an atexit handler to de-register it.""" def undo(device): cmd_runner.run(['losetup', '-d', device], as_root=True).wait() proc = cmd_runner.run( ['losetup', '-f', '--show', image_file, '--offset', str(offset), '--sizelimit', str(size)], stdout=subprocess.PIPE, as_root=True) device, _ = proc.communicate() device = device.strip() atexit.register(undo, device) return device def calculate_partition_size_and_offset(image_file): """Return the size and offset of the boot and root partitions. Both the size and offset are in sectors. :param image_file: A string containing the path to the image_file. :return: A 4-tuple containing the offset and size of the boot partition followed by the offset and size of the root partition. """ # Here we can use parted.Device to read the partitions because we're # reading from a regular file rather than a block device. If it was a # block device we'd need root rights. disk = Disk(Device(image_file)) vfat_partition = None for partition in disk.partitions: if 'boot' in partition.getFlagsAsString(): geometry = partition.geometry vfat_offset = geometry.start * 512 vfat_size = geometry.length * 512 vfat_partition = partition assert vfat_partition is not None, ( "Couldn't find boot partition on %s" % image_file) linux_partition = vfat_partition.nextPartition() geometry = linux_partition.geometry linux_offset = geometry.start * 512 linux_size = geometry.length * 512 return vfat_size, vfat_offset, linux_size, linux_offset def get_boot_and_root_partitions_for_media(media, board_config): """Return the device files for the boot and root partitions of media. For boot we use partition number 1 plus the board's defined partition offset and for root we use partition number 2 plus the board's offset. This function must only be used for block devices. """ assert media.is_block_device, ( "This function must only be used for block devices") boot_partition = _get_device_file_for_partition_number( media.path, 1 + board_config.mmc_part_offset) root_partition = _get_device_file_for_partition_number( media.path, 2 + board_config.mmc_part_offset) assert boot_partition is not None and root_partition is not None, ( "Could not find boot/root partition for %s" % media.path) return boot_partition, root_partition def _get_device_file_for_partition_number(device, partition): """Return the device file for the partition number on the given device. e.g. /dev/sda1 for the first partition on device /dev/sda or /dev/mmcblk0p3 for the third partition on /dev/mmcblk0. """ # This could be simpler but UDisks doesn't make it easy for us: # https://bugs.freedesktop.org/show_bug.cgi?id=33113. for dev_file in glob.glob("%s?*" % device): device_path = _get_udisks_device_path(dev_file) udisks_dev = dbus.SystemBus().get_object(UDISKS, device_path) part_number = udisks_dev.Get( device_path, 'PartitionNumber', dbus_interface=DBUS_PROPERTIES) if part_number == partition: return str(udisks_dev.Get( device_path, 'DeviceFile', dbus_interface=DBUS_PROPERTIES)) return None def _get_udisks_device_path(device): """Return the UDisks path for the given device.""" bus = dbus.SystemBus() udisks = dbus.Interface( bus.get_object(UDISKS, "/org/freedesktop/UDisks"), UDISKS) return udisks.get_dbus_method('FindDeviceByDeviceFile')(device) def convert_size_to_bytes(size): """Convert a size string in Kbytes, Mbytes or Gbytes to bytes.""" unit = size[-1].upper() real_size = int(size[:-1]) if unit == 'K': real_size = real_size * 1024 elif unit == 'M': real_size = real_size * 1024 * 1024 elif unit == 'G': real_size = real_size * 1024 * 1024 * 1024 else: raise ValueError("Unknown size format: %s. Use K[bytes], M[bytes] " "or G[bytes]" % size) # Round the size of the raw disk image up to a multiple of 256K so it is # an exact number of SD card erase blocks in length. Otherwise Linux # under qemu cannot access the last part of the card and is likely to # complain that the last partition on the disk has been truncated. This # doesn't appear to work in all cases, though, as can be seen on # https://bugs.launchpad.net/linux-linaro/+bug/673335. if real_size % (1024 * 256): cylinders = real_size / CYLINDER_SIZE real_size = cylinders * CYLINDER_SIZE real_size = ((((real_size - 1) / (1024 * 256)) + 1) * (1024 * 256)) return real_size def run_sfdisk_commands(commands, heads, sectors, cylinders, device, as_root=True, stderr=None): """Run the given commands under sfdisk. Every time sfdisk is invoked it will repartition the device so to create multiple partitions you should craft a list of newline-separated commands to be executed in a single sfdisk run. :param commands: A string of sfdisk commands; each on a separate line. :return: A 2-tuple containing the subprocess' stdout and stderr. """ args = ['sfdisk', '-D', '-H', str(heads), '-S', str(sectors)] if cylinders is not None: args.extend(['-C', str(cylinders)]) args.append(device) proc = cmd_runner.run( args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr, as_root=as_root) return proc.communicate("%s\n" % commands) def create_partitions(board_config, media, heads, sectors, cylinders=None): """Partition the given media according to the board requirements. :param board_config: A BoardConfig class. :param media: A setup_partitions.Media object to partition. :param heads: Number of heads to use in the disk geometry of partitions. :param sectors: Number of sectors to use in the disk geometry of partitions. :param cylinders: The number of cylinders to pass to sfdisk's -C argument. If None the -C argument is not passed. """ if media.is_block_device: # Overwrite any existing partition tables with a fresh one. proc = cmd_runner.run( ['parted', '-s', media.path, 'mklabel', 'msdos'], as_root=True) proc.wait() sfdisk_cmd = board_config.get_sfdisk_cmd() run_sfdisk_commands(sfdisk_cmd, heads, sectors, cylinders, media.path) # Sync and sleep to wait for the partition to settle. cmd_runner.run(['sync']).wait() # Sleeping just 1 second seems to be enough here, but if we start getting # errors because the disk is not partitioned then we should revisit this. # XXX: This sleep can probably die now; need to do more tests before doing # so, though. time.sleep(5) class Media(object): """A representation of the media where Linaro will be installed.""" def __init__(self, path): self.path = path self.is_block_device = path.startswith('/dev/')
_______________________________________________ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev