#!/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 "${@}"