#!/bin/bash command -v unpack_img >/dev/null || . /lib/img-lib.sh # config_get SECTION KEY < FILE # read an .ini-style config file, find the KEY in the given SECTION, and return # the value provided for that key. # ex: product=$(config_get Main Product < /.buildstamp) config_get() { local section="$1" key="$2" cursec="" k="" v="" while read line; do case "$line" in \#*) continue ;; \[*\]*) cursec="${line#[}"; cursec="${cursec%%]*}" ;; *=*) k=$(echo ${line%%=*}); v=$(echo ${line#*=}) ;; esac if [ "$cursec" = "$section" ] && [ "$k" == "$key" ]; then echo $v break fi done } find_iso() { local f="" p="" iso="" isodir="$1" tmpmnt=$(mkuniqdir /run/install tmpmnt) for f in $isodir/*.iso; do [ -e $f ] || continue mount -o loop,ro $f $tmpmnt || continue # Valid ISOs either have stage2 in one of the supported paths # or have a .treeinfo that might tell use where to find the stage2 image. # If it does not have any of those, it is not valid and will not be used. for p in $tmpmnt/LiveOS/squashfs.img $tmpmnt/images/install.img $tmpmnt/.treeinfo; do if [ -e $p ]; then iso=$f; break; fi done umount $tmpmnt if [ "$iso" ]; then echo "$iso"; return 0; fi done return 1 } find_runtime() { [ -f "$1" ] && [ "${1%.iso}" == "$1" ] && echo "$1" && return local ti_img="" dir="$1" [ -e $dir/.treeinfo ] && \ ti_img=$(config_get stage2 mainimage < $dir/.treeinfo) for f in $ti_img images/install.img LiveOS/squashfs.img; do [ -e "$dir/$f" ] && echo "$dir/$f" && return done } find_tty() { # find the real tty for /dev/console local tty="console" while [ -f /sys/class/tty/$tty/active ]; do tty=$(< /sys/class/tty/$tty/active) tty=${tty##* } # last item in the list done echo $tty } repodir="/run/install/repo" isodir="/run/install/isodir" rulesfile="/etc/udev/rules.d/90-anaconda.rules" # try to find a usable runtime image from the repo mounted at $mnt. # if successful, move the mount(s) to $repodir/$isodir. anaconda_live_root_dir() { local img="" iso="" srcdir="" mnt="$1" path="$2"; shift 2 img=$(find_runtime $mnt/$path) if [ -n "$img" ]; then info "anaconda: found $img" [ "$mnt" = "$repodir" ] || { mount --make-rprivate /; mount --move $mnt $isodir; } anaconda_auto_updates $repodir/$path/images else if [ "${path%.iso}" != "$path" ]; then iso=$path path=${path%/*.iso} else iso=$(find_iso $mnt/$path) fi [ -n "$iso" ] || { warn "no suitable images"; return 1; } info "anaconda: found $iso" mount --make-rprivate / mount --move $mnt $isodir iso=${isodir}/${iso#$mnt} mount -o loop,ro $iso $repodir img=$(find_runtime $repodir) || { warn "$iso has no suitable runtime"; } anaconda_auto_updates $isodir/$path/images fi # FIXME: make rd.live.ram clever enough to do this for us if [ "$1" = "--copy-to-ram" ]; then echo "Copying installer image to RAM..." echo "(this may take a few minutes)" cp $img /run/install/install.img img=/run/install/install.img umount $repodir [ -n "$iso" ] && umount $isodir fi [ -e "$img" ] && /sbin/dmsquash-live-root $img } # find updates.img/product.img/RHUpdates and unpack/copy them so they'll # end up in the location(s) that anaconda expects them anaconda_auto_updates() { local dir="$1" if [ -d $dir/RHupdates ]; then copytree $dir/RHupdates /updates fi if [ -e $dir/updates.img ]; then unpack_updates_img $dir/updates.img /updates fi if [ -e $dir/product.img ]; then unpack_updates_img $dir/product.img /updates fi } # Unpack an image into the given dir. unpack_updates_img() { local img="$1" tmpdir="/tmp/${1##*/}.$$" outdir="${2:-/updates}" # NOTE: unpack_img $img $outdir can clobber existing subdirs in $outdir, # which is why we use a tmpdir and copytree (which doesn't clobber) unpack_img $img $tmpdir copytree $tmpdir $outdir rm -rf $tmpdir } # These could probably be in dracut-lib or similar copytree() { local src="$1" dest="$2" mkdir -p "$dest"; dest=$(readlink -f -q "$dest") ( cd "$src"; cp -a . -t "$dest" ) } disk_to_dev_path() { case "$1" in CDLABEL=*|LABEL=*) echo "/dev/disk/by-label/${1#*LABEL=}" ;; UUID=*) echo "/dev/disk/by-uuid/${1#UUID=}" ;; /dev/*) echo "$1" ;; *) echo "/dev/$1" ;; esac } find_mount() { local dev mnt etc wanted_dev="$(readlink -e -q $1)" while read dev mnt etc; do [ "$dev" = "$wanted_dev" ] && echo $mnt && return 0 done < /proc/mounts return 1 } when_diskdev_appears() { local dev="${1#/dev/}" cmd=""; shift cmd="/sbin/initqueue --settled --onetime --name $1 $*" { printf 'SUBSYSTEM=="block", KERNEL=="%s", RUN+="%s"\n' "$dev" "$cmd" printf 'SUBSYSTEM=="block", SYMLINK=="%s", RUN+="%s"\n' "$dev" "$cmd" } >> $rulesfile } when_any_cdrom_appears() { local cmd="/sbin/initqueue --settled --onetime --name autocd $*" printf 'SUBSYSTEM=="block", ENV{ID_CDROM_MEDIA}=="1", RUN+="%s"\n' "$cmd" \ >> $rulesfile } plymouth_running() { type plymouth >/dev/null 2>&1 && plymouth --ping 2>/dev/null } # print something to the display (and put it in the log so we know what's up) tell_user() { if plymouth_running; then # NOTE: if we're doing graphical splash but we don't have all the # font-rendering libraries, no message will appear. plymouth display-message --text="$*" echo "$*" # this goes to journal only else echo "$*" >&2 # this goes to journal+console fi } dev_is_cdrom() { udevadm info --query=property --name=$1 | grep -q 'ID_CDROM=1' } # dracut doesn't bring up the network unless: # a) $netroot is set (i.e. you have a network root device), or # b) /tmp/net.ifaces exists. # So for non-root things that need the network (like kickstart) we need to # make sure /tmp/net.ifaces exists. # For details see 40network/net-genrules.sh (and the rest of 40network). set_neednet() { # if there's no netroot, make sure /tmp/net.ifaces exists [ -z "$netroot" ] && >> /tmp/net.ifaces } parse_kickstart() { /sbin/parse-kickstart $1 > /etc/cmdline.d/80-kickstart.conf unset CMDLINE # re-read the commandline . /tmp/ks.info # save the parsed kickstart [ -e "$parsed_kickstart" ] && cp $parsed_kickstart /run/install/ks.cfg } # This is where we actually run the kickstart. Whee! # We can't just add udev rules (we'll miss devices that are already active), # and we can't just run the scripts manually (we'll miss devices that aren't # yet active - think driver disks!). # # So: we have to write out the rules and then retrigger them. # # Really what we want to do here is just start over from the "cmdline" # phase, but since we can't do that, we'll kind of fake it. # # XXX THIS IS KIND OF A GROSS HACK AND WE NEED A BETTER WAY TO DO IT run_kickstart() { local do_disk="" do_net="" # kickstart's done - time to find a real root device [ "$root" = "anaconda-kickstart" ] && root="" # don't look for the kickstart again kickstart="" # re-parse new cmdline stuff from the kickstart . $hookdir/cmdline/*parse-anaconda-repo.sh . $hookdir/cmdline/*parse-livenet.sh # TODO: parse for other stuff ks might set (dd? other stuff?) case "$repotype" in http*|ftp|nfs*) do_net=1 ;; cdrom|hd|bd) do_disk=1 ;; esac [ "$root" = "anaconda-auto-cd" ] && do_disk=1 # kickstart Driver Disk Handling # parse-kickstart may have added network inst.dd entries to the cmdline # Or it may have written devices to /tmp/dd_ks # Does network need to be rerun? dd_args="$(getargs dd= inst.dd=)" for dd in $dd_args; do case "${dd%%:*}" in http|https|ftp|nfs|nfs4) do_net=1 rm /tmp/dd_net.done break ;; esac done # Run the driver update UI for disks if [ -e "/tmp/dd_args_ks" ]; then # TODO: Seems like this should be a function, a mostly same version is used in 3 places start_driver_update "Kickstart Driver Update Disk" rm /tmp/dd_args_ks fi # replay udev events to trigger actions if [ "$do_disk" ]; then . $hookdir/pre-trigger/*repo-genrules.sh udevadm control --reload udevadm trigger --action=change --subsystem-match=block fi if [ "$do_net" ]; then udevadm trigger --action=online --subsystem-match=net fi # and that's it - we're back to the mainloop. > /tmp/ks.cfg.done # let wait_for_kickstart know that we're done. } wait_for_kickstart() { echo "[ -e /tmp/ks.cfg.done ]" > $hookdir/initqueue/finished/kickstart.sh } wait_for_updates() { echo "[ -e /tmp/liveupdates.done ]" > $hookdir/initqueue/finished/updates.sh } start_driver_update() { local title="$1" tty=$(find_tty) # save module state cat /proc/modules > /tmp/dd_modules info "Starting $title Service on $tty" systemctl start driver-updates@$tty.service status=$(systemctl -p ExecMainStatus show driver-updates@$tty.service) info "DD status=$status" }