Step1: build with busybox.
Signed-off-by: Chen Wang <wangchen20@iscas.ac.cn>
This commit is contained in:
167
support/scripts/apply-patches.sh
Executable file
167
support/scripts/apply-patches.sh
Executable file
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env bash
|
||||
# A little script I whipped up to make it easy to
|
||||
# patch source trees and have sane error handling
|
||||
# -Erik
|
||||
#
|
||||
# (c) 2002 Erik Andersen <andersen@codepoet.org>
|
||||
#
|
||||
# Parameters:
|
||||
# - "-s", optional. Silent operation, don't print anything if there
|
||||
# isn't any error.
|
||||
# - the build directory, optional, default value is '.'. The place where are
|
||||
# the package sources.
|
||||
# - the patch directory, optional, default '../kernel-patches'. The place
|
||||
# where are the scripts you want to apply.
|
||||
# - other parameters are the patch name patterns, optional, default value is
|
||||
# '*'. Pattern(s) describing the patch names you want to apply.
|
||||
#
|
||||
# The script will look recursively for patches from the patch directory. If a
|
||||
# file named 'series' exists then the patches mentioned in it will be applied
|
||||
# as plain patches, regardless of their file name. If no 'series' file exists,
|
||||
# the script will look for file names matching pattern(s). If the name
|
||||
# ends with '.tar.*', '.tbz2' or '.tgz', the file is considered as an archive
|
||||
# and will be uncompressed into a directory named
|
||||
# '.patches-name_of_the_archive-unpacked'. It's the turn of this directory to
|
||||
# be scanned with '*' as pattern. Remember that scanning is recursive. Other
|
||||
# files than series file and archives are considered as a patch.
|
||||
#
|
||||
# Once a patch is found, the script will try to apply it. If its name doesn't
|
||||
# end with '.gz', '.bz', '.bz2', '.xz', '.zip', '.Z', '.diff*' or '.patch*',
|
||||
# it will be skipped. If necessary, the patch will be uncompressed before being
|
||||
# applied. The list of the patches applied is stored in '.applied_patches_list'
|
||||
# file in the build directory.
|
||||
|
||||
set -e
|
||||
|
||||
silent=
|
||||
if [ "$1" = "-s" ] ; then
|
||||
# add option to be used by the patch tool
|
||||
silent=-s
|
||||
shift
|
||||
fi
|
||||
|
||||
# Set directories from arguments, or use defaults.
|
||||
builddir=${1-.}
|
||||
patchdir=${2-../kernel-patches}
|
||||
shift 2
|
||||
patchpattern=${@-*}
|
||||
|
||||
export TAR=${TAR:-tar}
|
||||
|
||||
# use a well defined sorting order
|
||||
export LC_COLLATE=C
|
||||
|
||||
if [ ! -d "${builddir}" ] ; then
|
||||
echo "Aborting. '${builddir}' is not a directory."
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d "${patchdir}" ] ; then
|
||||
echo "Aborting. '${patchdir}' is not a directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove any rejects present BEFORE patching - Because if there are
|
||||
# any, even if patches are well applied, at the end it will complain
|
||||
# about rejects in builddir.
|
||||
find ${builddir}/ '(' -name '*.rej' -o -name '.*.rej' ')' -print0 | \
|
||||
xargs -0 -r rm -f
|
||||
|
||||
function apply_patch {
|
||||
path="${1%%/}"
|
||||
patch="${2}"
|
||||
case "${path}" in
|
||||
/*) ;;
|
||||
*) path="$PWD/${path}";;
|
||||
esac
|
||||
if [ "$3" ]; then
|
||||
type="series"; uncomp="cat"
|
||||
else
|
||||
case "$patch" in
|
||||
*.gz)
|
||||
type="gzip"; uncomp="gunzip -dc"; ;;
|
||||
*.bz)
|
||||
type="bzip"; uncomp="bunzip -dc"; ;;
|
||||
*.bz2)
|
||||
type="bzip2"; uncomp="bunzip2 -dc"; ;;
|
||||
*.xz)
|
||||
type="xz"; uncomp="unxz -dc"; ;;
|
||||
*.zip)
|
||||
type="zip"; uncomp="unzip -d"; ;;
|
||||
*.Z)
|
||||
type="compress"; uncomp="uncompress -c"; ;;
|
||||
*.diff*)
|
||||
type="diff"; uncomp="cat"; ;;
|
||||
*.patch*)
|
||||
type="patch"; uncomp="cat"; ;;
|
||||
*)
|
||||
echo "Unsupported file type for ${path}/${patch}, skipping";
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ -z "$silent" ] ; then
|
||||
echo ""
|
||||
echo "Applying $patch using ${type}: "
|
||||
fi
|
||||
if [ ! -e "${path}/$patch" ] ; then
|
||||
echo "Error: missing patch file ${path}/$patch"
|
||||
exit 1
|
||||
fi
|
||||
existing="$(grep -E "/${patch}\$" ${builddir}/.applied_patches_list || true)"
|
||||
if [ -n "${existing}" ]; then
|
||||
echo "Error: duplicate filename '${patch}'"
|
||||
echo "Conflicting files are:"
|
||||
echo " already applied: ${existing}"
|
||||
echo " to be applied : ${path}/${patch}"
|
||||
exit 1
|
||||
fi
|
||||
echo "${path}/${patch}" >> ${builddir}/.applied_patches_list
|
||||
${uncomp} "${path}/$patch" | patch -F0 -g0 -p1 --no-backup-if-mismatch -d "${builddir}" -t -N $silent
|
||||
if [ $? != 0 ] ; then
|
||||
echo "Patch failed! Please fix ${patch}!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function scan_patchdir {
|
||||
local path=$1
|
||||
shift 1
|
||||
patches=${@-*}
|
||||
|
||||
# If there is a series file, use it instead of using ls sort order
|
||||
# to apply patches. Skip line starting with a dash.
|
||||
if [ -e "${path}/series" ] ; then
|
||||
# The format of a series file accepts a second field that is
|
||||
# used to specify the number of directory components to strip
|
||||
# when applying the patch, in the form -pN (N an integer >= 0)
|
||||
# We assume this field to always be -p1 whether it is present
|
||||
# or missing.
|
||||
series_patches="`grep -Ev "^#" ${path}/series | cut -d ' ' -f1 2> /dev/null`"
|
||||
for i in $series_patches; do
|
||||
apply_patch "$path" "$i" series
|
||||
done
|
||||
else
|
||||
for i in `cd $path; ls -d $patches 2> /dev/null` ; do
|
||||
if [ -d "${path}/$i" ] ; then
|
||||
scan_patchdir "${path}/$i"
|
||||
elif echo "$i" | grep -q -E "\.tar(\..*)?$|\.tbz2?$|\.tgz$" ; then
|
||||
unpackedarchivedir="$builddir/.patches-$(basename $i)-unpacked"
|
||||
rm -rf "$unpackedarchivedir" 2> /dev/null
|
||||
mkdir "$unpackedarchivedir"
|
||||
${TAR} -C "$unpackedarchivedir" -xaf "${path}/$i"
|
||||
scan_patchdir "$unpackedarchivedir"
|
||||
else
|
||||
apply_patch "$path" "$i"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
touch ${builddir}/.applied_patches_list
|
||||
scan_patchdir "$patchdir" "$patchpattern"
|
||||
|
||||
# Check for rejects...
|
||||
if [ "`find $builddir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ] ; then
|
||||
echo "Aborting. Reject files found."
|
||||
exit 1
|
||||
fi
|
||||
96
support/scripts/check-bin-arch
Executable file
96
support/scripts/check-bin-arch
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# List of hardcoded paths that should be ignored, as they may
|
||||
# contain binaries for an architecture different from the
|
||||
# architecture of the target.
|
||||
declare -a IGNORES=(
|
||||
# Skip firmware files, they could be ELF files for other
|
||||
# architectures
|
||||
"/lib/firmware"
|
||||
"/usr/lib/firmware"
|
||||
|
||||
# Skip kernel modules
|
||||
# When building a 32-bit userland on 64-bit architectures, the kernel
|
||||
# and its modules may still be 64-bit. To keep the basic
|
||||
# check-bin-arch logic simple, just skip this directory.
|
||||
"/lib/modules"
|
||||
"/usr/lib/modules"
|
||||
|
||||
# Skip files in /usr/share, several packages (qemu,
|
||||
# pru-software-support) legitimately install ELF binaries that
|
||||
# are not for the target architecture
|
||||
"/usr/share"
|
||||
|
||||
# Skip files in {/usr,}/lib/grub, since it is possible to have
|
||||
# it for a different architecture (e.g. i386 grub on x86_64).
|
||||
"/lib/grub"
|
||||
"/usr/lib/grub"
|
||||
|
||||
# Guile modules are ELF files, with a "None" machine
|
||||
"/usr/lib/guile"
|
||||
)
|
||||
|
||||
while getopts p:l:r:a:i: OPT ; do
|
||||
case "${OPT}" in
|
||||
p) package="${OPTARG}";;
|
||||
l) pkg_list="${OPTARG}";;
|
||||
r) readelf="${OPTARG}";;
|
||||
a) arch_name="${OPTARG}";;
|
||||
i)
|
||||
# Ensure we do have single '/' as separators,
|
||||
# and that we have a leading and a trailing one.
|
||||
pattern="$(sed -r -e 's:/+:/:g; s:^/*:/:; s:/*$:/:;' <<<"${OPTARG}")"
|
||||
IGNORES+=("${pattern}")
|
||||
;;
|
||||
:) error "option '%s' expects a mandatory argument\n" "${OPTARG}";;
|
||||
\?) error "unknown option '%s'\n" "${OPTARG}";;
|
||||
esac
|
||||
done
|
||||
|
||||
if test -z "${package}" -o -z "${pkg_list}" -o -z "${readelf}" -o -z "${arch_name}" ; then
|
||||
echo "Usage: $0 -p <pkg> -l <pkg-file-list> -r <readelf> -a <arch name> [-i PATH ...]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exitcode=0
|
||||
|
||||
# Only split on new lines, for filenames-with-spaces
|
||||
IFS="
|
||||
"
|
||||
|
||||
while read f; do
|
||||
for ignore in "${IGNORES[@]}"; do
|
||||
if [[ "${f}" =~ ^"${ignore}" ]]; then
|
||||
continue 2
|
||||
fi
|
||||
done
|
||||
|
||||
# Skip symlinks. Some symlinks may have absolute paths as
|
||||
# target, pointing to host binaries while we're building.
|
||||
if [[ -L "${TARGET_DIR}/${f}" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Get architecture using readelf. We pipe through 'head -1' so
|
||||
# that when the file is a static library (.a), we only take
|
||||
# into account the architecture of the first object file.
|
||||
arch=$(LC_ALL=C ${readelf} -h "${TARGET_DIR}/${f}" 2>&1 | \
|
||||
sed -r -e '/^ Machine: +(.+)/!d; s//\1/;' | head -1)
|
||||
|
||||
# If no architecture found, assume it was not an ELF file
|
||||
if test "${arch}" = "" ; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Architecture is correct
|
||||
if test "${arch}" = "${arch_name}" ; then
|
||||
continue
|
||||
fi
|
||||
|
||||
printf 'ERROR: architecture for "%s" is "%s", should be "%s"\n' \
|
||||
"${f}" "${arch}" "${arch_name}"
|
||||
|
||||
exitcode=1
|
||||
done < <( sed -r -e "/^${package},\.(.+)$/!d; s//\1/;" ${pkg_list} )
|
||||
|
||||
exit ${exitcode}
|
||||
111
support/scripts/check-host-rpath
Executable file
111
support/scripts/check-host-rpath
Executable file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script scans $(HOST_DIR)/{bin,sbin} for all ELF files, and checks
|
||||
# they have an RPATH to $(HOST_DIR)/lib if they need libraries from
|
||||
# there.
|
||||
|
||||
# Override the user's locale so we are sure we can parse the output of
|
||||
# readelf(1) and file(1)
|
||||
export LC_ALL=C
|
||||
|
||||
main() {
|
||||
local pkg="${1}"
|
||||
local hostdir="${2}"
|
||||
local perpackagedir="${3}"
|
||||
local file ret
|
||||
|
||||
# Remove duplicate and trailing '/' for proper match
|
||||
hostdir="$( sed -r -e 's:/+:/:g; s:/$::;' <<<"${hostdir}" )"
|
||||
|
||||
ret=0
|
||||
while read file; do
|
||||
is_elf "${file}" || continue
|
||||
elf_needs_rpath "${file}" "${hostdir}" || continue
|
||||
check_elf_has_rpath "${file}" "${hostdir}" "${perpackagedir}" && continue
|
||||
if [ ${ret} -eq 0 ]; then
|
||||
ret=1
|
||||
printf "***\n"
|
||||
printf "*** ERROR: package %s installs executables without proper RPATH:\n" "${pkg}"
|
||||
fi
|
||||
printf "*** %s\n" "${file}"
|
||||
done < <( find "${hostdir}"/{bin,sbin} -type f 2>/dev/null )
|
||||
|
||||
return ${ret}
|
||||
}
|
||||
|
||||
is_elf() {
|
||||
local f="${1}"
|
||||
|
||||
readelf -l "${f}" 2>/dev/null \
|
||||
|grep -E 'Requesting program interpreter:' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# This function tells whether a given ELF executable (first argument)
|
||||
# needs a RPATH pointing to the host library directory or not. It
|
||||
# needs such an RPATH if at least of the libraries used by the ELF
|
||||
# executable is available in the host library directory. This function
|
||||
# returns 0 when a RPATH is needed, 1 otherwise.
|
||||
#
|
||||
# With per-package directory support, ${hostdir} will point to the
|
||||
# current package per-package host directory, and this is where this
|
||||
# function will check if the libraries needed by the executable are
|
||||
# located (or not). In practice, the ELF executable RPATH may point to
|
||||
# another package per-package host directory, but that is fine because
|
||||
# if such an executable is within the current package per-package host
|
||||
# directory, its libraries will also have been copied into the current
|
||||
# package per-package host directory.
|
||||
elf_needs_rpath() {
|
||||
local file="${1}"
|
||||
local hostdir="${2}"
|
||||
local lib
|
||||
|
||||
while read lib; do
|
||||
[ -e "${hostdir}/lib/${lib}" ] && return 0
|
||||
done < <( readelf -d "${file}" 2>/dev/null \
|
||||
|sed -r -e '/^.* \(NEEDED\) .*Shared library: \[(.+)\]$/!d;' \
|
||||
-e 's//\1/;' \
|
||||
)
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# This function checks whether at least one of the RPATH of the given
|
||||
# ELF executable (first argument) properly points to the host library
|
||||
# directory (second argument), either through an absolute RPATH or a
|
||||
# relative RPATH. In the context of per-package directory support,
|
||||
# ${hostdir} (second argument) points to the current package host
|
||||
# directory. However, it is perfectly valid for an ELF binary to have
|
||||
# a RPATH pointing to another package per-package host directory,
|
||||
# which is why such RPATH is also accepted (the per-package directory
|
||||
# gets passed as third argument). Having a RPATH pointing to the host
|
||||
# directory will make sure the ELF executable will find at runtime the
|
||||
# shared libraries it depends on. This function returns 0 when a
|
||||
# proper RPATH was found, or 1 otherwise.
|
||||
check_elf_has_rpath() {
|
||||
local file="${1}"
|
||||
local hostdir="${2}"
|
||||
local perpackagedir="${3}"
|
||||
local rpath dir
|
||||
|
||||
while read rpath; do
|
||||
for dir in ${rpath//:/ }; do
|
||||
# Remove duplicate and trailing '/' for proper match
|
||||
dir="$( sed -r -e 's:/+:/:g; s:/$::;' <<<"${dir}" )"
|
||||
[ "${dir}" = "${hostdir}/lib" ] && return 0
|
||||
[ "${dir}" = "\$ORIGIN/../lib" ] && return 0
|
||||
# This check is done even for builds where
|
||||
# BR2_PER_PACKAGE_DIRECTORIES is disabled. In this case,
|
||||
# PER_PACKAGE_DIR and therefore ${perpackagedir} points to
|
||||
# a non-existent directory, and this check will always be
|
||||
# false.
|
||||
[[ ${dir} =~ "${perpackagedir}/"[^/]+/host/lib ]] && return 0
|
||||
done
|
||||
done < <( readelf -d "${file}" 2>/dev/null \
|
||||
|sed -r -e '/.* \(R(UN)?PATH\) +Library r(un)?path: \[(.+)\]$/!d' \
|
||||
-e 's//\3/;' \
|
||||
)
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
main "${@}"
|
||||
69
support/scripts/check-kernel-headers.sh
Executable file
69
support/scripts/check-kernel-headers.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script (and the embedded C code) will check that the actual
|
||||
# headers version match the user told us they were:
|
||||
#
|
||||
# - if both versions are the same, all is well.
|
||||
#
|
||||
# - if the actual headers are older than the user told us, this is
|
||||
# an error.
|
||||
#
|
||||
# - if the actual headers are more recent than the user told us, and
|
||||
# we are doing a strict check, then this is an error.
|
||||
#
|
||||
# - if the actual headers are more recent than the user told us, and
|
||||
# we are doing a loose check, then a warning is printed, but this is
|
||||
# not an error.
|
||||
|
||||
BUILDDIR="${1}"
|
||||
SYSROOT="${2}"
|
||||
# Make sure we have enough version components
|
||||
HDR_VER="${3}.0.0"
|
||||
CHECK="${4}" # 'strict' or 'loose'
|
||||
|
||||
HDR_M="${HDR_VER%%.*}"
|
||||
HDR_V="${HDR_VER#*.}"
|
||||
HDR_m="${HDR_V%%.*}"
|
||||
|
||||
# Exit on any error, so we don't try to run an unexisting program if the
|
||||
# compilation fails.
|
||||
set -e
|
||||
|
||||
# Set the clean-up trap in advance to prevent a race condition in which we
|
||||
# create the file but get a SIGTERM before setting it. Notice that we don't
|
||||
# need to care about EXEC being empty, since 'rm -f ""' does nothing.
|
||||
trap 'rm -f "${EXEC}"' EXIT
|
||||
|
||||
EXEC="$(mktemp -p "${BUILDDIR}" -t .check-headers.XXXXXX)"
|
||||
|
||||
# We do not want to account for the patch-level, since headers are
|
||||
# not supposed to change for different patchlevels, so we mask it out.
|
||||
# This only applies to kernels >= 3.0, but those are the only one
|
||||
# we actually care about; we treat all 2.6.x kernels equally.
|
||||
${HOSTCC} -imacros "${SYSROOT}/usr/include/linux/version.h" \
|
||||
-x c -o "${EXEC}" - <<_EOF_
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc __attribute__((unused)),
|
||||
char** argv __attribute__((unused)))
|
||||
{
|
||||
int l = LINUX_VERSION_CODE & ~0xFF;
|
||||
int h = KERNEL_VERSION(${HDR_M},${HDR_m},0);
|
||||
|
||||
if ((l >= h) && !strcmp("${CHECK}", "loose"))
|
||||
return 0;
|
||||
|
||||
if (l != h) {
|
||||
printf("Incorrect selection of kernel headers: ");
|
||||
printf("expected %d.%d.x, got %d.%d.x\n", ${HDR_M}, ${HDR_m},
|
||||
((LINUX_VERSION_CODE>>16) & 0xFF),
|
||||
((LINUX_VERSION_CODE>>8) & 0xFF));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
_EOF_
|
||||
|
||||
"${EXEC}"
|
||||
193
support/scripts/fix-rpath
Executable file
193
support/scripts/fix-rpath
Executable file
@@ -0,0 +1,193 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (C) 2016 Samuel Martin <s.martin49@gmail.com>
|
||||
# Copyright (C) 2017 Wolfgang Grandegger <wg@grandegger.com>
|
||||
#
|
||||
# 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; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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
|
||||
|
||||
usage() {
|
||||
cat <<EOF >&2
|
||||
Usage: ${0} TREE_KIND
|
||||
|
||||
Description:
|
||||
|
||||
This script scans a tree and sanitize ELF files' RPATH found in there.
|
||||
|
||||
Sanitization behaves the same whatever the kind of the processed tree,
|
||||
but the resulting RPATH differs. The rpath sanitization is done using
|
||||
"patchelf --make-rpath-relative".
|
||||
|
||||
Arguments:
|
||||
|
||||
TREE_KIND Kind of tree to be processed.
|
||||
Allowed values: host, target, staging
|
||||
|
||||
Environment:
|
||||
|
||||
PATCHELF patchelf program to use
|
||||
(default: HOST_DIR/bin/patchelf)
|
||||
|
||||
HOST_DIR host directory
|
||||
STAGING_DIR staging directory
|
||||
TARGET_DIR target directory
|
||||
|
||||
TOOLCHAIN_EXTERNAL_DOWNLOAD_INSTALL_DIR
|
||||
(default HOST_DIR/opt/ext-toolchain)
|
||||
|
||||
PARALLEL_JOBS number of parallel jobs to run
|
||||
|
||||
Returns: 0 if success or 1 in case of error
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
: "${PATCHELF:=${HOST_DIR}/bin/patchelf}"
|
||||
|
||||
# ELF files should not be in these sub-directories
|
||||
HOST_EXCLUDEPATHS="/share/terminfo"
|
||||
STAGING_EXCLUDEPATHS="/usr/include /usr/share/terminfo"
|
||||
TARGET_EXCLUDEPATHS="/lib/firmware"
|
||||
|
||||
declare -a sanitize_extra_args
|
||||
rootdir=
|
||||
|
||||
patch_file() {
|
||||
local file="${1}"
|
||||
|
||||
# check if it's an ELF file
|
||||
rpath="$("${PATCHELF}" --print-rpath "${file}" 2>&1)"
|
||||
if test $? -ne 0 ; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# make files writable if necessary
|
||||
changed="$(chmod -c u+w "${file}")"
|
||||
|
||||
# With per-package directory support, most RPATH of host
|
||||
# binaries will point to per-package directories. This won't
|
||||
# work with the --make-rpath-relative ${rootdir} invocation as
|
||||
# the per-package host directory is not within ${rootdir}. So,
|
||||
# we rewrite all RPATHs pointing to per-package directories so
|
||||
# that they point to the global host directory.
|
||||
# shellcheck disable=SC2001 # ${var//search/replace} hard when search or replace have / in them
|
||||
changed_rpath="$(echo "${rpath}" | sed "s@${PER_PACKAGE_DIR}/[^/]\+/host@${HOST_DIR}@g")"
|
||||
if test "${rpath}" != "${changed_rpath}" ; then
|
||||
"${PATCHELF}" --set-rpath "${changed_rpath}" "${file}"
|
||||
fi
|
||||
|
||||
# call patchelf to sanitize the rpath
|
||||
"${PATCHELF}" --make-rpath-relative "${rootdir}" "${sanitize_extra_args[@]}" "${file}"
|
||||
# restore the original permission
|
||||
test "${changed}" != "" && chmod u-w "${file}"
|
||||
}
|
||||
|
||||
patch_files() {
|
||||
while read -r -d $'\0' file; do
|
||||
# for performance reasons, we want to do as little work as
|
||||
# possible on non-ELF files. therefore, make sure that the
|
||||
# file at least starts with the ELF magic before handing it of
|
||||
# to patchelf, which will then perform the proper validation.
|
||||
read -r -n4 magic <"${file}" && test "${magic}" != $'\x7fELF' && continue
|
||||
|
||||
patch_file "${file}"
|
||||
done
|
||||
}
|
||||
|
||||
main() {
|
||||
local tree
|
||||
local -a find_args
|
||||
|
||||
tree="${1}"
|
||||
|
||||
if ! "${PATCHELF}" --version > /dev/null 2>&1; then
|
||||
echo "Error: can't execute patchelf utility '${PATCHELF}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "${tree}" in
|
||||
host)
|
||||
rootdir="${HOST_DIR}"
|
||||
|
||||
# do not process the sysroot (only contains target binaries)
|
||||
find_args+=( "-path" "${STAGING_DIR}" "-prune" "-o" )
|
||||
|
||||
# do not process the external toolchain installation directory to
|
||||
# avoid breaking it.
|
||||
test "${TOOLCHAIN_EXTERNAL_DOWNLOAD_INSTALL_DIR}" != "" && \
|
||||
find_args+=( "-path" "${TOOLCHAIN_EXTERNAL_DOWNLOAD_INSTALL_DIR}" "-prune" "-o" )
|
||||
|
||||
for excludepath in ${HOST_EXCLUDEPATHS}; do
|
||||
find_args+=( "-path" "${HOST_DIR}""${excludepath}" "-prune" "-o" )
|
||||
done
|
||||
|
||||
# do not process the patchelf binary but a copy to work-around "file in use"
|
||||
find_args+=( "-path" "${PATCHELF}" "-prune" "-o" )
|
||||
cp "${PATCHELF}" "${PATCHELF}.__to_be_patched"
|
||||
|
||||
# we always want $ORIGIN-based rpaths to make it relocatable.
|
||||
sanitize_extra_args+=( "--relative-to-file" )
|
||||
;;
|
||||
|
||||
staging)
|
||||
rootdir="${STAGING_DIR}"
|
||||
|
||||
# ELF files should not be in these sub-directories
|
||||
for excludepath in ${STAGING_EXCLUDEPATHS}; do
|
||||
find_args+=( "-path" "${STAGING_DIR}""${excludepath}" "-prune" "-o" )
|
||||
done
|
||||
|
||||
# should be like for the target tree below
|
||||
sanitize_extra_args+=( "--no-standard-lib-dirs" )
|
||||
;;
|
||||
|
||||
target)
|
||||
rootdir="${TARGET_DIR}"
|
||||
|
||||
for excludepath in ${TARGET_EXCLUDEPATHS}; do
|
||||
find_args+=( "-path" "${TARGET_DIR}""${excludepath}" "-prune" "-o" )
|
||||
done
|
||||
|
||||
# we don't want $ORIGIN-based rpaths but absolute paths without rootdir.
|
||||
# we also want to remove rpaths pointing to /lib or /usr/lib.
|
||||
sanitize_extra_args+=( "--no-standard-lib-dirs" )
|
||||
;;
|
||||
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
work=$(mktemp --tmpdir -d fix-rpath.XXXXXXXX)
|
||||
|
||||
find_args+=( "-type" "f" "-print0" )
|
||||
find "${rootdir}" "${find_args[@]}" \
|
||||
| split -t '\0' -a4 -d -n "r/${PARALLEL_JOBS:-1}" "-" "${work}/part"
|
||||
|
||||
for part in "${work}/part"*; do
|
||||
patch_files <"${part}" &
|
||||
done
|
||||
wait
|
||||
|
||||
rm -rf "${work}"
|
||||
|
||||
# Restore patched patchelf utility
|
||||
test "${tree}" = "host" && mv "${PATCHELF}.__to_be_patched" "${PATCHELF}"
|
||||
|
||||
# ignore errors
|
||||
return 0
|
||||
}
|
||||
|
||||
main "${@}"
|
||||
486
support/scripts/mkusers
Executable file
486
support/scripts/mkusers
Executable file
@@ -0,0 +1,486 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
myname="${0##*/}"
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Configurable items
|
||||
FIRST_USER_UID=1000
|
||||
LAST_USER_UID=1999
|
||||
FIRST_USER_GID=1000
|
||||
LAST_USER_GID=1999
|
||||
# use names from /etc/adduser.conf
|
||||
FIRST_SYSTEM_UID=100
|
||||
LAST_SYSTEM_UID=999
|
||||
FIRST_SYSTEM_GID=100
|
||||
LAST_SYSTEM_GID=999
|
||||
# argument to automatically crease system/user id
|
||||
AUTO_SYSTEM_ID=-1
|
||||
AUTO_USER_ID=-2
|
||||
|
||||
# No more is configurable below this point
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
error() {
|
||||
local fmt="${1}"
|
||||
shift
|
||||
|
||||
printf "%s: " "${myname}" >&2
|
||||
# shellcheck disable=SC2059 # fmt is the format passed to error()
|
||||
printf "${fmt}" "${@}" >&2
|
||||
}
|
||||
fail() {
|
||||
error "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
if [ ${#} -ne 2 ]; then
|
||||
fail "usage: %s USERS_TABLE TARGET_DIR\n"
|
||||
fi
|
||||
USERS_TABLE="${1}"
|
||||
TARGET_DIR="${2}"
|
||||
shift 2
|
||||
PASSWD="${TARGET_DIR}/etc/passwd"
|
||||
SHADOW="${TARGET_DIR}/etc/shadow"
|
||||
GROUP="${TARGET_DIR}/etc/group"
|
||||
# /etc/gshadow is not part of the standard skeleton, so not everybody
|
||||
# will have it, but some may have it, and its content must be in sync
|
||||
# with /etc/group, so any use of gshadow must be conditional.
|
||||
GSHADOW="${TARGET_DIR}/etc/gshadow"
|
||||
|
||||
# We can't simply source ${BR2_CONFIG} as it may contains constructs
|
||||
# such as:
|
||||
# BR2_DEFCONFIG="$(CONFIG_DIR)/defconfig"
|
||||
# which when sourced from a shell script will eventually try to execute
|
||||
# a command named 'CONFIG_DIR', which is plain wrong for virtually every
|
||||
# systems out there.
|
||||
# So, we have to scan that file instead. Sigh... :-(
|
||||
PASSWD_METHOD="sha-256"
|
||||
# PASSWD_METHOD="$( sed -r -e '/^BR2_TARGET_GENERIC_PASSWD_METHOD="(.*)"$/!d;' \
|
||||
# -e 's//\1/;' \
|
||||
# "${BR2_CONFIG}" \
|
||||
# )"
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
get_uid() {
|
||||
local username="${1}"
|
||||
|
||||
awk -F: -v username="${username}" \
|
||||
'$1 == username { printf( "%d\n", $3 ); }' "${PASSWD}"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
get_ugid() {
|
||||
local username="${1}"
|
||||
|
||||
awk -F: -v username="${username}" \
|
||||
'$1 == username { printf( "%d\n", $4 ); }' "${PASSWD}"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
get_gid() {
|
||||
local group="${1}"
|
||||
|
||||
awk -F: -v group="${group}" \
|
||||
'$1 == group { printf( "%d\n", $3 ); }' "${GROUP}"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
get_members() {
|
||||
local group="${1}"
|
||||
|
||||
awk -F: -v group="${group}" \
|
||||
'$1 == group { printf( "%s\n", $4 ); }' "${GROUP}"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
get_username() {
|
||||
local uid="${1}"
|
||||
|
||||
awk -F: -v uid="${uid}" \
|
||||
'$3 == uid { printf( "%s\n", $1 ); }' "${PASSWD}"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
get_group() {
|
||||
local gid="${1}"
|
||||
|
||||
awk -F: -v gid="${gid}" \
|
||||
'$3 == gid { printf( "%s\n", $1 ); }' "${GROUP}"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
get_ugroup() {
|
||||
local username="${1}"
|
||||
local ugid
|
||||
|
||||
ugid="$( get_ugid "${username}" )"
|
||||
if [ -n "${ugid}" ]; then
|
||||
get_group "${ugid}"
|
||||
fi
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Sanity-check the new user/group:
|
||||
# - check the gid is not already used for another group
|
||||
# - check the group does not already exist with another gid
|
||||
# - check the user does not already exist with another gid
|
||||
# - check the uid is not already used for another user
|
||||
# - check the user does not already exist with another uid
|
||||
# - check the user does not already exist in another group
|
||||
check_user_validity() {
|
||||
local username="${1}"
|
||||
local uid="${2}"
|
||||
local group="${3}"
|
||||
local gid="${4}"
|
||||
local _uid _ugid _gid _username _group _ugroup
|
||||
|
||||
_group="$( get_group "${gid}" )"
|
||||
_gid="$( get_gid "${group}" )"
|
||||
_ugid="$( get_ugid "${username}" )"
|
||||
_username="$( get_username "${uid}" )"
|
||||
_uid="$( get_uid "${username}" )"
|
||||
_ugroup="$( get_ugroup "${username}" )"
|
||||
|
||||
if [ "${username}" = "root" ]; then
|
||||
fail "invalid username '%s\n'" "${username}"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086 # gid is a non-empty int
|
||||
# shellcheck disable=SC2166 # [ .. -o .. ] works well in this case
|
||||
if [ ${gid} -lt -2 -o ${gid} -eq 0 ]; then
|
||||
fail "invalid gid '%d' for '%s'\n" ${gid} "${username}"
|
||||
elif [ ${gid} -ge 0 ]; then
|
||||
# check the gid is not already used for another group
|
||||
if [ -n "${_group}" -a "${_group}" != "${group}" ]; then
|
||||
fail "gid '%d' for '%s' is already used by group '%s'\n" \
|
||||
${gid} "${username}" "${_group}"
|
||||
fi
|
||||
|
||||
# check the group does not already exists with another gid
|
||||
# Need to split the check in two, otherwise '[' complains it
|
||||
# is missing arguments when _gid is empty
|
||||
if [ -n "${_gid}" ] && [ ${_gid} -ne ${gid} ]; then
|
||||
fail "group '%s' for '%s' already exists with gid '%d' (wants '%d')\n" \
|
||||
"${group}" "${username}" ${_gid} ${gid}
|
||||
fi
|
||||
|
||||
# check the user does not already exists with another gid
|
||||
# Need to split the check in two, otherwise '[' complains it
|
||||
# is missing arguments when _ugid is empty
|
||||
if [ -n "${_ugid}" ] && [ ${_ugid} -ne ${gid} ]; then
|
||||
fail "user '%s' already exists with gid '%d' (wants '%d')\n" \
|
||||
"${username}" ${_ugid} ${gid}
|
||||
fi
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086 # uid is a non-empty int
|
||||
# shellcheck disable=SC2166 # [ .. -o .. ] works well in this case
|
||||
if [ ${uid} -lt -2 -o ${uid} -eq 0 ]; then
|
||||
fail "invalid uid '%d' for '%s'\n" ${uid} "${username}"
|
||||
elif [ ${uid} -ge 0 ]; then
|
||||
# check the uid is not already used for another user
|
||||
if [ -n "${_username}" -a "${_username}" != "${username}" ]; then
|
||||
fail "uid '%d' for '%s' already used by user '%s'\n" \
|
||||
${uid} "${username}" "${_username}"
|
||||
fi
|
||||
|
||||
# check the user does not already exists with another uid
|
||||
# Need to split the check in two, otherwise '[' complains it
|
||||
# is missing arguments when _uid is empty
|
||||
if [ -n "${_uid}" ] && [ ${_uid} -ne ${uid} ]; then
|
||||
fail "user '%s' already exists with uid '%d' (wants '%d')\n" \
|
||||
"${username}" ${_uid} ${uid}
|
||||
fi
|
||||
fi
|
||||
|
||||
# check the user does not already exist in another group
|
||||
# shellcheck disable=SC2166 # [ .. -a .. ] works well in this case
|
||||
if [ -n "${_ugroup}" -a "${_ugroup}" != "${group}" ]; then
|
||||
fail "user '%s' already exists with group '%s' (wants '%s')\n" \
|
||||
"${username}" "${_ugroup}" "${group}"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Generate a unique GID for given group. If the group already exists,
|
||||
# then simply report its current GID. Otherwise, generate the lowest GID
|
||||
# that is:
|
||||
# - not 0
|
||||
# - comprised in [$2..$3]
|
||||
# - not already used by a group
|
||||
generate_gid() {
|
||||
local group="${1}"
|
||||
local mingid="${2}"
|
||||
local maxgid="${3}"
|
||||
local gid
|
||||
|
||||
gid="$( get_gid "${group}" )"
|
||||
if [ -z "${gid}" ]; then
|
||||
for(( gid=mingid; gid<=maxgid; gid++ )); do
|
||||
if [ -z "$( get_group "${gid}" )" ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
# shellcheck disable=SC2086 # gid and maxgid are non-empty ints
|
||||
if [ ${gid} -gt ${maxgid} ]; then
|
||||
fail "can not allocate a GID for group '%s'\n" "${group}"
|
||||
fi
|
||||
fi
|
||||
printf "%d\n" "${gid}"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Add a group; if it does already exist, remove it first
|
||||
add_one_group() {
|
||||
local group="${1}"
|
||||
local gid="${2}"
|
||||
local members
|
||||
|
||||
# Generate a new GID if needed
|
||||
# shellcheck disable=SC2086 # gid is a non-empty int
|
||||
if [ ${gid} -eq ${AUTO_USER_ID} ]; then
|
||||
gid="$( generate_gid "${group}" $FIRST_USER_GID $LAST_USER_GID )"
|
||||
elif [ ${gid} -eq ${AUTO_SYSTEM_ID} ]; then
|
||||
gid="$( generate_gid "${group}" $FIRST_SYSTEM_GID $LAST_SYSTEM_GID )"
|
||||
fi
|
||||
|
||||
members=$(get_members "$group")
|
||||
# Remove any previous instance of this group, and re-add the new one
|
||||
sed -i --follow-symlinks -e '/^'"${group}"':.*/d;' "${GROUP}"
|
||||
printf "%s:x:%d:%s\n" "${group}" "${gid}" "${members}" >>"${GROUP}"
|
||||
|
||||
# Ditto for /etc/gshadow if it exists
|
||||
if [ -f "${GSHADOW}" ]; then
|
||||
sed -i --follow-symlinks -e '/^'"${group}"':.*/d;' "${GSHADOW}"
|
||||
printf "%s:*::\n" "${group}" >>"${GSHADOW}"
|
||||
fi
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Generate a unique UID for given username. If the username already exists,
|
||||
# then simply report its current UID. Otherwise, generate the lowest UID
|
||||
# that is:
|
||||
# - not 0
|
||||
# - comprised in [$2..$3]
|
||||
# - not already used by a user
|
||||
generate_uid() {
|
||||
local username="${1}"
|
||||
local minuid="${2}"
|
||||
local maxuid="${3}"
|
||||
|
||||
local uid
|
||||
|
||||
uid="$( get_uid "${username}" )"
|
||||
if [ -z "${uid}" ]; then
|
||||
for(( uid=minuid; uid<=maxuid; uid++ )); do
|
||||
if [ -z "$( get_username "${uid}" )" ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
# shellcheck disable=SC2086 # uid is a non-empty int
|
||||
if [ ${uid} -gt ${maxuid} ]; then
|
||||
fail "can not allocate a UID for user '%s'\n" "${username}"
|
||||
fi
|
||||
fi
|
||||
printf "%d\n" "${uid}"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Add given user to given group, if not already the case
|
||||
add_user_to_group() {
|
||||
local username="${1}"
|
||||
local group="${2}"
|
||||
local _f
|
||||
|
||||
for _f in "${GROUP}" "${GSHADOW}"; do
|
||||
[ -f "${_f}" ] || continue
|
||||
sed -r -i --follow-symlinks \
|
||||
-e 's/^('"${group}"':.*:)(([^:]+,)?)'"${username}"'(,[^:]+*)?$/\1\2\4/;' \
|
||||
-e 's/^('"${group}"':.*)$/\1,'"${username}"'/;' \
|
||||
-e 's/,+/,/' \
|
||||
-e 's/:,/:/' \
|
||||
"${_f}"
|
||||
done
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Encode a password
|
||||
encode_password() {
|
||||
local passwd="${1}"
|
||||
|
||||
mkpasswd -m "${PASSWD_METHOD}" "${passwd}"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Add a user; if it does already exist, remove it first
|
||||
add_one_user() {
|
||||
local username="${1}"
|
||||
local uid="${2}"
|
||||
local group="${3}"
|
||||
local gid="${4}"
|
||||
local passwd="${5}"
|
||||
local home="${6}"
|
||||
local shell="${7}"
|
||||
local groups="${8}"
|
||||
local comment="${9}"
|
||||
local _f _group _home _shell _gid _passwd
|
||||
|
||||
# First, sanity-check the user
|
||||
check_user_validity "${username}" "${uid}" "${group}" "${gid}"
|
||||
|
||||
# Generate a new UID if needed
|
||||
# shellcheck disable=SC2086 # uid is a non-empty int
|
||||
if [ ${uid} -eq ${AUTO_USER_ID} ]; then
|
||||
uid="$( generate_uid "${username}" $FIRST_USER_UID $LAST_USER_UID )"
|
||||
elif [ ${uid} -eq ${AUTO_SYSTEM_ID} ]; then
|
||||
uid="$( generate_uid "${username}" $FIRST_SYSTEM_UID $LAST_SYSTEM_UID )"
|
||||
fi
|
||||
|
||||
# Remove any previous instance of this user
|
||||
for _f in "${PASSWD}" "${SHADOW}"; do
|
||||
sed -r -i --follow-symlinks -e '/^'"${username}"':.*/d;' "${_f}"
|
||||
done
|
||||
|
||||
_gid="$( get_gid "${group}" )"
|
||||
_shell="${shell}"
|
||||
if [ "${shell}" = "-" ]; then
|
||||
_shell="/bin/false"
|
||||
fi
|
||||
case "${home}" in
|
||||
-) _home="/";;
|
||||
/) fail "home can not explicitly be '/'\n";;
|
||||
/*) _home="${home}";;
|
||||
*) fail "home must be an absolute path\n";;
|
||||
esac
|
||||
case "${passwd}" in
|
||||
-)
|
||||
_passwd=""
|
||||
;;
|
||||
!=*)
|
||||
_passwd='!'"$( encode_password "${passwd#!=}" )"
|
||||
;;
|
||||
=*)
|
||||
_passwd="$( encode_password "${passwd#=}" )"
|
||||
;;
|
||||
*)
|
||||
_passwd="${passwd}"
|
||||
;;
|
||||
esac
|
||||
|
||||
printf "%s:x:%d:%d:%s:%s:%s\n" \
|
||||
"${username}" "${uid}" "${_gid}" \
|
||||
"${comment}" "${_home}" "${_shell}" \
|
||||
>>"${PASSWD}"
|
||||
printf "%s:%s:::::::\n" \
|
||||
"${username}" "${_passwd}" \
|
||||
>>"${SHADOW}"
|
||||
|
||||
# Add the user to its additional groups
|
||||
if [ "${groups}" != "-" ]; then
|
||||
for _group in ${groups//,/ }; do
|
||||
add_user_to_group "${username}" "${_group}"
|
||||
done
|
||||
fi
|
||||
|
||||
# If the user has a home, chown it
|
||||
# (Note: stdout goes to the fakeroot-script)
|
||||
if [ "${home}" != "-" ]; then
|
||||
mkdir -p "${TARGET_DIR}/${home}"
|
||||
printf "chown -h -R %d:%d '%s'\n" "${uid}" "${_gid}" "${TARGET_DIR}/${home}"
|
||||
fi
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
main() {
|
||||
local username uid group gid passwd home shell groups comment
|
||||
local line
|
||||
local auto_id
|
||||
local -a ENTRIES
|
||||
|
||||
# Some sanity checks
|
||||
if [ ${FIRST_USER_UID} -le 0 ]; then
|
||||
fail "FIRST_USER_UID must be >0 (currently %d)\n" ${FIRST_USER_UID}
|
||||
fi
|
||||
if [ ${FIRST_USER_GID} -le 0 ]; then
|
||||
fail "FIRST_USER_GID must be >0 (currently %d)\n" ${FIRST_USER_GID}
|
||||
fi
|
||||
|
||||
# Read in all the file in memory, exclude empty lines and comments
|
||||
# mapfile reads all lines, even the last one if it is missing a \n
|
||||
mapfile -t ENTRIES < <( sed -r -e 's/#.*//; /^[[:space:]]*$/d;' "${USERS_TABLE}" )
|
||||
|
||||
# We first create groups whose gid is positive, and then we create groups
|
||||
# whose gid is automatic, so that, if a group is defined both with
|
||||
# a specified gid and an automatic gid, we ensure the specified gid is
|
||||
# used, rather than a different automatic gid is computed.
|
||||
|
||||
# First, create all the main groups which gid is *not* automatic
|
||||
for line in "${ENTRIES[@]}"; do
|
||||
read -r username uid group gid passwd home shell groups comment <<<"${line}"
|
||||
# shellcheck disable=SC2086 # gid is a non-empty int
|
||||
[ ${gid} -ge 0 ] || continue # Automatic gid
|
||||
add_one_group "${group}" "${gid}"
|
||||
done
|
||||
|
||||
# Then, create all the main groups which gid *is* automatic
|
||||
for line in "${ENTRIES[@]}"; do
|
||||
read -r username uid group gid passwd home shell groups comment <<<"${line}"
|
||||
# shellcheck disable=SC2086 # gid is a non-empty int
|
||||
[ ${gid} -lt 0 ] || continue # Non-automatic gid
|
||||
add_one_group "${group}" "${gid}"
|
||||
done
|
||||
|
||||
# Then, create all the additional groups
|
||||
# If any additional group is already a main group, we should use
|
||||
# the gid of that main group; otherwise, we can use any gid - a
|
||||
# system gid if the uid is a system user (<= LAST_SYSTEM_UID),
|
||||
# otherwise a user gid.
|
||||
for line in "${ENTRIES[@]}"; do
|
||||
read -r username uid group gid passwd home shell groups comment <<<"${line}"
|
||||
if [ "${groups}" != "-" ]; then
|
||||
# shellcheck disable=SC2086 # uid is a non-empty int
|
||||
if [ ${uid} -le 0 ]; then
|
||||
auto_id=${uid}
|
||||
elif [ ${uid} -le ${LAST_SYSTEM_UID} ]; then
|
||||
auto_id=${AUTO_SYSTEM_ID}
|
||||
else
|
||||
auto_id=${AUTO_USER_ID}
|
||||
fi
|
||||
for g in ${groups//,/ }; do
|
||||
add_one_group "${g}" "${auto_id}"
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
# When adding users, we do as for groups, in case two packages create
|
||||
# the same user, one with an automatic uid, the other with a specified
|
||||
# uid, to ensure the specified uid is used, rather than an incompatible
|
||||
# uid be generated.
|
||||
|
||||
# Now, add users whose uid is *not* automatic
|
||||
for line in "${ENTRIES[@]}"; do
|
||||
read -r username uid group gid passwd home shell groups comment <<<"${line}"
|
||||
[ "${username}" != "-" ] || continue # Magic string to skip user creation
|
||||
# shellcheck disable=SC2086 # uid is a non-empty int
|
||||
[ ${uid} -ge 0 ] || continue # Automatic uid
|
||||
add_one_user "${username}" "${uid}" "${group}" "${gid}" "${passwd}" \
|
||||
"${home}" "${shell}" "${groups}" "${comment}"
|
||||
done
|
||||
|
||||
# Finally, add users whose uid *is* automatic
|
||||
for line in "${ENTRIES[@]}"; do
|
||||
read -r username uid group gid passwd home shell groups comment <<<"${line}"
|
||||
[ "${username}" != "-" ] || continue # Magic string to skip user creation
|
||||
# shellcheck disable=SC2086 # uid is a non-empty int
|
||||
[ ${uid} -lt 0 ] || continue # Non-automatic uid
|
||||
add_one_user "${username}" "${uid}" "${group}" "${gid}" "${passwd}" \
|
||||
"${home}" "${shell}" "${groups}" "${comment}"
|
||||
done
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
main "${@}"
|
||||
Reference in New Issue
Block a user