/
koreader.sh
executable file
·243 lines (215 loc) · 9.93 KB
/
koreader.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#!/bin/sh
export LC_ALL="en_US.UTF-8"
# working directory of koreader
KOREADER_DIR="${0%/*}"
# we're always starting from our working directory
cd "${KOREADER_DIR}" || exit
# Attempt to switch to a sensible CPUFreq governor when that's not already the case...
current_cpufreq_gov="$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)"
# NOTE: We're being fairly conservative here, because what's used and what's available varies depending on HW...
if [ "${current_cpufreq_gov}" != "ondemand" ] && [ "${current_cpufreq_gov}" != "interactive" ]; then
# NOTE: Go with ondemand, because it's likely to be the lowest common denominator.
# Plus, interactive is hard to tune right, and only really interesting when it's a recent version,
# which I somehow doubt is the case anywhere here...
if grep -q ondemand /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors; then
ORIG_CPUFREQ_GOV="${current_cpufreq_gov}"
echo "ondemand" >"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
fi
fi
# NOTE: That doesn't actually help us poor userspace plebs, but, short of switching to performance,
# I don't really have a golden bullet here... (conservative's rubberbanding is terrible, so that's a hard pass).
# All I can say is that userspace is a terrible idea and behaves *very* strangely (c.f., #4114).
# update to new version from OTA directory
ko_update_check() {
NEWUPDATE="${KOREADER_DIR}/ota/koreader.updated.tar"
INSTALLED="${KOREADER_DIR}/ota/koreader.installed.tar"
if [ -f "${NEWUPDATE}" ]; then
./fbink -q -y -7 -pmh "Updating KOReader"
# 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))'
fail=$?
# Cleanup behind us...
if [ "${fail}" -eq 0 ]; then
mv "${NEWUPDATE}" "${INSTALLED}"
./fbink -q -y -6 -pm "Update successful :)"
./fbink -q -y -5 -pm "KOReader will start momentarily . . ."
else
# Huh ho...
./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
fi
}
# NOTE: Keep doing an initial update check, in addition to one during the restart loop, so we can pickup potential updates of this very script...
ko_update_check
# If an update happened, and was successful, reexec
if [ -n "${fail}" ] && [ "${fail}" -eq 0 ]; then
# By now, we know we're in the right directory, and our script name is pretty much set in stone, so we can forgo using $0
exec ./koreader.sh "${@}"
fi
# load our own shared libraries if possible
export LD_LIBRARY_PATH="${KOREADER_DIR}/libs:${LD_LIBRARY_PATH}"
# export trained OCR data directory
export TESSDATA_PREFIX="data"
# export dict directory
export STARDICT_DATA_DIR="data/dict"
# export external font directory
export EXT_FONT_DIR="/mnt/onboard/fonts"
# fast and dirty way of check if we are called from nickel
# through fmon/KFMon, or from another launcher (KSM or advboot)
# Do not delete this line because KSM detects newer versions of KOReader by the presence of the phrase 'from_nickel'.
export FROM_NICKEL="false"
if pkill -0 nickel; then
FROM_NICKEL="true"
fi
if [ "${FROM_NICKEL}" = "true" ]; then
# Detect if we were started from KFMon
FROM_KFMON="false"
if pkill -0 kfmon; then
# That's a start, now check if KFMon truly is our parent...
if [ "$(pidof kfmon)" -eq "${PPID}" ]; then
FROM_KFMON="true"
fi
fi
# Siphon a few things from nickel's env (namely, stuff exported by rcS *after* on-animator.sh has been launched)...
eval "$(xargs -n 1 -0 <"/proc/$(pidof nickel)/environ" | grep -e DBUS_SESSION_BUS_ADDRESS -e NICKEL_HOME -e WIFI_MODULE -e LANG -e WIFI_MODULE_PATH -e INTERFACE 2>/dev/null)"
export DBUS_SESSION_BUS_ADDRESS NICKEL_HOME WIFI_MODULE LANG WIFI_MODULE_PATH INTERFACE
# flush disks, might help avoid trashing nickel's DB...
sync
# stop kobo software because it's running
# NOTE: We don't need to kill KFMon, it's smart enough not to allow running anything else while we're up
killall -TERM nickel hindenburg sickel fickel fmon 2>/dev/null
fi
# fallback for old fmon, KFMon and advboot users (-> if no args were passed to the script, start the FM)
if [ "$#" -eq 0 ]; then
args="/mnt/onboard"
else
args="$*"
fi
# check whether PLATFORM & PRODUCT have a value assigned by rcS
if [ ! -n "${PRODUCT}" ]; then
PRODUCT="$(/bin/kobo_config.sh 2>/dev/null)"
export PRODUCT
fi
# PLATFORM is used in koreader for the path to the WiFi drivers (as well as when restarting nickel)
if [ ! -n "${PLATFORM}" ]; then
PLATFORM="freescale"
if dd if="/dev/mmcblk0" bs=512 skip=1024 count=1 | grep -q "HW CONFIG"; then
CPU="$(ntx_hwconfig -s -p /dev/mmcblk0 CPU 2>/dev/null)"
PLATFORM="${CPU}-ntx"
fi
if [ "${PLATFORM}" != "freescale" ] && [ ! -e "/etc/u-boot/${PLATFORM}/u-boot.mmc" ]; then
PLATFORM="ntx508"
fi
export PLATFORM
fi
# Make sure we have a sane-ish INTERFACE env var set...
if [ ! -n "${INTERFACE}" ]; then
# That's what we used to hardcode anyway
INTERFACE="eth0"
export INTERFACE
fi
# end of value check of PLATFORM
# If we're on a Forma, make sure we start in an orientation we know how to handle (i.e., Portrait, buttons on the Right)
# Because NTX likes mounting panels in weird native rotations, this is actually FB_ROTATE_CCW (3).
# And because shit gets even weirder, we have to echo 1 to get 3 (possibly because 2 is the native rotation, and 3 ^ 2 = 1).
if [ "${PRODUCT}" = "frost" ]; then
# Only mess with this if we were started from Nickel
if [ "${FROM_NICKEL}" = "true" ]; then
# Don't do anything if we're already in the right orientation.
if [ "$(cat /sys/class/graphics/fb0/rotate)" -ne "3" ]; then
echo 1 >/sys/class/graphics/fb0/rotate
# Sleep a bit, for good measure
usleep 250000
fi
fi
fi
# NOTE: We don't have to restore anything on exit, nickel's startup process will take care of everything (pickel -> nickel).
# In the same vein, swap to 8bpp,
# because 16bpp is the worst idea in the history of time, as RGB565 is generally a PITA without hardware blitting,
# and 32bpp usually gains us nothing except a performance hit (we're not Qt5 with its QPainter constraints).
# The reduced size & complexity should hopefully make things snappier,
# (and hopefully prevent the JIT for going crazy on high-density screens...).
# NOTE: Even though pickel/Nickel appear to restore their preferred fb setup, we'll have to do it ourselves,
# because things are a bit wonky otherwise. Plus, we get to play nice with every launch method that way.
# So, remember the current bitdepth, so we can restore it on exit.
ORIG_FB_BPP="$(./fbdepth -g)"
# Sanity check...
case "${ORIG_FB_BPP}" in
16) ;;
32) ;;
*)
# Hu oh? Don't do anything...
unset ORIG_FB_BPP
;;
esac
# The actual swap is done in a function, because we can disable it in the Developer settings, and we want to honor it on restart.
ko_do_fbdepth() {
# Check if the swap has been disabled...
if grep -q '\["dev_startup_no_fbdepth"\] = true' 'settings.reader.lua' 2>/dev/null; then
# Swap back to the original bitdepth (in case this was a restart)
if [ -n "${ORIG_FB_BPP}" ]; then
./fbdepth -d "${ORIG_FB_BPP}" >>crash.log 2>&1
fi
else
# Swap to 8bpp if things looke sane
if [ -n "${ORIG_FB_BPP}" ]; then
./fbdepth -d 8 >>crash.log 2>&1
fi
fi
}
# Remount the SD card RW if it's inserted and currently RO
if awk '$4~/(^|,)ro($|,)/' /proc/mounts | grep ' /mnt/sd '; then
mount -o remount,rw /mnt/sd
fi
# we keep at most 500KB worth of crash log
if [ -e crash.log ]; then
tail -c 500000 crash.log >crash.log.new
mv -f crash.log.new crash.log
fi
RETURN_VALUE=85
while [ $RETURN_VALUE -eq 85 ]; do
# Do an update check now, so we can actually update KOReader via the "Restart KOReader" menu entry ;).
ko_update_check
# Do the fb depth switch, unless it's been disabled
ko_do_fbdepth
./reader.lua "${args}" >>crash.log 2>&1
RETURN_VALUE=$?
done
# Restore original fb bitdepth if need be...
if [ -n "${ORIG_FB_BPP}" ]; then
./fbdepth -d "${ORIG_FB_BPP}" >>crash.log 2>&1
fi
# Restore original CPUFreq governor if need be...
if [ -n "${ORIG_CPUFREQ_GOV}" ]; then
echo "${ORIG_CPUFREQ_GOV}" >"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
fi
if [ "${FROM_NICKEL}" = "true" ]; then
if [ "${FROM_KFMON}" != "true" ]; then
# start kobo software because it was running before koreader
./nickel.sh &
else
if grep -q "reboot_on_exit=false" "/mnt/onboard/.adds/kfmon/config/koreader.ini" 2>/dev/null; then
# KFMon asked us to restart nickel on exit (default since KFMon 0.9.5)
./nickel.sh &
else
# KFMon asked us to restart the device on exit
/sbin/reboot
fi
fi
else
# if we were called from advboot then we must reboot to go to the menu
# NOTE: This is actually achieved by checking if KSM or a KSM-related script is running:
# This might lead to false-positives if you use neither KSM nor advboot to launch KOReader *without nickel running*.
if ! pgrep -f kbmenu >/dev/null 2>&1; then
/sbin/reboot
fi
fi
exit $RETURN_VALUE