Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/sh
- #
- # Hybris adaptation bootstrapping initramfs init script.
- #
- # Copyright (c) 2014 Jolla Oy
- #
- # This program is free software; you can redistribute it and/or modify it under
- # the terms of the GNU General Public License version 2 as published by the
- # Free Software Foundation.
- #
- # Authors:
- # - Tom Swindell <t.swindell@rubyx.co.uk>
- # - David Greaves <david@dgreaves.com>
- #
- # This init script runs in early boot in initrd and does a switch_root
- # to the real rootfs. It can also be copied into rootfs and provide
- # monitoring of the boot process there too.
- # Be careful - you can't run any external commands until busybox has installed.
- # General logging
- set -x
- exec > /init.log 2>&1
- echo "Running Mer Boat Loader"
- BOOTLOGO=
- ALWAYSDEBUG=
- DATA_PARTITION=/dev/store/cm-data
- DEFAULT_OS=sailfishos
- set_welcome_msg(){
- cat <<EOF > /etc/issue.net
- Welcome to the Mer/SailfishOS Boat loader debug init system.
- Log so far is in /init.log
- To make post-switch_root halt before starting systemd, perform:
- EOF
- if [ "$DONE_SWITCH" = "no" ]; then
- cat <<EOF >> /etc/issue.net
- touch /target/init_enter_debug2
- EOF
- else
- cat <<EOF >> /etc/issue.net
- touch /init_enter_debug2
- EOF
- fi
- cat <<EOF >> /etc/issue.net
- (When run post-switch_root, telnet is on port 2323, not 23)
- EOF
- HALT_BOOT="${1:-y}"
- if [ "$HALT_BOOT" = "y" ]; then
- cat <<EOF >> /etc/issue.net
- You may inject commands into init shell process (PID 1):
- To see output of commands as they're injected:
- tail -f /init.log &
- To run a command:
- echo "ls -l /" >/init-ctl/stdin
- (Be careful if you experiment with exec as you need to terminate
- daemons and disable busybox hotplug handling)
- To allow init to continue:
- echo "continue" >/init-ctl/stdin
- EOF
- fi
- if [ "$DONE_SWITCH" = "no" ]; then
- cat <<EOF >> /etc/issue.net
- In order to work safely with the device's mmc you should
- echo "umount_stowaways" >/init-ctl/stdin
- Then you can mount and modify exported mass storage on host. When done
- echo "mount_stowaways" >/init-ctl/stdin
- EOF
- fi
- }
- export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
- # Default setting is rndis - add mass_storage for a debug boot
- # enable using usb_setup
- USB_FUNCTIONS=rndis
- ANDROID_USB=/sys/class/android_usb/android0
- GADGET_DIR=/config/usb_gadget
- LOCAL_IP=192.168.2.15
- DONE_SWITCH=no
- # Are we running in real rootfs
- if [ "$0" = "/init-debug" ]; then
- DONE_SWITCH=yes
- fi
- # Get options from kernel command line
- get_opt() {
- for param in $(cat /proc/cmdline); do
- echo "$param" | grep "^$1=*" | cut -d'=' -f2
- done
- }
- # Minimal mounts for initrd or pre-init debug session
- do_mount_devprocsys()
- {
- echo "########################## mounting devprocsys"
- mkdir /dev
- mount -t devtmpfs devtmpfs /dev
- # telnetd needs /dev/pts/ entries
- mkdir /dev/pts
- mount -t devpts devpts /dev/pts
- mkdir /proc
- mkdir /sys
- mount -t sysfs sysfs /sys
- mount -t proc proc /proc
- mkdir /config
- mount -t configfs none /config
- }
- do_hotplug_scan()
- {
- echo /sbin/mdev > /proc/sys/kernel/hotplug
- mdev -s
- # There is no way to know when all hotplug events have been processed :(
- sleep 2
- }
- bootsplash() {
- if [ x$BOOTLOGO = x1 ]; then
- zcat /bootsplash.gz > /dev/fb0
- fi
- }
- mount_stowaways() {
- echo "########################## mounting stowaways"
- if [ ! -z $DATA_PARTITION ]; then
- echo "[initramfs] Activating LVM..."
- mkdir /boot
- mount -o ro -t ext3 /dev/mmcblk0p13 /boot
- LVM_SYSTEM_DIR=/boot/etc/lvm /boot/usr/sbin/lvm.static vgscan
- sleep 2
- LVM_SYSTEM_DIR=/boot/etc/lvm /boot/usr/sbin/lvm.static vgmknodes
- sleep 2
- LVM_SYSTEM_DIR=/boot/etc/lvm /boot/usr/sbin/lvm.static vgchange -a y
- umount /boot
- data_subdir="$(get_opt data_subdir)"
- mkdir /data
- mkdir /target
- mount $DATA_PARTITION /data
- ln -s /data/media/0/.stowaways /data
- mount --bind /data/${data_subdir}/.stowaways/${DEFAULT_OS} /target
- mkdir /target/data # in new fs
- mount --bind /data/${data_subdir} /target/data
- else
- echo "Failed to mount /target, device node '$DATA_PARTITION' not found!" >> /diagnosis.log
- fi
- mount
- }
- umount_stowaways() {
- if [ ! -z $DATA_PARTITION ]; then
- umount /target/data
- umount /target
- umount /data
- fi
- }
- # Sugar for accessing usb config
- write() {
- echo -n "$2" > "$1"
- }
- inject_loop() {
- INJ_DIR=/init-ctl
- INJ_STDIN=$INJ_DIR/stdin
- mkdir $INJ_DIR
- mkfifo $INJ_STDIN
- echo "This entire directory is for debugging init - it can safely be removed" > $INJ_DIR/README
- echo "########################## Beginning inject loop"
- while : ; do
- while read IN; do
- if [ "$IN" = "continue" ]; then break 2;fi
- $IN
- done <$INJ_STDIN
- done
- rm -rf $INJ_DIR # Clean up if we exited nicely
- echo "########################## inject loop done"
- }
- # This sets up the USB with whatever USB_FUNCTIONS are set to via configfs
- usb_setup_configfs() {
- G_USB_ISERIAL=$GADGET_DIR/g1/strings/0x409/serialnumber
- mkdir $GADGET_DIR/g1
- write $GADGET_DIR/g1/idVendor "0x18D1"
- write $GADGET_DIR/g1/idProduct "0xD001"
- mkdir $GADGET_DIR/g1/strings/0x409
- write $GADGET_DIR/g1/strings/0x409/serialnumber "$1"
- write $GADGET_DIR/g1/strings/0x409/manufacturer "Mer Boat Loader"
- write $GADGET_DIR/g1/strings/0x409/product "$CUSTOMPRODUCT"
- if echo $USB_FUNCTIONS | grep -q "rndis"; then
- mkdir $GADGET_DIR/g1/functions/rndis.usb0
- mkdir $GADGET_DIR/g1/functions/rndis_bam.rndis
- fi
- echo $USB_FUNCTIONS | grep -q "mass_storage" && mkdir $GADGET_DIR/g1/functions/storage.0
- mkdir $GADGET_DIR/g1/configs/c.1
- mkdir $GADGET_DIR/g1/configs/c.1/strings/0x409
- write $GADGET_DIR/g1/configs/c.1/strings/0x409/configuration "$USB_FUNCTIONS"
- if echo $USB_FUNCTIONS | grep -q "rndis"; then
- ln -s $GADGET_DIR/g1/functions/rndis.usb0 $GADGET_DIR/g1/configs/c.1
- ln -s $GADGET_DIR/g1/functions/rndis_bam.rndis $GADGET_DIR/g1/configs/c.1
- fi
- echo $USB_FUNCTIONS | grep -q "mass_storage" && ln -s $GADGET_DIR/g1/functions/storage.0 $GADGET_DIR/g1/configs/c.1
- echo "$(ls /sys/class/udc)" > $GADGET_DIR/g1/UDC
- }
- # This sets up the USB with whatever USB_FUNCTIONS are set to via android_usb
- usb_setup_android_usb() {
- G_USB_ISERIAL=$ANDROID_USB/iSerial
- write $ANDROID_USB/enable 0
- write $ANDROID_USB/functions ""
- write $ANDROID_USB/enable 1
- usleep 500000 # 0.5 delay to attempt to remove rndis function
- write $ANDROID_USB/enable 0
- write $ANDROID_USB/idVendor 18D1
- write $ANDROID_USB/idProduct D001
- write $ANDROID_USB/iManufacturer "Mer Boat Loader"
- write $ANDROID_USB/iProduct "$CUSTOMPRODUCT"
- write $ANDROID_USB/iSerial "$1"
- write $ANDROID_USB/functions $USB_FUNCTIONS
- write $ANDROID_USB/enable 1
- }
- # This determines which USB setup method is going to be used
- usb_setup() {
- if [ -d $ANDROID_USB ]; then
- usb_setup_android_usb $1
- elif [ -d $GADGET_DIR ]; then
- usb_setup_configfs $1
- fi
- }
- # This lets us communicate errors to host (if it needs disable/enable then that's a problem)
- usb_info() {
- # make sure USB is settled
- echo "########################## usb_info: $1"
- sleep 1
- write $G_USB_ISERIAL "$1"
- }
- run_debug_session() {
- CUSTOMPRODUCT=$1
- echo "########################## Debug session : $1"
- usb_setup "Mer Debug setting up (DONE_SWITCH=$DONE_SWITCH)"
- USB_IFACE=notfound
- /sbin/ifconfig rndis0 $LOCAL_IP && USB_IFACE=rndis0
- if [ x$USB_IFACE = xnotfound ]; then
- /sbin/ifconfig usb0 $LOCAL_IP && USB_IFACE=usb0
- fi
- # Report for the logs
- /sbin/ifconfig -a
- # Unable to set up USB interface? Reboot.
- if [ x$USB_IFACE = xnotfound ]; then
- usb_info "Mer Debug: ERROR: could not setup USB as usb0 or rndis0"
- dmesg
- sleep 60 # plenty long enough to check usb on host
- reboot -f
- fi
- # Create /etc/udhcpd.conf file.
- echo "start 192.168.2.20" > /etc/udhcpd.conf
- echo "end 192.168.2.90" >> /etc/udhcpd.conf
- echo "lease_file /var/udhcpd.leases" >> /etc/udhcpd.conf
- echo "interface $USB_IFACE" >> /etc/udhcpd.conf
- echo "option subnet 255.255.255.0" >> /etc/udhcpd.conf
- # Be explicit about busybox so this works in a rootfs too
- echo "########################## starting dhcpd"
- $EXPLICIT_BUSYBOX udhcpd
- HALT_BOOT="${2:-y}"
- set_welcome_msg $HALT_BOOT
- if [ -z $DISABLE_TELNET ]; then
- # Non-blocking telnetd
- echo "########################## starting telnetd"
- # We run telnetd on different ports pre/post-switch_root This
- # avoids problems with an unterminated pre-switch_root telnetd
- # hogging the port
- $EXPLICIT_BUSYBOX telnetd -b ${LOCAL_IP}:${TELNET_DEBUG_PORT} -l /bin/sh
- # For some reason this does not work in rootfs
- usb_info "Mer Debug telnet on port $TELNET_DEBUG_PORT on $USB_IFACE $LOCAL_IP - also running udhcpd"
- fi
- if [ "$HALT_BOOT" = "y" ]; then
- # Some logging output
- ps -wlT
- ps -ef
- netstat -lnp
- cat /proc/mounts
- sync
- # Run command injection loop = can be exited via 'continue'
- inject_loop
- fi
- }
- # writes to /diagnosis.log if there's a problem
- check_kernel_config() {
- echo "Checking kernel config"
- if [ ! -e /proc/config.gz ]; then
- echo "No /proc/config.gz. Enable CONFIG_IKCONFIG and CONFIG_IKCONFIG_PROC" >> /diagnosis.log
- else
- # Must be =y
- for x in CONFIG_CGROUPS CONFIG_AUTOFS4_FS CONFIG_DEVTMPFS_MOUNT CONFIG_DEVTMPFS CONFIG_UNIX CONFIG_INOTIFY_USER CONFIG_SYSVIPC CONFIG_NET CONFIG_PROC_FS CONFIG_SIGNALFD CONFIG_SYSFS CONFIG_TMPFS_POSIX_ACL CONFIG_VT; do
- zcat /proc/config.gz | grep -E "^$x=y\$" || echo "$x=y not found in /proc/config.gz" >> /diagnosis.log
- done
- # Must not be =y
- for x in CONFIG_DUMMY CONFIG_SYSFS_DEPRECATED; do
- zcat /proc/config.gz | grep -E "^$x=y\$" && echo "$x=y found in /proc/config.gz, must be disabled" >> /diagnosis.log
- done
- fi
- }
- # Now either initrd or rootfs sequence
- if [ "$DONE_SWITCH" = "no" ]; then
- EXPLICIT_BUSYBOX=""
- TELNET_DEBUG_PORT=23
- /bin/busybox --install -s
- date
- do_mount_devprocsys
- do_hotplug_scan
- # Support /dev/mmcXXX only in initrd phase
- ln -s . /dev/block
- ln -s /proc/mounts /etc/mtab
- check_kernel_config
- bootsplash
- mount_stowaways
- # No target debug unless we debug here too (for now)
- DBG_REASON=""
- [ -e /diagnosis.log ] && DBG_REASON="Refusing to boot. See /diagnosis.log (in initrd only)"
- [ "$(get_opt bootmode)" = "debug" ] && DBG_REASON="bootmode=debug on kernel command line"
- [ x$ALWAYSDEBUG = x1 ] && DBG_REASON="Always debug: rndis + mass_storage"
- [ -f /target/init_enter_debug ] && DBG_REASON="/init_enter_debug exists"
- [ -f /target/init_disable_telnet ] && DISABLE_TELNET="y"
- if ! [ "$DBG_REASON" = "" ] ; then
- # During debug we export mmc too (some variations in location here)
- lun=/sys/class/android_usb/f_mass_storage/lun/file
- if [ -f $lun ]; then echo /dev/mmcblk0 > $lun; fi
- lun=/sys/class/android_usb/f_mass_storage/lun0/file
- if [ -f $lun ]; then echo /dev/mmcblk0 > $lun; fi
- USB_FUNCTIONS=rndis,mass_storage
- run_debug_session $DBG_REASON
- # Tidy up before we switch_root (rootfs init-debug leaves these running during bootup)
- killall telnetd
- killall udhcpd
- USB_FUNCTIONS=rndis
- usb_setup "Mer Debug: done debug, disabling storage"
- fi
- # Disable mdev hotplug now - let udev handle it in main boot
- echo "" > /proc/sys/kernel/hotplug
- if [ -f "/target/init-debug" ]; then
- exec switch_root /target /init-debug &> /target/init-debug-stderrout
- else
- # Prefer /sbin/preinit over /sbin/init
- [ -x /target/sbin/preinit ] && INIT=/sbin/preinit || INIT=/sbin/init
- if [ -x "/target$INIT" ]; then
- exec switch_root /target $INIT --log-level=debug --log-target=kmsg &> /target/init-stderrout
- fi
- fi
- run_debug_session "Failed to boot init in real rootfs"
- else
- # We're in the real rootfs running as init-debug
- EXPLICIT_BUSYBOX="/bin/busybox-static"
- TELNET_DEBUG_PORT=2323
- do_mount_devprocsys
- HALT_BOOT="n"
- [ -f /init_enter_debug2 ] && HALT_BOOT="y"
- [ -f /init_disable_telnet ] && DISABLE_TELNET="y"
- run_debug_session "init-debug in real rootfs" $HALT_BOOT
- # If we don't do this then udev will not be able to create /dev/*
- rm /dev/block
- # Now try to boot the real init
- # Prefer /sbin/preinit over /sbin/init
- [ -x /sbin/preinit ] && INIT=/sbin/preinit || INIT=/sbin/init
- exec $INIT --log-level=debug --log-target=kmsg &> /boot/systemd_stdouterr
- run_debug_session "init in real rootfs failed"
- fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement