#!/bin/sh # Mini/Temporary ProteanOS Development Kit # miniprokit.sh # Main program file # # Copyright (C) 2013, 2014 Patrick "P. J." McDermott # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set -u SHA256SUMS=' -- NEW SUMS -- 93444257ed8d5b0b3f299841232f25faed44207fe083b2d3e39a903be3d60cbd all_all_base 7d08de7c02cc3be6f9d618a44384ac49fcced1a598c2621070c71ae445abf128 all_ao751h_base 25a729e39f1ef375a6147ee2a340b0221c388054cd628fc1e2d6f6dee6683d78 all_dev_base 9aa434941778e09de1be487066c337264591dca7a24b69c5e976be9964550d5c all_dimension2400_base 18c6c5c2ec797249ada7a155be202eec060df9ab2477b02252de155cffc42d91 all_x60_base e940a8ea0b8a736cec119e6a968b26578c3dc17036913c088b7696fd0311d4ac amd64-linux-glibc_all_base d9169e0f7700f0cf982ceb9c140c6da3d69dda0c1aa211573b60a6b1c0cba033 amd64-linux-glibc_dev_base 8ef53dbed5bab874150b1cb7c29bbb2d291d390e952169793a6d5b547cc03063 i686-linux-glibc_all_base b0a5a28b62be4b4e8fe4eee5f358b9e0faab84bab2cebb490167ad3f1a9d60a7 i686-linux-glibc_ao751h_base f3c4d55f873e125a1bff5d0d843e97a7e0bc796cf6a9c0b825219f812fb3d30d i686-linux-glibc_dev_base 725e582a8bc31ec313b2a6f4e6a7c09ee744ef487828dcdc4ea97df50435f742 i686-linux-glibc_dimension2400_base b08ee7a91a7c8350f4578bab1468d65def4b6a5e45a9f8eaa08f0923f977c866 i686-linux-glibc_x60_base 1df55a00659f82da3a595c154ce2fbfb4b9ca355b5bc6edceb34076536d7f09d src_all_base -- OLD SUMS -- 85295d78765aeae41c5e18708967be0ce3619055a29c32e4be69dc259a1f6924 all_all_base 7d08de7c02cc3be6f9d618a44384ac49fcced1a598c2621070c71ae445abf128 all_ao751h_base 25a729e39f1ef375a6147ee2a340b0221c388054cd628fc1e2d6f6dee6683d78 all_dev_base 9aa434941778e09de1be487066c337264591dca7a24b69c5e976be9964550d5c all_dimension2400_base 18c6c5c2ec797249ada7a155be202eec060df9ab2477b02252de155cffc42d91 all_x60_base 54174d2f1ce2597c371cd0281d04f8dde3cc017402c21e6b38db99e36e6e0ed4 amd64-linux-glibc_all_base d9169e0f7700f0cf982ceb9c140c6da3d69dda0c1aa211573b60a6b1c0cba033 amd64-linux-glibc_dev_base f0a338ebb6fdbfa50fae0cf72219df184724c1c4e3b6221e28aece139d88ffdf i686-linux-glibc_all_base 17bb325c679a2d63e56a71c54065c78b5f41db8f42d21cf64c47fbc5984944cb i686-linux-glibc_ao751h_base f3c4d55f873e125a1bff5d0d843e97a7e0bc796cf6a9c0b825219f812fb3d30d i686-linux-glibc_dev_base 68d247caf5c9ac6626c2253fd410c9e1dfe38845c458727bf234364bcd0fc007 i686-linux-glibc_dimension2400_base bd0ee0250cfdc10fdb02828668868bebf77f4051d00b3af0f6a3b443f4e5fced i686-linux-glibc_x60_base 2105c0ddb13eb04fc3bade8a274b800d3a324ad93b738dfad5b3ecff700b3920 src_all_base -- END SUMS -- ' PKGS=' base-files busybox '\ 'libc-bin libc.6 libopkg.1 opkg linux-image proteanos-branding ' INSTALL_SERVICE=\ '#!/bin/sh /etc/rc.common start() { log "Configuring packages" printf "disabled\n" >/etc/rc.policy opkg install $(opkg list-installed | cut -d " " -f 1) printf "enabled\n" >/etc/rc.policy rm "${SCRIPT}" } ' main() { local cmd= if [ ${#} -lt 1 ]; then print_usage >&2 exit 1 fi cmd="${1}" shift 1 case "${cmd}" in 'install') cmd_install "${@}" ;; 'shell') cmd_shell "${@}" ;; esac return 0 } print_usage() { printf 'Usage: %s []\n\n' "${0}" printf 'Available commands are:\n' printf ' install install a ProteanOS system\n' printf ' shell enter a ProteanOS shell\n' } error() { local status=${1} local fmt="${2}" shift 2 printf "Error: ${fmt}\n" "${@}" >&2 exit ${status} } info() { local fmt="${1}" shift 1 printf "${fmt}\n" "${@}" } cmd_install() { local usage= local opt= local arch= local plat= local mirror= local foreign= local root= local uname_m= local uname_s= local aps_list= local aps= local url_aps= local feed= local sha256sum= local line= local package= local filename= usage='[-a ] [-P ] [-m ] [-F] ' while getopts 'a:P:m:F' opt; do case ${opt} in a) arch="${OPTARG}";; P) plat="${OPTARG}";; m) mirror="${OPTARG}";; F) foreign=true;; ?) printf 'Usage: %s install %s\n' \ "${0}" "${usage}" >&2 exit 1 ;; esac done shift $(($OPTIND - 1)) if [ ${#} -ne 1 ]; then printf 'Usage: %s install %s\n' "${0}" "${usage}" >&2 exit 1 fi root="${1}" if [ "x${arch}" = 'x' ]; then uname_m="$( (uname -m) 2>/dev/null)" || uname_m='?' uname_s="$( (uname -s) 2>/dev/null)" || uname_s='?' case "${uname_m}:${uname_s}" in 'i686:Linux') arch='i686-linux-glibc';; 'x86_64:Linux') arch='amd64-linux-glibc';; '?:?') error 2 'Error: Architecture unknown';; *) error 2 'Error: Architecture unsupported';; esac fi info 'Using architecture %s' "${arch}" if [ "x${plat}" = 'x' ]; then plat='dev' fi info 'Using platform %s' "${plat}" if [ "x${mirror}" = 'x' ]; then rand=$(date '+%S') rand=$(($rand % 3)) case ${rand} in 0) mirror='http://us.mirror.gnu.dk/pub/proteanos' ;; 1) mirror='http://eu.mirror.gnu.dk/pub/proteanos' ;; 2) mirror='http://mirror.oss.maxcdn.com/proteanos' ;; esac fi info 'Using mirror %s' "${mirror}" if [ "x${foreign}" = 'x' ]; then foreign=false fi info 'Setting up root...' mkdir -p "${root}/etc/opkg" \ "${root}/var/lib/opkg/lists" "${root}/var/lib/opkg/info" \ "${root}/var/cache/opkg/archives" "${root}/tmp/opkg" || \ error 2 'Failed to set up root' info 'Configuring opkg and retrieving Packages...' exec 3>"${root}/etc/opkg/opkg.conf" || \ error 2 'Failed to open opkg.conf' aps_list="${arch}_${plat}_base ${arch}_all_base" [ "x${plat}" = 'xdev' ] || aps_list="${aps_list} all_${plat}_base" aps_list="${aps_list} all_all_base src_all_base" for aps in ${aps_list}; do url_aps="$(printf '%s\n' "${aps}" | sed 's|_|/|g')" feed="${mirror}/feeds/dev/trunk/${url_aps}" printf 'src %s %s\n' "trunk_${aps}" "${feed}" >&3 wget -q -O "${root}/var/lib/opkg/lists/trunk_${aps}" \ "${feed}/Packages" || \ error 2 'Failed to download %s' "${feed}/Packages" sha256sum="$(sha256sum \ "${root}/var/lib/opkg/lists/trunk_${aps}" | \ cut -d ' ' -f 1)" printf '%s' "${SHA256SUMS}" | grep -Fq "${sha256sum} ${aps}" \ || error 2 'Checksum of Packages index file failed%s' \ '; try fetching the latest miniprokit script' done printf '\ndest root /\n' >&3 printf 'arch %s 1\n' 'all' "${arch}" 'src' >&3 exec 3>&- while IFS='' read -r line; do if [ "x${line%: *}" = 'xPackage' ]; then package="${line#Package: }" elif [ "x${line%: *}" = 'xFilename' ]; then filename="${line#Filename: }" elif [ "x${line%: *}" = 'xSHA256sum' ]; then sha256sum="${line#SHA256sum: }" elif [ "x${line}" = 'x' ]; then printf '%s\n' "${PKGS}" | grep -Fq " ${package} " || \ continue get_pkg "${root}" "${mirror}" \ "${package}" "${filename}" "${sha256sum}" fi done <<-EOF $(cat "${root}/var/lib/opkg/lists/trunk_"*) EOF configure "${root}" "${foreign}" } get_pkg() { local root="${1}" local mirror="${2}" local package="${3}" local filename="${4}" local sha256sum="${5}" local file= local control= local field= local printed= info 'Downloading %s...' "${package}" filename="${filename#../../../../../../}" wget -q -O "${root}/var/cache/opkg/archives/${filename##*/}" \ "${mirror}/${filename}" || error 2 'Failed to download package' filename="var/cache/opkg/archives/${filename##*/}" printf '%s %s\n' "${sha256sum}" "${root}/${filename}" | \ sha256sum -c >/dev/null 2>&1 \ || error 2 'Checksum of source package file failed' info 'Unpacking %s...' "${package}" mkdir "${root}/tmp/opkg/${package}" ( cd "${root}" tar -xzOf "${filename}" data.tar.gz \ >"tmp/opkg/${package}/data.tar.gz" tar -xzf "tmp/opkg/${package}/data.tar.gz" cd "tmp/opkg/${package}" tar -xzOf "../../../${filename}" control.tar.gz | \ tar -xz ) tar -tzf "${root}/tmp/opkg/${package}/data.tar.gz" | sed 's/^\.//' \ >"${root}/var/lib/opkg/info/${package}.list" rm -f "${root}/tmp/opkg/${package}/data.tar.gz" for file in "${root}/tmp/opkg/${package}/"*; do mv "${file}" "${root}/var/lib/opkg/info/${package}.${file##*/}" done rmdir "${root}/tmp/opkg/${package}" # Write status file. exec 3>>"${root}/var/lib/opkg/status" control="${root}/var/lib/opkg/info/${package}.control" for field in Package Version Depends Recommends Suggests \ Provides Replaces Conflicts; do grep "^${field}: " "${control}" >&3 done printf 'Status: install ok unpacked\n' >&3 for field in Essential Architecture; do grep "^${field}: " "${control}" >&3 done if [ -r "${root}/var/lib/opkg/info/${package}.conffiles" ]; then printed=false while read -r file; do ${printed} || printf 'Conffiles:\n' >&3 printf ' %s %s\n' "${file}" "$(md5sum \ "${root}/${file}" | cut -d ' ' -f 1)" \ >&3 printed=true done <"${root}/var/lib/opkg/info/${package}.conffiles" fi printf 'Installed-Time: %s\n\n' "$(date '+%s')" >&3 exec 3>&- rm -f "${root}/${filename}" } configure() { local root="${1}" local foreign="${2}" if ! ${foreign}; then info 'Configuring packages...' printf 'disabled\n' >"${root}/etc/rc.policy" chroot "${root}" /bin/sh -c \ 'opkg install $(opkg list-installed | cut -d " " -f 1)' printf 'enabled\n' >"${root}/etc/rc.policy" [ -r /etc/resolv.conf ] && cp /etc/resolv.conf "${root}/etc" [ -r /etc/hostname ] && cp /etc/hostname "${root}/etc" [ -e "${root}/etc/passwd" ] || printf \ 'root::0:0:root:/root:/bin/sh\n' >"${root}/etc/passwd" else printf '%s' "${INSTALL_SERVICE}" >"${root}/etc/rc.d/S10install" chmod 0755 "${root}/etc/rc.d/S10install" printf 'proteanos\n' >"${root}/etc/hostname" [ -e "${root}/etc/passwd" ] || printf \ 'root::0:0:root:/root:/bin/sh\n' >"${root}/etc/passwd" fi } cmd_shell() { local root= local arch= if [ ${#} -ne 1 ]; then printf 'Usage: %s shell \n' "${0}" >&2 exit 1 fi root="${1}" if ! [ -d "${root}" ] || ! [ -r "${root}/etc/proteanos_arch" ]; then error 2 'Error: ProteanOS root file system not found' fi arch="$(cat "${root}/etc/proteanos_arch")" case "${arch}" in *'-linux-'*) mount -t proc proc "${root}/proc" mount -t sysfs sys "${root}/sys" mount -o bind /dev "${root}/dev" mount -t devpts -o noexec,nosuid,gid=5,mode=0620 \ devpts "${root}/dev/pts" ;; *) error 2 'ProteanOS architecture %s not supported' \ "${arch}" esac chroot "${root}" /bin/sh printf '\nExiting...\n' case "$(cat "${root}/etc/proteanos_arch")" in *'-linux-'*) umount "${root}/dev/pts" umount "${root}/proc" umount "${root}/sys" while ! umount "${root}/dev"; do # umount sometimes complains that ${root}/dev is # busy. Here's a kludge to try to handle that. # This is a bind mount, so we better make sure # it gets unmounted; otherwise, `rm -Rf ${root}` # can be painful. sleep 1 done ;; esac } main "${@}"