etch

#!/bin/sh
#$Id$
#This file is part of EdgeBSD etch
#Copyright (c) 2014-2022 Pierre Pronchery <khorben@edgebsd.org>
#
#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
#FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
#DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
#SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#variables
PREFIX="/usr"
#executables
AR="ar"
BZIP2="bzip2"
CUT="cut"
FDISK="fdisk"
[ $VERBOSE -eq 2 ] && FDISK="$FDISK -v"
[ $VERBOSE -ge 3 ] && FDISK="$FDISK -vv"
GREP="grep"
GZIP="gzip"
MOUNT="mount"
NEWFS_EXT2FS="newfs_ext2fs -V 0"
[ $VERBOSE -ge 2 ] && NEWFS_EXT2FS="newfs_ext2fs -V 1"
[ $VERBOSE -ge 3 ] && NEWFS_EXT2FS="newfs_ext2fs -V 2"
SED="sed"
SYSCTL="sysctl"
TAR="tar"
TR="tr"
UMOUNT="umount"
VNCONFIG="vnconfig"
XZ="xz"
[ $VERBOSE -eq 2 ] && WGET="wget"
[ $VERBOSE -ge 3 ] && WGET="wget -v"
#platform-specific
[ -z "$DEBIAN_ARCH" ] && DEBIAN_ARCH="$(uname -m)"
case "$DEBIAN_ARCH" in
i?86)
DEBIAN_ARCH="i386"
;;
"x86_64")
DEBIAN_ARCH="amd64"
;;
esac
[ -z "$DEBIAN_MIRROR" ] && DEBIAN_MIRROR="http://ftp.debian.org"
[ -z "$DEBIAN_VERSION" ] && DEBIAN_VERSION="stable"
[ -z "$DEBIAN_REPOSITORIES" ] && DEBIAN_REPOSITORIES="main"
[ -z "$DEBIAN_SOURCES" ] && DEBIAN_SOURCES="deb $DEBIAN_MIRROR/debian $DEBIAN_VERSION $DEBIAN_REPOSITORIES"
[ -z "$DEBIAN_PACKAGES" ] && DEBIAN_PACKAGES="apt bash makedev vim"
#functions
#install_base
_install_base()
{
_info "Downloading the package databases..."
_install_base_download || return 2
_info "Caching the package databases..."
#FIXME cache per repository/architecture?
$DEBUG $MKDIR cache || return 2
required=
while read method mirror version repositories; do
[ "$method" = "" ] && continue
for i in "$repositories"; do
url="$mirror/dists/$version/$i/binary-$DEBIAN_ARCH/Packages.gz"
if [ ! -f "$url" ]; then
_error "$i: Missing Packages.gz file for repository"
return $?
fi
package=
filename=
priority=
while read variable value; do
case "$variable" in
"Package:")
cache="cache/$value.control"
if [ "$cache" -nt "$url" ]; then
exec 3> "$DEVNULL"
else
exec 3> "$cache"
echo "$variable $value" 1>&3
fi
package="$value"
;;
"Priority:")
[ "$value" = "required" ] &&
priority="$value"
echo "$variable $value" 1>&3
;;
"Filename:")
filename="$value"
echo "$variable $mirror/$value" 1>&3
;;
"")
exec 3>&-
[ -n "$priority" ] && required="$required
$package $mirror/$filename"
package=
filename=
priority=
;;
*)
echo "$variable $value" 1>&3
;;
esac
done << EOF
$($GZIP -d -c "$url")
EOF
exec 3>&-
done
done << EOF
$DEBIAN_SOURCES
EOF
#install every package marked as required
_info "Installing the base system..."
echo "$required" | while read package filename; do
[ -n "$package" ] || continue
_install_package "$package" "$filename" || return 2
done
}
_install_base_download()
{
while read method mirror version repositories; do
[ "$method" = "" ] && continue
for i in "$repositories"; do
#download the package database
url="$mirror/dists/$version/$i/binary-$DEBIAN_ARCH/Packages.gz"
filename=$(_download "$url")
[ $? -eq 0 ] || return 2
done
done << EOF
$DEBIAN_SOURCES
EOF
}
#install_bootloader
_install_bootloader()
{
#FIXME implement
:
}
#install_configure
_install_configure()
{
$DEBUG $SUDO $MKDIR "$DESTDIR/etc" || return 2
_install_configure_apt || return 2
_install_configure_fstab || return 2
_install_configure_hostname || return 2
_install_configure_motd || return 2
_install_configure_services || return 2
_install_configure_timezone || return 2
_install_configure_user || return 2
}
_install_configure_apt()
{
available="/var/lib/dpkg/available"
info="/var/lib/dpkg/info"
status="/var/lib/dpkg/status"
#only configure apt if it is installed
[ -f "$DESTDIR$PREFIX/bin/apt-get" ] || return 0
#/etc/apt/sources.list
$DEBUG $SUDO $MKDIR "$DESTDIR/etc/apt" || return 2
$DEBUG $CAT > "$DESTDIR/etc/apt/sources.list" << EOF
$DEBIAN_SOURCES
EOF
[ $? -eq 0 ] || return 2
#/var/lib/dpkg/{available,status}
_info "Registering packages..."
while read method mirror version repositories; do
[ "$method" = "" ] && continue
for i in "$repositories"; do
#download the package database
url="$mirror/dists/$version/$i/binary-$DEBIAN_ARCH/Packages.gz"
if [ ! -f "$url" ]; then
_error "$i: Missing Packages.gz file for repository"
return $?
fi
package=
description=0
while read line; do
if [ -z "$line" ]; then
[ -n "$package" ] && echo 1>&3
package=
description=0
fi
l="${line%%:*}"
case "$l" in
"Package")
package="${line#Package: }"
[ -f "$DESTDIR$info/${package}.control" ] || package=
;;
"Filename"|"MD5sum"|"SHA1"|"SHA256"|"Tag"|"Task")
continue
;;
"Tag"|"Homepage")
#FIXME may be in the description
description=0
;;
esac
if [ $description -eq 0 ]; then
echo "$line" 1>&4
[ -n "$package" -a "$l" != "Size" ] && echo "$line" 1>&3
else
echo " $line" 1>&4
[ -n "$package" ] && echo " $line" 1>&3
fi
case "$l" in
"Package")
[ -n "$package" -a $description -eq 0 ] &&
echo "Status: install ok installed" 1>&3
;;
"Description")
description=1
;;
esac
done << EOF
$($GZIP -d -c "$url")
EOF
[ $? -eq 0 ] || return 2
done
done 3> "$DESTDIR$status" 4> "$DESTDIR$available" << EOF
$DEBIAN_SOURCES
EOF
}
_install_configure_fstab()
{
#/etc/fstab
_info "Configuring the system partitions..."
$DEBUG $SUDO $MKDIR -m 0755 -- "$DESTDIR/mnt/cdrom" \
"$DESTDIR/mnt/usb" || return 2
#FIXME restore
$DEBUG $CAT > "$DESTDIR/etc/fstab" << EOF
EOF
[ $? -eq 0 ] || return 2
}
_install_configure_hostname()
{
#FIXME implement
:
}
_install_configure_motd()
{
#FIXME implement
:
}
_install_configure_services()
{
#FIXME implement
:
}
_install_configure_timezone()
{
#FIXME implement
:
}
_install_configure_user()
{
#FIXME implement
:
}
#install_kernel
_install_kernel()
{
#FIXME implement
:
}
#install_package
_install_package()
{
case $# in
1)
_install_package_name "$1"
;;
2)
_install_package_filename "$1" "$2"
;;
*)
_usage "_package package url"
return $?
;;
esac
}
_install_package_extract()
{
package="$1"
filename="$2"
info="/var/lib/dpkg/info"
list="$info/${package}.list"
sedcmd="-e 's|/$||' -e 's|^\./|/|' -e 's|^\.|/.|'"
deflatecmd=
_info "Installing package ${package}..."
$DEBUG $SUDO $MKDIR "$DESTDIR$info" || return 2
for member in $($AR -t "$filename"); do
case "$member" in
control.tar.bz2|data.tar.bz2)
deflatecmd="$BZIP2 -d -c"
;;
control.tar.gz|data.tar.gz)
deflatecmd="$GZIP -d -c"
;;
control.tar.xz|data.tar.xz)
deflatecmd="$XZ -d -c"
;;
control.tar.*|data.tar.*)
_error "${member##*.}: Unsupported compression method"
return $?
;;
*)
continue
;;
esac
case "$member" in
control.tar.*)
$AR -p "$filename" "$member" | $deflatecmd \
| $DEBUG $TAR -tf - | $CUT -c 3- \
| while read file; do
[ -z "$file" ] && continue
$DEBUG $AR -p "$filename" "$member" \
| $deflatecmd | \
(cd "$DESTDIR$info" && \
$SH -c "$TAR -xpf - \"./$file\" \
&& $DEBUG $MV -- \"$file\" \"${package}.$file\"") \
|| return 2
done
;;
data.tar.*)
$DEBUG $AR -p "$filename" "$member" | $deflatecmd | \
(cd "$DESTDIR" && $SH -c \
"$TAR -xpvf - | $SED $sedcmd > \"$DESTDIR/$list.part\"") \
|| return 2
$DEBUG $MV -- "$DESTDIR${list}.part" "$DESTDIR$list" \
|| return 2
;;
esac
done
}
_install_package_filename()
{
package="$1"
url="$2"
depends=1
[ $# -eq 3 ] && depends="$3"
info="/var/lib/dpkg/info"
control="$info/${package}.control"
list="$info/${package}.list"
#check if the package is already installed
[ -f "$DESTDIR$list" ] && return 0
#download the package
filename=$(_download "$url")
[ $? -eq 0 ] || return 2
#extract the package
_install_package_extract "$package" "$filename" || return 2
#install the dependencies if requested
[ $depends -eq 0 ] && return 0
[ -f "$DESTDIR$control" ] || return 2
while read variable value; do
case "$variable" in
"Pre-Depends:"|"Depends:")
depends=$(echo "$value" | $SED -e 's/,//g' \
-e 's/ ([^)]*)//g' \
-e 's/ | \{1,\}[-a-zA-Z0-9.]\{1,\}//g')
for d in $depends; do
(_install_package_name "$d") \
|| return 2
done
;;
esac
done < "$DESTDIR$control"
}
_install_package_name()
{
package="$1"
info="/var/lib/dpkg/info"
list="$info/${package}.list"
fallback_package=
fallback_filename=
#check if the package is already installed
[ -f "$DESTDIR$list" ] && return 0
#obtain the filename for this package
cache="cache/$package.control"
#could not install the package
if [ ! -f "$cache" ]; then
#look for provides
while read variable value; do
fallback_package="${variable#cache/}"
fallback_package="${fallback_package%.control:Provides:}"
cache="cache/$fallback_package.control"
if [ -f "$cache" ]; then
package="$fallback_package"
break
fi
done << EOF
$($GREP -r "^Provides: $package\$" "cache")
EOF
if [ "$package" != "$fallback_package" ]; then
_error "$package: Package not found"
return $?
fi
fi
while read variable value; do
case "$variable" in
"Filename:")
(_install_package_filename "$package" "$value")
return $?
;;
esac
done < "$cache"
#could not install the package
_error "$package: Invalid cache for this package"
return 2
}
#install_package_configure
_install_package_configure()
{
#FIXME implement
:
}
#install_packages
_install_packages()
{
_info "Installing packages..."
#install every package
for package in $DEBIAN_PACKAGES; do
_install_package "${package}" || return 2
done
}
#volume_format
_volume_format()
{
disknames=$($SYSCTL "hw.disknames")
i=0
for diskname in $disknames; do
[ "$diskname" = "vnd$i" ] && i=$((i + 1))
done
VND="vnd$i"
$DEBUG $SUDO $VNCONFIG -c "$VND" "$TARGET" || return 2
_info "Formatting partition ${VND}e..."
$DEBUG $SUDO $NEWFS_EXT2FS "${VND}e"
if [ $? -ne 0 ]; then
$DEBUG $SUDO $VNCONFIG -u "$VND"
return 2
fi
}
#volume_mount
_volume_mount()
{
$DEBUG $SUDO $MKDIR -- "$DESTDIR" || return 2
$DEBUG $SUDO $MOUNT "/dev/${VND}e" "$DESTDIR"
}
#volume_partition
_volume_partition()
{
size=$((IMAGE_SIZE * IMAGE_BS / 512 - 63))
_info "Partitioning the disk..."
$DEBUG $SUDO $FDISK -Ffau0s "131/63/$size" "$TARGET" || return 2
}
#volume_umount
_volume_umount()
{
ret=0
$DEBUG $SUDO $UMOUNT "/dev/${VND}e" || return 2
$DEBUG $SUDO $VNCONFIG -u "$VND" || return 2
return $ret
}