Add tix-upgrade(8).

This commit is contained in:
Jonas 'Sortie' Termansen 2017-04-02 18:41:59 +02:00
parent b98d0d1f18
commit 9a3e5ee33a
18 changed files with 932 additions and 13 deletions

View File

@ -237,6 +237,8 @@ sysroot-system: sysroot-fsh sysroot-base-headers
echo /etc/sortix-release >> "$(SYSROOT)/tix/manifest/system"
ln -sf sortix-release "$(SYSROOT)/etc/os-release"
echo /etc/os-release >> "$(SYSROOT)/tix/manifest/system"
find etc | sed -e 's,^,/,' >> "$(SYSROOT)/tix/manifest/system"
cp -RT etc "$(SYSROOT)/etc"
find share | sed -e 's,^,/,' >> "$(SYSROOT)/tix/manifest/system"
cp -RT share "$(SYSROOT)/share"
export SYSROOT="$(SYSROOT)" && \
@ -274,6 +276,7 @@ else ifneq ($(SORTIX_INCLUDE_SOURCE),no)
cp Makefile -t "$(SYSROOT)/src"
cp README -t "$(SYSROOT)/src"
cp -RT build-aux "$(SYSROOT)/src/build-aux"
cp -RT etc "$(SYSROOT)/src/etc"
cp -RT share "$(SYSROOT)/src/share"
(for D in $(MODULES); do (cp -R $$D -t "$(SYSROOT)/src" && $(MAKE) -C "$(SYSROOT)/src/$$D" clean) || exit $$?; done)
endif
@ -457,6 +460,9 @@ $(LIVE_INITRD): sysroot
echo "include /etc/default/passwd.d/*" >> $(LIVE_INITRD).d/etc/passwd
echo "root::0:root" > $(LIVE_INITRD).d/etc/group
echo "include /etc/default/group.d/*" >> $(LIVE_INITRD).d/etc/group
(echo 'channel = $(CHANNEL)' && \
echo 'release_key = $(RELEASE_KEY)' && \
echo 'release_sig_url = $(RELEASE_SIG_URL)') > $(LIVE_INITRD).d/etc/upgrade.conf
mkdir -p $(LIVE_INITRD).d/home
mkdir -p $(LIVE_INITRD).d/root -m 700
cp -RT "$(SYSROOT)/etc/skel" $(LIVE_INITRD).d/root

View File

@ -1,3 +1,3 @@
set_minimal="cut dash e2fsprogs grep grub mdocml sed xargs"
set_basic="$set_minimal binutils bison bzip2 diffutils ed flex gawk gcc git gzip libcurl libcurses libssl libstdc++ nano ntpd make patch pkg-config python ssh tar vim wget xz xorriso"
set_minimal="cut dash e2fsprogs grep grub libssl mdocml sed signify tar wget xargs xorriso xz"
set_basic="$set_minimal binutils bison bzip2 diffutils ed flex gawk gcc git gzip libcurl libcurses libstdc++ nano ntpd make patch pkg-config python ssh vim"
sets="basic minimal"

View File

@ -1,2 +1,6 @@
VERSION=1.1dev
CHANNEL?=nightly
RELEASE?=$(VERSION)
RELEASE_MASTER?=https://sortix.org/release
RELEASE_KEY=/etc/signify/sortix-$(VERSION).pub
RELEASE_SIG_URL?=$(RELEASE_MASTER)/$(CHANNEL)/$(HOST_MACHINE).sh.sig

View File

@ -0,0 +1,2 @@
untrusted comment: signify public key
RWQiTQbFzyZJVobf/pn53Jp3njhRB9DgwkMaNakCpDE9RaTABMjlbz9W

View File

@ -0,0 +1,2 @@
untrusted comment: signify public key
RWQnkSm9lj1YIZYpt1Y3mHYzFsaky82gQF6CrW4lme9OoEYzSIl2ZsIC

View File

@ -0,0 +1,2 @@
untrusted comment: signify public key
RWTGrBXmGvl2zUpCa47ui5EyPsnitKLjsCZ2YZphNY8F3b33t6QWYDs1

View File

@ -0,0 +1,2 @@
untrusted comment: signify public key
RWRTbLQ+3+a9I5yche2BEVP03TRtumGO4Vgq1AQ/5bRj8JAJ1R0+vpxE

View File

@ -22,6 +22,10 @@ as part of
.Xr installation 7
to match what was installed.
.Pp
The file also controls the actions of
.Xr tix 8
when upgrading releases and installing ports.
.Pp
Developers may wish to customize what happens to
.Pa /src
on a system upgrade.
@ -45,7 +49,32 @@ Lines are supposed to contain assignments to variables.
An assignment is the name of the variable, whitespace, an equal character,
whitespace, the value, whitespace, and then the end of the line.
.Bl -tag -width "12345678"
.It Sy grub Ns "=" Ns Oo Sy no "|" yes Oc (default Sy no ) .
.It Sy channel Ns "=" Ns Ar channel
If the current release has an upgrade path named
.Ar channel
to a new release,
then system upgrades will upgrade to that new release.
If no such release path exists or if this variable is not set, upgrades will
continue to upgrade to the current release series.
Depending on the current release, the offically supported values are
.Sy stable
for stable releases and
.Sy nightly
for development releases.
Downgrading releases is not supported. For instance, if the current system is
a development release, specifying
.Sy stable
will not downgrade the system to the previous stable release, as no such upgrade
path exists.
Instead upgrades will upgrade to the next stable release when it becomes
available.
.It Sy force_mirror Ns "=" Ns Oo Sy no "|" yes Oc (default Sy no )
Use the preferred mirror set with
.Sy mirror
even if the file specified by
.Sy release_sig_url
does not list it.
.It Sy grub Ns "=" Ns Oo Sy no "|" yes Oc (default Sy no )
States GRUB is used as the bootloader.
If either the
.Sy system
@ -57,7 +86,18 @@ then the bootloader is reinstalled
.Xr ( grub-install 8 )
and updated
.Xr ( update-grub 8 ) .
.It Sy newsrc Ns "=" Ns Oo Sy no "|" yes Oc (default Sy no ) .
.It Sy mirror Ns "=" Ns Ar mirror
Download releases and ports from this preferred
.Ar mirror ,
a URL to the top level directory of a mirror.
The mirror is only used if the file specified by
.Sy release_sig_url
lists this mirror, unless
.Sy force_mirror
is set to
.Sy yes .
If no mirror is set, a default mirror is used.
.It Sy newsrc Ns "=" Ns Oo Sy no "|" yes Oc (default Sy no )
Place the new source code in
.Pa /newsrc
and move any existing
@ -69,17 +109,39 @@ This preserves the current
directory.
This takes precedence over and disables the behavior described under
.Sy src .
.It Sy ports Ns "=" Ns Oo Sy no "|" yes Oc (default Sy yes ) .
.It Sy ports Ns "=" Ns Oo Sy no "|" yes Oc (default Sy yes )
Install the new ports.
Ports that don't exist anymore will be removed.
.It Sy src Ns "=" Ns Oo Sy no "|" yes Oc (default Sy no ) .
.It Sy release_key Ns "=" Ns Ar release_key
Verify the file specified by
.Sy release_sig_url
with the
.Xr signify 1
public key file at the path
.Ar release_key .
This variable is updated during system upgrades and there is no need to change
this variable manually.
.It Sy release_sig_url Ns "=" Ns Ar release_sig_url
Download the meta-information about the current release from the URL
.Ar release_sig_url .
This file is verified with the
.Xr signify 1
public key in the
.Sy release_key
variable.
The file describes the current release, provides checksums of all the published
files, lists all the supported mirrors, provides instructions on how to upgrade
to this release, and lists all the supported upgrade paths to new releases.
This variable is updated during system upgrades and there is no need to change
this variable manually.
.It Sy src Ns "=" Ns Oo Sy no "|" yes Oc (default Sy no )
Place the new source code in
.Pa /src
and move any existing
.Pa /src
into
.Pa /oldsrc .
.It Sy system Ns "=" Ns Oo Sy no "|" yes Oc (default Sy yes ) .
.It Sy system Ns "=" Ns Oo Sy no "|" yes Oc (default Sy yes )
Install the new system.
The upgrade hooks are run if needed as described in
.Xr following-development 7 .
@ -96,6 +158,18 @@ then regenerate
The defaults will be used if
.Pa /etc/upgrade.conf
is missing.
If
.Sy release_key
or
.Sy release_sig_url
are absent,
.Xr tix 8
will not be able to upgrade the current system nor install ports.
If
.Sy channel
is absent,
.Xr tix 8
will not upgrade to new releases.
.Sh FILES
.Bl -tag -width "/etc/upgrade.conf" -compact
.It Pa /etc/upgrade.conf
@ -103,11 +177,12 @@ Upgrade configuration.
.El
.Sh EXAMPLES
.Bd -literal
system = yes
grub = yes
ports = yes
src = no
grub = yes
system = yes
.Ed
.Sh SEE ALSO
.Xr upgrade 7 ,
.Xr sysupgrade 8
.Xr sysupgrade 8 ,
.Xr tix 8

View File

@ -37,6 +37,10 @@ void conf_init(struct conf* conf)
void conf_free(struct conf* conf)
{
free(conf->channel);
free(conf->mirror);
free(conf->release_key);
free(conf->release_sig_url);
conf_init(conf);
}
@ -60,12 +64,43 @@ static bool conf_assign(struct conf* conf,
const char* path,
off_t line_number)
{
if ( !strcmp(name, "grub") )
char* new_value;
if ( !strcmp(name, "channel") )
{
if ( !(new_value = strdup(value)) )
return false;
free(conf->channel);
conf->channel = new_value;
}
else if ( !strcmp(name, "force_mirror") )
conf->force_mirror = conf_boolean(name, value, path, line_number);
else if ( !strcmp(name, "grub") )
conf->grub = conf_boolean(name, value, path, line_number);
else if ( !strcmp(name, "mirror") )
{
if ( !(new_value = strdup(value)) )
return false;
free(conf->mirror);
conf->mirror = new_value;
}
else if ( !strcmp(name, "newsrc") )
conf->newsrc = conf_boolean(name, value, path, line_number);
else if ( !strcmp(name, "ports") )
conf->ports = conf_boolean(name, value, path, line_number);
else if ( !strcmp(name, "release_key") )
{
if ( !(new_value = strdup(value)) )
return false;
free(conf->release_key);
conf->release_key = new_value;
}
else if ( !strcmp(name, "release_sig_url") )
{
if ( !(new_value = strdup(value)) )
return false;
free(conf->release_sig_url);
conf->release_sig_url = new_value;
}
else if ( !strcmp(name, "src") )
conf->src = conf_boolean(name, value, path, line_number);
else if ( !strcmp(name, "system") )

View File

@ -22,9 +22,14 @@
struct conf
{
char* channel;
bool force_mirror;
bool grub;
char* mirror;
bool newsrc;
bool ports;
char* release_key;
char* release_sig_url;
bool src;
bool system;
};

View File

@ -494,6 +494,21 @@ int main(void)
// TODO: You can leave this program by pressing ^C but it can leave your
// system in an inconsistent state.
if ( conf.channel )
install_configurationf("upgrade.conf", "a", "channel = %s\n",
conf.channel);
if ( conf.force_mirror != false )
install_configurationf("upgrade.conf", "a", "force_mirror = %s\n",
conf.force_mirror ? "yes" : "no");
if ( conf.mirror )
install_configurationf("upgrade.conf", "a", "mirror = %s\n",
conf.mirror);
if ( conf.release_key )
install_configurationf("upgrade.conf", "a", "release_key = %s\n",
conf.release_key);
if ( conf.release_sig_url )
install_configurationf("upgrade.conf", "a", "release_sig_url = %s\n",
conf.release_sig_url);
install_configurationf("upgrade.conf", "a", "src = yes\n");
// TODO: GUI support.

View File

@ -330,6 +330,10 @@ int main(int argc, char* argv[])
if ( copy_files )
{
// TODO: Update /etc/upgrade.conf with new release values.
// TODO: What about native upgrades using make sysmerge? Should those
// values be updated then? Should there be an option to control
// this behavior?
const char* target = "";
if ( wait )
{

View File

@ -868,6 +868,7 @@ int main(void)
}
if ( conf.system )
upgrade_finalize(target_release, &new_release, "", ".");
// TODO: Update /etc/upgrade.conf with new release values.
if ( conf.system )
{
printf(" - Creating initrd...\n");

View File

@ -26,11 +26,14 @@ tix-vars \
PROGRAMS:=\
$(BINARIES) \
tix-clean \
tix-eradicate-libtool-la \
tix-fetch \
tix-iso-add \
tix-iso-bootconfig \
tix-iso-liveconfig \
tix-port \
tix-upgrade \
MANPAGES8=\
tix-build.8 \

68
tix/tix-clean Executable file
View File

@ -0,0 +1,68 @@
#!/bin/sh
# Copyright (c) 2017 Jonas 'Sortie' Termansen.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# tix-clean
# Remove temporary tix files.
set -e
collection=""
sysroot=""
dashdash=
previous_option=
for argument do
if test -n "$previous_option"; then
eval $previous_option=\$argument
previous_option=
continue
fi
case $argument in
*=?*) parameter=$(expr "X$argument" : '[^=]*=\(.*\)' || true) ;;
*=) parameter= ;;
*) parameter=yes ;;
esac
case $dashdash$argument in
--) dashdash=yes ;;
-o) previous_option=output ;;
--collection=*) collection=$parameter ;;
--collection) previous_option=collection ;;
--sysroot=*) sysroot=$parameter ;;
--sysroot) previous_option=sysroot ;;
-*) echo "$0: unrecognized option $argument" >&2
exit 1 ;;
*)
if [ $operand = 1 ]; then
input="$argument"
operand=2
elif [ $operand = 2 ]; then
directory="$argument"
operand=3
else
echo "$0: unexpected extra operand $argument" >&2
exit 1
fi
;;
esac
done
if test -n "$previous_option"; then
echo "$0: option '$argument' requires an argument" >&2
exit 1
fi
rm -rf "$collection/var/cache/tix"

424
tix/tix-fetch Executable file
View File

@ -0,0 +1,424 @@
#!/bin/sh
# Copyright (c) 2017, 2021 Jonas 'Sortie' Termansen.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# tix-fetch
# Download operating system files.
set -e
boot=false
collection=""
continue=""
execpatch=false
initrd=false
insecure_downgrade_to_http=false
insecure_no_check_certificate=false
input_release_file=
input_release_sig_file=
input_sha256sum=
normalize=false
output=""
outputdir=""
output_release_file= # TODO: A better term for this?
output_release_sig_file= # TODO: A better term for this?
output_sha256sum=
patch=false
port=false
porttix=false
release=false
sha256=false
sha256sum=false
source=false
source_full=false
srctix=false
sysroot=""
toolchain=false
url=false
url_master=false
url_master_release=false
url_mirror=false
url_mirror_release=false
url_release_sig=false
url_sha256sum=false
# TODO: Option to select this default:
# TODO: This hides errors. Fix wget so it has a quiet, but errors, mode.
wget_options="-q --show-progress"
# TODO: Ability to get source code easily for gcc/binutils/libstdc++.
dashdash=
previous_option=
for argument do
if test -n "$previous_option"; then
eval $previous_option=\$argument
previous_option=
shift
continue
fi
case $argument in
*=?*) parameter=$(expr "X$argument" : '[^=]*=\(.*\)' || true) ;;
*=) parameter= ;;
*) parameter=yes ;;
esac
case $dashdash$argument in
--) dashdash=yes ;;
-c) continue="-c" ;;
# TODO: Support -ofoo
-o) previous_option=output ;;
-O) previous_option=outputdir ;;
-q) wget_options="-q" ;;
-v) wget_options="-v" ;;
--boot) boot=true ;;
--collection=*) collection=$parameter ;;
--collection) previous_option=collection ;;
--continue) continue="--continue" ;;
--download-non-verbose) previous_option="-nv" ;;
--download-non-verbose) previous_option="-v" ;;
--download-quiet) previous_option="-q" ;;
--download-verbose) previous_option="-v" ;;
--execpatch) execpatch=true ;;
--initrd) initrd=true ;;
--input-release-file=*) input_release_file=$parameter ;;
--insecure-downgrade-to-http) insecure_downgrade_to_http=true ;;
--insecure-no-check-certificate) insecure_no_check_certificate=true ;;
--input-release-file) previous_option=input_release_file ;;
--input-release-sig-file=*) input_release_sig_file=$parameter ;;
--input-release-sig-file) previous_option=input_release_sig_file ;;
--input-sha256sum=*) input_sha256sum=$parameter ;;
--input-sha256sum) previous_option=input_sha256sum ;;
--normalize) normalize=true ;;
--nv) wget_options="-nv" ;;
--outputdir=*) outputdir=$parameter ;;
--outputdir) previous_option=outputdir ;;
--output=*) output=$parameter ;;
--output) previous_option=output ;;
--output-release-file=*) output_release_file=$parameter ;;
--output-release-file) previous_option=output_release_file ;;
--output-release-sig-file=*) output_release_sig_file=$parameter ;;
--output-release-sig-file) previous_option=output_release_sig_file ;;
--output-sha256sum=*) output_sha256sum=$parameter ;;
--output-sha256sum) previous_option=output_sha256sum ;;
--patch) patch=true ;;
--port) port=true ;;
--porttix) porttix=true ;;
--release) release=true ;;
--sha256) sha256=true ;;
--sha256sum) sha256sum=true ;;
--source-full) source_full=true ;;
--source) source=true ;;
--srctix) srctix=true ;;
--sysroot) previous_option=sysroot ;;
--sysroot=*) sysroot=$parameter ;;
--toolchain) toolchain=true ;;
--url) url=true ;;
--url-master) url_master=true ;;
--url-mirror) url_mirror=true ;;
--url-master-release) url_master_release=true ;;
--url-mirror-release) url_mirror_release=true ;;
--url-release-sig) url_release_sig=true ;;
--url-sha256sum) url_sha256sum=true ;;
--wget-options) previous_option=wget_options ;;
--wget-options=*) wget_options=$parameter ;;
-*) echo "$0: unrecognized option $argument" >&2
exit 1 ;;
*) break ;;
esac
shift
done
if test -n "$previous_option"; then
echo "$0: option '$argument' requires an argument" >&2
exit 1
fi
# TODO: Mutually incompatible options.
conf() {
grep -E "^$1[[:space:]]*=" -- "$collection/etc/upgrade.conf" |
tail -n 1 |
sed -E 's/^[^=]*=[[:space:]]*(|.*[^[:space:]])[[:space:]]*/\1/'
}
tmpdir=$(mktemp -dt tix-fetch-port.XXXXXX)
trap 'rm -rf -- "$tmpdir"' EXIT HUP INT QUIT TERM
RELEASE_KEY=$(conf release_key)
RELEASE_SIG_URL=$(conf release_sig_url)
PREFERRED_MIRROR=$(conf mirror)
FORCE_MIRROR=$(conf force_mirror)
USER_AGENT="$(uname -s)/$(uname -r) ($(uname -m); $(uname -v))"
if $insecure_no_check_certificate; then
echo "$0: warning: insecurely not checking https certificates" >&2
wget_options="$wget_options --no-check-certificate"
fi
if $insecure_downgrade_to_http; then
echo "$0: warning: insecurely downloading without https" >&2
RELEASE_SIG_URL="$(echo "$RELEASE_SIG_URL" | sed -E 's,^https:,http:,')"
fi
if $url_release_sig; then
printf "%s\n" "$RELEASE_SIG_URL"
exit
fi
# HACK: Provide more useful errors when wget is silent:
do_wget() {
(set +e
wget "$@"
status=$?
set -e
what=
case $status in
0) exit 0 ;;
1) what="Generic error" ;;
2) what="Parse error" ;;
3) what="File I/O error" ;;
4) what="Network I/O error" ;;
5) what="Transport Layer Security verification failure" ;;
6) what="Username/password failure" ;;
7) what="Protocol error" ;;
8) what="Error response" ;;
*) what="Exit code $status" ;;
esac
echo "$0: $what when running: wget $@" >&2
exit $status)
}
# Fetch signed release description.
if [ -z "$input_release_file" ]; then
if [ -z "$input_release_sig_file" ]; then
(cd "$tmpdir" &&
do_wget -U "$USER_AGENT" $wget_options -O release.sh.sig \
-- "$RELEASE_SIG_URL")
else
cp -T -- "$input_release_sig_file" "$tmpdir/release.sh.sig"
fi
signify -Vq -p "$RELEASE_KEY" -em "$tmpdir/release.sh"
else
cp -T -- "$input_release_file" "$tmpdir/release.sh"
fi
# Store the signed release file if requested.
if [ -n "$output_release_sig_file" ]; then
cp -T -- "$tmpdir/release.sh.sig" "$output_release_sig_file"
fi
# Store the release file (without signature) if requested.
if [ -n "$output_release_file" ]; then
cp -T -- "$tmpdir/release.sh" "$output_release_file"
fi
# Load the release description.
# TODO: SECURITY: REMOTE CODE EXECUTION OF SIGNED REMOTE CODE.
# TODO: SECURITY: Protect against responding with older release.sh.
. "`realpath -- "$tmpdir/release.sh"`" # Avoid PATH search with absolute path.
if $url_master; then
printf "%s\n" "$MASTER"
exit
elif $url_master_release; then
printf "%s\n" "$MASTER/$RELEASE"
exit
fi
# Default to the master mirror but switch to the preferred mirror if the release
# description knows about the mirror and believes it to be trustworthy.
MIRROR="$MASTER"
for POTENTIAL_MIRROR in $MIRRORS; do
if [ "$POTENTIAL_MIRROR" = "$PREFERRED_MIRROR" ]; then
MIRROR="$PREFERRED_MIRROR"
fi
done
if [ -n "$PREFERRED_MIRROR" ] && [ "$MIRROR" != "$PREFERRED_MIRROR" ]; then
if [ "$FORCE_MIRROR" = yes ]; then
MIRROR="$PREFERRED_MIRROR"
else
echo "$0: warning: ignoring unsupported mirror $PREFERRED_MIRROR" >&2
fi
fi
if $insecure_downgrade_to_http; then
MIRROR="$(echo "$MIRROR" | sed -E 's,^https:,http:,')"
fi
if $url_mirror; then
printf "%s\n" "$MIRROR"
exit
elif $url_mirror_release; then
printf "%s\n" "$MIRROR/$RELEASE"
exit
fi
RELEASE_URL="$MIRROR/$RELEASE"
# Fetch sha256sum file and check its SHA256 hash with the release description.
if $url_sha256sum; then
printf "%s\n" "$RELEASE_URL/$SHA256SUM_FILE"
exit
fi
if [ -z "$input_sha256sum" ]; then
# TODO: If the mirror doesn't work, try the master.
(cd "$tmpdir" &&
do_wget -U "$USER_AGENT" $wget_options -O sha256sum \
-- "$RELEASE_URL/$SHA256SUM_FILE")
else
cp -T -- "$input_sha256sum" "$tmpdir/sha256sum"
fi
# TODO: Check if upstream release description changed, if so, start over.
echo "$SHA256SUM_SHA256SUM $tmpdir/sha256sum" | sha256sum -cq
# Store the sha256sum file if requested.
if [ -n "$output_sha256sum" ]; then
cp -T -- "$tmpdir/sha256sum" "$output_sha256sum"
fi
escape_extended_regex() {
printf "%s\n" "$1" | sed -E -e 's/[[$()*?\+.^{|}]/\\\0/g'
}
# TODO: Remove:
#escape_extended_regex_test_self() {
# printf "%s\n" "$1" | grep -E "^$(escape_extended_regex "$1")\$"
#}
request() {
REQUEST="$1"
REQUESTDIR="$2"
REQUESTFINAL="${3-$1}"
FULLREQUEST="$REQUESTDIR$REQUEST"
if $url; then
printf '%s\n' "$RELEASE_URL/$FULLREQUEST"
return
fi
if $sha256 || $sha256sum; then
set +e # Don't fail if grep exits 1 (no match).
# TODO: Should this be a checksum(1) feature to look up a hash?
grep -E "^[0-9a-fA-F]{64} $(escape_extended_regex "$FULLREQUEST")$" \
"$tmpdir/sha256sum" > "$tmpdir/match"
EXITCODE=$?
set -e
if [ 2 -le "$EXITCODE" ]; then (exit $EXITCODE); fi
if $sha256 && [ -s "$tmpdir/match" ]; then
grep -Eo '^[0-9a-fA-F]{64}' "$tmpdir/match"
fi
if $sha256sum && [ -s "$tmpdir/match" ]; then
cat "$tmpdir/match"
fi
return
fi
# Decide the final location the file will end up.
if [ -n "$output" ]; then
FINAL="$output"
OUTPUTDIR=$(dirname -- "$output")
elif [ -n "$outputdir" ]; then
FINAL="$outputdir/$REQUESTFINAL"
OUTPUTDIR="$outputdir"
else
FINAL="$REQUESTFINAL"
OUTPUTDIR=.
fi
# If a resumable download, store the file directly to the destination path.
# Otherwise download to a temporary directory and move only to the final
# location if the cryptographic check is passed.
if [ -n "$continue" ]; then
DOWNLOADDIR="$OUTPUTDIR"
OUTPUT="$FINAL"
else
DOWNLOADDIR="$tmpdir/download"
OUTPUT="$DOWNLOADDIR/$REQUEST"
mkdir -p -- "$DOWNLOADDIR"
fi
# Fetch the file.
# TODO: If the mirror doesn't work, try the master.
(cd "$DOWNLOADDIR" &&
mkdir -p -- "$(dirname -- "$REQUEST")" &&
do_wget -U "$USER_AGENT" $wget_options $continue -O "$REQUEST" \
-- "$RELEASE_URL/$FULLREQUEST")
# Verify the cryptographic integrity of the fetched file.
ABSOLUTE_OUTPUT=$(realpath -- "$OUTPUT")
mkdir -p -- "$tmpdir/check"
(cd "$tmpdir/check" &&
mkdir -p -- "$(dirname -- "$FULLREQUEST")"
ln -s -- "$ABSOLUTE_OUTPUT" "$FULLREQUEST"
if ! sha256sum -q -C "$tmpdir/sha256sum" -- "$FULLREQUEST"; then
# Don't leave behind a file that didn't pass a cryptographic check.
if [ -n "$continue" ]; then
# TODO: Check if upstream release description changed, if so, start over.
echo "error: Deleting corrupted output file: $OUTPUT" 2>&1
rm -f -- "$OUTPUT"
fi
exit 1
fi)
rm -rf -- "$tmpdir/check"
# Move the file to the final destination if not already.
if [ -z "$continue" ]; then
if [ -z "$output" ]; then
(cd "$OUTPUTDIR" && mkdir -p -- "$(dirname -- "$REQUESTFINAL")")
fi
cp -T -- "$OUTPUT" "$FINAL"
rm -rf -- "$tmpdir/download"
fi
}
if $release; then
request "$BUILD_FILE" "" "$(basename -- "$BUILD_FILE")"
fi
# TODO: --source, --source-full
# TODO: --binutils, --gcc, --libstdc++
# Fetch each of the specified signed files from the mirror.
for REQUEST; do
# If --port then fetch the port by the requested name.
if $port; then
REQUEST="$REQUEST.tix.tar.xz"
REQUESTDIR="repository/$MACHINE-sortix/"
elif $boot; then
REQUEST="$REQUEST"
REQUESTDIR="$MACHINE/boot/"
elif $initrd; then
REQUEST="$REQUEST.initrd.xz"
REQUESTDIR="$MACHINE/boot/"
elif $patch; then
REQUEST="$REQUEST.patch"
REQUESTDIR="patches/"
elif $normalize; then
REQUEST="$REQUEST.normalize"
REQUESTDIR="patches/"
elif $srctix; then
REQUEST="$REQUEST.srctix.tar.xz"
REQUESTDIR="srctix/"
elif $porttix; then
REQUEST="$REQUEST.porttix.tar.xz"
REQUESTDIR="porttix/"
elif $toolchain; then
REQUESTDIR="toolchain/"
else
REQUESTDIR=""
fi
request "$REQUEST" "$REQUESTDIR"
done

230
tix/tix-upgrade Executable file
View File

@ -0,0 +1,230 @@
#!/bin/sh
# Copyright (c) 2017, 2021 Jonas 'Sortie' Termansen.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# tix-upgrade
# Upgrade operating system and ports.
set -e
cachedir=""
clean=false
collection=""
download_only=false
fetch_options=
ports_only=false
sysroot=""
upgrade_ports=false
upgrade_system=false
wait=""
dashdash=
previous_option=
for argument do
if test -n "$previous_option"; then
eval $previous_option=\$argument
previous_option=
shift
continue
fi
case $argument in
*=?*) parameter=$(expr "X$argument" : '[^=]*=\(.*\)' || true) ;;
*=) parameter= ;;
*) parameter=yes ;;
esac
case $dashdash$argument in
--) dashdash=yes ;;
-w) wait=-w ;;
--cachedir=*) cachedir=$parameter ;;
--cachedir) previous_option=cachedir ;;
--clean) clean=true ;;
--collection=*) collection=$parameter ;;
--collection) previous_option=collection ;;
--download-only) download_only=true ;;
--insecure-downgrade-to-http) fetch_options="$fetch_options $argument" ;;
--insecure-no-check-certificate) fetch_options="$fetch_options $argument" ;;
--ports) upgrade_ports=true ;;
--system) upgrade_system=true ;;
--sysroot) previous_option=sysroot ;;
--sysroot=*) sysroot=$parameter ;;
--wait) wait=--wait ;;
-*) echo "$0: unrecognized option $argument" >&2
exit 1 ;;
*) break ;;
esac
shift
done
if test -n "$previous_option"; then
echo "$0: option '$argument' requires an argument" >&2
exit 1
fi
# TODO: Reject additional operands.
if [ -z "$collection" ]; then
collection="$sysroot"
fi
if [ -n "$collection" ]; then
collection=$(cd "$collection" && pwd)
fi
if ! $upgrade_ports && ! $upgrade_system; then
upgrade_ports=true
upgrade_system=true
fi
# Update only ports if this isn't a whole system installation.
if [ ! -e "$collection/tix/manifest/system" ]; then
ports_only=true
fi
if [ -z "$cachedir" ]; then
cachedir="$collection/var/cache/tix"
fi
if $clean; then
echo "Removing cache directory: $cachedir"
rm -rf -- "$cachedir"
fi
mkdir -p -- "$cachedir"
mkdir -p -- "$cachedir/new"
# Fetch latest release.sig.sh from the master and its matching sha256sum file.
tix-fetch $fetch_options \
--output-release-sig-file="$cachedir/new/release.sh.sig" \
--output-sha256sum="$cachedir/new/sha256sum"
# If release.sig.sh or sha256sum changed, clean the cache directory of downloads
# that were currently in progress as they might not have the right checksums.
# TODO: This requires diff(1) in the base system! Avoid that. Get a cmp(1)!
if ! diff -- "$cachedir/release.sh.sig" \
"$cachedir/new/release.sh.sig" 1>/dev/null 2>/dev/null ||
! diff -- "$cachedir/sha256sum" \
"$cachedir/new/sha256sum" 1>/dev/null 2>/dev/null; then
rm -rf -- "$cachedir/boot"
rm -rf -- "$cachedir/repository"
rm -rf -- "$cachedir/sysroot"
fi
# Store the new release.sig.sh and sha256sum files so we can resume the download
# if cancelled and these files still match.
mv -- "$cachedir/new/release.sh.sig" "$cachedir/release.sh.sig"
mv -- "$cachedir/new/sha256sum" "$cachedir/sha256sum"
rm -rf -- "$cachedir/new"
mkdir -p "$cachedir/boot"
mkdir -p "$cachedir/repository"
if $upgrade_system; then
# Fetch the base system initrds from the mirror.
# TODO: What about the system source code in /src?
# TODO: Get the overlay initrd if it exists.
tix-fetch $fetch_options \
--input-release-sig-file="$cachedir/release.sh.sig" \
--input-sha256sum="$cachedir/sha256sum" \
-c --initrd -O "$cachedir/boot" -- system
fi
if $upgrade_ports; then
# Fetch each port from the mirror.
ports=$(LC_ALL=C sort -- "$collection/tix/installed.list")
# TODO: This fails if the port does not exist upstream.
mkdir -p "$cachedir/repository"
for port in $ports; do
# The port has a hash if if it exists upstream.
sha256=$(tix-fetch $fetch_options \
--input-release-sig-file="$cachedir/release.sh.sig" \
--input-sha256sum="$cachedir/sha256sum" \
--sha256 --port -- $port)
# If the port exists upstream, get the latest version.
if [ -n "$sha256" ]; then
tix-fetch $fetch_options \
--input-release-sig-file="$cachedir/release.sh.sig" \
--input-sha256sum="$cachedir/sha256sum" \
-c --port -O "$cachedir/repository" -- $port
fi
done
fi
# Stop if only downloading.
if $download_only; then
exit
fi
rm -rf -- "$cachedir/sysroot"
mkdir -p -- "$cachedir/sysroot"
if $upgrade_system; then
# Extract the base system into the sysroot.
rm -rf -- "$cachedir/sysroot"
mkdir -p -- "$cachedir/sysroot"
for initrd in system overlay; do
initrd_path="$cachedir/boot/$initrd.initrd"
if [ -e "$initrd_path.xz" ]; then
echo "Extracting $initrd.initrd.xz..."
unxz -k "$initrd_path.xz"
initrdfs "$initrd_path" extract -C "$cachedir/sysroot" /
rm -f "$initrd_path.xz"
fi
done
fi
# TODO: These install all the ports in "$cachedir/repository" but the directory
# might not have been cleared, it could contain unverified ports.
if $upgrade_system; then
# Do a full system upgrade using the sysroot and the new ports.
# TODO: If sysmerge -w, such as on ABI upgrades, the e2fsprogs package is not
# installed in the system root and the new initrd might not contain a
# /sbin/fsck.ext2 and the system can become bricked if it needs a fsck
# on boot.
# TODO: There's no support here for doing a sysmerge on a given sysroot.
if $upgrade_ports; then
# TODO: Get the architecture from somewhere else than /etc/machine?
tix-collection "$cachedir/sysroot" create \
--platform="$(cat -- "$sysroot/etc/machine")-sortix" \
--prefix= --generation=2
tix-install --collection="$cachedir/sysroot" -- "$cachedir/repository/"*
full=--full
else
# TODO: Is this case supported?
full=
fi
sysmerge $full $wait "$cachedir/sysroot"
elif $upgrade_ports; then
# Upgrade to each of the new ports.
# TODO: tix-install --reinstall is unsupported due to lack of support for
# files moving between manifests or being deleted.
tix-install --reinstall -- "$cachedir/repository/"*
fi
rm -rf -- "$cachedir/boot"
rm -rf -- "$cachedir/repository"
rm -rf -- "$cachedir/sysroot"
#tmp=
#trap '[ -n "$tmp" ] && rm -rf "$tmp"' EXIT HUP INT QUIT TERM
#tmp=$(mktemp -dt upgrade.XXXXXX)
#mkdir -p "$tmp/tmp"
#export TMPDIR="$tmp/tmp"
#(cd "$tmp" && tix-fetch --release -o sortix.iso)
#mkdir -p "$tmp/sortix.iso.d"
#echo "Extracting sortix.iso..."
#xorriso -osirrox on -indev "$tmp/sortix.iso" -extract / "$tmp/sortix.iso.d" > /dev/null 2> /dev/null
#rm -f "$tmp/sortix.iso"

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2015, 2016, 2017 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -170,6 +170,8 @@ static void version(FILE* fp, const char* argv0)
int main(int argc, char* argv[])
{
const char* tmp = getenv_def("TMPDIR", "/tmp");
params_t params;
memset(&params, 0, sizeof(params));
params.collection = NULL;
@ -245,7 +247,7 @@ int main(int argc, char* argv[])
errx(1, "error: no command specified.");
const char* cmd = argv[1];
if ( !strcmp(cmd, "install") )
if ( !strcmp(cmd, "old-install") )
{
if ( argc == 2 )
errx(1, "expected list of packages to install after `install'");
@ -276,6 +278,45 @@ int main(int argc, char* argv[])
return 0;
}
else if ( !strcmp(cmd, "install") )
{
initialize_tmp(tmp, "tix-install");
if ( chdir(tmp_root) < 0 )
err(1, "%s", tmp_root);
if ( fork_and_wait_or_death() )
{
char** fetch_argv = malloc(sizeof(char*) * (5 + (argc-2) + 1));
fetch_argv[0] = (char*) "tix-fetch";
fetch_argv[1] = (char*) "--collection";
fetch_argv[2] = params.collection;
fetch_argv[3] = (char*) "--port";
fetch_argv[4] = (char*) "--";
int offset = 5;
for ( int i = 0; i < argc-2; i++ )
fetch_argv[offset + i] = argv[2 + i];
fetch_argv[offset + argc-2] = NULL;
execvp(fetch_argv[0], (char* const*) fetch_argv);
err(127, "`%s'", fetch_argv[0]);
}
for ( int i = 2; i < argc; i++ )
{
const char* pkg_name = argv[i];
char* pkg_path = print_string("%s%s", pkg_name, ".tix.tar.xz");
if ( fork_and_wait_or_death() )
{
const char* install_argv[] =
{
"tix-install",
"--collection", params.collection,
"--", pkg_path,
NULL
};
execvp(install_argv[0], (char* const*) install_argv);
err(127, "`%s'", install_argv[0]);
}
}
}
else
{
fprintf(stderr, "%s: unknown command: `%s'\n", argv0, cmd);