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