From 3e74c9603ccabda082202c49db46e2348ff9f876 Mon Sep 17 00:00:00 2001 From: Frederick Grose Date: Feb 25 2023 06:20:07 +0000 Subject: livesys: Modernize shell code, don't require Bash. Use $() style command substitutions. Do not require the Bash shell. Use && || list control over -a -o test operators. Remove unused exists() function. Collect kernel command line once into a variable, and perform more robust parsing. Take advantage of losetup -f --show for assignment of variables for loop devices. Use ${mountopts:+$mountopts} expansion to nothing if mountopts is unset or empty in livesys-main. Use ${USERADDARGS:+$USERADDARGS} expansion to nothing if USERADDARGS is unset in livesys-main. Drop the unneeded -n (not zero-length) operator in test expressions, and use ! instead of -z (zero-length). This results in quicker-to-understand code as it more closely represents the variable object instead of the testing methodology and its double negatives. Clearly demark the run-on-first-boot-only code from the rest in livesys-main. Move, and comment to keep, the /.liveimg-configured flag file at the end of the livesys-main script, so that it is not set prematurely in a faulty script invocation. Replace touch with : > file syntax. Include a switch for rd.live.debug in livesys-main & livesys-late. Provide a filesystem check/repair function in functions and use it on a persistent home.img or home device filesystem. Also In functions: Update the strstr function to a simpler version from dracut. Drop the dependency on grep by using shell substring removal. Drop the Bash syntax $"..." for string translation for portability & security reasons. See https://www.gnu.org/software/gettext/manual/html_node/bash.html --- diff --git a/libexec/livesys/functions b/libexec/livesys/functions index 606e1bc..d7f2889 100644 --- a/libexec/livesys/functions +++ b/libexec/livesys/functions @@ -1,9 +1,15 @@ +#!/bin/sh # Functions to be used with livesys-* scripts -# returns OK if $1 contains $2 +# Check if gettext exists +if ! type gettext > /dev/null 2>&1; then + # If not, create a dummy function that returns the input verbatim + gettext() { printf '%s' "$1"; } +fi + +# returns OK if $1 contains literal string $2 (and isn't empty) strstr() { - [ "${1#*$2*}" = "$1" ] && return 1 - return 0 + [ "${1##*"$2"*}" != "$1" ] } # Run some action. Log its output. @@ -11,11 +17,15 @@ action() { local STRING rc STRING=$1 - echo -n "$STRING " + printf '%s' "$(gettext "${STRING} ")" shift - "$@" && success $"$STRING" || failure $"$STRING" + if "$@"; then + success "$(gettext "${STRING} ")" + else + failure "$(gettext "${STRING} ")" + fi rc=$? - echo + printf '\n' return $rc } @@ -26,26 +36,31 @@ BOOTUP=color # Column to start "[ OK ]" label in: RES_COL=60 # terminal sequence to move to that column: -MOVE_TO_COL="echo -en \\033[${RES_COL}G" +MOVE_TO_COL="printf \\033[${RES_COL}G" # Terminal sequence to set color to a 'success' (bright green): -SETCOLOR_SUCCESS="echo -en \\033[1;32m" +SETCOLOR_SUCCESS="printf \\033[1;32m" # Terminal sequence to set color to a 'failure' (bright red): -SETCOLOR_FAILURE="echo -en \\033[1;31m" +SETCOLOR_FAILURE="printf \\033[1;31m" # Terminal sequence to set color to a 'warning' (bright yellow): -SETCOLOR_WARNING="echo -en \\033[1;33m" +SETCOLOR_WARNING="printf \\033[1;33m" # Terminal sequence to reset to the default color: -SETCOLOR_NORMAL="echo -en \\033[0;39m" +SETCOLOR_NORMAL="printf \\033[0;39m" -# NOTE: /dev/ttyS* is serial console. "not a tty" is such as -# /dev/null associated when executed under systemd service units. -if LANG=C tty | grep -q -e '\(/dev/ttyS\|not a tty\)'; then - BOOTUP=serial - MOVE_TO_COL= - SETCOLOR_SUCCESS= - SETCOLOR_FAILURE= - SETCOLOR_WARNING= - SETCOLOR_NORMAL= -fi +# NOTE: /dev/ttyS* is serial console. +# 'not a tty' is reported when executed under systemd service units +# where /dev/null is associated with standard input + +test_tty=$(LC_ALL=C tty) +case "$test_tty" in + /dev/ttyS* | 'not a tty') + BOOTUP=serial + MOVE_TO_COL= + SETCOLOR_SUCCESS= + SETCOLOR_FAILURE= + SETCOLOR_WARNING= + SETCOLOR_NORMAL= + ;; +esac # Log that something succeeded success() { @@ -63,24 +78,55 @@ failure() { echo_success() { [ "$BOOTUP" = "color" ] && $MOVE_TO_COL - echo -n "[" + printf '%s' "[" [ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS - echo -n $" OK " + printf '%s' "$(gettext " OK ")" [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL - echo -n "]" - echo -ne "\r" + printf '%s' "]" + printf '\r' return 0 } echo_failure() { [ "$BOOTUP" = "color" ] && $MOVE_TO_COL - echo -n "[" + printf '%s' "[" [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE - echo -n $"FAILED" + printf '%s' "$(gettext "FAILED")" [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL - echo -n "]" - echo -ne "\r" + printf '%s' "]" + printf '\r' return 1 } +fscheck() { + local fstype="$1" + local fs="$2" + local d="${3:-$2}" + umount "$fs" >/dev/null 2>&1 || : + case "$fstype" in + ext[432]) + printf '\n' + flock "$d" e2fsck -yfv "$fs" || : + ;; + vfat|msdos) + printf '\n' + flock "$d" fsck.fat -avVw "$fs" + ;; + btrfs) + printf '# btrfs check -p --repair --force' + flock "$d" btrfs check -p --repair --force "$fs" + ;; + xfs) + printf '\n# xfs_repair -v' + flock "$d" xfs_repair -v "$fs" + ;; + f2fs) + printf '# fsck.f2fs -afy' + flock "$d" fsck.f2fs -afy "$fs" + ;; + *) + printf "\n\tERROR: Filesystem checking for '%s' is not\n \ + available.\n" "$fstype" + esac +} diff --git a/libexec/livesys/livesys-late b/libexec/livesys/livesys-late index 201a5d9..0b604d4 100755 --- a/libexec/livesys/livesys-late +++ b/libexec/livesys/livesys-late @@ -1,45 +1,47 @@ -#!/bin/bash +#!/bin/sh # # live: Late init script for live image # SPDX-License-Identifier: GPL-3.0-or-later -. /usr/libexec/livesys/functions - -if ! strstr "`cat /proc/cmdline`" rd.live.image || [ -e /.liveimg-late-configured ] ; then - exit 0 +cmdline=$(cat /proc/cmdline)' ' + +if [ "${cmdline##* rd.live.debug[= ]}" != "$cmdline" ] || + [ "${cmdline##* rdlivedebug[= ]}" != "$cmdline" ]; then + exec > /run/initramfs/livesys-late.$$.out 2>&1 + set -x + if [ "$BASH" ]; then + export \ + PS4='+ (${BASH_SOURCE}@${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' + else + export PS4='+ (${0##*/}@${LINENO}): ' + fi fi -exists() { - which $1 >/dev/null 2>&1 || return - $* -} +{ [ "${cmdline##* rd.live.image[= ]}" = "$cmdline" ] && + [ "${cmdline##* liveimg[= ]}" = "$cmdline" ]; } || + [ -e /.liveimg-late-configured ] && exit 0 -touch /.liveimg-late-configured +: > /.liveimg-late-configured # read some variables out of /proc/cmdline -for o in `cat /proc/cmdline` ; do - case $o in - ks=*) - ks="--kickstart=${o#ks=}" - ;; - xdriver=*) - xdriver="${o#xdriver=}" - ;; - esac -done +cut=${cmdline##* ks=} +[ ${#cut} -ne ${#cmdline} ] && ks=--kickstart="${cut%% *}" + +cut=${cmdline##* xdriver=} +[ ${#cut} -ne ${#cmdline} ] && xdriver="${cut%% *}" # if liveinst or textinst is given, start anaconda -if strstr "`cat /proc/cmdline`" liveinst ; then +if [ "${cmdline##* liveinst }" != "$cmdline" ]; then plymouth --quit - /usr/sbin/liveinst $ks + /usr/sbin/liveinst "$ks" fi -if strstr "`cat /proc/cmdline`" textinst ; then +if [ "${cmdline##* textinst }" != "$cmdline" ]; then plymouth --quit - /usr/sbin/liveinst --text $ks + /usr/sbin/liveinst --text "$ks" fi # configure X, allowing user to override xdriver -if [ -n "$xdriver" ]; then +if [ "$xdriver" ]; then cat > /etc/X11/xorg.conf.d/00-xdriver.conf < /run/initramfs/livesys-main.$$.out 2>&1 + set -x + if [ "$BASH" ]; then + export \ + PS4='+ (${BASH_SOURCE}@${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' + else + export PS4='+ (${0##*/}@${LINENO}): ' + fi fi -if [ -e /.liveimg-configured ] ; then - configdone=1 -fi +{ [ "${cmdline##* rd.live.image[= ]}" = "$cmdline" ] && + [ "${cmdline##* liveimg[= ]}" = "$cmdline" ]; } && exit 0 -exists() { - which $1 >/dev/null 2>&1 || return - $* -} +[ -e /.liveimg-configured ] && configdone=1 livedir="LiveOS" -for arg in `cat /proc/cmdline` ; do - if [ "${arg##rd.live.dir=}" != "${arg}" ]; then - livedir=${arg##rd.live.dir=} - continue - fi - if [ "${arg##live_dir=}" != "${arg}" ]; then - livedir=${arg##live_dir=} - fi -done +cut=${cmdline##* rd.live.dir[= ]} +[ ${#cut} -ne ${#cmdline} ] && livedir=${cut%% *} +len=${#cut} +cut=${cut##* live_dir[= ]} +[ ${#cut} -ne $len ] && livedir=${cut%% *} # enable swapfile if it exists -if ! strstr "`cat /proc/cmdline`" noswap && [ -f /run/initramfs/live/${livedir}/swap.img ] ; then - action "Enabling swap file" swapon /run/initramfs/live/${livedir}/swap.img -fi +strstr "$cmdline" ' noswap ' || { + [ -f /run/initramfs/live/"${livedir}"/swap.img ] && + action "Enabling swap file" swapon /run/initramfs/live/"${livedir}"/swap.img ;} mountPersistentHome() { # support label/uuid - if [ "${homedev##LABEL=}" != "${homedev}" -o "${homedev##UUID=}" != "${homedev}" ]; then - homedev=`/sbin/blkid -o device -t "$homedev"` + if [ "${homedev##LABEL=}" != "$homedev" ] || + [ "${homedev##UUID=}" != "$homedev" ]; then + homedev=$(blkid -o device -t "$homedev") fi - # if we're given a file rather than a blockdev, loopback it - if [ "${homedev##mtd}" != "${homedev}" ]; then + # if we're given a file rather than a blockdev, loop mount it + if [ "${homedev##mtd}" != "$homedev" ]; then # mtd devs don't have a block device but get magic-mounted with -t jffs2 mountopts="-t jffs2" elif [ ! -b "$homedev" ]; then - loopdev=`losetup -f` - if [ "${homedev##/run/initramfs/live}" != "${homedev}" ]; then + if [ "${homedev##/run/initramfs/live}" != "$homedev" ]; then action "Remounting live store r/w" mount -o remount,rw /run/initramfs/live fi - losetup $loopdev $homedev - homedev=$loopdev + homedev=$(losetup -f --show "$homedev") fi + homefs=$(blkid -s TYPE -o value "$homedev" 2>/dev/null) # if it's encrypted, we need to unlock it - if [ "$(/sbin/blkid -s TYPE -o value $homedev 2>/dev/null)" = "crypto_LUKS" ]; then + if [ "$homefs" = "crypto_LUKS" ]; then echo echo "Setting up encrypted /home device" plymouth ask-for-password --command="cryptsetup luksOpen $homedev EncHome" homedev=/dev/mapper/EncHome fi + if [ "$homedev" ] && [ "${cmdline##* rd.skipfsck[= ]}" = "$cmdline" ]; then + action "Checking home filesystem" fscheck "$homefs" "$homedev" + fi # and finally do the mount - mount $mountopts $homedev /home + mount ${mountopts:+$mountopts} "$homedev" /home # if we have /home under what's passed for persistent home, then # we should make that the real /home. useful for mtd device on olpc - if [ -d /home/home ]; then mount --bind /home/home /home ; fi + [ -d /home/home ] && mount --bind /home/home /home [ -x /sbin/restorecon ] && /sbin/restorecon /home - if [ -d /home/liveuser ]; then USERADDARGS="-M" ; fi + [ -d /home/liveuser ] && USERADDARGS="-M" } -findPersistentHome() { - for arg in `cat /proc/cmdline` ; do - if [ "${arg##persistenthome=}" != "${arg}" ]; then - homedev=${arg##persistenthome=} - fi - done -} - -if strstr "`cat /proc/cmdline`" persistenthome= ; then - findPersistentHome -elif [ -e /run/initramfs/live/${livedir}/home.img ]; then - homedev=/run/initramfs/live/${livedir}/home.img +cut=${cmdline##* persistenthome[= ]} +if [ ${#cut} -ne ${#cmdline} ]; then + homedev=${cut%% *} +elif [ -e /run/initramfs/live/"${livedir}"/home.img ]; then + homedev=/run/initramfs/live/"${livedir}"/home.img fi # if we have a persistent /home, then we want to go ahead and mount it -if ! strstr "`cat /proc/cmdline`" nopersistenthome && [ -n "$homedev" ] ; then +{ ! strstr "$cmdline" nopersistenthome && [ "$homedev" ]; } && action "Mounting persistent /home" mountPersistentHome -fi -if [ -n "$configdone" ]; then - exit 0 -fi +[ "$configdone" ] && exit 0 + +################### Code below runs only on first boot ##################### # add liveuser user with no passwd -action "Adding live user" useradd $USERADDARGS -c "Live System User" liveuser +action "Adding live user" useradd ${USERADDARGS:+"$USERADDARGS"} -c "Live System User" liveuser passwd -d liveuser > /dev/null usermod -aG wheel liveuser > /dev/null @@ -109,7 +105,7 @@ systemctl stop firstboot-text.service 2> /dev/null || : systemctl stop firstboot-graphical.service 2> /dev/null || : # don't use prelink on a running live image -sed -i 's/PRELINKING=yes/PRELINKING=no/' /etc/sysconfig/prelink &>/dev/null || : +sed -i 's/PRELINKING=yes/PRELINKING=no/' /etc/sysconfig/prelink >/dev/null 2>&1 || : # turn off mdmonitor by default systemctl --no-reload disable mdmonitor.service 2> /dev/null || : @@ -131,21 +127,17 @@ systemctl stop abrtd.service 2> /dev/null || : # Don't sync the system clock when running live (RHBZ #1018162) sed -i 's/rtcsync//' /etc/chrony.conf -# Mark things as configured -touch /.liveimg-configured - # add static hostname to work around xauth bug # https://bugzilla.redhat.com/show_bug.cgi?id=679486 # the hostname must be something else than 'localhost' # https://bugzilla.redhat.com/show_bug.cgi?id=1370222 hostnamectl set-hostname "localhost-live" - if [ -f /etc/sysconfig/livesys ]; then . /etc/sysconfig/livesys - if [ -n "${livesys_session}" ]; then + if [ "${livesys_session}" ]; then if [ -f "/usr/libexec/livesys/sessions.d/livesys-${livesys_session}" ]; then . /usr/libexec/livesys/sessions.d/"livesys-${livesys_session}" fi @@ -153,14 +145,15 @@ if [ -f /etc/sysconfig/livesys ]; then fi - -# allow extra stuff to be defined for derived spins (e.g. fedora labs) +# allow extra stuff to be defined for derived spins (e.g., fedora labs) if [ -f /var/lib/livesys/livesys-session-extra ]; then . /var/lib/livesys/livesys-session-extra fi - # make sure to set the right permissions and selinux contexts chown -R liveuser:liveuser /home/liveuser/ restorecon -RF /home/liveuser/ +#>>>>> Mark things as configured and keep this at the end of this script. <<<<< +: > /.liveimg-configured + diff --git a/libexec/livesys/sessions.d/livesys-budgie b/libexec/livesys/sessions.d/livesys-budgie index 6755bb1..7d8d1d8 100644 --- a/libexec/livesys/sessions.d/livesys-budgie +++ b/libexec/livesys/sessions.d/livesys-budgie @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-budgie: budgie-specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/libexec/livesys/sessions.d/livesys-cinnamon b/libexec/livesys/sessions.d/livesys-cinnamon index 40e9908..df52297 100755 --- a/libexec/livesys/sessions.d/livesys-cinnamon +++ b/libexec/livesys/sessions.d/livesys-cinnamon @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-cinnamon: cinnamon specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/libexec/livesys/sessions.d/livesys-gnome b/libexec/livesys/sessions.d/livesys-gnome index a2114f0..439ae52 100755 --- a/libexec/livesys/sessions.d/livesys-gnome +++ b/libexec/livesys/sessions.d/livesys-gnome @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-gnome: gnome-specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later @@ -22,7 +22,7 @@ FOE # don't run gnome-initial-setup mkdir ~liveuser/.config -touch ~liveuser/.config/gnome-initial-setup-done +: > ~liveuser/.config/gnome-initial-setup-done # suppress anaconda spokes redundant with gnome-initial-setup cat >> /etc/sysconfig/anaconda << FOE diff --git a/libexec/livesys/sessions.d/livesys-i3 b/libexec/livesys/sessions.d/livesys-i3 index 3ceb29c..39d63b1 100755 --- a/libexec/livesys/sessions.d/livesys-i3 +++ b/libexec/livesys/sessions.d/livesys-i3 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-i3: i3 specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/libexec/livesys/sessions.d/livesys-kde b/libexec/livesys/sessions.d/livesys-kde index af90b86..08646a5 100755 --- a/libexec/livesys/sessions.d/livesys-kde +++ b/libexec/livesys/sessions.d/livesys-kde @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-kde: kde specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/libexec/livesys/sessions.d/livesys-lxde b/libexec/livesys/sessions.d/livesys-lxde index 4f6e73a..0afd692 100755 --- a/libexec/livesys/sessions.d/livesys-lxde +++ b/libexec/livesys/sessions.d/livesys-lxde @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-lxde: lxde specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/libexec/livesys/sessions.d/livesys-lxqt b/libexec/livesys/sessions.d/livesys-lxqt index 8445793..3b8d8a9 100755 --- a/libexec/livesys/sessions.d/livesys-lxqt +++ b/libexec/livesys/sessions.d/livesys-lxqt @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-lxqt: lxqt specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/libexec/livesys/sessions.d/livesys-mate b/libexec/livesys/sessions.d/livesys-mate index b503b9a..ed62e8d 100755 --- a/libexec/livesys/sessions.d/livesys-mate +++ b/libexec/livesys/sessions.d/livesys-mate @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-mate: mate specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/libexec/livesys/sessions.d/livesys-soas b/libexec/livesys/sessions.d/livesys-soas index 7145dbf..bbac9f3 100755 --- a/libexec/livesys/sessions.d/livesys-soas +++ b/libexec/livesys/sessions.d/livesys-soas @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-soas: soas specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/libexec/livesys/sessions.d/livesys-sway b/libexec/livesys/sessions.d/livesys-sway index fe72cb9..cccb2bb 100755 --- a/libexec/livesys/sessions.d/livesys-sway +++ b/libexec/livesys/sessions.d/livesys-sway @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-sway: sway specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later @@ -26,7 +26,7 @@ mkdir /home/liveuser/Desktop echo "echo 'Please type liveinst and press Enter to start the installer'" >> /home/liveuser/.bashrc # use sway configuration files for live environment -if [ -n "$(ls /usr/share/sway/config.live.d/*.conf 2>/dev/null)" ]; then +if [ "$(ls /usr/share/sway/config.live.d/*.conf 2>/dev/null)" ]; then mkdir -p /home/liveuser/.config/sway/config.d/ ln -sf -t /home/liveuser/.config/sway/config.d /usr/share/sway/config.live.d/*.conf; fi diff --git a/libexec/livesys/sessions.d/livesys-xfce b/libexec/livesys/sessions.d/livesys-xfce index 246812a..8628c1f 100755 --- a/libexec/livesys/sessions.d/livesys-xfce +++ b/libexec/livesys/sessions.d/livesys-xfce @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # live-xfce: xfce specific setup for livesys # SPDX-License-Identifier: GPL-3.0-or-later