summaryrefslogtreecommitdiff
path: root/scripts/lib/wic/utils
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/utils')
-rw-r--r--scripts/lib/wic/utils/__init__.py0
-rw-r--r--scripts/lib/wic/utils/errors.py29
-rw-r--r--scripts/lib/wic/utils/fs_related.py84
-rw-r--r--scripts/lib/wic/utils/misc.py95
-rw-r--r--scripts/lib/wic/utils/oe/__init__.py22
-rw-r--r--scripts/lib/wic/utils/oe/misc.py250
-rw-r--r--scripts/lib/wic/utils/partitionedfs.py360
-rw-r--r--scripts/lib/wic/utils/runner.py110
-rw-r--r--scripts/lib/wic/utils/syslinux.py58
9 files changed, 1008 insertions, 0 deletions
diff --git a/scripts/lib/wic/utils/__init__.py b/scripts/lib/wic/utils/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/scripts/lib/wic/utils/__init__.py
diff --git a/scripts/lib/wic/utils/errors.py b/scripts/lib/wic/utils/errors.py
new file mode 100644
index 0000000..d1b514d
--- /dev/null
+++ b/scripts/lib/wic/utils/errors.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python -tt
+#
+# Copyright (c) 2007 Red Hat, Inc.
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program 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; version 2 of the License
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+class WicError(Exception):
+ pass
+
+class CreatorError(WicError):
+ pass
+
+class Usage(WicError):
+ pass
+
+class ImageError(WicError):
+ pass
diff --git a/scripts/lib/wic/utils/fs_related.py b/scripts/lib/wic/utils/fs_related.py
new file mode 100644
index 0000000..2e74461
--- /dev/null
+++ b/scripts/lib/wic/utils/fs_related.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python -tt
+#
+# Copyright (c) 2007, Red Hat, Inc.
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+#
+# This program 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; version 2 of the License
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from __future__ import with_statement
+import os
+import errno
+
+from wic.utils.oe.misc import exec_cmd
+
+def makedirs(dirname):
+ """A version of os.makedirs() that doesn't throw an
+ exception if the leaf directory already exists.
+ """
+ try:
+ os.makedirs(dirname)
+ except OSError, err:
+ if err.errno != errno.EEXIST:
+ raise
+
+class Disk:
+ """
+ Generic base object for a disk.
+ """
+ def __init__(self, size, device=None):
+ self._device = device
+ self._size = size
+
+ def create(self):
+ pass
+
+ def cleanup(self):
+ pass
+
+ def get_device(self):
+ return self._device
+ def set_device(self, path):
+ self._device = path
+ device = property(get_device, set_device)
+
+ def get_size(self):
+ return self._size
+ size = property(get_size)
+
+
+class DiskImage(Disk):
+ """
+ A Disk backed by a file.
+ """
+ def __init__(self, image_file, size):
+ Disk.__init__(self, size)
+ self.image_file = image_file
+
+ def exists(self):
+ return os.path.exists(self.image_file)
+
+ def create(self):
+ if self.device is not None:
+ return
+
+ blocks = self.size / 1024
+ if self.size - blocks * 1024:
+ blocks += 1
+
+ # create disk image
+ dd_cmd = "dd if=/dev/zero of=%s bs=1024 seek=%d count=1" % \
+ (self.image_file, blocks)
+ exec_cmd(dd_cmd)
+
+ self.device = self.image_file
diff --git a/scripts/lib/wic/utils/misc.py b/scripts/lib/wic/utils/misc.py
new file mode 100644
index 0000000..1415ae9
--- /dev/null
+++ b/scripts/lib/wic/utils/misc.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python -tt
+#
+# Copyright (c) 2010, 2011 Intel Inc.
+#
+# This program 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; version 2 of the License
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import time
+import wic.engine
+
+def build_name(kscfg, release=None, prefix=None, suffix=None):
+ """Construct and return an image name string.
+
+ This is a utility function to help create sensible name and fslabel
+ strings. The name is constructed using the sans-prefix-and-extension
+ kickstart filename and the supplied prefix and suffix.
+
+ kscfg -- a path to a kickstart file
+ release -- a replacement to suffix for image release
+ prefix -- a prefix to prepend to the name; defaults to None, which causes
+ no prefix to be used
+ suffix -- a suffix to append to the name; defaults to None, which causes
+ a YYYYMMDDHHMM suffix to be used
+
+ Note, if maxlen is less then the len(suffix), you get to keep both pieces.
+
+ """
+ name = os.path.basename(kscfg)
+ idx = name.rfind('.')
+ if idx >= 0:
+ name = name[:idx]
+
+ if release is not None:
+ suffix = ""
+ if prefix is None:
+ prefix = ""
+ if suffix is None:
+ suffix = time.strftime("%Y%m%d%H%M")
+
+ if name.startswith(prefix):
+ name = name[len(prefix):]
+
+ prefix = "%s-" % prefix if prefix else ""
+ suffix = "-%s" % suffix if suffix else ""
+
+ ret = prefix + name + suffix
+
+ return ret
+
+def find_canned(scripts_path, file_name):
+ """
+ Find a file either by its path or by name in the canned files dir.
+
+ Return None if not found
+ """
+ if os.path.exists(file_name):
+ return file_name
+
+ layers_canned_wks_dir = wic.engine.build_canned_image_list(scripts_path)
+ for canned_wks_dir in layers_canned_wks_dir:
+ for root, dirs, files in os.walk(canned_wks_dir):
+ for fname in files:
+ if fname == file_name:
+ fullpath = os.path.join(canned_wks_dir, fname)
+ return fullpath
+
+def get_custom_config(boot_file):
+ """
+ Get the custom configuration to be used for the bootloader.
+
+ Return None if the file can't be found.
+ """
+ scripts_path = os.path.abspath(os.path.dirname(__file__))
+ # Get the scripts path of poky
+ for x in range(0, 3):
+ scripts_path = os.path.dirname(scripts_path)
+
+ cfg_file = find_canned(scripts_path, boot_file)
+ if cfg_file:
+ with open(cfg_file, "r") as f:
+ config = f.read()
+ return config
+
+ return None
diff --git a/scripts/lib/wic/utils/oe/__init__.py b/scripts/lib/wic/utils/oe/__init__.py
new file mode 100644
index 0000000..0a81575
--- /dev/null
+++ b/scripts/lib/wic/utils/oe/__init__.py
@@ -0,0 +1,22 @@
+#
+# OpenEmbedded wic utils library
+#
+# Copyright (c) 2013, Intel Corporation.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# AUTHORS
+# Tom Zanussi <tom.zanussi (at] linux.intel.com>
+#
diff --git a/scripts/lib/wic/utils/oe/misc.py b/scripts/lib/wic/utils/oe/misc.py
new file mode 100644
index 0000000..81239ac
--- /dev/null
+++ b/scripts/lib/wic/utils/oe/misc.py
@@ -0,0 +1,250 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+# Copyright (c) 2013, Intel Corporation.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# DESCRIPTION
+# This module provides a place to collect various wic-related utils
+# for the OpenEmbedded Image Tools.
+#
+# AUTHORS
+# Tom Zanussi <tom.zanussi (at] linux.intel.com>
+#
+"""Miscellaneous functions."""
+
+import os
+from collections import defaultdict
+
+from wic import msger
+from wic.utils import runner
+
+# executable -> recipe pairs for exec_native_cmd
+NATIVE_RECIPES = {"mcopy": "mtools",
+ "mkdosfs": "dosfstools",
+ "mkfs.btrfs": "btrfs-tools",
+ "mkfs.ext2": "e2fsprogs",
+ "mkfs.ext3": "e2fsprogs",
+ "mkfs.ext4": "e2fsprogs",
+ "mkfs.vfat": "dosfstools",
+ "mksquashfs": "squashfs-tools",
+ "mkswap": "util-linux",
+ "parted": "parted",
+ "sgdisk": "gptfdisk",
+ "syslinux": "syslinux"
+ }
+
+def _exec_cmd(cmd_and_args, as_shell=False, catch=3):
+ """
+ Execute command, catching stderr, stdout
+
+ Need to execute as_shell if the command uses wildcards
+ """
+ msger.debug("_exec_cmd: %s" % cmd_and_args)
+ args = cmd_and_args.split()
+ msger.debug(args)
+
+ if as_shell:
+ ret, out = runner.runtool(cmd_and_args, catch)
+ else:
+ ret, out = runner.runtool(args, catch)
+ out = out.strip()
+ msger.debug("_exec_cmd: output for %s (rc = %d): %s" % \
+ (cmd_and_args, ret, out))
+
+ return (ret, out)
+
+
+def exec_cmd(cmd_and_args, as_shell=False, catch=3):
+ """
+ Execute command, catching stderr, stdout
+
+ Exits if rc non-zero
+ """
+ ret, out = _exec_cmd(cmd_and_args, as_shell, catch)
+
+ if ret != 0:
+ msger.error("exec_cmd: %s returned '%s' instead of 0" % \
+ (cmd_and_args, ret))
+
+ return out
+
+def cmd_in_path(cmd, path):
+ import scriptpath
+
+ scriptpath.add_bitbake_lib_path()
+
+ return bb.utils.which(path, cmd) != "" or False
+
+def exec_native_cmd(cmd_and_args, native_sysroot, catch=3, pseudo=""):
+ """
+ Execute native command, catching stderr, stdout
+
+ Need to execute as_shell if the command uses wildcards
+
+ Always need to execute native commands as_shell
+ """
+ # The reason -1 is used is because there may be "export" commands.
+ args = cmd_and_args.split(';')[-1].split()
+ msger.debug(args)
+
+ if pseudo:
+ cmd_and_args = pseudo + cmd_and_args
+ native_paths = \
+ "%s/sbin:%s/usr/sbin:%s/usr/bin" % \
+ (native_sysroot, native_sysroot, native_sysroot)
+ native_cmd_and_args = "export PATH=%s:$PATH;%s" % \
+ (native_paths, cmd_and_args)
+ msger.debug("exec_native_cmd: %s" % cmd_and_args)
+
+ # If the command isn't in the native sysroot say we failed.
+ if cmd_in_path(args[0], native_paths):
+ ret, out = _exec_cmd(native_cmd_and_args, True, catch)
+ else:
+ ret = 127
+
+ prog = args[0]
+ # shell command-not-found
+ if ret == 127 \
+ or (pseudo and ret == 1 and out == "Can't find '%s' in $PATH." % prog):
+ msg = "A native program %s required to build the image "\
+ "was not found (see details above).\n\n" % prog
+ recipe = NATIVE_RECIPES.get(prog)
+ if recipe:
+ msg += "Please bake it with 'bitbake %s-native' "\
+ "and try again.\n" % recipe
+ else:
+ msg += "Wic failed to find a recipe to build native %s. Please "\
+ "file a bug against wic.\n" % prog
+ msger.error(msg)
+ if out:
+ msger.debug('"%s" output: %s' % (args[0], out))
+
+ if ret != 0:
+ msger.error("exec_cmd: '%s' returned '%s' instead of 0" % \
+ (cmd_and_args, ret))
+
+ return ret, out
+
+BOOTDD_EXTRA_SPACE = 16384
+
+class BitbakeVars(defaultdict):
+ """
+ Container for Bitbake variables.
+ """
+ def __init__(self):
+ defaultdict.__init__(self, dict)
+
+ # default_image and vars_dir attributes should be set from outside
+ self.default_image = None
+ self.vars_dir = None
+
+ def _parse_line(self, line, image):
+ """
+ Parse one line from bitbake -e output or from .env file.
+ Put result key-value pair into the storage.
+ """
+ if "=" not in line:
+ return
+ try:
+ key, val = line.split("=")
+ except ValueError:
+ return
+ key = key.strip()
+ val = val.strip()
+ if key.replace('_', '').isalnum():
+ self[image][key] = val.strip('"')
+
+ def get_var(self, var, image=None):
+ """
+ Get bitbake variable from 'bitbake -e' output or from .env file.
+ This is a lazy method, i.e. it runs bitbake or parses file only when
+ only when variable is requested. It also caches results.
+ """
+ if not image:
+ image = self.default_image
+
+ if image not in self:
+ if image and self.vars_dir:
+ fname = os.path.join(self.vars_dir, image + '.env')
+ if os.path.isfile(fname):
+ # parse .env file
+ with open(fname) as varsfile:
+ for line in varsfile:
+ self._parse_line(line, image)
+ else:
+ print "Couldn't get bitbake variable from %s." % fname
+ print "File %s doesn't exist." % fname
+ return
+ else:
+ # Get bitbake -e output
+ cmd = "bitbake -e"
+ if image:
+ cmd += " %s" % image
+
+ log_level = msger.get_loglevel()
+ msger.set_loglevel('normal')
+ ret, lines = _exec_cmd(cmd)
+ msger.set_loglevel(log_level)
+
+ if ret:
+ print "Couldn't get '%s' output." % cmd
+ print "Bitbake failed with error:\n%s\n" % lines
+ return
+
+ # Parse bitbake -e output
+ for line in lines.split('\n'):
+ self._parse_line(line, image)
+
+ # Make first image a default set of variables
+ images = [key for key in self if key]
+ if len(images) == 1:
+ self[None] = self[image]
+
+ return self[image].get(var)
+
+# Create BB_VARS singleton
+BB_VARS = BitbakeVars()
+
+def get_bitbake_var(var, image=None):
+ """
+ Provide old get_bitbake_var API by wrapping
+ get_var method of BB_VARS singleton.
+ """
+ return BB_VARS.get_var(var, image)
+
+def parse_sourceparams(sourceparams):
+ """
+ Split sourceparams string of the form key1=val1[,key2=val2,...]
+ into a dict. Also accepts valueless keys i.e. without =.
+
+ Returns dict of param key/val pairs (note that val may be None).
+ """
+ params_dict = {}
+
+ params = sourceparams.split(',')
+ if params:
+ for par in params:
+ if not par:
+ continue
+ if not '=' in par:
+ key = par
+ val = None
+ else:
+ key, val = par.split('=')
+ params_dict[key] = val
+
+ return params_dict
diff --git a/scripts/lib/wic/utils/partitionedfs.py b/scripts/lib/wic/utils/partitionedfs.py
new file mode 100644
index 0000000..ad596d2
--- /dev/null
+++ b/scripts/lib/wic/utils/partitionedfs.py
@@ -0,0 +1,360 @@
+#!/usr/bin/env python -tt
+#
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+# Copyright (c) 2007, 2008 Red Hat, Inc.
+# Copyright (c) 2008 Daniel P. Berrange
+# Copyright (c) 2008 David P. Huff
+#
+# This program 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; version 2 of the License
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+from wic import msger
+from wic.utils.errors import ImageError
+from wic.utils.oe.misc import exec_cmd, exec_native_cmd
+
+# Overhead of the MBR partitioning scheme (just one sector)
+MBR_OVERHEAD = 1
+
+# Overhead of the GPT partitioning scheme
+GPT_OVERHEAD = 34
+
+# Size of a sector in bytes
+SECTOR_SIZE = 512
+
+class Image(object):
+ """
+ Generic base object for an image.
+
+ An Image is a container for a set of DiskImages and associated
+ partitions.
+ """
+ def __init__(self, native_sysroot=None):
+ self.disks = {}
+ self.partitions = []
+ # Size of a sector used in calculations
+ self.sector_size = SECTOR_SIZE
+ self._partitions_layed_out = False
+ self.native_sysroot = native_sysroot
+
+ def __add_disk(self, disk_name):
+ """ Add a disk 'disk_name' to the internal list of disks. Note,
+ 'disk_name' is the name of the disk in the target system
+ (e.g., sdb). """
+
+ if disk_name in self.disks:
+ # We already have this disk
+ return
+
+ assert not self._partitions_layed_out
+
+ self.disks[disk_name] = \
+ {'disk': None, # Disk object
+ 'numpart': 0, # Number of allocate partitions
+ 'realpart': 0, # Number of partitions in the partition table
+ 'partitions': [], # Indexes to self.partitions
+ 'offset': 0, # Offset of next partition (in sectors)
+ # Minimum required disk size to fit all partitions (in bytes)
+ 'min_size': 0,
+ 'ptable_format': "msdos"} # Partition table format
+
+ def add_disk(self, disk_name, disk_obj):
+ """ Add a disk object which have to be partitioned. More than one disk
+ can be added. In case of multiple disks, disk partitions have to be
+ added for each disk separately with 'add_partition()". """
+
+ self.__add_disk(disk_name)
+ self.disks[disk_name]['disk'] = disk_obj
+
+ def __add_partition(self, part):
+ """ This is a helper function for 'add_partition()' which adds a
+ partition to the internal list of partitions. """
+
+ assert not self._partitions_layed_out
+
+ self.partitions.append(part)
+ self.__add_disk(part['disk_name'])
+
+ def add_partition(self, size, disk_name, mountpoint, source_file=None, fstype=None,
+ label=None, fsopts=None, boot=False, align=None, no_table=False,
+ part_type=None, uuid=None):
+ """ Add the next partition. Prtitions have to be added in the
+ first-to-last order. """
+
+ ks_pnum = len(self.partitions)
+
+ # Converting kB to sectors for parted
+ size = size * 1024 / self.sector_size
+
+ part = {'ks_pnum': ks_pnum, # Partition number in the KS file
+ 'size': size, # In sectors
+ 'mountpoint': mountpoint, # Mount relative to chroot
+ 'source_file': source_file, # partition contents
+ 'fstype': fstype, # Filesystem type
+ 'fsopts': fsopts, # Filesystem mount options
+ 'label': label, # Partition label
+ 'disk_name': disk_name, # physical disk name holding partition
+ 'device': None, # kpartx device node for partition
+ 'num': None, # Partition number
+ 'boot': boot, # Bootable flag
+ 'align': align, # Partition alignment
+ 'no_table' : no_table, # Partition does not appear in partition table
+ 'part_type' : part_type, # Partition type
+ 'uuid': uuid} # Partition UUID
+
+ self.__add_partition(part)
+
+ def layout_partitions(self, ptable_format="msdos"):
+ """ Layout the partitions, meaning calculate the position of every
+ partition on the disk. The 'ptable_format' parameter defines the
+ partition table format and may be "msdos". """
+
+ msger.debug("Assigning %s partitions to disks" % ptable_format)
+
+ if self._partitions_layed_out:
+ return
+
+ self._partitions_layed_out = True
+
+ # Go through partitions in the order they are added in .ks file
+ for num in range(len(self.partitions)):
+ part = self.partitions[num]
+
+ if not self.disks.has_key(part['disk_name']):
+ raise ImageError("No disk %s for partition %s" \
+ % (part['disk_name'], part['mountpoint']))
+
+ if ptable_format == 'msdos' and part['part_type']:
+ # The --part-type can also be implemented for MBR partitions,
+ # in which case it would map to the 1-byte "partition type"
+ # filed at offset 3 of the partition entry.
+ raise ImageError("setting custom partition type is not " \
+ "implemented for msdos partitions")
+
+ # Get the disk where the partition is located
+ disk = self.disks[part['disk_name']]
+ disk['numpart'] += 1
+ if not part['no_table']:
+ disk['realpart'] += 1
+ disk['ptable_format'] = ptable_format
+
+ if disk['numpart'] == 1:
+ if ptable_format == "msdos":
+ overhead = MBR_OVERHEAD
+ elif ptable_format == "gpt":
+ overhead = GPT_OVERHEAD
+
+ # Skip one sector required for the partitioning scheme overhead
+ disk['offset'] += overhead
+
+ if disk['realpart'] > 3:
+ # Reserve a sector for EBR for every logical partition
+ # before alignment is performed.
+ if ptable_format == "msdos":
+ disk['offset'] += 1
+
+
+ if part['align']:
+ # If not first partition and we do have alignment set we need
+ # to align the partition.
+ # FIXME: This leaves a empty spaces to the disk. To fill the
+ # gaps we could enlargea the previous partition?
+
+ # Calc how much the alignment is off.
+ align_sectors = disk['offset'] % (part['align'] * 1024 / self.sector_size)
+
+ if align_sectors:
+ # If partition is not aligned as required, we need
+ # to move forward to the next alignment point
+ align_sectors = (part['align'] * 1024 / self.sector_size) - align_sectors
+
+ msger.debug("Realignment for %s%s with %s sectors, original"
+ " offset %s, target alignment is %sK." %
+ (part['disk_name'], disk['numpart'], align_sectors,
+ disk['offset'], part['align']))
+
+ # increase the offset so we actually start the partition on right alignment
+ disk['offset'] += align_sectors
+
+ part['start'] = disk['offset']
+ disk['offset'] += part['size']
+
+ part['type'] = 'primary'
+ if not part['no_table']:
+ part['num'] = disk['realpart']
+ else:
+ part['num'] = 0
+
+ if disk['ptable_format'] == "msdos":
+ if disk['realpart'] > 3:
+ part['type'] = 'logical'
+ part['num'] = disk['realpart'] + 1
+
+ disk['partitions'].append(num)
+ msger.debug("Assigned %s to %s%d, sectors range %d-%d size %d "
+ "sectors (%d bytes)." \
+ % (part['mountpoint'], part['disk_name'], part['num'],
+ part['start'], part['start'] + part['size'] - 1,
+ part['size'], part['size'] * self.sector_size))
+
+ # Once all the partitions have been layed out, we can calculate the
+ # minumim disk sizes.
+ for disk in self.disks.values():
+ disk['min_size'] = disk['offset']
+ if disk['ptable_format'] == "gpt":
+ disk['min_size'] += GPT_OVERHEAD
+
+ disk['min_size'] *= self.sector_size
+
+ def __create_partition(self, device, parttype, fstype, start, size):
+ """ Create a partition on an image described by the 'device' object. """
+
+ # Start is included to the size so we need to substract one from the end.
+ end = start + size - 1
+ msger.debug("Added '%s' partition, sectors %d-%d, size %d sectors" %
+ (parttype, start, end, size))
+
+ cmd = "parted -s %s unit s mkpart %s" % (device, parttype)
+ if fstype:
+ cmd += " %s" % fstype
+ cmd += " %d %d" % (start, end)
+
+ return exec_native_cmd(cmd, self.native_sysroot)
+
+ def __format_disks(self):
+ self.layout_partitions()
+
+ for dev in self.disks.keys():
+ disk = self.disks[dev]
+ msger.debug("Initializing partition table for %s" % \
+ (disk['disk'].device))
+ exec_native_cmd("parted -s %s mklabel %s" % \
+ (disk['disk'].device, disk['ptable_format']),
+ self.native_sysroot)
+
+ msger.debug("Creating partitions")
+
+ for part in self.partitions:
+ if part['num'] == 0:
+ continue
+
+ disk = self.disks[part['disk_name']]
+ if disk['ptable_format'] == "msdos" and part['num'] == 5:
+ # Create an extended partition (note: extended
+ # partition is described in MBR and contains all
+ # logical partitions). The logical partitions save a
+ # sector for an EBR just before the start of a
+ # partition. The extended partition must start one
+ # sector before the start of the first logical
+ # partition. This way the first EBR is inside of the
+ # extended partition. Since the extended partitions
+ # starts a sector before the first logical partition,
+ # add a sector at the back, so that there is enough
+ # room for all logical partitions.
+ self.__create_partition(disk['disk'].device, "extended",
+ None, part['start'] - 1,
+ disk['offset'] - part['start'] + 1)
+
+ if part['fstype'] == "swap":
+ parted_fs_type = "linux-swap"
+ elif part['fstype'] == "vfat":
+ parted_fs_type = "fat32"
+ elif part['fstype'] == "msdos":
+ parted_fs_type = "fat16"
+ elif part['fstype'] == "ontrackdm6aux3":
+ parted_fs_type = "ontrackdm6aux3"
+ else:
+ # Type for ext2/ext3/ext4/btrfs
+ parted_fs_type = "ext2"
+
+ # Boot ROM of OMAP boards require vfat boot partition to have an
+ # even number of sectors.
+ if part['mountpoint'] == "/boot" and part['fstype'] in ["vfat", "msdos"] \
+ and part['size'] % 2:
+ msger.debug("Substracting one sector from '%s' partition to " \
+ "get even number of sectors for the partition" % \
+ part['mountpoint'])
+ part['size'] -= 1
+
+ self.__create_partition(disk['disk'].device, part['type'],
+ parted_fs_type, part['start'], part['size'])
+
+ if part['part_type']:
+ msger.debug("partition %d: set type UID to %s" % \
+ (part['num'], part['part_type']))
+ exec_native_cmd("sgdisk --typecode=%d:%s %s" % \
+ (part['num'], part['part_type'],
+ disk['disk'].device), self.native_sysroot)
+
+ if part['uuid']:
+ msger.debug("partition %d: set UUID to %s" % \
+ (part['num'], part['uuid']))
+ exec_native_cmd("sgdisk --partition-guid=%d:%s %s" % \
+ (part['num'], part['uuid'], disk['disk'].device),
+ self.native_sysroot)
+
+ if part['boot']:
+ flag_name = "legacy_boot" if disk['ptable_format'] == 'gpt' else "boot"
+ msger.debug("Set '%s' flag for partition '%s' on disk '%s'" % \
+ (flag_name, part['num'], disk['disk'].device))
+ exec_native_cmd("parted -s %s set %d %s on" % \
+ (disk['disk'].device, part['num'], flag_name),
+ self.native_sysroot)
+
+ # Parted defaults to enabling the lba flag for fat16 partitions,
+ # which causes compatibility issues with some firmware (and really
+ # isn't necessary).
+ if parted_fs_type == "fat16":
+ if disk['ptable_format'] == 'msdos':
+ msger.debug("Disable 'lba' flag for partition '%s' on disk '%s'" % \
+ (part['num'], disk['disk'].device))
+ exec_native_cmd("parted -s %s set %d lba off" % \
+ (disk['disk'].device, part['num']),
+ self.native_sysroot)
+
+ def cleanup(self):
+ if self.disks:
+ for dev in self.disks:
+ disk = self.disks[dev]
+ try:
+ disk['disk'].cleanup()
+ except:
+ pass
+
+ def assemble(self, image_file):
+ msger.debug("Installing partitions")
+
+ for part in self.partitions:
+ source = part['source_file']
+ if source:
+ # install source_file contents into a partition
+ cmd = "dd if=%s of=%s bs=%d seek=%d count=%d conv=notrunc" % \
+ (source, image_file, self.sector_size,
+ part['start'], part['size'])
+ exec_cmd(cmd)
+
+ msger.debug("Installed %s in partition %d, sectors %d-%d, "
+ "size %d sectors" % \
+ (source, part['num'], part['start'],
+ part['start'] + part['size'] - 1, part['size']))
+
+ os.rename(source, image_file + '.p%d' % part['num'])
+
+ def create(self):
+ for dev in self.disks.keys():
+ disk = self.disks[dev]
+ disk['disk'].create()
+
+ self.__format_disks()
+
+ return
diff --git a/scripts/lib/wic/utils/runner.py b/scripts/lib/wic/utils/runner.py
new file mode 100644
index 0000000..7431917
--- /dev/null
+++ b/scripts/lib/wic/utils/runner.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python -tt
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program 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; version 2 of the License
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import subprocess
+
+from wic import msger
+
+def runtool(cmdln_or_args, catch=1):
+ """ wrapper for most of the subprocess calls
+ input:
+ cmdln_or_args: can be both args and cmdln str (shell=True)
+ catch: 0, quitely run
+ 1, only STDOUT
+ 2, only STDERR
+ 3, both STDOUT and STDERR
+ return:
+ (rc, output)
+ if catch==0: the output will always None
+ """
+
+ if catch not in (0, 1, 2, 3):
+ # invalid catch selection, will cause exception, that's good
+ return None
+
+ if isinstance(cmdln_or_args, list):
+ cmd = cmdln_or_args[0]
+ shell = False
+ else:
+ import shlex
+ cmd = shlex.split(cmdln_or_args)[0]
+ shell = True
+
+ if catch != 3:
+ dev_null = os.open("/dev/null", os.O_WRONLY)
+
+ if catch == 0:
+ sout = dev_null
+ serr = dev_null
+ elif catch == 1:
+ sout = subprocess.PIPE
+ serr = dev_null
+ elif catch == 2:
+ sout = dev_null
+ serr = subprocess.PIPE
+ elif catch == 3:
+ sout = subprocess.PIPE
+ serr = subprocess.STDOUT
+
+ try:
+ process = subprocess.Popen(cmdln_or_args, stdout=sout,
+ stderr=serr, shell=shell)
+ (sout, serr) = process.communicate()
+ # combine stdout and stderr, filter None out
+ out = ''.join(filter(None, [sout, serr]))
+ except OSError, err:
+ if err.errno == 2:
+ # [Errno 2] No such file or directory
+ msger.error('Cannot run command: %s, lost dependency?' % cmd)
+ else:
+ raise # relay
+ finally:
+ if catch != 3:
+ os.close(dev_null)
+
+ return (process.returncode, out)
+
+def show(cmdln_or_args):
+ # show all the message using msger.verbose
+
+ rcode, out = runtool(cmdln_or_args, catch=3)
+
+ if isinstance(cmdln_or_args, list):
+ cmd = ' '.join(cmdln_or_args)
+ else:
+ cmd = cmdln_or_args
+
+ msg = 'running command: "%s"' % cmd
+ if out:
+ out = out.strip()
+ if out:
+ msg += ', with output::'
+ msg += '\n +----------------'
+ for line in out.splitlines():
+ msg += '\n | %s' % line
+ msg += '\n +----------------'
+
+ msger.verbose(msg)
+ return rcode
+
+def outs(cmdln_or_args, catch=1):
+ # get the outputs of tools
+ return runtool(cmdln_or_args, catch)[1].strip()
+
+def quiet(cmdln_or_args):
+ return runtool(cmdln_or_args, catch=0)[0]
diff --git a/scripts/lib/wic/utils/syslinux.py b/scripts/lib/wic/utils/syslinux.py
new file mode 100644
index 0000000..aace286
--- /dev/null
+++ b/scripts/lib/wic/utils/syslinux.py
@@ -0,0 +1,58 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+# This program 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; version 2 of the License
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# AUTHOR
+# Adrian Freihofer <adrian.freihofer (at] neratec.com>
+
+
+import re
+from wic import msger
+
+
+def serial_console_form_kargs(kernel_args):
+ """
+ Create SERIAL... line from kernel parameters
+
+ syslinux needs a line SERIAL port [baudrate [flowcontrol]]
+ in the syslinux.cfg file. The config line is generated based
+ on kernel boot parameters. The the parameters of the first
+ ttyS console are considered for syslinux config.
+ @param kernel_args kernel command line
+ @return line for syslinux config file e.g. "SERIAL 0 115200"
+ """
+ syslinux_conf = ""
+ for param in kernel_args.split():
+ param_match = re.match("console=ttyS([0-9]+),?([0-9]*)([noe]?)([0-9]?)(r?)", param)
+ if param_match:
+ syslinux_conf += "SERIAL " + param_match.group(1)
+ # baudrate
+ if param_match.group(2):
+ syslinux_conf += " " + param_match.group(2)
+ # parity
+ if param_match.group(3) and param_match.group(3) != 'n':
+ msger.warning("syslinux does not support parity for console. {} is ignored."
+ .format(param_match.group(3)))
+ # number of bits
+ if param_match.group(4) and param_match.group(4) != '8':
+ msger.warning("syslinux supports 8 bit console configuration only. {} is ignored."
+ .format(param_match.group(4)))
+ # flow control
+ if param_match.group(5) and param_match.group(5) != '':
+ msger.warning("syslinux console flowcontrol configuration. {} is ignored."
+ .format(param_match.group(5)))
+ break
+
+ return syslinux_conf