def wic_create(wks_file, rootfs_dir, bootimg_dir, kernel_dir, native_sysroot, options): """ Create image wks_file - user-defined OE kickstart file rootfs_dir - absolute path to the build's /rootfs dir bootimg_dir - absolute path to the build's boot artifacts directory kernel_dir - absolute path to the build's kernel directory native_sysroot - absolute path to the build's native sysroots dir image_output_dir - dirname to create for image options - wic command line options (debug, bmap, etc) Normally, the values for the build artifacts values are determined by 'wic -e' from the output of the 'bitbake -e' command given an image name e.g. 'core-image-minimal' and a given machine set in local.conf. If that's the case, the variables get the following values from the output of 'bitbake -e': rootfs_dir: IMAGE_ROOTFS kernel_dir: DEPLOY_DIR_IMAGE native_sysroot: STAGING_DIR_NATIVE In the above case, bootimg_dir remains unset and the plugin-specific image creation code is responsible for finding the bootimg artifacts. In the case where the values are passed in explicitly i.e 'wic -e' is not used but rather the individual 'wic' options are used to explicitly specify these values. """ try: oe_builddir = os.environ["BUILDDIR"] except KeyError: raise WicError( "BUILDDIR not found, exiting. (Did you forget to source oe-init-build-env?)" ) if not os.path.exists(options.outdir): os.makedirs(options.outdir) pname = options.imager plugin_class = PluginMgr.get_plugins('imager').get(pname) if not plugin_class: raise WicError('Unknown plugin: %s' % pname) plugin = plugin_class(wks_file, rootfs_dir, bootimg_dir, kernel_dir, native_sysroot, oe_builddir, options) plugin.do_create() logger.info("The image(s) were created using OE kickstart file:\n %s", wks_file)
def _build_initramfs_path(rootfs_dir, cr_workdir): """ Create path for initramfs image """ initrd = get_bitbake_var("INITRD_LIVE") or get_bitbake_var("INITRD") if not initrd: initrd_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") if not initrd_dir: raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting.") image_name = get_bitbake_var("IMAGE_BASENAME") if not image_name: raise WicError("Couldn't find IMAGE_BASENAME, exiting.") image_type = get_bitbake_var("INITRAMFS_FSTYPES") if not image_type: raise WicError("Couldn't find INITRAMFS_FSTYPES, exiting.") machine = os.path.basename(initrd_dir) initrd = glob.glob( '%s/%s*%s.%s' % (initrd_dir, image_name, machine, image_type))[0] if not os.path.exists(initrd): # Create initrd from rootfs directory initrd = "%s/initrd.cpio.gz" % cr_workdir initrd_dir = "%s/INITRD" % cr_workdir shutil.copytree("%s" % rootfs_dir, \ "%s" % initrd_dir, symlinks=True) if os.path.isfile("%s/init" % rootfs_dir): shutil.copy2("%s/init" % rootfs_dir, "%s/init" % initrd_dir) elif os.path.lexists("%s/init" % rootfs_dir): os.symlink(os.readlink("%s/init" % rootfs_dir), \ "%s/init" % initrd_dir) elif os.path.isfile("%s/sbin/init" % rootfs_dir): shutil.copy2("%s/sbin/init" % rootfs_dir, \ "%s" % initrd_dir) elif os.path.lexists("%s/sbin/init" % rootfs_dir): os.symlink(os.readlink("%s/sbin/init" % rootfs_dir), \ "%s/init" % initrd_dir) else: raise WicError("Couldn't find or build initrd, exiting.") exec_cmd("cd %s && find . | cpio -o -H newc -R +0:+0 >./initrd.cpio " \ % initrd_dir, as_shell=True) exec_cmd("gzip -f -9 -c %s/initrd.cpio > %s" \ % (cr_workdir, initrd), as_shell=True) shutil.rmtree(initrd_dir) return initrd
def _get_part_image(self, pnum): if pnum not in self.partitions: raise WicError("Partition %s is not in the image") part = self.partitions[pnum] if not part.fstype.startswith("fat"): raise WicError("Not supported fstype: {}".format(part.fstype)) if pnum not in self._partimages: tmpf = tempfile.NamedTemporaryFile(prefix="wic-part") dst_fname = tmpf.name tmpf.close() sparse_copy(self.imagepath, dst_fname, skip=part.start, length=part.size) self._partimages[pnum] = dst_fname return self._partimages[pnum]
def do_copy_mender_env(self, deploydir, cr_workdir, hdddir, source_params): """ Copy mender grub env files """ if not 'mender_grub_env' in source_params: raise WicError("mender_grub_env is unset!") if not source_params['mender_grub_env']: raise WicError("bad mender_grub_env!") copy_tree( "%s/grub-mender-grubenv/%s/EFI" % (deploydir, source_params['mender_grub_env']), "%s/EFI" % hdddir)
def do_prepare_partition(cls, part, source_params, cr, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, rootfs_dir, native_sysroot): """ Called to do the actual content population for a partition i.e. it 'prepares' the partition to be incorporated into the image. """ if not kernel_dir: kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") if not kernel_dir: raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") logger.debug('Kernel dir: %s', kernel_dir) if 'file' not in source_params: raise WicError("No file specified") if 'unpack' in source_params: img = os.path.join(kernel_dir, source_params['file']) src = os.path.join(cr_workdir, os.path.splitext(source_params['file'])[0]) RawCopyPlugin.do_image_uncompression(img, src, cr_workdir) else: src = os.path.join(kernel_dir, source_params['file']) dst = os.path.join( cr_workdir, "%s.%s" % (os.path.basename(source_params['file']), part.lineno)) if not os.path.exists(os.path.dirname(dst)): os.makedirs(os.path.dirname(dst)) if 'skip' in source_params: sparse_copy(src, dst, skip=int(source_params['skip'])) else: sparse_copy(src, dst) # get the size in the right units for kickstart (kB) du_cmd = "du -Lbks %s" % dst out = exec_cmd(du_cmd) filesize = int(out.split()[0]) if filesize > part.size: part.size = filesize if part.label: RawCopyPlugin.do_image_label(part.fstype, dst, part.label) part.source_file = dst
def __init__(self, wks_file, rootfs_dir, bootimg_dir, kernel_dir, native_sysroot, oe_builddir, options): try: self.ks = KickStart(wks_file) except KickStartError as err: raise WicError(str(err)) # parse possible 'rootfs=name' items self.rootfs_dir = dict(rdir.split('=') for rdir in rootfs_dir.split(' ')) self.bootimg_dir = bootimg_dir self.kernel_dir = kernel_dir self.native_sysroot = native_sysroot self.oe_builddir = oe_builddir self.outdir = options.outdir self.compressor = options.compressor self.bmap = options.bmap self.name = "%s-%s" % (os.path.splitext(os.path.basename(wks_file))[0], strftime("%Y%m%d%H%M")) self.workdir = tempfile.mkdtemp(dir=self.outdir, prefix='tmp.wic.') self._image = None self.ptable_format = self.ks.bootloader.ptable self.parts = self.ks.partitions # as a convenience, set source to the boot partition source # instead of forcing it to be set via bootloader --source for part in self.parts: if not self.ks.bootloader.source and part.mountpoint == "/boot": self.ks.bootloader.source = part.source break image_path = self._full_path(self.workdir, self.parts[0].disk, "direct") self._image = PartitionedImage(image_path, self.ptable_format, self.parts, self.native_sysroot)
def do_prepare_partition( cls, part, source_params, cr, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, dir_dict, native_sysroot, ): """Populate a partition given directory with files.""" img_link_name = get_bitbake_var("IMAGE_LINK_NAME") signed_base64_root_hash_suffix = ".root_hash.txt.sha256.base64" img_deploy_dir = get_bitbake_var("IMGDEPLOYDIR") try: subdir = source_params["subdir"] except KeyError: raise WicError( "Required source parameter 'subdir' not found, exiting") subdir_src = os.path.join(img_deploy_dir, subdir) subdir_dst = os.path.join(cr_workdir, subdir) logger.debug("Subdir source dir: {}".format(subdir_src)) logger.debug("Subdir dest dir: {}".format(subdir_dst)) shutil.copytree(subdir_src, subdir_dst) part.prepare_rootfs(cr_workdir, oe_builddir, subdir_dst, native_sysroot, False)
def do_image_label(fstype, dst, label): if fstype.startswith('ext'): cmd = 'tune2fs -L %s %s' % (label, dst) elif fstype in ('msdos', 'vfat'): cmd = 'dosfslabel %s %s' % (dst, label) elif fstype == 'btrfs': cmd = 'btrfs filesystem label %s %s' % (dst, label) elif fstype == 'swap': cmd = 'mkswap -L %s %s' % (label, dst) elif fstype == 'squashfs': raise WicError("It's not possible to update a squashfs " "filesystem label '%s'" % (label)) else: raise WicError("Cannot update filesystem label: " "Unknown fstype: '%s'" % (fstype)) exec_cmd(cmd)
def gen_ubootscript(cls, part, source_params, cr, rootdir, hdddir): u_boot_script = os.path.join(rootdir, "etc/default/u-boot-script") if not os.path.exists(u_boot_script): raise WicError("u-boot-scripts package not installed") # Write new /etc/default/u-boot-script ''' with open(u_boot_script, 'w') as cfg: cfg.write('# Generated by wic, bootpart plugin\n') cfg.write('ROOT_PARTITION="%d"\n' % part.realnum) cfg.write('KERNEL_ARGS="root=%s %s"\n' % \ (cr.rootdev, cr.ks.bootloader.append or "")) no_initrd = source_params.get('no_initrd') or '' cfg.write('NO_INITRD="%s"\n' % no_initrd) overlays = source_params.get('overlays') or '' cfg.write('OVERLAYS="%s"\n' % overlays) script_prepend = source_params.get('script_prepend') or '' cfg.write('SCRIPT_PREPEND="%s"\n' % script_prepend) ''' # Run update-u-boot-script in the target rootfs results = glob.glob(os.path.join("/usr/bin/qemu-*-static")) qemu_static = results[0] if len(results) > 0 else None if qemu_static: cp_cmd = "cp -L %s %s/usr/bin" % (qemu_static, rootdir) exec_cmd(cp_cmd) update_cmd = "chroot %s sh -c update-u-boot-script" % rootdir exec_cmd(update_cmd) if qemu_static: rm_cmd = "rm -f %s/usr/bin/%s" % (rootdir, qemu_static) exec_cmd(rm_cmd)
def runtool(cmdln_or_args): """ wrapper for most of the subprocess calls input: cmdln_or_args: can be both args and cmdln str (shell=True) return: rc, output """ 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 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 and decode out = ''.join([out.decode('utf-8') for out in [sout, serr] if out]) except OSError as err: if err.errno == 2: # [Errno 2] No such file or directory raise WicError('Cannot run command: %s, lost dependency?' % cmd) else: raise # relay return process.returncode, out
def wic_list(args, scripts_path): """ Print the list of images or source plugins. """ if args.list_type is None: return False if args.list_type == "images": list_canned_images(scripts_path) return True elif args.list_type == "source-plugins": list_source_plugins() return True elif len(args.help_for) == 1 and args.help_for[0] == 'help': wks_file = args.list_type fullpath = find_canned_image(scripts_path, wks_file) if not fullpath: raise WicError("No image named %s found, exiting. " "(Use 'wic list images' to list available images, " "or specify a fully-qualified OE kickstart (.wks) " "filename)" % wks_file) list_canned_image_help(scripts_path, fullpath) return True return False
def get_plugins(cls, ptype): """Get dictionary of <plugin_name>:<class> pairs.""" if ptype not in PLUGIN_TYPES: raise WicError('%s is not valid plugin type' % ptype) # collect plugin directories if not cls._plugin_dirs: cls._plugin_dirs = [os.path.join(os.path.dirname(__file__), 'plugins')] layers = get_bitbake_var("BBLAYERS") or '' for layer_path in layers.split(): for script_plugin_dir in SCRIPTS_PLUGIN_DIR: path = os.path.join(layer_path, script_plugin_dir) path = os.path.abspath(os.path.expanduser(path)) if path not in cls._plugin_dirs and os.path.isdir(path): cls._plugin_dirs.insert(0, path) if ptype not in PLUGINS: # load all ptype plugins for pdir in cls._plugin_dirs: ppath = os.path.join(pdir, ptype) if os.path.isdir(ppath): for fname in os.listdir(ppath): if fname.endswith('.py'): mname = fname[:-3] mpath = os.path.join(ppath, fname) logger.debug("loading plugin module %s", mpath) SourceFileLoader(mname, mpath).load_module() return PLUGINS.get(ptype)
def remove(self, pnum, path): """Remove files/dirs from the partition.""" partimg = self._get_part_image(pnum) if self.partitions[pnum].fstype.startswith('ext'): cmd = "{} {} -wR 'rm {}'".format(self.debugfs, self._get_part_image(pnum), path) out = exec_cmd(cmd , as_shell=True) for line in out.splitlines(): if line.startswith("rm:"): if "file is a directory" in line: # Try rmdir to see if this is an empty directory. This won't delete # any non empty directory so let user know about any error that this might # generate. print(exec_cmd("{} {} -wR 'rmdir {}'".format(self.debugfs, self._get_part_image(pnum), path), as_shell=True)) else: raise WicError("Could not complete operation: wic %s" % str(line)) else: # fat cmd = "{} -i {} ::{}".format(self.mdel, partimg, path) try: exec_cmd(cmd) except WicError as err: if "not found" in str(err) or "non empty" in str(err): # mdel outputs 'File ... not found' or 'directory .. non empty" # try to use mdeltree as path could be a directory cmd = "{} -i {} ::{}".format(self.mdeltree, partimg, path) exec_cmd(cmd) else: raise err self._put_part_image(pnum)
def get_rootfs_size(self, actual_rootfs_size=0): """ Calculate the required size of rootfs taking into consideration --size/--fixed-size flags as well as overhead and extra space, as specified in kickstart file. Raises an error if the `actual_rootfs_size` is larger than fixed-size rootfs. """ if self.fixed_size: rootfs_size = self.fixed_size if actual_rootfs_size > rootfs_size: raise WicError("Actual rootfs size (%d kB) is larger than " "allowed size %d kB" % (actual_rootfs_size, rootfs_size)) else: extra_blocks = self.get_extra_block_count(actual_rootfs_size) if extra_blocks < self.extra_space: extra_blocks = self.extra_space rootfs_size = actual_rootfs_size + extra_blocks rootfs_size *= self.overhead_factor logger.debug( "Added %d extra blocks to %s to get to %d total blocks", extra_blocks, self.mountpoint, rootfs_size) return rootfs_size
def do_prepare_partition(cls, part, source_params, cr, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, rootfs_dir, native_sysroot): """ Called to do the actual content population for a partition i.e. it 'prepares' the partition to be incorporated into the image. In this case, does the following: - sets up a vfat partition - copies all files listed in IMAGE_BOOT_FILES variable """ hdddir = "%s/boot.%d" % (cr_workdir, part.lineno) if not kernel_dir: kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") if not kernel_dir: raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") logger.debug('Kernel dir: %s', bootimg_dir) for task in cls.install_task: src_path, dst_path = task logger.debug('Install %s as %s', src_path, dst_path) install_cmd = "install -m 0644 -D %s %s" \ % (os.path.join(kernel_dir, src_path), os.path.join(hdddir, dst_path)) exec_cmd(install_cmd) logger.debug('Prepare boot partition using rootfs in %s', hdddir) part.prepare_rootfs(cr_workdir, oe_builddir, hdddir, native_sysroot, False)
def __init__(self, imagepath, native_sysroot, fstypes=('fat', 'ext')): self.imagepath = imagepath self.native_sysroot = native_sysroot self.fstypes = fstypes self._partitions = None self._partimages = {} self._lsector_size = None self._psector_size = None self._ptable_format = None # find parted # read paths from $PATH environment variable # if it fails, use hardcoded paths pathlist = "/bin:/usr/bin:/usr/sbin:/sbin/" try: self.paths = os.environ['PATH'] + ":" + pathlist except KeyError: self.paths = pathlist if native_sysroot: for path in pathlist.split(':'): self.paths = "%s%s:%s" % (native_sysroot, path, self.paths) self.parted = find_executable("parted", self.paths) if not self.parted: raise WicError("Can't find executable parted") self.partitions = self.get_partitions()
def _prop(self, name): """Get path to the executable in a lazy way.""" aname = "_%s" % name if getattr(self, aname) is None: setattr(self, aname, find_executable(name, self.paths)) if not getattr(self, aname): raise WicError("Can't find executable {}".format(name)) return getattr(self, aname)
def do_configure_partition(cls, part, source_params, creator, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, native_sysroot): """ Called before do_prepare_partition(), creates syslinux config """ hdddir = "%s/hdd/boot" % cr_workdir install_cmd = "install -d %s" % hdddir exec_cmd(install_cmd) bootloader = creator.ks.bootloader custom_cfg = None if bootloader.configfile: custom_cfg = get_custom_config(bootloader.configfile) if custom_cfg: # Use a custom configuration for grub syslinux_conf = custom_cfg logger.debug( "Using custom configuration file %s " "for syslinux.cfg", bootloader.configfile) else: raise WicError("configfile is specified but failed to " "get it from %s." % bootloader.configfile) if not custom_cfg: # Create syslinux configuration using parameters from wks file splash = os.path.join(cr_workdir, "/hdd/boot/splash.jpg") if os.path.exists(splash): splashline = "menu background splash.jpg" else: splashline = "" syslinux_conf = "" syslinux_conf += "PROMPT 0\n" syslinux_conf += "TIMEOUT " + str(bootloader.timeout) + "\n" syslinux_conf += "\n" syslinux_conf += "ALLOWOPTIONS 1\n" syslinux_conf += "SERIAL 0 115200\n" syslinux_conf += "\n" if splashline: syslinux_conf += "%s\n" % splashline syslinux_conf += "DEFAULT boot\n" syslinux_conf += "LABEL boot\n" kernel = get_bitbake_var("KERNEL_IMAGE") initrd = get_bitbake_var("INITRD_IMAGE") syslinux_conf += "KERNEL " + kernel + "\n" syslinux_conf += "APPEND label=boot root=%s initrd=%s %s\n" % \ (creator.rootdev, initrd, bootloader.append) logger.debug("Writing syslinux config %s/hdd/boot/syslinux.cfg", cr_workdir) cfg = open("%s/hdd/boot/syslinux.cfg" % cr_workdir, "w") cfg.write(syslinux_conf) cfg.close()
def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params): """ Create loader-specific systemd-boot config """ if source_params.get("initrd"): logger.debug("Ignoring initrd") install_cmd = "install -d {}/loader".format(hdddir) exec_cmd(install_cmd) install_cmd = "install -d {}/loader/entries".format(hdddir) exec_cmd(install_cmd) bootloader = creator.ks.bootloader copied = False for p in creator.ks.partitions: srcparams = splitsrcparams(p.sourceparams) if not isrootfs(srcparams): continue def write_entry_conf(conf, cfgpath): logger.debug("Writing systemd-boot entry config") cfg = open(cfgpath, "w") cfg.write(conf) cfg.close() def write_part_loader_conf(conf, cfgpath): logger.debug("Writing systemd-boot partition loader.conf") cfg = open(cfgpath, "w") cfg.write(loaderconf) cfg.close() if not p.label: raise WicError("Missing --label for rootfs") kernel = "/kernel/{}/bzImage".format(p.label) title = srcparams["boot-title"] if "boot-title" in srcparams else p.label bootconf = "" bootconf += "title {}\n".format(title) bootconf += "linux {}\n".format(kernel) bootconf += "options LABEL={} root=PARTUUID={} {}\n".format(p.label, p.uuid, bootloader.append) write_entry_conf(bootconf, "{}/hdd/boot/loader/entries/{}.conf".format(cr_workdir, p.label)) install_cmd = "install -d {}/hdd/boot/kernel/{}".format(cr_workdir, p.label) exec_cmd(install_cmd) loaderconf = "" loaderconf += "default {}\n".format(p.label) loaderconf += "timeout {}\n".format(bootloader.timeout) confpath = "{}/hdd/boot/kernel/{}/loader.conf".format(cr_workdir, p.label) write_part_loader_conf(loaderconf, confpath) if not copied: shutil.copyfile(confpath, "{}/hdd/boot/loader/loader.conf".format(cr_workdir)) copied = True assert copied, "copied must be True here"
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 and decode out = ''.join([out.decode('utf-8') for out in [sout, serr] if out]) except OSError as err: if err.errno == 2: # [Errno 2] No such file or directory raise WicError('Cannot run command: %s, lost dependency?' % cmd) else: raise # relay finally: if catch != 3: os.close(dev_null) return (process.returncode, out)
def remove_ext(self, pnum, path, recursive): """ Remove files/dirs and their contents from the partition. This only applies to ext* partition. """ abs_path = re.sub('\/\/+', '/', path) cmd = "{} {} -wR 'rm \"{}\"'".format(self.debugfs, self._get_part_image(pnum), abs_path) out = exec_cmd(cmd, as_shell=True) for line in out.splitlines(): if line.startswith("rm:"): if "file is a directory" in line: if recursive: # loop through content and delete them one by one if # flaged with -r subdirs = iter(self.dir(pnum, abs_path).splitlines()) next(subdirs) for subdir in subdirs: dir = subdir.split(':')[1].split(" ", 1)[1] if not dir == "." and not dir == "..": self.remove_ext(pnum, "%s/%s" % (abs_path, dir), recursive) rmdir_out = exec_cmd("{} {} -wR 'rmdir \"{}\"'".format( self.debugfs, self._get_part_image(pnum), abs_path.rstrip('/')), as_shell=True) for rmdir_line in rmdir_out.splitlines(): if "directory not empty" in rmdir_line: raise WicError( "Could not complete operation: \n%s \n" "use -r to remove non-empty directory" % rmdir_line) if rmdir_line.startswith("rmdir:"): raise WicError( "Could not complete operation: \n%s " "\n%s" % (str(line), rmdir_line)) else: raise WicError("Could not complete operation: \n%s " "\nUnable to remove %s" % (str(line), abs_path))
def do_configure_partition(cls, part, source_params, creator, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, native_sysroot): """ Called before do_prepare_partition(), creates loader-specific config """ if "loader" not in source_params: raise WicError("multi-bootimg-efi requires a loader, none specified") hdddir = "{}/hdd/boot".format(cr_workdir) install_cmd = "install -d {}/EFI/BOOT".format(hdddir) exec_cmd(install_cmd) if source_params["loader"] == "systemd-boot": cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params) else: raise WicError("Unrecognized multi-bootimg-efi loader: {}".format(source_params["loader"]))
def _get_bootimg_dir(cls, bootimg_dir, dirname): """ Check if dirname exists in default bootimg_dir or in STAGING_DIR. """ for result in (bootimg_dir, get_bitbake_var("STAGING_DATADIR")): if os.path.exists("%s/%s" % (result, dirname)): return result raise WicError("Couldn't find correct bootimg_dir, exiting")
def setup_workdir(self, workdir): if workdir: if os.path.exists(workdir): raise WicError("Internal workdir '%s' specified in wic arguments already exists!" % (workdir)) os.makedirs(workdir) return workdir else: return tempfile.mkdtemp(dir=self.outdir, prefix='tmp.wic.')
def do_prepare_partition(cls, part, source_params, image_creator, image_creator_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): logger.info("building syslinux-native...") exec_cmd("bitbake syslinux-native") if not is_exe(native_syslinux_nomtools): raise WicError("Couldn't find syslinux-nomtools (%s), exiting" % native_syslinux_nomtools) if part.rootfs is None: if 'ROOTFS_DIR' not in krootfs_dir: raise WicError("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: raise WicError("Couldn't find --rootfs-dir=%s connection or " "it is not a valid path, exiting" % part.rootfs) real_rootfs_dir = cls._get_rootfs_dir(rootfs_dir) part.rootfs_dir = real_rootfs_dir part.prepare_rootfs(image_creator_workdir, oe_builddir, real_rootfs_dir, native_sysroot) # install syslinux into rootfs partition syslinux_cmd = "syslinux-nomtools -d /boot -i %s" % part.source_file exec_native_cmd(syslinux_cmd, native_sysroot)
def prepare_rootfs(self, cr_workdir, oe_builddir, rootfs_dir, native_sysroot): """ Prepare content for a rootfs partition i.e. create a partition and fill it from a /rootfs dir. Currently handles ext2/3/4, btrfs and vfat. """ p_prefix = os.environ.get("PSEUDO_PREFIX", "%s/usr" % native_sysroot) p_localstatedir = os.environ.get("PSEUDO_LOCALSTATEDIR", "%s/../pseudo" % rootfs_dir) p_passwd = os.environ.get("PSEUDO_PASSWD", rootfs_dir) p_nosymlinkexp = os.environ.get("PSEUDO_NOSYMLINKEXP", "1") pseudo = "export PSEUDO_PREFIX=%s;" % p_prefix pseudo += "export PSEUDO_LOCALSTATEDIR=%s;" % p_localstatedir pseudo += "export PSEUDO_PASSWD=%s;" % p_passwd pseudo += "export PSEUDO_NOSYMLINKEXP=%s;" % p_nosymlinkexp pseudo += "%s " % get_bitbake_var("FAKEROOTCMD") rootfs = "%s/rootfs_%s.%s.%s" % (cr_workdir, self.label, self.lineno, self.fstype) if os.path.isfile(rootfs): os.remove(rootfs) if not self.fstype: raise WicError("File system for partition %s not specified in " "kickstart, use --fstype option" % self.mountpoint) # Get rootfs size from bitbake variable if it's not set in .ks file if not self.size: # Bitbake variable ROOTFS_SIZE is calculated in # Image._get_rootfs_size method from meta/lib/oe/image.py # using IMAGE_ROOTFS_SIZE, IMAGE_ROOTFS_ALIGNMENT, # IMAGE_OVERHEAD_FACTOR and IMAGE_ROOTFS_EXTRA_SPACE rsize_bb = get_bitbake_var('ROOTFS_SIZE') if rsize_bb: logger.warning( 'overhead-factor was specified, but size was not,' ' so bitbake variables will be used for the size.' ' In this case both IMAGE_OVERHEAD_FACTOR and ' '--overhead-factor will be applied') self.size = int(round(float(rsize_bb))) for prefix in ("ext", "btrfs", "vfat", "squashfs"): if self.fstype.startswith(prefix): method = getattr(self, "prepare_rootfs_" + prefix) method(rootfs, oe_builddir, rootfs_dir, native_sysroot, pseudo) self.source_file = rootfs # get the rootfs size in the right units for kickstart (kB) du_cmd = "du -Lbks %s" % rootfs out = exec_cmd(du_cmd) self.size = int(out.split()[0]) break
def verify_build_env(): """ Verify that the build environment is sane. Returns True if it is, false otherwise """ if not os.environ.get("BUILDDIR"): raise WicError("BUILDDIR not found, exiting. (Did you forget to source oe-init-build-env?)") return True
def __get_rootfs_dir(rootfs_dir): if os.path.isdir(rootfs_dir): return os.path.realpath(rootfs_dir) image_rootfs_dir = get_bitbake_var("IMAGE_ROOTFS", rootfs_dir) if not os.path.isdir(image_rootfs_dir): raise WicError("No valid artifact IMAGE_ROOTFS from image " "named %s has been found at %s, exiting." % (rootfs_dir, image_rootfs_dir)) return os.path.realpath(image_rootfs_dir)
def do_configure_partition(cls, part, source_params, creator, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, native_sysroot): """ Called before do_prepare_partition(), creates loader-specific config """ hdddir = "%s/hdd/boot" % cr_workdir install_cmd = "install -d %s/EFI/BOOT" % hdddir exec_cmd(install_cmd) try: if source_params['loader'] == 'grub-efi': cls.do_configure_grubefi(creator, cr_workdir) elif source_params['loader'] == 'systemd-boot': cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params) else: raise WicError("unrecognized bootimg-efi loader: %s" % source_params['loader']) except KeyError: raise WicError("bootimg-efi requires a loader, none specified")
def __getattr__(self, name): """Get path to the executable in a lazy way.""" if name in ("mdir", "mcopy", "mdel", "mdeltree", "sfdisk", "e2fsck", "resize2fs", "mkswap", "mkdosfs", "debugfs"): aname = "_%s" % name if aname not in self.__dict__: setattr(self, aname, find_executable(name, self.paths)) if aname not in self.__dict__ or self.__dict__[aname] is None: raise WicError("Can't find executable '{}'".format(name)) return self.__dict__[aname] return self.__dict__[name]