mirror of
git://git.yoctoproject.org/poky.git
synced 2025-07-19 21:09:03 +02:00

We are getting closer and closer to the year 2038 where the 32 bit time_t overflow will happen. While products (= embedded systems) with an expected life time of 15 years are still save the situation may change if your system has to survive the next 20 years. ext2 and ext3 filesystems are always affected by the time overflow, so let's warn the user if these filesystems are still being used. If ext4 is affected depends on the inode size chosen during filesystem creation. At least 256 bytes are necessary to be safe. As ext4 is used very often (and partitions may be created small first and extended later) this might be an issue for many users. Some filesystems created during CI runs were already affected by the Y2038 problem. By using `--mkfs-extraopts "-T default"` we tell mke2fs not to auto-detect the usage type based on the filesystem size. mke2fs will use the default values for tuning parameters instead. The inode size is one of these parameters. (From OE-Core rev: eecbe625558406680121d2a7e84917fea45ea9dc) Signed-off-by: Florian Bezdeka <florian.bezdeka@siemens.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
265 lines
8.2 KiB
Python
265 lines
8.2 KiB
Python
#
|
|
# Copyright (c) 2013, Intel Corporation.
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
#
|
|
# 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 logging
|
|
import os
|
|
import re
|
|
import subprocess
|
|
|
|
from collections import defaultdict
|
|
from distutils import spawn
|
|
|
|
from wic import WicError
|
|
|
|
logger = logging.getLogger('wic')
|
|
|
|
# executable -> recipe pairs for exec_native_cmd
|
|
NATIVE_RECIPES = {"bmaptool": "bmap-tools",
|
|
"dumpe2fs": "e2fsprogs",
|
|
"grub-mkimage": "grub-efi",
|
|
"isohybrid": "syslinux",
|
|
"mcopy": "mtools",
|
|
"mdel" : "mtools",
|
|
"mdeltree" : "mtools",
|
|
"mdir" : "mtools",
|
|
"mkdosfs": "dosfstools",
|
|
"mkisofs": "cdrtools",
|
|
"mkfs.btrfs": "btrfs-tools",
|
|
"mkfs.ext2": "e2fsprogs",
|
|
"mkfs.ext3": "e2fsprogs",
|
|
"mkfs.ext4": "e2fsprogs",
|
|
"mkfs.vfat": "dosfstools",
|
|
"mksquashfs": "squashfs-tools",
|
|
"mkswap": "util-linux",
|
|
"mmd": "mtools",
|
|
"parted": "parted",
|
|
"sfdisk": "util-linux",
|
|
"sgdisk": "gptfdisk",
|
|
"syslinux": "syslinux",
|
|
"tar": "tar"
|
|
}
|
|
|
|
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 _exec_cmd(cmd_and_args, as_shell=False):
|
|
"""
|
|
Execute command, catching stderr, stdout
|
|
|
|
Need to execute as_shell if the command uses wildcards
|
|
"""
|
|
logger.debug("_exec_cmd: %s", cmd_and_args)
|
|
args = cmd_and_args.split()
|
|
logger.debug(args)
|
|
|
|
if as_shell:
|
|
ret, out = runtool(cmd_and_args)
|
|
else:
|
|
ret, out = runtool(args)
|
|
out = out.strip()
|
|
if ret != 0:
|
|
raise WicError("_exec_cmd: %s returned '%s' instead of 0\noutput: %s" % \
|
|
(cmd_and_args, ret, out))
|
|
|
|
logger.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):
|
|
"""
|
|
Execute command, return output
|
|
"""
|
|
return _exec_cmd(cmd_and_args, as_shell)[1]
|
|
|
|
def find_executable(cmd, paths):
|
|
recipe = cmd
|
|
if recipe in NATIVE_RECIPES:
|
|
recipe = NATIVE_RECIPES[recipe]
|
|
provided = get_bitbake_var("ASSUME_PROVIDED")
|
|
if provided and "%s-native" % recipe in provided:
|
|
return True
|
|
|
|
return spawn.find_executable(cmd, paths)
|
|
|
|
def exec_native_cmd(cmd_and_args, native_sysroot, 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()
|
|
logger.debug(args)
|
|
|
|
if pseudo:
|
|
cmd_and_args = pseudo + cmd_and_args
|
|
|
|
hosttools_dir = get_bitbake_var("HOSTTOOLS_DIR")
|
|
|
|
native_paths = "%s/sbin:%s/usr/sbin:%s/usr/bin:%s/bin:%s" % \
|
|
(native_sysroot, native_sysroot,
|
|
native_sysroot, native_sysroot,
|
|
hosttools_dir)
|
|
|
|
native_cmd_and_args = "export PATH=%s:$PATH;%s" % \
|
|
(native_paths, cmd_and_args)
|
|
logger.debug("exec_native_cmd: %s", native_cmd_and_args)
|
|
|
|
# If the command isn't in the native sysroot say we failed.
|
|
if find_executable(args[0], native_paths):
|
|
ret, out = _exec_cmd(native_cmd_and_args, True)
|
|
else:
|
|
ret = 127
|
|
out = "can't find native executable %s in %s" % (args[0], native_paths)
|
|
|
|
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 make sure wic-tools have %s-native in its DEPENDS, "\
|
|
"build it with 'bitbake wic-tools' 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
|
|
raise WicError(msg)
|
|
|
|
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, matcher=re.compile(r"^([a-zA-Z0-9\-_+./~]+)=(.*)")):
|
|
"""
|
|
Parse one line from bitbake -e output or from .env file.
|
|
Put result key-value pair into the storage.
|
|
"""
|
|
if "=" not in line:
|
|
return
|
|
match = matcher.match(line)
|
|
if not match:
|
|
return
|
|
key, val = match.groups()
|
|
self[image][key] = val.strip('"')
|
|
|
|
def get_var(self, var, image=None, cache=True):
|
|
"""
|
|
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 = logger.getEffectiveLevel()
|
|
logger.setLevel(logging.INFO)
|
|
ret, lines = _exec_cmd(cmd)
|
|
logger.setLevel(log_level)
|
|
|
|
if ret:
|
|
logger.error("Couldn't get '%s' output.", cmd)
|
|
logger.error("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
|
|
if cache:
|
|
images = [key for key in self if key]
|
|
if len(images) == 1:
|
|
self[None] = self[image]
|
|
|
|
result = self[image].get(var)
|
|
if not cache:
|
|
self.pop(image, None)
|
|
|
|
return result
|
|
|
|
# Create BB_VARS singleton
|
|
BB_VARS = BitbakeVars()
|
|
|
|
def get_bitbake_var(var, image=None, cache=True):
|
|
"""
|
|
Provide old get_bitbake_var API by wrapping
|
|
get_var method of BB_VARS singleton.
|
|
"""
|
|
return BB_VARS.get_var(var, image, cache)
|