#!/bin/bash # # inst bits ruthlessly and viciously stolen from dracut [ -z "$DESTDIR" ] || exit 0 [ -z "$PLYMOUTH_LIBEXECDIR" ] && PLYMOUTH_LIBEXECDIR="@PLYMOUTH_LIBEXECDIR@" [ -z "$PLYMOUTH_DATADIR" ] && PLYMOUTH_DATADIR="@PLYMOUTH_DATADIR@" [ -z "$PLYMOUTH_PLUGIN_PATH" ] && PLYMOUTH_PLUGIN_PATH="$(plymouth --get-splash-plugin-path)" [ -z "$PLYMOUTH_LOGO_FILE" ] && PLYMOUTH_LOGO_FILE="@PLYMOUTH_LOGO_FILE@" [ -n "$PLYMOUTH_THEME_NAME" ] && THEME_OVERRIDE=1 [ -z "$PLYMOUTH_THEME_NAME" ] && PLYMOUTH_THEME_NAME=$(plymouth-set-default-theme) [ -z "$PLYMOUTH_CONFDIR" ] && PLYMOUTH_CONFDIR="@PLYMOUTH_CONF_DIR@" [ -z "$PLYMOUTH_POLICYDIR" ] && PLYMOUTH_POLICYDIR="@PLYMOUTH_POLICY_DIR@" [ -z "$PLYMOUTH_DAEMON_PATH" ] && PLYMOUTH_DAEMON_PATH="@PLYMOUTH_DAEMON_DIR@/plymouthd" [ -z "$PLYMOUTH_CLIENT_PATH" ] && PLYMOUTH_CLIENT_PATH="@PLYMOUTH_CLIENT_DIR@/plymouth" [ -z "$SYSTEMD_UNIT_DIR" ] && SYSTEMD_UNIT_DIR="@SYSTEMD_UNIT_DIR@" # Generic substring function. If $2 is in $1, return 0. strstr() { [ "${1#*$2*}" != "$1" ]; } ddebug() { [ "$verbose" = "true" ] && echo "$@" } # normalize_path # Prints the normalized path, where it removes any duplicated # and trailing slashes. # Example: # $ normalize_path ///test/test// # /test/test normalize_path() { shopt -q -s extglob set -- "${1//+(\/)//}" shopt -q -u extglob echo "${1%/}" } # convert_abs_rel # Prints the relative path, when creating a symlink to from . # Example: # $ convert_abs_rel /usr/bin/test /bin/test-2 # ../../bin/test-2 # $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test convert_abs_rel() { local __current __absolute __abssize __cursize __newpath local -i __i __level set -- "$(normalize_path "$1")" "$(normalize_path "$2")" # corner case #1 - self looping link [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; } # corner case #2 - own dir link [[ "${1%/*}" == "$2" ]] && { echo "."; return; } IFS="/" __current=($1) IFS="/" __absolute=($2) __abssize=${#__absolute[@]} __cursize=${#__current[@]} while [[ ${__absolute[__level]} == ${__current[__level]} ]] do (( __level++ )) if (( __level > __abssize || __level > __cursize )) then break fi done for ((__i = __level; __i < __cursize-1; __i++)) do if ((__i > __level)) then __newpath=$__newpath"/" fi __newpath=$__newpath".." done for ((__i = __level; __i < __abssize; __i++)) do if [[ -n $__newpath ]] then __newpath=$__newpath"/" fi __newpath=$__newpath${__absolute[__i]} done echo "$__newpath" } # Install a directory, keeping symlinks as on the original system. # Example: if /lib points to /lib64 on the host, "inst_dir /lib/file" # will create ${initdir}/lib64, ${initdir}/lib64/file, # and a symlink ${initdir}/lib -> lib64. inst_dir() { [[ -e ${initdir}/"$1" ]] && return 0 # already there local _dir="$1" _part="${1%/*}" _file while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do _dir="$_part $_dir" _part=${_part%/*} done # iterate over parent directories for _file in $_dir; do [[ -e "${initdir}/$_file" ]] && continue if [[ -L $_file ]]; then inst_symlink "$_file" else # create directory mkdir -m 0755 -p "${initdir}/$_file" || return 1 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file" chmod u+w "${initdir}/$_file" fi done } # $1 = file to copy to ramdisk # $2 (optional) Name for the file on the ramdisk # Location of the image dir is assumed to be $initdir # We never overwrite the target if it exists. inst_simple() { [[ -f "$1" ]] || return 1 strstr "$1" "/" || return 1 local _src=$1 target="${2:-$1}" if ! [[ -d ${initdir}/$target ]]; then [[ -e ${initdir}/$target ]] && return 0 [[ -L ${initdir}/$target ]] && return 0 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}" fi # install checksum files also if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then inst "${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac" fi ddebug "Installing $_src" cp --sparse=always -pfL "$_src" "${initdir}/$target" } # find symlinks linked to given library file # $1 = library file # Function searches for symlinks by stripping version numbers appended to # library filename, checks if it points to the same target and finally # prints the list of symlinks to stdout. # # Example: # rev_lib_symlinks libfoo.so.8.1 # output: libfoo.so.8 libfoo.so # (Only if libfoo.so.8 and libfoo.so exists on host system.) rev_lib_symlinks() { [[ ! $1 ]] && return 0 local fn="$1" orig="$(readlink -f "$1")" links='' [[ ${fn} =~ .*\.so\..* ]] || return 1 until [[ ${fn##*.} == so ]]; do fn="${fn%.*}" [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}" done echo "${links}" } # Same as above, but specialized to handle dynamic libraries. # It handles making symlinks according to how the original library # is referenced. inst_library() { local _src="$1" _dest=${2:-$1} _lib _reallib _symlink strstr "$1" "/" || return 1 [[ -e $initdir/$_dest ]] && return 0 if [[ -L $_src ]]; then # install checksum files also if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac" fi _reallib=$(readlink -f "$_src") inst_simple "$_reallib" "$_reallib" inst_dir "${_dest%/*}" [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/} ln -sfn $(convert_abs_rel "${_dest}" "${_reallib}") "${initdir}/${_dest}" else inst_simple "$_src" "$_dest" fi # Create additional symlinks. See rev_symlinks description. for _symlink in $(rev_lib_symlinks $_src) $(rev_lib_symlinks $_reallib); do [[ ! -e $initdir/$_symlink ]] && { ddebug "Creating extra symlink: $_symlink" inst_symlink $_symlink } done } # find a binary. If we were not passed the full path directly, # search in the usual places to find the binary. find_binary() { if [[ -z ${1##/*} ]]; then if [[ -x $1 ]] || { strstr "$1" ".so" && ldd $1 &>/dev/null; }; then echo $1 return 0 fi fi type -P $1 } # Same as above, but specialized to install binary executables. # Install binary executable, and all shared library dependencies, if any. inst_binary() { local _bin _target _bin=$(find_binary "$1") || return 1 _target=${2:-$_bin} [[ -e $initdir/$_target ]] && return 0 [[ -L $_bin ]] && inst_symlink $_bin $_target && return 0 local _file _line local _so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)' # I love bash! LC_ALL=C ldd "$_bin" 2>/dev/null | while read _line; do [[ $_line = 'not a dynamic executable' ]] && break if [[ $_line =~ $_so_regex ]]; then _file=${BASH_REMATCH[1]} [[ -e ${initdir}/$_file ]] && continue inst_library "$_file" continue fi if [[ $_line =~ not\ found ]]; then dfatal "Missing a shared library required by $_bin." dfatal "Run \"ldd $_bin\" to find out what it is." dfatal "$_line" dfatal "dracut cannot create an initrd." exit 1 fi done inst_simple "$_bin" "$_target" } # same as above, except for shell scripts. # If your shell script does not start with shebang, it is not a shell script. inst_script() { local _bin _bin=$(find_binary "$1") || return 1 shift local _line _shebang_regex read -r -n 80 _line <"$_bin" # If debug is set, clean unprintable chars to prevent messing up the term [[ $debug ]] && _line=$(echo -n "$_line" | tr -c -d '[:print:][:space:]') _shebang_regex='(#! *)(/[^ ]+).*' [[ $_line =~ $_shebang_regex ]] || return 1 inst "${BASH_REMATCH[2]}" && inst_simple "$_bin" "$@" } # same as above, but specialized for symlinks inst_symlink() { local _src=$1 _target=${2:-$1} _realsrc strstr "$1" "/" || return 1 [[ -L $1 ]] || return 1 [[ -L $initdir/$_target ]] && return 0 _realsrc=$(readlink -f "$_src") if ! [[ -e $initdir/$_realsrc ]]; then if [[ -d $_realsrc ]]; then inst_dir "$_realsrc" else inst "$_realsrc" fi fi [[ ! -e $initdir/${_target%/*} ]] && inst_dir "${_target%/*}" [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/} ln -sfn $(convert_abs_rel "${_target}" "${_realsrc}") "$initdir/$_target" } # general purpose installation function # Same args as above. inst() { local _x case $# in 1) ;; 2) [[ ! $initdir && -d $2 ]] && export initdir=$2 [[ $initdir = $2 ]] && set $1;; 3) [[ -z $initdir ]] && export initdir=$2 set $1 $3;; *) dfatal "inst only takes 1 or 2 or 3 arguments" exit 1;; esac for _x in inst_symlink inst_script inst_binary inst_simple; do $_x "$@" && return 0 done return 1 } # install function specialized for hooks # $1 = type of hook, $2 = hook priority (lower runs first), $3 = hook # All hooks should be POSIX/SuS compliant, they will be sourced by init. inst_hook() { if ! [[ -f $3 ]]; then dfatal "Cannot install a hook ($3) that does not exist." dfatal "Aborting initrd creation." exit 1 elif ! strstr "$hookdirs" "$1"; then dfatal "No such hook type $1. Aborting initrd creation." exit 1 fi inst_simple "$3" "/lib/dracut/hooks/${1}/${2}${3##*/}" } # install any of listed files # # If first argument is '-d' and second some destination path, first accessible # source is installed into this path, otherwise it will installed in the same # path as source. If none of listed files was installed, function return 1. # On first successful installation it returns with 0 status. # # Example: # # inst_any -d /bin/foo /bin/bar /bin/baz # # Lets assume that /bin/baz exists, so it will be installed as /bin/foo in # initramfs. inst_any() { local to f [[ $1 = '-d' ]] && to="$2" && shift 2 for f in "$@"; do if [[ -e $f ]]; then [[ $to ]] && inst "$f" "$to" && return 0 inst "$f" && return 0 fi done return 1 } function usage() { local output="/dev/stdout" local rc=0 if [ "$1" == "error" ]; then output="/dev/stderr" rc=1 fi echo "usage: plymouth [ --verbose | -v ] { --targetdir | -t } " > $output exit $rc } verbose=false INITRDDIR="" while [ $# -gt 0 ]; do case $1 in --verbose|-v) verbose=true ;; --targetdir|-t) shift INITRDDIR="$1" ;; --help|-h) usage normal ;; *) usage error break ;; esac shift done [ -z "$INITRDDIR" ] && usage error mkdir -p ${INITRDDIR}${PLYMOUTH_DATADIR}/plymouth/themes inst ${PLYMOUTH_DAEMON_PATH} $INITRDDIR /sbin/plymouthd inst ${PLYMOUTH_CLIENT_PATH} $INITRDDIR /bin/plymouth inst ${PLYMOUTH_DATADIR}/plymouth/themes/text/text.plymouth $INITRDDIR inst ${PLYMOUTH_PLUGIN_PATH}/text.so $INITRDDIR inst ${PLYMOUTH_DATADIR}/plymouth/themes/details/details.plymouth $INITRDDIR inst ${PLYMOUTH_PLUGIN_PATH}/details.so $INITRDDIR inst ${PLYMOUTH_LOGO_FILE} $INITRDDIR inst @RELEASE_FILE@ $INITRDDIR inst ${PLYMOUTH_POLICYDIR}/plymouthd.defaults $INITRDDIR inst ${PLYMOUTH_CONFDIR}/plymouthd.conf $INITRDDIR if [ -z "$PLYMOUTH_THEME_NAME" ]; then echo "No default plymouth plugin is set" > /dev/stderr exit 1 fi if [ $THEME_OVERRIDE ]; then conf=$INITRDDIR/${PLYMOUTH_CONFDIR}/plymouthd.conf echo "modifying plymouthd.conf: Theme=$PLYMOUTH_THEME_NAME" > /dev/stderr sed -i "s/^ *Theme *=.*/# theme modified by plymouth-populate-initrd\nTheme=$PLYMOUTH_THEME_NAME/" $conf fi PLYMOUTH_MODULE_NAME=$(grep "ModuleName *= *" ${PLYMOUTH_DATADIR}/plymouth/themes/${PLYMOUTH_THEME_NAME}/${PLYMOUTH_THEME_NAME}.plymouth | sed 's/ModuleName *= *//') if [ ! -f ${PLYMOUTH_PLUGIN_PATH}/${PLYMOUTH_MODULE_NAME}.so ]; then echo "The default plymouth plugin (${PLYMOUTH_MODULE_NAME}) doesn't exist" > /dev/stderr exit 1 fi inst ${PLYMOUTH_PLUGIN_PATH}/${PLYMOUTH_MODULE_NAME}.so $INITRDDIR [ -f "${PLYMOUTH_PLUGIN_PATH}/renderers/drm.so" ] && inst ${PLYMOUTH_PLUGIN_PATH}/renderers/drm.so $INITRDDIR inst ${PLYMOUTH_PLUGIN_PATH}/renderers/frame-buffer.so $INITRDDIR if [ -d ${PLYMOUTH_DATADIR}/plymouth/themes/${PLYMOUTH_THEME_NAME} ]; then for x in ${PLYMOUTH_DATADIR}/plymouth/themes/${PLYMOUTH_THEME_NAME}/* ; do [ ! -f "$x" ] && continue inst $x $INITRDDIR done fi if [ -L ${PLYMOUTH_DATADIR}/plymouth/themes/default.plymouth ]; then cp -a ${PLYMOUTH_DATADIR}/plymouth/themes/default.plymouth $INITRDDIR${PLYMOUTH_DATADIR}/plymouth/themes fi if [ -n "$SYSTEMD_UNIT_DIR" -a -d "$SYSTEMD_UNIT_DIR" ]; then inst $SYSTEMD_UNIT_DIR/systemd-ask-password-plymouth.path $INITRDDIR inst $SYSTEMD_UNIT_DIR/systemd-ask-password-plymouth.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/plymouth-switch-root.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/plymouth-start.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/plymouth-quit.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/plymouth-quit-wait.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/plymouth-reboot.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/plymouth-kexec.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/plymouth-poweroff.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/plymouth-halt.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/initrd-switch-root.target.wants/plymouth-switch-root.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/sysinit.target.wants/plymouth-start.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/multi-user.target.wants/plymouth-quit.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/multi-user.target.wants/plymouth-quit-wait.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/reboot.target.wants/plymouth-reboot.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/kexec.target.wants/plymouth-kexec.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/poweroff.target.wants/plymouth-poweroff.service $INITRDDIR inst $SYSTEMD_UNIT_DIR/halt.target.wants/plymouth-halt.service $INITRDDIR fi # vim:ts=8:sw=4:sts=4:et