efi-sync

Automatically install your kernel and initrd into the EFI
git clone git://git.server.ky/slackcoder/efi-sync
Log | Files | Refs | README

efi-sync (3835B)


      1 #!/bin/bash
      2 
      3 trap graceful_exit INT TERM
      4 
      5 # Inofity events which signal something changed.
      6 MODIFICATION_EVENTS="CREATE,CLOSE_WRITE,MOVED_TO,MOVED_FROM,MOVE"
      7 
      8 # Signals if the watcher should stop.
      9 STOP=false
     10 
     11 graceful_exit () {
     12   STOP=true
     13 
     14   if [[ ! -z "$KPID" ]]; then
     15     kill -TERM $KPID >/dev/null 2>/dev/null
     16   fi
     17   if [[ ! -z "$MPID" ]]; then
     18     kill -TERM $MPID >/dev/null 2>/dev/null
     19   fi
     20 }
     21 
     22 load_config() {
     23   KERNEL=/boot/vmlinuz
     24   EFI_KERNEL=/boot/efi/EFI/Slackware/vmlinuz
     25   INITRD=/boot/initrd.gz
     26   EFI_INITRD=/boot/efi/EFI/Slackware/initrd.gz
     27 
     28   if [[ -f /etc/efi-sync.conf ]]; then
     29     source /etc/efi-sync.conf || exit 1
     30   fi
     31 
     32   INSTALL_PROGRAMS="slackpkg,upgradepkg,installpkg,removepkg"
     33   WAIT_TIME=1
     34 }
     35 
     36 log () {
     37   echo "$(date --rfc-3339=seconds) $@"
     38 }
     39 
     40 require_efi () {
     41   if ! mount | grep vfat >/dev/null; then
     42     log "the efi partition must be mounted"
     43     exit 1
     44   fi
     45 }
     46 
     47 require_root () {
     48   if [[ "$(id --user --name)" != "root" ]]; then
     49     log "command must be run as root"
     50     exit 1
     51   fi
     52 }
     53 
     54 
     55 efi_install () {
     56   require_root
     57   require_efi
     58   load_config
     59 
     60   KERNEL_VERSION="$(file $(realpath "$KERNEL") | sed -E 's/.* version (\S*) .*/\1/')"
     61 
     62   if ! cp -H "$KERNEL" "${EFI_KERNEL}"; then
     63     log "Failed to copy '${KERNEL}' into your EFI at '${EFI_KERNEL}'."
     64     return 1
     65   fi
     66   log  "Installed $(realpath "$KERNEL")."
     67 
     68   if [[ -f /etc/mkinitrd.conf ]]; then
     69     if ! mkinitrd -F -c -k "${KERNEL_VERSION}" >/dev/null 2>&1; then
     70       log "mkinitrd.conf detected but failed to build your initial ramdisk for '${KERNEL_VERSION}'."
     71       return 1
     72     fi
     73     log "mkinitrd.conf detected and successfully built your initial ramdisk for '${KERNEL_VERSION}'."
     74   fi
     75 
     76   if [[ -f "$INITRD" ]] && [[ "$INITRD" != "$EFI_INITRD" ]]; then
     77     if [[ "$INITRD" != "$EFI_INITRD" ]] && ! cp -H "$INITRD" "${EFI_INITRD}"; then
     78       log "Failed to copy '${INITRD}' into your EFI at '${EFI_INITRD}'."
     79       return 1
     80     fi
     81     log  "Installed the initial RAM disk '${INITRD}'."
     82   fi
     83 }
     84 
     85 efi_watch () {
     86   require_root
     87   require_efi
     88   load_config
     89 
     90   while ! $STOP; do
     91     log  "Watching ${KERNEL} for updates."
     92 
     93     >/dev/null inotifywait "$(dirname "$KERNEL")" --include "./$(basename $KERNEL)$" \
     94       --event "$MODIFICATION_EVENTS" \
     95       --quiet &
     96     KPID="$!"
     97 
     98     # Watching for directory updates is enough and helps avoid the system's watch limit.
     99     readarray -d '' INITRD_FILES < <(find /lib/firmware /lib/modules -type d -print0)
    100     >/dev/null inotifywait \
    101       --event "$MODIFICATION_EVENTS" \
    102       --quiet \
    103       --recursive \
    104       "${INITRD_FILES[@]}" &
    105     MPID="$!"
    106 
    107     if ! wait -n "$KPID" "$MPID" || $STOP; then
    108       kill -TERM $KPID $MPID >/dev/null 2>/dev/null
    109       continue
    110     fi
    111     kill -TERM $KPID $MPID >/dev/null 2>/dev/null
    112     unset KPID MPID
    113 
    114     # Be safe and consider changes to the kernel system which happen during
    115     # installation.
    116     #
    117     # Use file creation time to check if re-installation is needed.
    118     TIMESTAMP_FILE="$(mktemp -t "efi-sync.XXXXXXX")"
    119 
    120     while true; do
    121       touch "$TIMESTAMP_FILE"
    122 
    123       let "count = 0"
    124       while [[ $count -lt $WAIT_TIME ]]; do
    125         if ps -C "$INSTALL_PROGRAMS" >/dev/null; then
    126           let "count = 0"
    127 	  sleep 1
    128 
    129 	  continue
    130 	fi
    131 
    132         let "count = $count + 1"
    133 	sleep 1
    134       done
    135 
    136       efi_install
    137 
    138       NEW_FILES="$(find "$KERNEL" /lib/firmware /lib/modules -newer "$TIMESTAMP_FILE")"
    139       if [[ -z "$NEW_FILES" ]]; then
    140         break
    141       fi
    142     done
    143 
    144     rm "$TIMESTAMP_FILE"
    145   done
    146 
    147   log  "Stopped watching ${KERNEL} for updates."
    148 }
    149 
    150 case "$1" in
    151   'install')
    152     efi_install
    153     ;;
    154   'watch')
    155     efi_watch
    156     ;;
    157   *)
    158     echo "Usage: $0 [install|watch]"
    159     echo ""
    160     echo -e "\t- install: install the kernel and initrd into your EFI."
    161     echo -e "\t- watch: install on updates to your kernel"
    162     echo ""
    163 esac