Add tix-upgrade(8).

This commit is contained in:
Jonas 'Sortie' Termansen 2017-04-02 18:41:59 +02:00
parent 1623063a72
commit 9d447f48e7
19 changed files with 1004 additions and 13 deletions

View File

@ -231,6 +231,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)" && \
@ -269,6 +271,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
@ -452,6 +455,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/root -m 700
cp -RT "$(SYSROOT)/etc/skel" $(LIVE_INITRD).d/root
(echo "You can view the documentation for new users by typing:" && \

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 irssi libcurl libcurses libssl libstdc++ m4 make nano ntpd patch perl pkg-config python ssh tar texinfo vim wget xz xorriso"
set_minimal="cut dash e2fsprogs grep grub libssl mdocml sed signify tar wget xargs xz"
set_basic="$set_minimal binutils bison bzip2 diffutils ed flex gawk gcc git gzip irssi libcurl libcurses libstdc++ m4 make nano ntpd patch perl pkg-config python ssh texinfo vim xorriso"
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.
@ -44,7 +48,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
@ -56,7 +85,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
@ -68,17 +108,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 .
@ -95,6 +157,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
@ -102,13 +176,14 @@ Upgrade configuration.
.El
.Sh EXAMPLES
.Bd -literal
system = yes
grub = yes
ports = yes
src = no
grub = yes
system = yes
.Ed
.Sh SEE ALSO
.Xr autoinstall.conf 5 ,
.Xr autoupgrade.conf 5 ,
.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

@ -485,6 +485,8 @@ void upgrade_prepare(const struct release* old_release,
}
free(path);
}
// TODO: Add upstream mirror to /etc/upgrade.conf.
}
void upgrade_finalize(const struct release* old_release,

View File

@ -630,6 +630,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");
bool kblayout_setable = 0 <= tcgetblob(0, "kblayout", NULL, 0) ||

View File

@ -403,6 +403,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* sysmerge = target;
if ( wait )
{

View File

@ -904,6 +904,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,12 +26,15 @@ tix-vars \
PROGRAMS:=\
$(BINARIES) \
tix-clean \
tix-eradicate-libtool-la \
tix-fetch \
tix-iso-add \
tix-iso-bootconfig \
tix-iso-liveconfig \
tix-port \
tix-repository \
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"

451
tix/tix-fetch Executable file
View File

@ -0,0 +1,451 @@
#!/bin/sh
# Copyright (c) 2017, 2021, 2023 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
package=false
release=false
repository_metadata=false
sha256=false
sha256sum=false
source=false
source_full=false
sysroot=""
toolchain=false
url=false
url_main=false
url_main_release=false
url_mirror=false
url_mirror_release=false
url_release_sig=false
url_sha256sum=false
upgrade=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) wget_options="-nv" ;;
--download-non-verbose) wget_options="-v" ;;
--download-quiet) wget_options="-q" ;;
--download-verbose) wget_options="-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 ;;
--output-upgrade-file=*) output_upgrade_file=$parameter ;;
--output-upgrade-file) previous_option=output_upgrade_file ;;
--package) package=true ;;
--patch) patch=true ;;
--repository-metadata) repository_metadata=true ;;
--sha256) sha256=true ;;
--sha256sum) sha256sum=true ;;
--source-full) source_full=true ;;
--source) source=true ;;
--sysroot) previous_option=sysroot ;;
--sysroot=*) sysroot=$parameter ;;
--toolchain) toolchain=true ;;
--upgrade) upgrade=true ;;
--url) url=true ;;
--url-main) url_main=true ;;
--url-mirror) url_mirror=true ;;
--url-main-release) url_main_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() {
sed -E -e 's/([a-zA-Z0-9_]+) *? *= */\U\1=/' \
-e 's/=yes$/=true/' -e 's/no$/=false/' "$3" | \
tix-vars -d "$2" - "$4"
}
tmpdir=$(mktemp -dt tix-fetch.XXXXXX)
trap 'rm -rf -- "$tmpdir"' EXIT HUP INT QUIT TERM
upgrade_conf="${collection%/}/etc/upgrade.conf"
CHANNEL=$(conf -d '' "$upgrade_conf" CHANNEL)
RELEASE_KEY=$(conf -d '' "$upgrade_conf" RELEASE_KEY)
RELEASE_SIG_URL=$(conf -d '' "$upgrade_conf" RELEASE_SIG_URL)
PREFERRED_MIRROR=$(conf -d '' "$upgrade_conf" PREFERRED_MIRROR)
FORCE_MIRROR=$(conf -d '' "$upgrade_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.
download_release_sh() {
(cd "$tmpdir" &&
do_wget -U "$USER_AGENT" $wget_options -O release.sh.sig \
-- "$RELEASE_SIG_URL")
signify -Vq -p "$RELEASE_KEY" -em "$tmpdir/release.sh"
}
true > "$tmpdir/upgrade.sh"
if [ -z "$input_release_file" -a -z "$input_release_sig_file" ]; then
download_release_sh
# TODO: tix-vars's output is not quoted so it can be input again.
tix-vars "$tmpdir/release.sh" | \
grep -E '^UPGRADE_=' | \
cat > "$tmpdir/upgrade.sh"
UPGRADE_SIG_URL=$(tix-vars -d '' "$tmpdir/upgrade.sh" UPGRADE_SIG_URL)
if $upgrade && [ -n "$UPGRADE_SIG_URL" ]; then
RELEASE_SIG_URL="$UPGRADE_SIG_URL"
RELEASE_KEY=$(tix-vars "$tmpdir/upgrade.sh" UPGRADE_KEY)
download_release_sh
fi
fi
if [ -n "$input_release_file" ]; then
cp -T -- "$input_release_file" "$tmpdir/release.sh"
elif [ -n "$input_release_sig_file" ]; then
signify -Vq -p "$RELEASE_KEY" -em "$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
# Store the upgrade file if requested.
if [ -n "$output_upgrade_file" ]; then
cp -T -- "$tmpdir/upgrade.sh" "$output_upgrade_file"
fi
# Load the release description.
# TODO: SECURITY: Protect against responding with older release.sh.
# TODO: DO NOT SUBMIT: Temporary compatibility.
MAIN=$(tix-vars -d '' "$tmpdir/release.sh" MAIN)
MASTER=$(tix-vars -d '' "$tmpdir/release.sh" MASTER)
if [ -z "$MAIN" ]; then
MAIN="$MASTER"
fi
RELEASE=$(tix-vars "$tmpdir/release.sh" RELEASE)
MACHINE=$(tix-vars "$tmpdir/release.sh" MACHINE)
SHA256SUM_FILE=$(tix-vars -d sha256sum "$tmpdir/release.sh" SHA256SUM_FILE)
SHA256SUM_SHA256SUM=$(tix-vars "$tmpdir/release.sh" SHA256SUM_SHA256SUM)
MIRRORS=$(tix-vars -d '' "$tmpdir/release.sh" MIRRORS)
if $url_main; then
printf "%s\n" "$MAIN"
exit
elif $url_main_release; then
printf "%s\n" "$MAIN/$RELEASE"
exit
fi
# Default to the main mirror but switch to the preferred mirror if the release
# description knows about the mirror and believes it to be trustworthy.
MIRROR="$MAIN"
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" = true ]; then
MIRROR="$PREFERRED_MIRROR"
else
echo "$0: warning: ignoring unsupported mirror $PREFERRED_MIRROR" >&2
fi
fi
# TODO: Make sure the distant future http downgrade is supported.
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 main.
(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'
}
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 main.
(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
MIRRORS=$(tix-vars "$tmpdir/release.sh" BUILD_FILE)
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 $package; then
REQUEST="$REQUEST.tix.tar.xz"
REQUESTDIR="repository/$MACHINE-sortix/"
elif $repository_metadata; then
REQUESTDIR="repository/$MACHINE-sortix/"
elif $boot; then
REQUEST="$REQUEST"
REQUESTDIR="$MACHINE/boot/"
elif $initrd; then
REQUEST="$REQUEST.tar.xz"
REQUESTDIR="$MACHINE/boot/"
elif $patch; then
REQUEST="$REQUEST.patch"
REQUESTDIR="patches/"
elif $normalize; then
REQUEST="$REQUEST.normalize"
REQUESTDIR="patches/"
elif $toolchain; then
REQUESTDIR="toolchain/"
else
REQUESTDIR=""
fi
request "$REQUEST" "$REQUESTDIR"
done

273
tix/tix-upgrade Executable file
View File

@ -0,0 +1,273 @@
#!/bin/sh
# Copyright (c) 2017, 2021, 2023, 2024 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=""
cancel=false
clean=false
collection=/
download_only=false
fetch_options=
sysroot=""
upgrade=--upgrade
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 ;;
--cancel) cancel=true ;;
--clean) clean=true ;;
--collection=*) collection=$parameter ;;
--collection) previous_option=collection ;;
--download-only) download_only=true ;;
--fetch-options=*) fetch_options="$parameter" ;;
--fetch-options) previous_option=fetch_options ;;
--insecure-downgrade-to-http) fetch_options="$fetch_options $argument" ;;
--insecure-no-check-certificate) fetch_options="$fetch_options $argument" ;;
--no-upgrade) upgrade= ;;
--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
if [ 0 -lt $# ]; then
echo "$0: Unexpected extra operand: $1" >&2
exit 1
fi
conf() {
sed -E -e 's/([a-zA-Z0-9_]+) *? *= */\U\1=/' \
-e 's/=yes$/=true/' -e 's/no$/=false/' "$3" | \
tix-vars -d "$2" - "$4"
}
escape_extended_regex_sed() {
printf "%s\n" "$1" | sed -E -e 's/[[$()*?\+.^{|}'"$2"']/\\\0/g'
}
collection=$(cd "$collection" && pwd)
if ! $upgrade_ports && ! $upgrade_system; then
upgrade_ports=true
upgrade_system=true
if [ -e "$collection/etc/upgrade.conf" ]; then
upgrade_ports=$(conf -d true "$collection/etc/upgrade.conf" PORTS)
upgrade_system=$(conf -d true "$collection/etc/upgrade.conf" SYSTEM)
fi
fi
# If this isn't a system installation, only upgrade the ports.
if [ ! -e "$collection/tix/manifest/system" ]; then
upgrade_system=false
fi
case "$upgrade_system$upgrade_ports" in
truefalse) what_to_upgrade=--system;;
falsetrue) what_to_upgrade=--ports;;
*) what_to_upgrade=;;
esac
if [ -z "$cachedir" ]; then
cachedir="${collection%/}/var/cache/tix"
fi
if $cancel || $clean; then
echo "Removing cache directory: $cachedir"
rm -rf -- "$cachedir"
fi
if $cancel; then
sysmerge -t "$collection" --cancel
exit
fi
mkdir -p -- "$cachedir"
mkdir -p -- "$cachedir/new"
# Fetch the latest official signed release.sh and its matching sha256sum file.
tix-fetch $fetch_options \
--collection="$collection" \
--output-release-file="$cachedir/new/release.sh" \
--output-sha256sum="$cachedir/new/sha256sum" \
--output-upgrade-file="$cachedir/new/upgrade.sh" \
$upgrade
# If release.sh or sha256sum changed, clean the cache directory of downloads
# that were currently in progress as they might not have the right checksums.
if [ ! -e "$cachedir/release.sh" ] ||
[ ! -e "$cachedir/sha256sum" ] ||
[ ! -e "$cachedir/upgrade.sh" ] ||
! (cd "$cachedir/new" && sha256sum release.sh sha256sum upgrade.sh) |
(cd "$cachedir" && sha256sum -cs); then
rm -rf -- "$cachedir/boot"
rm -rf -- "$cachedir/repository"
rm -rf -- "$cachedir/sysroot"
fi
# Store the new release.sh and sha256sum files so we can resume the download
# if cancelled and these files still match.
mv -- "$cachedir/new/release.sh" "$cachedir/release.sh"
mv -- "$cachedir/new/sha256sum" "$cachedir/sha256sum"
mv -- "$cachedir/new/upgrade.sh" "$cachedir/upgrade.sh"
rm -rf -- "$cachedir/new"
# Check if we're upgrading to a new release.
UPGRADE_SIG_URL=$(tix-vars -d '' "$cachedir/upgrade.sh" UPGRADE_SIG_URL)
if [ -n "$UPGRADE_SIG_URL" ]; then
UPGRADE_CHANNEL=$(tix-vars "$cachedir/upgrade.sh" UPGRADE_CHANNEL)
UPGRADE_KEY=$(tix-vars "$cachedir/upgrade.sh" UPGRADE_KEY)
UPGRADE_NAME=$(tix-vars "$cachedir/upgrade.sh" UPGRADE_NAME)
if [ -n "$upgrade" ]; then
echo "Upgrading to $UPGRADE_NAME."
else
echo "Ignoring available upgrade to $UPGRADE_NAME."
fi
fi
# Decide what binary packages to upgrade.
installed_packages=$(LC_ALL=C ls -- "$collection/tix/tixinfo")
if $upgrade_system && $upgrade_ports; then
upgrade_packages="$installed_packages"
else
upgrade_packages=
for package in $installed_packages; do
is_system=$(tix-vars -d false "$collection/tix/tixinfo/$package" SYSTEM)
if ($upgrade_system && [ "$is_system" = true ]) ||
($upgrade_ports && [ "$is_system" = false ]); then
upgrade_packages="$upgrade_packages $package"
fi
done
fi
# TODO: Tracking sets like minimal/basic/full with new mandatory or recommended ports.
mkdir -p -- "$cachedir/repository"
tix-fetch $fetch_options \
--collection="$collection" \
--input-release-file="$cachedir/release.sh" \
--input-sha256sum="$cachedir/sha256sum" \
--repository-metadata -O "$cachedir/repository" renames.list
# Follow RENAMES recursively to handle renames, splits, and deletions.
rename() {
if grep -Eq "^$(escape_extended_regex_sed "$1"):" \
"$cachedir/repository/renames.list"; then
for new in $(grep -E "^$(escape_extended_regex_sed "$1"):" \
"$cachedir/repository/renames.list" |
grep -Eo '[^:]*$'); do
rename "$new"
done
else
echo "$1" | grep -Eo '^[^@]*'
fi
}
# Determine the final package list after the renames.
packages=""
for package in $(LC_ALL=C ls -- "$collection/tix/tixinfo"); do
edition=$(tix-vars -d 1 "$collection/tix/tixinfo/$package" EDITION)
packages="$packages $(rename "$package@$edition")"
done
# Sort and deduplicate the package list and check for existence.
packages=$(for package in $packages; do
# The package exists upstream if it has a hash.
if [ -n "$(tix-fetch $fetch_options \
--collection="$collection" \
--input-release-file="$cachedir/release.sh" \
--input-sha256sum="$cachedir/sha256sum" \
--sha256 --package -- $package)" ]; then
echo $package
fi
done | LC_ALL=C sort -u)
# Fetch each binary package from the mirror.
for package in $packages; do
tix-fetch $fetch_options \
--collection="$collection" \
--input-release-file="$cachedir/release.sh" \
--input-sha256sum="$cachedir/sha256sum" \
-c --package -O "$cachedir/repository" -- $package
done
# Stop if only downloading.
if $download_only; then
exit
fi
rm -rf -- "$cachedir/sysroot"
mkdir -p -- "$cachedir/sysroot"
# Forward the upgrade metadata.
UPGRADE_SIG_URL=$(tix-vars -d '' "$cachedir/upgrade.sh" UPGRADE_SIG_URL)
if [ -n $upgrade ] && [ -n "$UPGRADE_SIG_URL" ]; then
mkdir -p -- "$cachedir/etc"
# TODO: More flexible and simple model.
cat > "$cachedir/etc/upgrade.conf" << EOF
channel = $UPGRADE_CHANNEL
release_key = $UPGRADE_KEY
release_sig_url = $UPGRADE_SIG_URL
EOF
fi
# Extract the binary packages into the sysroot.
for package in $packages; do
echo "Extracting $package.tix.tar.xz..."
tar -C "$cachedir/sysroot" -xJf "$cachedir/repository/$package.tix.tar.xz"
rm -f "$cachedir/repository/$package.tix.tar.xz"
done
# Merge the new sysroot onto the installation.
sysmerge -t "$collection" --full $what_to_upgrade $wait "$cachedir/sysroot"
rm -rf -- "$cachedir/repository"
rm -rf -- "$cachedir/sysroot"

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, 2016, 2023 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2015, 2016, 2017, 2023 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
@ -186,6 +186,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;
@ -260,7 +262,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'");
@ -298,6 +300,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*) "--package";
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);