From e0a67bb6567b05f6bc7b77745002936f25ce1997 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Sun, 25 Apr 2021 01:15:38 +0200 Subject: [PATCH] OTA: Handle tar checkpointing visual feedback w/ an FBInk daemon (#7588) Instead of forking it on every checkpoint. Won't change much in the grand scheme of things, but FIFOs are fun. --- frontend/device/kindle/powerd.lua | 2 +- platform/cervantes/koreader.sh | 12 +++++++++--- platform/kindle/koreader.sh | 12 +++++++++--- platform/kobo/koreader.sh | 12 +++++++++--- platform/pocketbook/koreader.app | 10 ++++++++-- platform/remarkable/koreader.sh | 12 +++++++++--- spec/unit/device_spec.lua | 2 +- 7 files changed, 46 insertions(+), 16 deletions(-) diff --git a/frontend/device/kindle/powerd.lua b/frontend/device/kindle/powerd.lua index 5d61ee62c..3de9c9c68 100644 --- a/frontend/device/kindle/powerd.lua +++ b/frontend/device/kindle/powerd.lua @@ -94,7 +94,7 @@ function KindlePowerD:setIntensityHW(intensity) -- NOTE: when intensity is 0, we want to *really* kill the light, so do it manually -- (asking lipc to set it to 0 would in fact set it to > 0 on ! canTurnFrontlightOff Kindles). -- We do *both* to make the fl restore on resume less jarring on devices where lipc 0 != off. - os.execute("echo -n ".. intensity .." > " .. self.fl_intensity_file) + os.execute("printf '%s' ".. intensity .." > " .. self.fl_intensity_file) end end diff --git a/platform/cervantes/koreader.sh b/platform/cervantes/koreader.sh index e4dc89e85..3bdb84424 100755 --- a/platform/cervantes/koreader.sh +++ b/platform/cervantes/koreader.sh @@ -14,14 +14,19 @@ ko_update_check() { INSTALLED="${KOREADER_DIR}/ota/koreader.installed.tar" if [ -f "${NEWUPDATE}" ]; then ./fbink -q -y -7 -pmh "Updating KOReader" + # Setup the FBInk daemon + export FBINK_NAMED_PIPE="/tmp/koreader.fbink" + rm -f "${FBINK_NAMED_PIPE}" + FBINK_PID="$(./fbink --daemon 1 %KOREADER% -q -y -6 -P 0)" # NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature # NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;). FILESIZE="$(stat -c %b "${NEWUPDATE}")" BLOCKS="$((FILESIZE / 20))" export CPOINTS="$((BLOCKS / 100))" # shellcheck disable=SC2016 - ./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='./fbink -q -y -6 -P $(($TAR_CHECKPOINT/$CPOINTS))' + ./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='printf "%s" $((TAR_CHECKPOINT / CPOINTS)) > ${FBINK_NAMED_PIPE}' fail=$? + kill -TERM "${FBINK_PID}" # Cleanup behind us... if [ "${fail}" -eq 0 ]; then mv "${NEWUPDATE}" "${INSTALLED}" @@ -32,8 +37,9 @@ ko_update_check() { ./fbink -q -y -6 -pmh "Update failed :(" ./fbink -q -y -5 -pm "KOReader may fail to function properly!" fi - rm -f "${NEWUPDATE}" # always purge newupdate in all cases to prevent update loop - unset BLOCKS CPOINTS + rm -f "${NEWUPDATE}" # always purge newupdate to prevent update loops + unset CPOINTS FBINK_NAMED_PIPE + unset BLOCKS FILESIZE FBINK_PID # Ensure everything is flushed to disk before we restart. This *will* stall for a while on slow storage! sync fi diff --git a/platform/kindle/koreader.sh b/platform/kindle/koreader.sh index c17fd2c55..c8ed1829c 100755 --- a/platform/kindle/koreader.sh +++ b/platform/kindle/koreader.sh @@ -121,6 +121,10 @@ ko_update_check() { logmsg "Updating KOReader . . ." # Let our checkpoint script handle the detailed visual feedback... eips_print_bottom_centered "Updating KOReader" 3 + # Setup the FBInk daemon + export FBINK_NAMED_PIPE="/tmp/koreader.fbink" + rm -f "${FBINK_NAMED_PIPE}" + FBINK_PID="$(/var/tmp/fbink --daemon 1 %KOREADER% -q -y -6 -P 0)" # NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature # NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;). FILESIZE="$(stat -c %b "${NEWUPDATE}")" @@ -132,8 +136,9 @@ ko_update_check() { # which we cannot use because it's been mounted noexec for a few years now... cp -pf "${KOREADER_DIR}/tar" /var/tmp/gnutar # shellcheck disable=SC2016 - /var/tmp/gnutar --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='/var/tmp/fbink -q -y -6 -P $(($TAR_CHECKPOINT/$CPOINTS))' -C "/mnt/us" -xf "${NEWUPDATE}" + /var/tmp/gnutar --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='printf "%s" $((TAR_CHECKPOINT / CPOINTS)) > ${FBINK_NAMED_PIPE}' -C "/mnt/us" -xf "${NEWUPDATE}" fail=$? + kill -TERM "${FBINK_PID}" # And remove our temporary tar binary... rm -f /var/tmp/gnutar # Cleanup behind us... @@ -153,8 +158,9 @@ ko_update_check() { eips_print_bottom_centered "Update failed :(" 2 eips_print_bottom_centered "KOReader may fail to function properly" 1 fi - rm -f "${NEWUPDATE}" # always purge newupdate in all cases to prevent update loop - unset BLOCKS CPOINTS + rm -f "${NEWUPDATE}" # always purge newupdate to prevent update loops + unset CPOINTS FBINK_NAMED_PIPE + unset BLOCKS FILESIZE FBINK_PID # Ensure everything is flushed to disk before we restart. This *will* stall for a while on slow storage! sync fi diff --git a/platform/kobo/koreader.sh b/platform/kobo/koreader.sh index 0ca1913d2..a41503162 100755 --- a/platform/kobo/koreader.sh +++ b/platform/kobo/koreader.sh @@ -87,14 +87,19 @@ ko_update_check() { INSTALLED="${KOREADER_DIR}/ota/koreader.installed.tar" if [ -f "${NEWUPDATE}" ]; then ./fbink -q -y -7 -pmh "Updating KOReader" + # Setup the FBInk daemon + export FBINK_NAMED_PIPE="/tmp/koreader.fbink" + rm -f "${FBINK_NAMED_PIPE}" + FBINK_PID="$(./fbink --daemon 1 %KOREADER% -q -y -6 -P 0)" # NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature # NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;). FILESIZE="$(stat -c %b "${NEWUPDATE}")" BLOCKS="$((FILESIZE / 20))" export CPOINTS="$((BLOCKS / 100))" # shellcheck disable=SC2016 - ./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='./fbink -q -y -6 -P $(($TAR_CHECKPOINT/$CPOINTS))' + ./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='printf "%s" $((TAR_CHECKPOINT / CPOINTS)) > ${FBINK_NAMED_PIPE}' fail=$? + kill -TERM "${FBINK_PID}" # Cleanup behind us... if [ "${fail}" -eq 0 ]; then mv "${NEWUPDATE}" "${INSTALLED}" @@ -110,8 +115,9 @@ ko_update_check() { ./fbink -q -y -6 -pmh "Update failed :(" ./fbink -q -y -5 -pm "KOReader may fail to function properly!" fi - rm -f "${NEWUPDATE}" # always purge newupdate in all cases to prevent update loop - unset BLOCKS CPOINTS + rm -f "${NEWUPDATE}" # always purge newupdate to prevent update loops + unset CPOINTS FBINK_NAMED_PIPE + unset BLOCKS FILESIZE FBINK_PID # Ensure everything is flushed to disk before we restart. This *will* stall for a while on slow storage! sync fi diff --git a/platform/pocketbook/koreader.app b/platform/pocketbook/koreader.app index 0544d7346..cf8ea5529 100755 --- a/platform/pocketbook/koreader.app +++ b/platform/pocketbook/koreader.app @@ -26,6 +26,10 @@ ko_update_check() { INSTALLED="${KOREADER_DIR}/ota/koreader.installed.tar" if [ -f "${NEWUPDATE}" ]; then "${KOREADER_DIR}/fbink" -q -y -7 -pmh "Updating KOReader" + # Setup the FBInk daemon + export FBINK_NAMED_PIPE="/tmp/.koreader.fbink" + rm -f "${FBINK_NAMED_PIPE}" + FBINK_PID="$("${KOREADER_DIR}/fbink" --daemon 1 %KOREADER% -q -y -6 -P 0)" # NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature # NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;). FILESIZE="$(stat -c %b "${NEWUPDATE}")" @@ -35,8 +39,9 @@ ko_update_check() { # c.f., https://github.com/koreader/koreader/issues/7581 KO_PB_TARLOG="/tmp/.koreader.tar" # shellcheck disable=SC2016 - "${KOREADER_DIR}/tar" --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='${KOREADER_DIR}/fbink -q -y -6 -P $(($TAR_CHECKPOINT/$CPOINTS))' -C "/mnt/ext1" -xf "${NEWUPDATE}" 2>"${KO_PB_TARLOG}" + "${KOREADER_DIR}/tar" --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='printf "%s" $((TAR_CHECKPOINT / CPOINTS)) > ${FBINK_NAMED_PIPE}' -C "/mnt/ext1" -xf "${NEWUPDATE}" 2>"${KO_PB_TARLOG}" fail=$? + kill -TERM "${FBINK_PID}" # As mentioned above, filter out potential chmod & utime failures... if [ "${fail}" -ne 0 ]; then if [ "$(grep -Evc '(Cannot utime|Cannot change mode|Exiting with failure status due to previous errors)' "${KO_PB_TARLOG}")" -eq "0" ]; then @@ -56,7 +61,8 @@ ko_update_check() { "${KOREADER_DIR}/fbink" -q -y -5 -pm "KOReader may fail to function properly!" fi rm -f "${NEWUPDATE}" # always purge newupdate to prevent update loops - unset BLOCKS CPOINTS + unset CPOINTS FBINK_NAMED_PIPE + unset BLOCKS FILESIZE FBINK_PID # Ensure everything is flushed to disk before we restart. This *will* stall for a while on slow storage! sync fi diff --git a/platform/remarkable/koreader.sh b/platform/remarkable/koreader.sh index f0b8975c1..d950cfa67 100755 --- a/platform/remarkable/koreader.sh +++ b/platform/remarkable/koreader.sh @@ -30,14 +30,19 @@ ko_update_check() { fi ./fbink -q -y -7 -pmh "Updating KOReader" + # Setup the FBInk daemon + export FBINK_NAMED_PIPE="/tmp/koreader.fbink" + rm -f "${FBINK_NAMED_PIPE}" + FBINK_PID="$(./fbink --daemon 1 %KOREADER% -q -y -6 -P 0)" # NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature # NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;). FILESIZE="$(stat -c %b "${NEWUPDATE}")" BLOCKS="$((FILESIZE / 20))" export CPOINTS="$((BLOCKS / 100))" # shellcheck disable=SC2016 - ./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='./fbink -q -y -6 -P $(($TAR_CHECKPOINT/$CPOINTS))' + ./tar xf "${NEWUPDATE}" --strip-components=1 --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='printf "%s" $((TAR_CHECKPOINT / CPOINTS)) > ${FBINK_NAMED_PIPE}' fail=$? + kill -TERM "${FBINK_PID}" # Cleanup behind us... if [ "${fail}" -eq 0 ]; then mv "${NEWUPDATE}" "${INSTALLED}" @@ -48,8 +53,9 @@ ko_update_check() { ./fbink -q -y -6 -pmh "Update failed :(" ./fbink -q -y -5 -pm "KOReader may fail to function properly!" fi - rm -f "${NEWUPDATE}" # always purge newupdate in all cases to prevent update loop - unset BLOCKS CPOINTS + rm -f "${NEWUPDATE}" # always purge newupdate to prevent update loops + unset CPOINTS FBINK_NAMED_PIPE + unset BLOCKS FILESIZE FBINK_PID # Ensure everything is flushed to disk before we restart. This *will* stall for a while on slow storage! busybox sync diff --git a/spec/unit/device_spec.lua b/spec/unit/device_spec.lua index 2fa4d7de5..f85c8bace 100644 --- a/spec/unit/device_spec.lua +++ b/spec/unit/device_spec.lua @@ -242,7 +242,7 @@ describe("device module", function() kindle_dev.powerd:toggleFrontlight() assert.stub(os.execute).was_called_with( - "echo -n 0 > /sys/class/backlight/max77696-bl/brightness") + "printf '%s' 0 > /sys/class/backlight/max77696-bl/brightness") -- Here be shenanigans: we don't override powerd's fl_intensity when we turn the light off, -- so that we can properly turn it back on at the previous intensity ;) assert.is.same(kindle_dev.powerd.fl_intensity, 5)