On Tue, Apr 21, 2015 at 11:08:32PM +0200, Adrian Freihofer wrote: > The wic plugin creates a disk image containig one ext2/3/4 partition. > No additional boot partition is required. Syslinux is installed into > the image. The target device is a legacy BIOS PC. > > Purpose of this plugin: > Other avaliable plugins create a fat partition for /boot and an ext > partition for rootfs. Current linux-yocto kernel packages are not > compatible with this disk layout. The boot partition is not mounted > by default, hence the kernel is installed into rootfs and not into > boot partition. A kernel update ends up in a bricked device. The old > kernel which is still in boot likely does not even boot with updated > kernel modules from /. Even if the boot partition is mounted during > the kernel update the update will fail. The kernel package installs > a symbolic link which is not supported by the fat partition. > Creating just one ext partition for boot and rootfs solves all issues > related to package based kernel updates on the device. > > The plugin depends on syslinux-nomtools a user space installer for > syslinux on ext filesystems. > Thanks to Robert Yang who implemented syslinux-nomtools and supported > the implementation of this plugin. > Thank you for the update. See my comments below.
I'd suggest to fix at least this pylint warnings: C: 78, 4: Class method do_configure_partition should have 'cls' as first argument (bad-classmethod-argument) C:119, 4: Class method do_prepare_partition should have 'cls' as first argument (bad-classmethod-argument) C:167, 4: Class method do_install_disk should have 'cls' as first argument (bad-classmethod-argument) C:183, 8: Invalid variable name "rc" (invalid-name) > Signed-off-by: Adrian Freihofer <adrian.freiho...@gmail.com> > --- > scripts/lib/wic/kickstart/__init__.py | 13 ++ > .../lib/wic/plugins/source/rootfs_pcbios_ext.py | 185 > +++++++++++++++++++++ > scripts/lib/wic/utils/syslinux.py | 60 +++++++ > 3 files changed, 258 insertions(+) > create mode 100644 scripts/lib/wic/plugins/source/rootfs_pcbios_ext.py > create mode 100644 scripts/lib/wic/utils/syslinux.py > > diff --git a/scripts/lib/wic/kickstart/__init__.py > b/scripts/lib/wic/kickstart/__init__.py > index 111723b..1530c41 100644 > --- a/scripts/lib/wic/kickstart/__init__.py > +++ b/scripts/lib/wic/kickstart/__init__.py > @@ -104,6 +104,19 @@ def get_kernel_args(ks, default="ro rd.live.image"): > return default > return "%s %s" %(default, ks.handler.bootloader.appendLine) > > +def get_kernel_args_console_serial(kargs): > + """ > + Extract kernel parameters related to serial consoles > + """ > + consoles = [] > + for param in kargs.split(): > + param_match = > re.match("console=(ttyS|ttyUSB)([0-9]+),?([0-9]*)([noe]?)([0-9]?)(r?)", param) > + if param_match: > + # console name without index, console index, baudrate, parity, > number of bits, flow control > + consoles.append((param_match.group(1), param_match.group(2), > param_match.group(3), > + param_match.group(4), param_match.group(5), > param_match.group(6))) > + return consoles > + > def get_menu_args(ks, default=""): > if not hasattr(ks.handler.bootloader, "menus"): > return default > diff --git a/scripts/lib/wic/plugins/source/rootfs_pcbios_ext.py > b/scripts/lib/wic/plugins/source/rootfs_pcbios_ext.py > new file mode 100644 > index 0000000..b0ad299 > --- /dev/null > +++ b/scripts/lib/wic/plugins/source/rootfs_pcbios_ext.py > @@ -0,0 +1,185 @@ > +# 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 distribute 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 mo 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. > +# > +# AUTHOR > +# Adrian Freihofer <adrian.freihofer (at] neratec.com> > +# > + > +import os > +from wic import kickstart > +from wic import msger > +from wic.utils import syslinux > +from wic.utils import runner > +from wic.utils.oe import misc > +from wic.utils.errors import ImageError > +from wic.pluginbase import SourcePlugin > + > + > +# pylint: disable=no-init > +class RootfsPlugin(SourcePlugin): > + """ > + Create root partition and install syslinux bootloader > + > + This plugin creates a disk image containing a bootable root partition > with > + syslinux installed. The filesystem is ext2/3/4, no extra boot partition > is > + required. > + > + Example kickstart file: > + part / --source rootfs-pcbios-ext --ondisk sda --fstype=ext4 --label > rootfs --align 1024 > + bootloader --source rootfs-pcbios-ext --timeout=0 --append="rootwait > rootfstype=ext4" > + > + The first line generates a root file system including a syslinux.cfg file > + The "--source rootfs-pcbios-ext" in the second line triggers the > installation > + of ldlinux.sys into the image. > + """ > + > + name = 'rootfs-pcbios-ext' > + > + @staticmethod > + def __get_rootfs_dir(rootfs_dir): Do we really need name mangling here? I beleive one leading underscore should be enough. > + """ > + Find rootfs pseudo dir > + > + If rootfs_dir is a directory consider it as rootfs directory. > + Otherwise ask bitbake about the IMAGE_ROOTFS directory. > + """ > + if os.path.isdir(rootfs_dir): > + return rootfs_dir > + > + bitbake_env_lines = misc.find_bitbake_env_lines(rootfs_dir) > + if not bitbake_env_lines: > + msg = "Couldn't get bitbake environment, exiting." > + msger.error(msg) msger.error("Couldn't get bitbake environment, exiting.") is more readable from my point of view. > + > + image_rootfs_dir = misc.find_artifact(bitbake_env_lines, > "IMAGE_ROOTFS") > + if not os.path.isdir(image_rootfs_dir): > + msg = "No valid artifact IMAGE_ROOTFS from image named" > + msg += " %s has been found at %s, exiting.\n" % \ > + (rootfs_dir, image_rootfs_dir) > + msger.error(msg) > + > + return image_rootfs_dir > + > + # pylint: disable=unused-argument > + @classmethod > + def do_configure_partition(self, part, source_params, cr, cr_workdir, > + oe_builddir, bootimg_dir, kernel_dir, > + native_sysroot): > + """ > + Creates syslinux config in rootfs directory > + > + Called before do_prepare_partition() > + """ > + rootdev = cr._get_boot_config()[0] > + options = cr.ks.handler.bootloader.appendLine > + > + syslinux_conf = "" > + syslinux_conf += "PROMPT 0\n" > + > + timeout = kickstart.get_timeout(cr.ks) > + if not timeout: > + timeout = 0 > + syslinux_conf += "TIMEOUT " + str(timeout) + "\n" > + syslinux_conf += "ALLOWOPTIONS 1\n" > + > + # Derive SERIAL... line from from kernel boot parameters > + syslinux_conf += syslinux.serial_console_form_kargs(options) > + > + syslinux_conf += "DEFAULT linux\n" > + syslinux_conf += "LABEL linux\n" > + syslinux_conf += " KERNEL /boot/bzImage\n" > + > + if cr._ptable_format == 'msdos': > + rootstr = rootdev > + else: > + raise ImageError("Unsupported partition table format found") > + > + syslinux_conf += " APPEND label=boot root=%s %s\n" % (rootstr, > options) > + > + syslinux_cfg = os.path.join(cr.rootfs_dir['ROOTFS_DIR'], "boot", > "syslinux.cfg") > + msger.debug("Writing syslinux config %s" % syslinux_cfg) > + cfg = open(syslinux_cfg, "w") > + cfg.write(syslinux_conf) > + cfg.close() Please use 'with' statement here: https://docs.python.org/2/reference/compound_stmts.html#the-with-statement > + > + @classmethod > + def do_prepare_partition(self, part, source_params, cr, cr_workdir, > + oe_builddir, bootimg_dir, kernel_dir, > + krootfs_dir, native_sysroot): > + """ > + Creates partition out of rootfs directory > + > + Prepare content for a rootfs partition i.e. create a partition > + and fill it from a /rootfs dir. > + Install syslinux bootloader into root partition image file > + """ > + def is_exe(exepath): > + """Verify exepath is an executable file""" > + return os.path.isfile(exepath) and os.access(exepath, os.X_OK) > + > + # Make sure syslinux-nomtools is available in native sysroot or fail > + native_syslinux_nomtools = os.path.join(native_sysroot, > "usr/bin/syslinux-nomtools") > + if not is_exe(native_syslinux_nomtools): > + msger.info("building syslinux-native...") > + misc.exec_cmd("bitbake syslinux-native") > + if not is_exe(native_syslinux_nomtools): > + msger.error("Couldn't find syslinux-nomtools (%s), exiting\n" % > + native_syslinux_nomtools) > + > + if part.rootfs is None: > + if 'ROOTFS_DIR' not in krootfs_dir: > + msg = "Couldn't find --rootfs-dir, exiting" > + msger.error(msg) msger.error("Couldn't find --rootfs-dir, exiting") > + rootfs_dir = krootfs_dir['ROOTFS_DIR'] > + else: > + if part.rootfs in krootfs_dir: > + rootfs_dir = krootfs_dir[part.rootfs] > + elif part.rootfs: > + rootfs_dir = part.rootfs > + else: > + msg = "Couldn't find --rootfs-dir=%s connection" > + msg += " or it is not a valid path, exiting" > + msger.error(msg % part.rootfs) > + > + real_rootfs_dir = self.__get_rootfs_dir(rootfs_dir) > + > + part.set_rootfs(real_rootfs_dir) > + part.prepare_rootfs(cr_workdir, oe_builddir, real_rootfs_dir, > native_sysroot) > + > + # install syslinux into rootfs partition > + syslinux_cmd = "syslinux-nomtools -d /boot -i %s" % part.source_file > + misc.exec_native_cmd(syslinux_cmd, native_sysroot) > + > + @classmethod > + def do_install_disk(self, disk, disk_name, cr, workdir, oe_builddir, > + bootimg_dir, kernel_dir, native_sysroot): > + """ > + Assemble partitions to disk image > + > + Called after all partitions have been prepared and assembled into a > + disk image. In this case, we install the MBR. > + """ > + mbrfile = os.path.join(native_sysroot, "usr/share/syslinux/mbr.bin") > + if not os.path.exists(mbrfile): > + msger.error("Couldn't find %s. Has syslinux-native been baked?" > % mbrfile) > + > + full_path = disk['disk'].device > + msger.debug("Installing MBR on disk %s as %s with size %s bytes" \ > + % (disk_name, full_path, disk['min_size'])) > + > + rc = runner.show(['dd', 'if=%s' % mbrfile, 'of=%s' % full_path, > 'conv=notrunc']) > + if rc != 0: > + raise ImageError("Unable to set MBR to %s" % full_path) > diff --git a/scripts/lib/wic/utils/syslinux.py > b/scripts/lib/wic/utils/syslinux.py > new file mode 100644 > index 0000000..24d8c4e > --- /dev/null > +++ b/scripts/lib/wic/utils/syslinux.py > @@ -0,0 +1,60 @@ > +# 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> > + > + > +from wic import msger > +from wic import kickstart > + > + > +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. > + @param kernel_args kernel command line > + @return line for syslinux config file e.g. "SERIAL 0 115200" > + """ > + syslinux_conf = "" > + > + serial_args = kickstart.get_kernel_args_console_serial(kernel_args) > + try: > + if serial_args[0][1] == 'ttyS': > + syslinux_conf += "SERIAL " + serial_args[0][2] > + try: # baudrate > + syslinux_conf += serial_args[0][2] > + except IndexError: > + pass > + try: # parity > + if serial_args[0][2] != 'n': > + msger.warning("syslinux does not support parity for > console") > + except IndexError: > + pass > + try: # number of bits > + if serial_args[0][3] != '8': > + msger.warning("syslinux supports 8 bit console > configuration only") > + except IndexError: > + pass > + try: # flow control > + if serial_args[0][4] != '': > + msger.warning("syslinux console flowcontrol > configuration is ignored") > + except IndexError: > + pass Would it be more readable not to separate parsing of kernel args into get_kernel_args_console_serial ? > + except IndexError: > + pass > + > + return syslinux_conf + "\n" > -- > 2.1.0 > > -- > _______________________________________________ > Openembedded-core mailing list > Openembedded-core@lists.openembedded.org > http://lists.openembedded.org/mailman/listinfo/openembedded-core -- -- Regards, Ed -- _______________________________________________ Openembedded-core mailing list Openembedded-core@lists.openembedded.org http://lists.openembedded.org/mailman/listinfo/openembedded-core