#!/bin/sh -Cefu set -Cefu export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin mode="${1:-}" extra_arg="${2:-}" part_root0=s2a part_root1=s3a raw_device="`find /dev -type c -name 'mmcsd?' | sort | head -1`" raw_device_basename="${raw_device##*/}" active_rootfs_device="`kenv vfs.root.mountfrom | cut -d : -f 2`" active_rootfs_device_basename="${active_rootfs_device##*/}" active_raw_device="$active_rootfs_device" active_raw_device="${active_raw_device%*$part_root0}" active_raw_device="${active_raw_device%*$part_root1}" active_raw_device_basename="${active_raw_device##*/}" if [ "$raw_device" != "$active_raw_device" ] then raw_device="$active_raw_device" raw_device_basename="$active_raw_device_basename" fi case "$active_rootfs_device" in "/dev/$raw_device_basename$part_root0") active_rootfs_label=root0 ;; "/dev/$raw_device_basename$part_root1") active_rootfs_label=root1 ;; *) if [ "$mode" = mksd ] then active_rootfs_label= else exit 1 fi ;; esac case "$active_rootfs_label" in root0) inactive_rootfs_label=root1 inactive_rootfs_device="/dev/$raw_device_basename$part_root1" ;; root1) inactive_rootfs_label=root0 inactive_rootfs_device="/dev/$raw_device_basename$part_root0" ;; *) if [ "$mode" = mksd ] then inactive_rootfs_label= inactive_rootfs_device= else exit 1 fi ;; esac device_root="/dev/ufs/$inactive_rootfs_label" device_boot=/dev/msdosfs/BOOT device_conf=/dev/ufs/conf device_inst=/dev/ufs/inst loader_path=efi/boot loader_file=bootarm.efi loader_src=/boot/loader.efi loader_env_path=efi/freebsd loader_env_file=loader.env mountpoint_root=/mnt mountpoint_boot=/mnt mountpoint_conf=/root/conf if [ "$mode" = init -o "$mode" = mksd ] then mountpoint_conf=/mnt fi root_tmp=/root/tmp if [ "$mode" = mksd ] then root_tmp=/tmp fi lock_file="$root_tmp/upgrade.lock" upgrade_urls=' https://0.ask-m-001.update.connection-targets.devices.hardware.asperger.ee https://1.ask-m-001.update.connection-targets.devices.hardware.asperger.ee https://2.ask-m-001.update.connection-targets.devices.hardware.asperger.ee http://0.ask-m-001.update.connection-targets.devices.hardware.asperger.ee http://1.ask-m-001.update.connection-targets.devices.hardware.asperger.ee http://2.ask-m-001.update.connection-targets.devices.hardware.asperger.ee ' upgrade_file=upgrade.uzip signature_file="$upgrade_file.sig" upgrade_pubkey=/root/upgrade.pub upgrade_tmp_dir="$root_tmp/upgrade" upgrade_tmp_dir_size=256m mountpoint_media=/media xz_raw_upgrade_file=upgrade.img.xz raw_signature_file=upgrade.img.sig local_raw_signature_file="$root_tmp/$raw_signature_file.bin" local_raw_base64_signature_file="$local_raw_signature_file.b64" remote_last_updated_file=last-updated.txt remote_last_updated_signature_file="$remote_last_updated_file.sig" local_last_updated_file="$root_tmp/$remote_last_updated_file" local_last_updated_signature_file="$root_tmp/$remote_last_updated_signature_file" local_last_updated_binary_signature_file="$local_last_updated_signature_file.bin" last_updated_file=/root/last-updated.txt if [ "$mode" = mksd ] then upgrade_pubkey=/root/files/embedded/overlays/npinc/root/root/upgrade.pub fi _set_power_led() { local led_dir=/dev/led local led= if [ ! -d "$led_dir" ] then return fi led="`find \"$led_dir\" -type c -name '*p*w*r*'`" if [ "$led" ] then echo "$1" > "$led" fi } _clean_exit() { _set_power_led 0 } _flash_power_led() { _set_power_led f0 } _mount_boot() { umount "$mountpoint_boot" || true fsck_msdosfs -y "$device_boot" mount_msdosfs -o noatime "$device_boot" "$mountpoint_boot" } _umount_boot() { umount "$mountpoint_boot" fsck_msdosfs -y "$device_boot" } _fsck_conf() { fsck -y "$device_conf" } _mount_conf() { umount "$mountpoint_conf" || true _fsck_conf mount -o noatime "$device_conf" "$mountpoint_conf" } _umount_conf() { umount "$mountpoint_conf" _fsck_conf } _remount_conf() { local fstab=/etc/fstab local conf_fs="$mountpoint_conf" local type="$1" case "$type" in ro|rw) ;; *) exit 1 ;; esac local opts_and_fs="`awk -v \"v=$conf_fs\" '$2==v{print$4" "$2}' \"$fstab\" | sed \"s|r[ow]|$type|\"`" case "$opts_and_fs" in r?',noatime '$conf_fs) ;; *) exit 1 ;; esac if [ "$type" = rw ] then _fsck_conf fi cmd="mount -uo $opts_and_fs" echo "> $cmd" $cmd if [ "$type" = ro ] then _fsck_conf fi } _mount_inactive_root() { umount "$mountpoint_root" || true fsck -y "$device_root" mount -o noatime "$device_root" "$mountpoint_root" } _umount_inactive_root() { umount "$mountpoint_root" fsck -y "$device_root" } _power_failure_safe_copy_file() { local src="$1" local dst="$2" local tmp="$dst.tmp" cp "$src" "$tmp" sync sync sync mv "$tmp" "$dst" sync sync sync } _update_loader() { _mount_boot local owd="`pwd`" cd "$mountpoint_boot/$loader_path" if ! cmp "$loader_src" "$loader_file" then _power_failure_safe_copy_file "$loader_src" "$loader_file" fi cd "$owd" _umount_boot echo 'update loader' } _switch_rootfs() { _mount_boot local owd="`pwd`" cd "$mountpoint_boot/$loader_env_path" _power_failure_safe_copy_file \ "$loader_env_file.$inactive_rootfs_label" "$loader_env_file" cd "$owd" _umount_boot echo "rootfs=$inactive_rootfs_label" } _fetch() { mdconfig -d -u 100 || true umount "$upgrade_tmp_dir" || true rmdir "$upgrade_tmp_dir" || true mkdir "$upgrade_tmp_dir" mount -t tmpfs -o "size=$upgrade_tmp_dir_size" tmpfs "$upgrade_tmp_dir" cd "$upgrade_tmp_dir" for upgrade_url in $upgrade_urls do fetch "$upgrade_url/$signature_file" && break done for upgrade_url in $upgrade_urls do fetch "$upgrade_url/$upgrade_file" && break done openssl enc -base64 -d -in "$signature_file" \ | openssl dgst -sha512 -verify "$upgrade_pubkey" \ -signature /dev/stdin "$upgrade_file" kldload geom_uzip || true mdconfig -u 100 -f "$upgrade_file" mount -o ro,noatime /dev/md100.uzip "$mountpoint_media" } _rsync() { rsync -avhhhiHAXUS \ --delete \ --exclude=/.snap \ "$mountpoint_media/" \ "$mountpoint_root/" } _image() { local target_device="$inactive_rootfs_device" local skip_if_latest=1 local verified= if [ "${1:-}" -a "${2:-}" = function-mode-install ] then target_device="$1" skip_if_latest= fi if [ ! "$target_device" ] then return fi echo 'fetch last updated signature' for upgrade_url in $upgrade_urls do fetch -o "$local_last_updated_signature_file" \ "$upgrade_url/$remote_last_updated_signature_file" && break done openssl enc -base64 -d -in "$local_last_updated_signature_file" \ -out "$local_last_updated_binary_signature_file" echo 'fetch last updated' verified= for upgrade_url in $upgrade_urls do fetch -o - "$upgrade_url/$remote_last_updated_file" \ | tee "$local_last_updated_file" \ | openssl dgst -sha512 -verify "$upgrade_pubkey" \ -signature "$local_last_updated_binary_signature_file" \ && verified=1 if [ "$verified" ] then break fi done if [ ! "$verified" ] then exit 1 fi echo -n 'remote ' date -r "`cat \"$local_last_updated_file\"`" '+[%s] %F %T %z/%Z' if [ "$skip_if_latest" ] then echo -n 'local ' date -r "`cat \"$last_updated_file\"`" '+[%s] %F %T %z/%Z' if `cmp -s "$local_last_updated_file" "$last_updated_file"` then echo 'remote and local times are same, no upgrade needed' rm -f "$local_last_updated_signature_file" \ "$local_last_updated_binary_signature_file" \ "$local_last_updated_file" exit else echo upgrade fi fi echo 'fetch upgrade signature' for upgrade_url in $upgrade_urls do fetch -o "$local_raw_base64_signature_file" \ "$upgrade_url/$raw_signature_file" && break done openssl enc -base64 -d -in "$local_raw_base64_signature_file" \ -out "$local_raw_signature_file" echo 'fetch upgrade' verified= for upgrade_url in $upgrade_urls do fetch -q -o - "$upgrade_url/$xz_raw_upgrade_file" \ | xzcat \ | mbuffer -o "$target_device" -o - \ | openssl dgst -sha512 -verify "$upgrade_pubkey" \ -signature "$local_raw_signature_file" && verified=1 if [ "$verified" ] then break fi done if [ ! "$verified" ] then exit 1 fi } _reboot() { shutdown -r now "$1" } _pre() { _flash_power_led _mount_inactive_root } _post() { _umount_inactive_root _switch_rootfs _reboot upgrade } _geom_uzip_upgrade() { _flash_power_led _fetch _mount_inactive_root _rsync _umount_inactive_root _switch_rootfs _reboot upgrade } _upgrade() { _flash_power_led _image _switch_rootfs _reboot upgrade } _switch_rootfs_and_reboot() { _flash_power_led _switch_rootfs _reboot 'switch rootfs' } _info() { echo "active rootfs = $active_rootfs_label ($active_rootfs_device)" if [ -f "$last_updated_file" ] then echo -n 'last updated = ' date -r "`cat \"$last_updated_file\"`" '+[%s] %F %T %z/%Z' fi } _generate_system_id() { local id_dir="$mountpoint_conf" local id_file="$id_dir/id.txt" pwgen -A 8 1 > "$id_file" } _sshd_keygen_alg() { local key_dir="$mountpoint_conf" local alg="$1" local keyfile= case "$alg" in rsa|ecdsa|ed25519) keyfile="$key_dir/ssh_host_${alg}_key" ;; *) return ;; esac if [ -f "$keyfile" ] then echo "$alg host key exists" return fi echo "generating $alg host key" ssh-keygen -q -t "$alg" -f "$keyfile" -N '' ssh-keygen -l -f "$keyfile.pub" } _sshd_keygen() { _sshd_keygen_alg rsa _sshd_keygen_alg ecdsa _sshd_keygen_alg ed25519 } _generate_ssh_keys() { local key_dir="$mountpoint_conf" _sshd_keygen ssh-keygen -f "$key_dir/id_rsa" -N '' } _exit_if_exists() { if [ -r "$1" ] then echo "file '$1' already exists" exit 1 fi } _subj() { echo "/C=$c/ST=$st/L=$l/O=$o/OU=$ou/CN=$cn/emailAddress=$emailaddress" } _ssl_request_certificate() { local csr="$1" local crt="$2" local interface=bridge0 local local_ip=10.100.0.100 local remote_ip=10.100.0.1 local remote_port=19 local nc_prepend= if ! `which -s nc` then nc_prepend='env LD_LIBRARY_PATH=/root /root/' fi ifconfig "$interface" inet "$local_ip/24" ${nc_prepend}nc "$remote_ip" "$remote_port" < "$csr" > "$crt" rm "$csr" ifconfig "$interface" inet -alias } _ssl() { local conf_dir="$mountpoint_conf" local tmp_dir="$root_tmp" local ca_dir=/root/install/priv/ca if [ "$1" = function-mode-install -o "$1" = function-mode-first-boot ] then tmp_dir=/tmp fi local id="`cat \"$conf_dir/id.txt\"`" local ca_key="$ca_dir/ca.key" local ca_crt="$ca_dir/ca.crt" local ca_srl="$tmp_dir/ca.srl.`date +%s`" local key="$conf_dir/client.key" local csr="$tmp_dir/client.csr" local crt="$conf_dir/client.crt" local dh="$conf_dir/client.dh" local bits=4096 local days=365000 local c=EE local st=Harjumaa local l=Saue local o='OY Asperger' local ou=hardware local cn="$id" local emailaddress=hardware@asperger.ee local command="$2" case "$command" in key) _exit_if_exists "$key" openssl genrsa -out "$key" "$bits" chown root:poe "$key" chmod 640 "$key" ;; csr) _exit_if_exists "$csr" openssl req -new -sha512 -key "$key" -out "$csr" \ -subj "`_subj`" ;; crt) _exit_if_exists "$crt" if [ "$1" = function-mode-first-boot ] then _ssl_request_certificate "$csr" "$crt" else openssl x509 -req -sha512 -in "$csr" \ -out "$crt" -CA "$ca_crt" -CAkey "$ca_key" \ -CAserial "$ca_srl" -CAcreateserial \ -days "$days" -extfile /root/ext.conf \ -extensions custom_client fi ;; dh) _exit_if_exists "$dh" openssl dhparam -out "$dh" "$bits" ;; info) openssl x509 -in "$crt" -noout -text \ -certopt no_header,no_version,no_sigdump,no_extensions \ | head -11 ;; fullinfo) openssl x509 -in "$crt" -noout -text \ | less ;; csrinfo) openssl req -in "$csr" -noout -text \ | less ;; esac } _ssl_local_initialize() { local arg="${1:-}" local function= for function in key csr crt do _ssl "${arg:-function-mode-install}" "$function" done } _generate_initial_system_configuration() { local arg="${1:-}" _generate_system_id _generate_ssh_keys _ssl_local_initialize "$arg" } _install() { local arg="${1:-}" local dev="$raw_device_basename" local bootpart_align=32m local part_align_mb=4 local part_align="${part_align_mb}m" local bsdpart_align="$(($part_align_mb * 1024 * 1024 / 512))" local boot_size=64m local dualroot_mbr_size=3g local dualroot_bsd_size=2920m local allwinner_uboot=1 local uboot_file=/root/install/uboot/u-boot-sunxi-with-spl.bin local tar_tar_boot=1 local boot_dir=/root/install/msdosfs local tar_tar_root= local conf_gen=1 if [ "$arg" = function-mode-make-sd-card ] then dev="$extra_arg" bootpart_align=64m dualroot_mbr_size=800m dualroot_bsd_size=720m uboot_file=/usr/local/share/u-boot/u-boot-nanopi_m1plus/u-boot-sunxi-with-spl.bin boot_dir=/root/files/embedded/overlays/npinc-sd-standalone/boot conf_gen= fi if [ ! "$dev" ] then return fi _flash_power_led local mountpoint= for mountpoint in "$mountpoint_boot" "$mountpoint_root" \ "$mountpoint_conf" do umount "$mountpoint" || true done unset mountpoint dd if=/dev/zero "of=/dev/$dev" bs=10m status=progress || true trim -f "/dev/$dev" || true gpart create -s mbr "$dev" gpart add -t fat16 -s "$boot_size" -a "$bootpart_align" "$dev" gpart add -t freebsd -s "$dualroot_mbr_size" -a "$part_align" "$dev" gpart add -t freebsd -s "$dualroot_mbr_size" -a "$part_align" "$dev" gpart add -t freebsd -a "$part_align" "$dev" gpart create -s bsd "${dev}s2" gpart create -s bsd "${dev}s3" gpart create -s bsd "${dev}s4" gpart add -t freebsd-ufs -b "$bsdpart_align" -s "$dualroot_bsd_size" -a "$part_align" "${dev}s2" gpart add -t freebsd-ufs -a "$part_align" -i 4 "${dev}s2" gpart add -t freebsd-ufs -b "$bsdpart_align" -s "$dualroot_bsd_size" -a "$part_align" "${dev}s3" gpart add -t freebsd-ufs -a "$part_align" -i 4 "${dev}s3" gpart add -t freebsd-ufs -b "$bsdpart_align" -a "$part_align" -i 5 "${dev}s4" if [ "$allwinner_uboot" ] then dd "if=$uboot_file" "of=/dev/$dev" bs=1k seek=8 conv=sync \ status=progress fi newfs_msdos -A -F 16 -L boot "${dev}s1" if [ "$tar_tar_root" ] then newfs -t -U -L root0 "$dev$part_root0" newfs -t -U -L root1 "$dev$part_root1" fi newfs -t -U -L conf "${dev}s2d" newfs -t -U -L inst "${dev}s4e" if [ "$tar_tar_boot" ] then _mount_boot tar cf - -C "$boot_dir" . \ | tar xpf - -C "$mountpoint_boot" || true _umount_boot fi if [ "$conf_gen" ] then _mount_conf _generate_initial_system_configuration cp -a /root/install/dh/ "$mountpoint_conf" _umount_conf else _fsck_conf fi if [ "$tar_tar_root" ] then local label= for label in root0 root1 do fsck -y "/dev/ufs/$label" mount -o noatime "/dev/ufs/$label" "$mountpoint_root" tar cf - --one-file-system -C / . \ | tar xpf - -C "$mountpoint_root" cp -a /root/install/etc/ "$mountpoint_root/etc" umount "$mountpoint_root" fsck -y "/dev/ufs/$label" done unset label else local root_dev= for root_dev in "/dev/$dev$part_root0" "/dev/$dev$part_root1" do _image "$root_dev" function-mode-install done unset root_dev fi fsck -y "$device_inst" _set_power_led f9 } _boot_copy_files() { _mount_boot cp -av "$root_tmp/boot/" "$mountpoint_boot" || true _umount_boot } _first_boot() { local arg="${1:-}" local confirm= local service= _remount_conf rw if [ "$arg" = reinit ] then echo echo echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! echo echo ' BIG SCARY WARNING' echo ' DELETING ALL CONFIGURATION!' echo ' ARE YOU SURE?' echo ' THIS ALSO DISABLES THE ASK-M.EE SERVICE' echo ' UNTIL YOU REQUEST NEW CERTIFICATE FROM MANUFACTURER' echo ' TYPE "YES" IN ALL UPPERCASE LETTERS AND PRESS ENTER' echo ' TO CONFIM' echo ' ALL OTHER INPUTS CANCEL THE ACTION' echo echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! echo echo read -p '> ' confirm if [ "$confirm" = YES ] then find "$mountpoint_conf" -depth 1 -not -name .snap \ -delete else _remount_conf ro exit fi fi _generate_initial_system_configuration function-mode-first-boot _remount_conf ro if [ "$arg" != from-rcng ] then for service in sshd poedaemon do service "$service" restart || true done fi } _periodic_upgrade() { sleep "`jot -r 1 0 10000`" _upgrade } _requested_upgrade() { sleep "`jot -r 1 10 20`" _upgrade } if [ "${3:-}" != run ] then lockf -t 0 "$lock_file" "$0" "$mode" "$extra_arg" run exit fi trap _clean_exit `trap -l` util_name="${0##*/}" case "$util_name" in ro|rw) _remount_conf "$util_name" exit ;; esac unset util_name case "$mode" in pre) _pre ;; post) _post ;; geom-uzip-upgrade) _geom_uzip_upgrade ;; upgrade|'') _upgrade ;; update-loader) _update_loader ;; switch-rootfs-and-reboot|sw) _switch_rootfs_and_reboot ;; info) _info ;; init) _install ;; mksd) _install function-mode-make-sd-card ;; bcp) _boot_copy_files ;; firstboot) _first_boot "$extra_arg" ;; from-watchdog-periodic-upgrade) _periodic_upgrade ;; from-watchdog-requested-upgrade) _requested_upgrade ;; bm) _mount_boot ;; bu) _umount_boot ;; *) exit 1 ;; esac