#!/system/bin/sh ### Rozhuk Ivan 2018-2023 ### optstart.sh ### # Workaround to find 'dirname' on system, at least at /system/xbin - busybox. export PATH=/bin:/sbin:/system/bin:/system/xbin export THIS_SCRIPT_NAME=`readlink -nf "${0}"` export OPT_BIN_DIR=`dirname "${THIS_SCRIPT_NAME}"` export OPT_ROOT_DIR=`dirname "${OPT_BIN_DIR}"` export OPT_ROOT_PARENT_DIR=`dirname "${OPT_ROOT_DIR}"` # Restore PATH. export PATH=${OPT_ROOT_DIR}/bin:${OPT_ROOT_DIR}/sbin:/bin:/sbin:/system/bin:/system/xbin MNT_POINT_LIST='/ /system /system_ext /system/system_ext' echo "optstart.sh: ${0}: init entware: ${OPT_ROOT_DIR}" > /dev/kmsg # Sleep for few random seconds to reduce possible concurence. # Use last digit of shell PID as random. sleep `echo ${$} | tr -d '\n' | tail -c1` # Check is we need run. if [ -f "${OPT_ROOT_DIR}/var/run/entware_init_done" ]; then echo "optstart.sh: ${0}: entware already initialized." > /dev/kmsg return 0 fi # Check user/selinux context. if [ -f '/system/bin/id' ]; then __SELINUX_CONTEXT=`/system/bin/id -Z` case "${__SELINUX_CONTEXT}" in (*'u:r:su:s0'*|*'magisk'*) # 'u:r:su:s0', 'context=u:r:magisk:s0' echo "optstart.sh: ${0}: running as ${__SELINUX_CONTEXT}." > /dev/kmsg ;; *) # Try to change SeLinux context to magisk. echo "optstart.sh: ${0}: need to re run ${THIS_SCRIPT_NAME} as root@magisk." > /dev/kmsg if [ -f '/sbin/su' ]; then /sbin/su sh -c "${THIS_SCRIPT_NAME}" > /dev/kmsg 2>&1 return 0 fi if [ -f '/system/bin/su' ]; then /system/bin/su sh -c "${THIS_SCRIPT_NAME}" > /dev/kmsg 2>&1 return 0 fi echo "optstart.sh: ${0}: su not found, expect fail to start." > /dev/kmsg ;; esac fi # Prepare rootfs. if [ ! -e '/opt' ] || [ ! -e '/etc' ] || [ ! -e '/bin' ]; then # Unprotect. /system/bin/mount -o rw,remount '/' > /dev/kmsg 2>&1 # Make /opt. if [ ! -e '/opt' ]; then # Prefer dir+mount by historic reasons with samsung devices. mkdir -p '/opt' > /dev/kmsg 2>&1 if [ -d '/opt' ]; then chmod 0755 '/opt' > /dev/kmsg 2>&1 else # Probably not enough space. ln -sf "${OPT_ROOT_DIR}" '/' > /dev/kmsg 2>&1 fi /system/bin/chcon 'u:object_r:system_file:s0' '/opt' > /dev/kmsg 2>&1 fi # Make /etc. if [ ! -e '/etc' ]; then ln -sf '/system/etc' '/' > /dev/kmsg 2>&1 fi # Make /bin and sh. if [ ! -e '/bin' ]; then ln -sf "/system/bin" '/' > /dev/kmsg 2>&1 fi # Protect again. /system/bin/mount -o ro,remount '/' > /dev/kmsg 2>&1 fi # Mount staff. _bind_file_opt2sys() { # filename local __SRC="${OPT_ROOT_DIR}/etc/${1}" local __DST="/system/etc/${1}" # Is source file exist? [ ! -f "${__SRC}" ] && return 0 # Is target file exist and it is not symlink? if [ ! -f "${__DST}" ] || [ -L "${__DST}" ]; then # Remount as RW. for __MNT_POINT in ${MNT_POINT_LIST}; do [ ! -r "${__MNT_POINT}" ] && continue /system/bin/mount -o rw,remount "${__MNT_POINT}" > /dev/null 2>&1 done # Create empty file. rm -f "${__DST}" > /dev/kmsg 2>&1 touch "${__DST}" > /dev/kmsg 2>&1 chmod 0644 "${__DST}" > /dev/kmsg 2>&1 chown 0:0 "${__DST}" > /dev/kmsg 2>&1 /system/bin/chcon 'u:object_r:system_file:s0' "${__DST}" > /dev/kmsg 2>&1 # Remount as RO. for __MNT_POINT in ${MNT_POINT_LIST}; do [ ! -r "${__MNT_POINT}" ] && continue /system/bin/mount -o ro,remount "${__MNT_POINT}" > /dev/null 2>&1 done fi # Mount bind. /system/bin/mount -o ro,bind "${__SRC}" "${__DST}" > /dev/kmsg 2>&1 } _link_file_opt2sys() { # filename local __SRC="${OPT_ROOT_DIR}/etc/${1}" local __DST="/system/etc/${1}" # Is source file exist? [ ! -f "${__SRC}" ] && return 0 # Is target file exist and point to proper location? [ "${__SRC}" == `readlink -nf "${__DST}"` ] && return 0 # Remount as RW. for __MNT_POINT in ${MNT_POINT_LIST}; do [ ! -r "${__MNT_POINT}" ] && continue /system/bin/mount -o rw,remount "${__MNT_POINT}" > /dev/null 2>&1 done # Create symlink. rm -f "${__DST}" > /dev/kmsg 2>&1 ln -sfv "${__SRC}" '/system/etc/' > /dev/kmsg 2>&1 chmod 0644 "${__DST}" > /dev/kmsg 2>&1 chown 0:0 "${__DST}" > /dev/kmsg 2>&1 /system/bin/chcon 'u:object_r:system_file:s0' "${__DST}" > /dev/kmsg 2>&1 # Remount as RO. for __MNT_POINT in ${MNT_POINT_LIST}; do [ ! -r "${__MNT_POINT}" ] && continue /system/bin/mount -o ro,remount "${__MNT_POINT}" > /dev/null 2>&1 done } # Mount /opt root, if not symlinked. if [ -d '/opt' ] && [ ! -L '/opt' ]; then /system/bin/mount -o rw,bind "${OPT_ROOT_DIR}" '/opt' > /dev/kmsg 2>&1 fi # Mount tmpfs. /system/bin/mount -t tmpfs -o rw,nosuid,nodev,size=32m tmpfs "${OPT_ROOT_DIR}/tmp" > /dev/kmsg 2>&1 /system/bin/mount -t tmpfs -o rw,nosuid,nodev,size=8m tmpfs "${OPT_ROOT_DIR}/var/log" > /dev/kmsg 2>&1 /system/bin/mount -t tmpfs -o rw,nosuid,nodev,size=2m tmpfs "${OPT_ROOT_DIR}/var/run" > /dev/kmsg 2>&1 # Bind files. # Hosts file not work on Android 12+ if it symlink. _bind_file_opt2sys 'hosts' # Link files. # entware build busybox with glibc, it requires /etc/resolv.conf and # /etc/nsswitch.conf to resolve domain names. for __FILE2SYS in 'group' 'passwd' 'nsswitch.conf' 'resolv.conf'; do _link_file_opt2sys "${__FILE2SYS}" done # Mark here as started, service init may take long time. touch "${OPT_ROOT_DIR}/var/run/entware_init_done" # Start services. # Make sure tha SSH bootstrap done. if [ ! -s "${OPT_ROOT_DIR}/etc/ssh/ssh_host_rsa_key" ] || \ [ ! -s "${OPT_ROOT_DIR}/etc/ssh/ssh_host_ecdsa_key" ] || \ [ ! -s "${OPT_ROOT_DIR}/etc/ssh/ssh_host_ed25519_key" ]; then # Remount as RW. for __MNT_POINT in ${OPT_ROOT_PARENT_DIR} ${OPT_ROOT_DIR} '/opt'; do [ ! -r "${__MNT_POINT}" ] && continue /system/bin/mount -o rw,remount "${__MNT_POINT}" > /dev/null 2>&1 done # Generating SSH host keys. ${OPT_ROOT_DIR}/bin/ssh-keygen -A # Remount as RO. for __MNT_POINT in ${OPT_ROOT_PARENT_DIR} ${OPT_ROOT_DIR} '/opt'; do [ ! -r "${__MNT_POINT}" ] && continue /system/bin/mount -o ro,remount "${__MNT_POINT}" > /dev/null 2>&1 done fi unset LD_LIBRARY_PATH unset LD_PRELOAD ${OPT_ROOT_DIR}/etc/init.d/rc.unslung start > /dev/kmsg 2>&1 echo "optstart.sh: ${0}: entware init done." > /dev/kmsg # Workaround: after this process exit init system may kill all child # zombie processes to cleanup resources. # Loop forever. while true; do sleep 60000; done