Third generation Tix.

The .tix.tar.xz binary package format now stores the contents in the root
rather than the data/ subdirectory and the tix metadata now has the same
layout as the loose files in /tix, such that a .tix.tar.xz package can
simply be directly extracted into the filesystem. The /tix/manifest/ is now
included in the binary package rather than being generated on installation.

The /tix/collection.conf and /tix/tixinfo metadata files are now in the
tix-vars(1) format in the style of port(5).

The /tix/installed.list file has been removed since it isn't loose file
compatible and one can list the /tix/tixinfo directory instead.

The /tix/repository.list file has been removed since the feature is unused
and doesn't match the future direction of tix.

The kernel support for tix binary packages has been removed since it will
simply install by extracting the tar archive into the root filesystem.

Add the post-install sha256sum to the port version stamp.
This commit is contained in:
Jonas 'Sortie' Termansen 2023-07-15 16:43:27 +02:00
parent b819428bd2
commit d189183900
16 changed files with 670 additions and 512 deletions

View File

@ -464,7 +464,7 @@ $(LIVE_INITRD): sysroot
echo "You can view the installation instructions by typing:" && \
echo && \
echo " man installation") > $(LIVE_INITRD).d/root/welcome
tix-collection $(LIVE_INITRD).d create --platform=$(HOST) --prefix= --generation=2
tix-collection $(LIVE_INITRD).d create --platform=$(HOST) --prefix= --generation=3
LC_ALL=C ls -A $(LIVE_INITRD).d | \
tar -cf $(LIVE_INITRD) -C $(LIVE_INITRD).d --numeric-owner --owner=0 --group=0 -T -
rm -rf $(LIVE_INITRD).d

View File

@ -82,7 +82,7 @@ export CXXFLAGS
# Initialize Tix package management in the system root if absent.
if [ "$OPERATION" = build ]; then
if [ ! -e "$SYSROOT/tix/collection.conf" ]; then
tix-collection "$SYSROOT" create --platform=$HOST --prefix= --generation=2
tix-collection "$SYSROOT" create --platform=$HOST --prefix= --generation=3
fi
fi
@ -138,7 +138,7 @@ for PACKAGE in $PACKAGES; do
--collection="$SYSROOT" \
--destination="$SORTIX_REPOSITORY_DIR" \
${END:+--end="$END"} \
--generation=2 \
--generation=3 \
--host=$HOST \
${SORTIX_PORTS_MIRROR:+--mirror="$SORTIX_PORTS_MIRROR"} \
--mirror-directory="$SORTIX_MIRROR_DIR" \

View File

@ -371,7 +371,7 @@ for port in $ports; do
fi
if \$port_$(portvar "$port"); then
echo -n "Loading /$tix ($(human_size $tix)) ... "
module /$tix --tix
module /$tix
echo done
fi
EOF

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2011-2016, 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
@ -447,18 +447,6 @@ static bool ReadTar(TAR* TAR)
}
}
static bool SearchTar(struct initrd_context* ctx, TAR* TAR, const char* path)
{
OpenTar(TAR, ctx->initrd, ctx->initrd_size);
while ( ReadTar(TAR) )
{
if ( !strcmp(TAR->name, path) )
return true;
}
CloseTar(TAR);
return false;
}
static void ExtractTarObject(Ref<Descriptor> desc,
struct initrd_context* ctx,
TAR* TAR)
@ -517,166 +505,6 @@ static void ExtractTar(Ref<Descriptor> desc, struct initrd_context* ctx)
CloseTar(&TAR);
}
static bool TarIsTix(struct initrd_context* ctx)
{
TAR TAR;
bool result = SearchTar(ctx, &TAR, "tix/tixinfo");
CloseTar(&TAR);
return result;
}
static char* tixinfo_lookup(const char* info,
size_t info_size,
const char* what)
{
size_t what_length = strlen(what);
while ( info_size )
{
size_t line_length = 0;
while ( line_length < info_size && info[line_length] != '\n' )
line_length++;
if ( what_length <= line_length &&
!strncmp(info, what, what_length) &&
info[what_length] == '=' )
{
char* result = strndup(info + what_length + 1,
line_length - (what_length + 1));
if ( !result )
Panic("initrd tar malloc failure");
return result;
}
info += line_length;
info_size -= line_length;
if ( info_size && info[0] == '\n' )
{
info++;
info_size--;
}
}
return NULL;
}
static void DescriptorWriteLine(Ref<Descriptor> desc,
ioctx_t* ioctx,
const char* str)
{
size_t len = strlen(str);
while ( str[0] )
{
ssize_t done = desc->write(ioctx, (unsigned char*) str, len);
if ( done <= 0 )
PanicF("initrd tix metadata write: %m");
str += done;
len -= done;
}
if ( desc->write(ioctx, (unsigned char*) "\n", 1) != 1 )
PanicF("initrd tix metadata write: %m");
}
static int manifest_sort(const void* a_ptr, const void* b_ptr)
{
const char* a = *(const char* const*) a_ptr;
const char* b = *(const char* const*) b_ptr;
return strcmp(a, b);
}
static void ExtractTix(Ref<Descriptor> desc, struct initrd_context* ctx)
{
TAR TAR;
if ( !SearchTar(ctx, &TAR, "tix/tixinfo") )
Panic("initrd was not tix");
char* pkg_name =
tixinfo_lookup((const char*) TAR.data, TAR.size, "pkg.name");
if ( !pkg_name )
Panic("initrd tixinfo lacked pkg.name");
if ( desc->mkdir(&ctx->ioctx, "/tix", 0755) < 0 && errno != EEXIST )
PanicF("/tix: %m");
if ( desc->mkdir(&ctx->ioctx, "/tix/tixinfo", 0755) < 0 && errno != EEXIST )
PanicF("/tix/tixinfo: %m");
if ( desc->mkdir(&ctx->ioctx, "/tix/manifest", 0755) < 0 && errno != EEXIST )
PanicF("/tix/manifest: %m");
char* tixinfo_path;
if ( asprintf(&tixinfo_path, "/tix/tixinfo/%s", pkg_name) < 0 )
Panic("initrd tar malloc failure");
char* TAR_oldname = TAR.name;
TAR.name = tixinfo_path;
ExtractTarObject(desc, ctx, &TAR);
TAR.name = TAR_oldname;
free(tixinfo_path);
CloseTar(&TAR);
Ref<Descriptor> installed_list =
desc->open(&ctx->ioctx, "/tix/installed.list",
O_CREATE | O_WRITE | O_APPEND, 0644);
if ( !installed_list )
PanicF("/tix/installed.list: %m");
DescriptorWriteLine(installed_list, &ctx->ioctx, pkg_name);
installed_list.Reset();
size_t manifest_list_size = 0;
OpenTar(&TAR, ctx->initrd, ctx->initrd_size);
while ( ReadTar(&TAR) )
{
if ( !strncmp(TAR.name, "data", 4) && TAR.name[4] == '/' )
manifest_list_size++;
}
CloseTar(&TAR);
char** manifest_list = new char*[manifest_list_size];
if ( !manifest_list )
Panic("initrd tar malloc failure");
OpenTar(&TAR, ctx->initrd, ctx->initrd_size);
size_t manifest_list_count = 0;
while ( ReadTar(&TAR) )
{
if ( strncmp(TAR.name, "data", 4) != 0 || TAR.name[4] != '/' )
continue;
char* path = strdup(TAR.name + 4);
if ( !path )
Panic("initrd tar malloc failure");
size_t length = strlen(path);
// Trim the trailing slash from directories.
if ( 2 <= length && path[length-1] == '/' )
path[length-1] = '\0';
manifest_list[manifest_list_count++] = path;
}
CloseTar(&TAR);
qsort(manifest_list, manifest_list_count, sizeof(char*), manifest_sort);
char* manifest_path;
if ( asprintf(&manifest_path, "/tix/manifest/%s", pkg_name) < 0 )
Panic("initrd tar malloc failure");
Ref<Descriptor> manifest =
desc->open(&ctx->ioctx, manifest_path, O_WRITE | O_CREATE | O_TRUNC, 0644);
if ( !manifest )
PanicF("%s: %m", manifest_path);
free(manifest_path);
for ( size_t i = 0; i < manifest_list_count; i++ )
DescriptorWriteLine(manifest, &ctx->ioctx, manifest_list[i]);
manifest.Reset();
for ( size_t i = 0; i < manifest_list_count; i++ )
free(manifest_list[i]);
delete[] manifest_list;
OpenTar(&TAR, ctx->initrd, ctx->initrd_size);
const char* subdir = "data/";
size_t subdir_length = strlen(subdir);
while ( ReadTar(&TAR) )
{
bool name_data = !strncmp(TAR.name, subdir, subdir_length) &&
TAR.name[subdir_length];
bool linkname_data = !strncmp(TAR.linkname, subdir, subdir_length) &&
TAR.linkname[subdir_length];
if ( name_data )
{
TAR.name += subdir_length;
if ( linkname_data )
TAR.linkname += subdir_length;
ExtractTarObject(desc, ctx, &TAR);
TAR.name -= subdir_length;
if ( linkname_data )
TAR.linkname -= subdir_length;
}
}
CloseTar(&TAR);
free(pkg_name);
}
static int ExtractTo_mkdir(Ref<Descriptor> desc, ioctx_t* ctx,
const char* path, mode_t mode)
{
@ -791,16 +619,7 @@ static void ExtractModule(struct multiboot_mod_list* module,
ExtractInitrd(desc, ctx);
else if ( sizeof(struct tar) <= ctx->initrd_size &&
!memcmp(ctx->initrd + offsetof(struct tar, magic), "ustar", 5) )
{
if ( !strcmp(cmdline, "--tar") )
ExtractTar(desc, ctx);
else if ( !strcmp(cmdline, "--tix") )
ExtractTix(desc, ctx);
else if ( TarIsTix(ctx) )
ExtractTix(desc, ctx);
else
ExtractTar(desc, ctx);
}
ExtractTar(desc, ctx);
else if ( sizeof(xz_magic) <= ctx->initrd_size &&
!memcmp(ctx->initrd, xz_magic, sizeof(xz_magic)) )
Panic("Bootloader failed to decompress an xz initrd, "

View File

@ -69,6 +69,26 @@ releasing Sortix x.y, foo." to allow the maintainer to easily
.Xr grep 1
for it after a release.
.Sh CHANGES
.Ss Third generation Tix
The tix binary package format has upgraded from generation 2 to 3 and has a new
internal layout that can be directly extracted into the filesystem.
The metatdata in
.Pa /tix
is now using the
.Xr tix-vars 1
format in the style of
.Xr port 5 .
.Pp
Tix must be upgraded to build the new ports:
.Bd -literal
cd /src/tix &&
make clean &&
make install
.Ed
.Pp
An upgrade hook will migrate the
.Pa /tix
metadata to tix generation 3.
.Ss Add include and comment support to passwd(5) and group(5)
The
.Xr passwd 5

View File

@ -95,8 +95,8 @@ command shows the current memory usage.
.Ss Third Party Software
Releases come with useful third party software installed.
The
.Pa /tix/installed.list
file lists all currently installed ports.
.Pa /tix/tixinfo
directory lists all currently installed ports.
.Ss Source Code
Releases come full with the system source code in
.Pa /src

View File

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, 2018, 2020, 2021 Jonas 'Sortie' Termansen.
* Copyright (c) 2016, 2017, 2018, 2020, 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
@ -19,9 +19,11 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -111,6 +113,74 @@ static bool hook_needs_to_be_run(const char* source_prefix,
return result;
}
// If a hook needs to run a finalization step after the upgrade, it can leave
// behind a .running file in the hooks directory, which is deleted once the
// hook has run.
__attribute__((used))
static char* hook_finalization_file(const char* target_prefix, const char* hook)
{
char* target_path;
if ( asprintf(&target_path, "%s/share/sysinstall/hooks/%s.running",
target_prefix, hook) < 0 )
{
warn("malloc");
_exit(2);
}
return target_path;
}
__attribute__((used))
static void hook_want_finalization(const char* target_prefix, const char* hook)
{
// TODO: After releasing Sortix 1.1, remove compatibility for Sortix 1.0
// not having the /share/sysinstall/hooks directory.
char* path;
if ( asprintf(&path, "%s/share/sysinstall", target_prefix) < 0 )
{
warn("malloc");
_exit(2);
}
mkdir(path, 0755);
free(path);
if ( asprintf(&path, "%s/share/sysinstall/hooks", target_prefix) < 0 )
{
warn("malloc");
_exit(2);
}
mkdir(path, 0755);
free(path);
char* target_path = hook_finalization_file(target_prefix, hook);
int fd = open(target_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if ( fd < 0 )
{
warn("%s", target_path);
_exit(2);
}
close(fd);
free(target_path);
}
__attribute__((used))
static bool hook_needs_finalization(const char* target_prefix, const char* hook)
{
char* target_path = hook_finalization_file(target_prefix, hook);
bool result = !access_or_die(target_path, F_OK);
free(target_path);
return result;
}
__attribute__((used))
static void hook_did_finalization(const char* target_prefix, const char* hook)
{
char* target_path = hook_finalization_file(target_prefix, hook);
if ( unlink(target_path) && errno != ENOENT )
{
warn("%s", target_path);
_exit(2);
}
free(target_path);
}
void upgrade_prepare(const struct release* old_release,
const struct release* new_release,
const char* source_prefix,
@ -354,6 +424,42 @@ void upgrade_prepare(const struct release* old_release,
}
free(group_path);
}
// TODO: After releasing Sortix 1.1, remove this compatibility.
if ( hook_needs_to_be_run(source_prefix, target_prefix,
"sortix-1.1-tix-3g") )
{
char* path = join_paths(target_prefix, "/tix/collection.conf");
if ( !path )
{
warn("malloc");
_exit(2);
}
FILE* fp = fopen(path, "w");
if ( fp )
{
printf(" - Migrating to tix version 3...\n");
struct utsname uts;
uname(&uts);
if ( fprintf(fp, "TIX_COLLECTION_VERSION=3\n") < 0 ||
fprintf(fp, "PREFIX=\n") < 0 ||
fprintf(fp, "PLATFORM=%s-%s\n",
uts.machine, uts.sysname) < 0 ||
fclose(fp) == EOF )
{
warn("%s", path);
_exit(2);
}
}
else
{
warn("%s", path);
_exit(2);
}
free(path);
// Delay deleting installed.list since it's needed for the upgrade.
hook_want_finalization(target_prefix, "sortix-1.1-tix-3g");
}
}
void upgrade_finalize(const struct release* old_release,
@ -365,6 +471,36 @@ void upgrade_finalize(const struct release* old_release,
(void) new_release;
(void) source_prefix;
(void) target_prefix;
if ( hook_needs_finalization(target_prefix, "sortix-1.1-tix-3g") )
{
printf(" - Finishing migration to tix version 3...\n");
char* path = join_paths(target_prefix, "/tix/installed.list");
if ( !path )
{
warn("malloc");
_exit(2);
}
if ( unlink(path) < 0 && errno != ENOENT )
{
warn("%s", path);
_exit(2);
}
free(path);
path = join_paths(target_prefix, "/tix/repository.list");
if ( !path )
{
warn("malloc");
_exit(2);
}
if ( unlink(path) < 0 && errno != ENOENT )
{
warn("%s", path);
_exit(2);
}
free(path);
hook_did_finalization(target_prefix, "sortix-1.1-tix-3g");
}
}
// TODO: After releasing Sortix 1.1, remove this compatibility. These manifests

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, 2020, 2021 Jonas 'Sortie' Termansen.
* Copyright (c) 2015, 2018, 2020, 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
@ -20,6 +20,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@ -479,8 +480,8 @@ void install_manifest(const char* manifest,
_exit(2);
}
}
// Write out the new manifests atomically afterwards to ensure no paths are
// leaked if the operation is aborted part way.
// Write out the new tixinfo afterwards to ensure no paths are leaked if the
// operation is aborted part way.
char* in_tixinfo;
char* out_tixinfo;
if ( asprintf(&in_tixinfo, "%s/tix/tixinfo/%s", from_prefix,
@ -537,81 +538,6 @@ void install_manifest(const char* manifest,
}
free(in_tixinfo);
free(out_tixinfo);
// Likewise write out the new installation list atomically afterwards to
// ensure no manifests are leaked if the operation is aborted part way.
char* installed_path;
char* installed_path_new;
if ( asprintf(&installed_path, "%s/tix/installed.list", to_prefix) < 0 ||
asprintf(&installed_path_new, "%s/tix/installed.list.new",
to_prefix) < 0 )
{
warn("malloc");
_exit(2);
}
size_t installed_count;
char** installed = read_lines_file(installed_path, &installed_count);
if ( !installed )
{
warn("%s", installed_path);
_exit(2);
}
size_t installed_length = installed_count;
if ( is_tix )
{
bool found = false;
for ( size_t i = 0; !found && i < installed_count; i++ )
found = !strcmp(installed[i], manifest);
if ( !found && !string_array_append(&installed, &installed_count,
&installed_length, manifest) )
{
warn("malloc");
_exit(2);
}
}
else
{
size_t o = 0;
for ( size_t i = 0; i < installed_count; i++ )
{
if ( !strcmp(installed[i], manifest) )
free(installed[i]);
else
installed[o++] = installed[i];
}
installed_count = o;
}
string_array_sort_strcmp(installed, installed_count);
mode_t temp_umask = umask(0022);
FILE* installed_fp = fopen(installed_path_new, "w");
if ( !installed_fp )
{
warn("%s", installed_path_new);
_exit(2);
}
umask(temp_umask);
for ( size_t i = 0; i < installed_count; i++ )
{
const char* name = installed[i];
if ( fputs(name, installed_fp) == EOF ||
fputc('\n', installed_fp) == EOF )
{
warn("%s", installed_path_new);
_exit(2);
}
}
if ( fclose(installed_fp) == EOF )
{
warn("%s", installed_path_new);
_exit(2);
}
if ( rename(installed_path_new, installed_path) < 0 )
{
warn("rename: %s -> %s", installed_path_new, installed_path);
_exit(2);
}
string_array_free(&installed, &installed_count, &installed_length);
free(installed_path);
free(installed_path_new);
if ( in_files != empty )
{
for ( size_t i = 0; i < in_files_count; i++ )
@ -701,36 +627,47 @@ void install_manifests(const char* const* manifests,
char** read_installed_list(const char* prefix, size_t* out_count)
{
char* path;
if ( asprintf(&path, "%s/tix/installed.list", prefix) < 0 )
char* tixinfo;
if ( asprintf(&tixinfo, "%s/tix/tixinfo", prefix) < 0 )
{
warn("malloc");
_exit(2);
}
size_t count;
size_t length;
char** installed;
size_t installed_count;
if ( !access_or_die(path, F_OK) )
if ( !string_array_init(&installed, &count, &length) )
{
if ( !(installed = read_lines_file(path, &installed_count)) )
{
warn("%s", path);
_exit(2);
}
string_array_sort_strcmp(installed, installed_count);
warn("malloc");
_exit(2);
}
else
DIR* dir = opendir(tixinfo);
if ( !dir )
{
installed = malloc(1);
if ( !installed )
if ( errno == ENOENT )
return *out_count = count, installed;
warn("opendir: %s", tixinfo);
_exit(2);
}
struct dirent* entry;
while ( (errno = 0, entry = readdir(dir)) )
{
if ( entry->d_name[0] == '.' )
continue;
if ( !string_array_append(&installed, &count, &length, entry->d_name) )
{
warn("malloc");
_exit(2);
}
installed_count = 0;
}
free(path);
*out_count = installed_count;
return installed;
if ( errno )
{
warn("readdir: %s", tixinfo);
_exit(2);
}
free(tixinfo);
string_array_sort_strcmp(installed, count);
return *out_count = count, installed;
}
void install_manifests_detect(const char* from_prefix,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014, 2015, 2016, 2020, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2013-2016, 2020, 2022-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
@ -27,6 +27,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
@ -667,22 +668,32 @@ static void Build(struct metainfo* minfo)
Make(minfo, build_target, NULL, true, subdir);
}
static void CreateDestination(void)
static void CreateDestination(struct metainfo* minfo)
{
char* tardir_rel = join_paths(tmp_root, "tix");
char* destdir_rel = join_paths(tardir_rel, "data");
char* tixdir_rel = join_paths(tardir_rel, "tix");
if ( mkdir(tardir_rel, 0777) < 0 )
err(1, "mkdir: %s", tardir_rel);
if ( mkdir(destdir_rel, 0755) != 0 )
err(1, "mkdir: `%s'", destdir_rel);
if ( mkdir(tixdir_rel, 0755) != 0 )
err(1, "mkdir: `%s'", tixdir_rel);
if ( !tardir_rel )
err(1, "malloc");
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
const char* prefix = 3 <= minfo->generation ? minfo->prefix : "";
char* prefixdir_rel = print_string("%s%s", tardir_rel, prefix);
if ( !prefixdir_rel )
err(1, "malloc");
if ( mkdir_p(prefixdir_rel, 0755) < 0 )
err(1, "mkdir: %s", prefixdir_rel);
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
if ( minfo->generation == 2 )
{
char* destdir_rel = join_paths(prefixdir_rel, "data");
char* tixdir_rel = join_paths(prefixdir_rel, "tix");
if ( mkdir(destdir_rel, 0755) != 0 )
err(1, "mkdir: `%s'", destdir_rel);
if ( mkdir(tixdir_rel, 0755) != 0 )
err(1, "mkdir: `%s'", tixdir_rel);
free(tixdir_rel);
free(destdir_rel);
}
free(prefixdir_rel);
free(tardir_rel);
free(destdir_rel);
free(tixdir_rel);
}
static void Install(struct metainfo* minfo)
@ -692,10 +703,12 @@ static void Install(struct metainfo* minfo)
metainfo_get_def(minfo, "MAKE_INSTALL_TARGET",
"pkg.make.install-target", "install");
char* tardir_rel = join_paths(tmp_root, "tix");
char* destdir_rel = join_paths(tardir_rel, "data");
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
char* destdir_rel = minfo->generation == 3 ? strdup(tardir_rel) :
join_paths(tardir_rel, "data");
char* destdir = realpath(destdir_rel, NULL);
if ( !destdir )
err(1, "realpath: %s", destdir_rel);
err(1, "realpath: %s", tardir_rel);
Make(minfo, install_target, destdir, true, subdir);
@ -716,7 +729,9 @@ static void PostInstall(struct metainfo* minfo)
const char* subdir = metainfo_get(minfo, "SUBDIR", "pkg.subdir");
char* tardir_rel = join_paths(tmp_root, "tix");
char* destdir_rel = join_paths(tardir_rel, "data");
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
char* destdir_rel = minfo->generation == 3 ? strdup(tardir_rel) :
join_paths(tardir_rel, "data");
char* destdir = realpath(destdir_rel, NULL);
if ( !destdir )
err(1, "realpath: %s", destdir_rel);
@ -758,9 +773,28 @@ static void TixInfo(struct metainfo* minfo)
char* tardir_rel = join_paths(tmp_root, "tix");
if ( !tardir_rel )
err(1, "malloc");
char* tixinfo_rel = join_paths(tardir_rel, "tix/tixinfo");
if ( !tixinfo_rel )
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
const char* prefix = 3 <= minfo->generation ? minfo->prefix : "";
char* prefixdir_rel = print_string("%s%s", tardir_rel, prefix);
if ( !prefixdir_rel )
err(1, "malloc");
char* tixdir_rel = join_paths(prefixdir_rel, "tix");
if ( !tixdir_rel )
err(1, "malloc");
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
if ( 3 <= minfo->generation && mkdir(tixdir_rel, 0755) && errno != EEXIST )
err(1, "%s", tixdir_rel);
char* tixinfodir_rel = join_paths(tixdir_rel, "tixinfo");
if ( !tixinfodir_rel )
err(1, "malloc");
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
if ( 3 <= minfo->generation &&
mkdir(tixinfodir_rel, 0755) && errno != EEXIST )
err(1, "%s", tixdir_rel);
char* tixinfo_rel = 3 <= minfo->generation ?
join_paths(tixinfodir_rel, minfo->package_name) :
strdup(tixinfodir_rel);
const char* alias = metainfo_get(minfo, "ALIAS_OF", "pkg.alias-of");
const char* runtime_deps =
metainfo_get(minfo, "RUNTIME_DEPS", "pkg.runtime-deps");
@ -772,20 +806,48 @@ static void TixInfo(struct metainfo* minfo)
if ( !tixinfo_fp )
err(1, "`%s'", tixinfo_rel);
fprintf(tixinfo_fp, "tix.version=1\n");
fprintf(tixinfo_fp, "tix.class=tix\n");
fprintf(tixinfo_fp, "tix.platform=%s\n", minfo->host);
fprintf(tixinfo_fp, "pkg.name=%s\n", minfo->package_name);
if ( alias )
fprintf(tixinfo_fp, "pkg.alias-of=%s\n", alias);
if ( 3 <= minfo->generation )
{
// TODO: Shell escape the values if needed.
fwrite_variable(tixinfo_fp, "TIX_VERSION", "3");
fwrite_variable(tixinfo_fp, "NAME", minfo->package_name);
const char* version = metainfo_get(minfo, "VERSION", "VERSION");
if ( version )
fwrite_variable(tixinfo_fp, "VERSION", version);
const char* version_2 = metainfo_get(minfo, "VERSION_2", "VERSION_2");
if ( version_2 )
fwrite_variable(tixinfo_fp, "VERSION_2", version_2);
fwrite_variable(tixinfo_fp, "PLATFORM", minfo->host);
if ( alias )
fwrite_variable(tixinfo_fp, "ALIAS_OF", alias);
else
{
if ( runtime_deps )
fwrite_variable(tixinfo_fp, "RUNTIME_DEPS", runtime_deps);
if ( location_independent )
fwrite_variable(tixinfo_fp, "LOCATION_INDEPENDENT", "true");
else
fwrite_variable(tixinfo_fp, "PREFIX", minfo->prefix);
}
}
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
else
{
if ( runtime_deps )
fprintf(tixinfo_fp, "pkg.runtime-deps=%s\n", runtime_deps);
if ( location_independent )
fprintf(tixinfo_fp, "pkg.location-independent=true\n");
fprintf(tixinfo_fp, "tix.version=1\n");
fprintf(tixinfo_fp, "tix.class=tix\n");
fprintf(tixinfo_fp, "tix.platform=%s\n", minfo->host);
fprintf(tixinfo_fp, "pkg.name=%s\n", minfo->package_name);
if ( alias )
fprintf(tixinfo_fp, "pkg.alias-of=%s\n", alias);
else
fprintf(tixinfo_fp, "pkg.prefix=%s\n", minfo->prefix);
{
if ( runtime_deps )
fprintf(tixinfo_fp, "pkg.runtime-deps=%s\n", runtime_deps);
if ( location_independent )
fprintf(tixinfo_fp, "pkg.location-independent=true\n");
else
fprintf(tixinfo_fp, "pkg.prefix=%s\n", minfo->prefix);
}
}
if ( ferror(tixinfo_fp) || fflush(tixinfo_fp) == EOF )
@ -793,27 +855,64 @@ static void TixInfo(struct metainfo* minfo)
fclose(tixinfo_fp);
free(tardir_rel);
free(prefixdir_rel);
free(tixdir_rel);
free(tixinfodir_rel);
free(tixinfo_rel);
}
static void TixManifest(struct metainfo* minfo)
{
if ( !fork_and_wait_or_recovery() )
return;
char* tardir_rel = join_paths(tmp_root, "tix");
if ( !tardir_rel )
err(1, "malloc");
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
const char* prefix = 3 <= minfo->generation ? minfo->prefix : "";
char* prefixdir_rel = print_string("%s%s", tardir_rel, prefix);
if ( !prefixdir_rel )
err(1, "malloc");
if ( chdir(prefixdir_rel) < 0 )
err(1, "%s", prefixdir_rel);
if ( mkdir("tix", 0755) && errno != EEXIST )
err(1, "%s", "tix");
if ( mkdir("tix/manifest", 0755) && errno != EEXIST )
err(1, "%s", "tix/manifest");
char* command;
if ( asprintf(&command,
"find . -name tix -prune -o -print | "
"sed -E -e 's,^\\.$,/,' -e 's,^\\./,/,' | "
"LC_ALL=C sort > tix/manifest/%s",
minfo->package_name) < 0 )
err(1, "malloc");
const char* cmd_argv[] = { "sh", "-c", command, NULL };
recovery_execvp(cmd_argv[0], (char* const*) cmd_argv);
err(127, "%s", cmd_argv[0]);
}
static void Package(struct metainfo* minfo)
{
if ( !fork_and_wait_or_recovery() )
return;
char* tardir_rel = join_paths(tmp_root, "tix");
if ( !tardir_rel )
err(1, "malloc");
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
const char* prefix = 3 <= minfo->generation ? minfo->prefix : "";
char* prefixdir_rel = print_string("%s%s", tardir_rel, prefix);
if ( !prefixdir_rel )
err(1, "malloc");
char* package_tix = print_string("%s/%s.tix.tar.xz",
minfo->destination, minfo->package_name);
if ( !package_tix )
err(1, "malloc");
printf("Creating `%s'...\n", package_tix);
fflush(stdout);
const char* cmd_argv[] =
{
minfo->tar,
"-C", tardir_rel,
"-C", prefixdir_rel,
"--remove-files",
"--create",
"--xz",
@ -821,12 +920,30 @@ static void Package(struct metainfo* minfo)
"--owner=0",
"--group=0",
"--file", package_tix,
"--",
"tix",
"data",
NULL
};
recovery_execvp(cmd_argv[0], (char* const*) cmd_argv);
err(127, "%s", cmd_argv[0]);
string_array_t cmd = string_array_make();
for ( size_t i = 0; cmd_argv[i]; i++ )
if ( !string_array_append(&cmd, cmd_argv[i]) )
err(1, "malloc");
struct dirent** entries;
int count = scandir(prefixdir_rel, &entries, NULL, alphasort);
if ( count < 0 )
err(1, "scandir: %s", prefixdir_rel);
for ( int i = 0; i < count; i++ )
{
const char* name = entries[i]->d_name;
if ( !strcmp(name, ".") || !strcmp(name, "..") || !strcmp(name, "tix") )
continue;
if ( !string_array_append(&cmd, name) )
err(1, "malloc");
}
if ( !string_array_append(&cmd, NULL) )
err(1, "malloc");
recovery_execvp(cmd.strings[0], (char* const*) cmd.strings);
err(127, "%s", cmd.strings[0]);
}
static void Compile(struct metainfo* minfo)
@ -970,7 +1087,7 @@ static void BuildPackage(struct metainfo* minfo)
"specify the intended destination prefix using --prefix",
minfo->package_name);
CreateDestination();
CreateDestination(minfo);
// Possibly build a native version of the package to aid cross-compilation.
// This is an anti-feature needed for broken packages that don't properly
@ -991,6 +1108,9 @@ static void BuildPackage(struct metainfo* minfo)
if ( SHOULD_DO_BUILD_STEP(BUILD_STEP_PACKAGE, minfo) )
{
TixInfo(minfo);
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
if ( 3 <= minfo->generation )
TixManifest(minfo);
Package(minfo);
}
}
@ -1144,6 +1264,9 @@ int main(int argc, char* argv[])
minfo.generation = atoi(generation_string);
free(generation_string);
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
if ( minfo.generation != 2 && minfo.generation != 3 )
errx(1, "Unsupported generation: %i", minfo.generation);
if ( !(minfo.start_step = step_of_step_name(start_step_string)) )
{
@ -1220,8 +1343,8 @@ int main(int argc, char* argv[])
minfo.tixbuildinfo = true;
minfo.package_info = string_array_make();
string_array_t* package_info = &minfo.package_info;
if ( !dictionary_append_file_path(package_info,
minfo.package_info_path) )
if ( variables_append_file_path(package_info,
minfo.package_info_path) < 0 )
err(1, "`%s'", minfo.package_info_path);
}
else

View File

@ -27,6 +27,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
@ -107,13 +108,6 @@ int main(int argc, char* argv[])
compact_arguments(&argc, &argv);
ParseOptionalCommandLineCollectionPrefix(&collection, &argc, &argv);
VerifyCommandLineCollection(&collection);
int generation = atoi(generation_string);
free(generation_string);
if ( !prefix )
prefix = strdup(collection);
if ( argc == 1 )
{
@ -121,12 +115,30 @@ int main(int argc, char* argv[])
exit(1);
}
// The collection directory might not exist yet.
if ( strcmp(argv[1], "create") != 0 )
VerifyCommandLineCollection(&collection);
int generation = atoi(generation_string);
free(generation_string);
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
if ( generation != 2 && generation != 3 )
errx(1, "Unsupported generation: %i", generation);
if ( !prefix )
prefix = strdup(collection);
const char* cmd = argv[1];
if ( !strcmp(cmd, "create") )
{
if ( !platform && !(platform = GetBuildTriplet()) )
err(1, "unable to determine platform, use --platform");
if ( mkdir_p(collection, 0755) != 0 )
err(1, "mkdir: `%s'", collection);
VerifyCommandLineCollection(&collection);
char* tix_path = join_paths(collection, "tix");
if ( mkdir_p(tix_path, 0755) != 0 )
err(1, "mkdir: `%s'", tix_path);
@ -149,26 +161,41 @@ int main(int argc, char* argv[])
errx(1, "error: `%s' already exists, a tix collection is "
"already installed at `%s'.", collection_conf_path,
collection);
fprintf(conf_fp, "tix.version=1\n");
fprintf(conf_fp, "tix.class=collection\n");
fprintf(conf_fp, "collection.generation=%i\n", generation);
fprintf(conf_fp, "collection.prefix=%s\n", !strcmp(prefix, "/") ? "" :
prefix);
fprintf(conf_fp, "collection.platform=%s\n", platform);
if ( 3 <= generation )
{
fwrite_variable(conf_fp, "TIX_COLLECTION_VERSION", "3");
fwrite_variable(conf_fp, "PREFIX",
!strcmp(prefix, "/") ? "" : prefix);
fwrite_variable(conf_fp, "PLATFORM", platform);
}
// TODO: After releasing Sortix 1.1, delete generation 2 compatibility.
else
{
fprintf(conf_fp, "tix.version=1\n");
fprintf(conf_fp, "tix.class=collection\n");
fprintf(conf_fp, "collection.generation=%i\n", generation);
fprintf(conf_fp, "collection.prefix=%s\n",
!strcmp(prefix, "/") ? "" : prefix);
fprintf(conf_fp, "collection.platform=%s\n", platform);
}
fclose(conf_fp);
free(collection_conf_path);
const char* repo_list_path = join_paths(tixdb_path, "repository.list");
FILE* repo_list_fp = fopen(repo_list_path, "w");
if ( !repo_list_fp )
err(1, "`%s'", repo_list_path);
fclose(repo_list_fp);
// TODO: After releasing Sortix 1.1, delete generation 2 compatibility.
if ( generation < 3 )
{
const char* repo_list_path = join_paths(tixdb_path, "repository.list");
FILE* repo_list_fp = fopen(repo_list_path, "w");
if ( !repo_list_fp )
err(1, "`%s'", repo_list_path);
fclose(repo_list_fp);
const char* inst_list_path = join_paths(tixdb_path, "installed.list");
FILE* inst_list_fp = fopen(inst_list_path, "w");
if ( !inst_list_fp )
err(1, "`%s'", inst_list_path);
fclose(inst_list_fp);
const char* inst_list_path = join_paths(tixdb_path, "installed.list");
FILE* inst_list_fp = fopen(inst_list_path, "w");
if ( !inst_list_fp )
err(1, "`%s'", inst_list_path);
fclose(inst_list_fp);
}
return 0;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, 2016, 2017, 2020, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2015-2017, 2020, 2022-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
@ -27,6 +27,7 @@
#include <errno.h>
#include <dirent.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
@ -78,50 +79,24 @@ void VerifyTixDatabase(const char* prefix,
err(1, "error: tix collection information unavailable: `%s'",
info_path);
}
char* installed_list_path = join_paths(tixdb_path, "installed.list");
FILE* installed_list_fp = fopen(installed_list_path, "a");
if ( !installed_list_fp )
{
warn("error: unable to open `%s' for writing",
installed_list_path);
errx(1, "error: `%s': do you have sufficient permissions to "
"administer this tix collection?", prefix);
}
fclose(installed_list_fp);
free(installed_list_path);
free(info_path);
}
bool IsPackageInstalled(const char* tixdb_path, const char* package)
{
char* installed_list_path = join_paths(tixdb_path, "installed.list");
FILE* installed_list_fp = fopen(installed_list_path, "r");
if ( !installed_list_fp )
err(1, "`%s'", installed_list_path);
bool ret = false;
char* line = NULL;
size_t line_size = 0;
ssize_t line_len;
while ( 0 < (line_len = getline(&line, &line_size, installed_list_fp)) )
{
if ( line[line_len-1] == '\n' )
line[--line_len] = '\0';
if ( !strcmp(line, package) )
{
ret = true;
break;
}
}
free(line);
if ( ferror(installed_list_fp) )
err(1, "`%s'", installed_list_path);
fclose(installed_list_fp);
free(installed_list_path);
return ret;
char* tixinfo_dir = join_paths(tixdb_path, "tixinfo");
if ( !tixinfo_dir )
err(1, "malloc");
char* tixinfo = join_paths(tixinfo_dir, package);
if ( !tixinfo )
err(1, "malloc");
bool installed = !access(tixinfo, F_OK);
free(tixinfo);
free(tixinfo_dir);
return installed;
}
// TODO: After releasing Sortix 1.1, delete generation 2 compatibility.
void MarkPackageAsInstalled(const char* tixdb_path, const char* package)
{
char* installed_list_path = join_paths(tixdb_path, "installed.list");
@ -228,18 +203,40 @@ int main(int argc, char* argv[])
char* coll_conf_path = join_paths(tix_directory_path, "collection.conf");
string_array_t coll_conf = string_array_make();
if ( !dictionary_append_file_path(&coll_conf, coll_conf_path) )
err(1, "`%s'", coll_conf_path);
VerifyTixCollectionConfiguration(&coll_conf, coll_conf_path);
free(coll_conf_path);
switch ( variables_append_file_path(&coll_conf, coll_conf_path) )
{
case -1: err(1, "%s", coll_conf_path);
case -2: errx(2, "%s: Syntax error", coll_conf_path);
}
const char* coll_generation = dictionary_get(&coll_conf, "collection.generation");
assert(coll_generation);
VerifyTixCollectionConfiguration(&coll_conf, coll_conf_path);
const char* coll_generation =
dictionary_get(&coll_conf, "TIX_COLLECTION_VERSION");
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
if ( !coll_generation )
coll_generation = dictionary_get(&coll_conf, "collection.generation");
if ( !coll_generation )
err(1, "%s: No TIX_COLLECTION_VERSION was set", coll_conf_path);
generation = atoi(coll_generation);
coll_prefix = dictionary_get(&coll_conf, "collection.prefix");
assert(coll_prefix);
coll_platform = dictionary_get(&coll_conf, "collection.platform");
assert(coll_platform);
if ( generation == 3 )
{
coll_prefix = dictionary_get(&coll_conf, "PREFIX");
coll_platform = dictionary_get(&coll_conf, "PLATFORM");
}
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
else if ( generation == 2 )
{
coll_prefix = dictionary_get(&coll_conf, "collection.prefix");
coll_platform = dictionary_get(&coll_conf, "collection.platform");
}
else
errx(1, "%s: Unsupported TIX_COLLECTION_VERSION: %i",
coll_conf_path, generation);
if ( !coll_prefix )
err(1, "%s: No PREFIX was set", coll_conf_path);
if ( !coll_platform )
err(1, "%s: No PLATFORM was set", coll_conf_path);
for ( int i = 1; i < argc; i++ )
InstallPackage(argv[i]);
@ -247,6 +244,7 @@ int main(int argc, char* argv[])
string_array_reset(&coll_conf);
free(tix_directory_path);
free(coll_conf_path);
return 0;
}
@ -263,25 +261,47 @@ void InstallPackage(const char* tix_path)
if ( !IsFile(tix_path) )
err(1, "`%s'", tix_path);
const char* tixinfo_path = "tix/tixinfo";
// TODO: After releasing Sortix 1.1, delete generation 2 compatibility.
bool modern = true;
const char* tixinfo_path = "tix/tixinfo/";
if ( !TarContainsFile(tix_path, tixinfo_path) )
errx(1, "`%s' doesn't contain a `%s' file", tix_path, tixinfo_path);
{
const char* tixinfo_path_old = "tix/tixinfo";
if ( !TarContainsFile(tix_path, tixinfo_path_old) )
errx(1, "`%s' doesn't contain a `%s' directory", tix_path,
tixinfo_path);
tixinfo_path = tixinfo_path_old;
modern = false;
}
string_array_t tixinfo = string_array_make();
FILE* tixinfo_fp = TarOpenFile(tix_path, tixinfo_path);
dictionary_append_file(&tixinfo, tixinfo_fp);
switch ( variables_append_file(&tixinfo, tixinfo_fp) )
{
case -1: err(1, "%s: %s", tix_path, tixinfo_path);
case -2: errx(1, "%s: %s: Syntax error", tix_path, tixinfo_path);
}
fclose(tixinfo_fp);
const char* package_name = dictionary_get(&tixinfo, "pkg.name");
const char* version = dictionary_get(&tixinfo, "TIX_VERSION");
if ( modern && (!version || strcmp(version, "3") != 0) )
errx(1, "%s: unsupported TIX_VERSION: %s", tix_path, version);
const char* package_name =
dictionary_get(&tixinfo, modern ? "NAME" : "pkg.name");
assert(package_name);
const char* package_prefix = dictionary_get(&tixinfo, "pkg.prefix");
const char* package_prefix =
dictionary_get(&tixinfo, modern ? "PREFIX" : "pkg.prefix");
assert(package_prefix || !package_prefix);
const char* package_platform = dictionary_get(&tixinfo, "tix.platform");
const char* package_platform =
dictionary_get(&tixinfo, modern ? "PLATFORM" : "tix.platform");
assert(package_platform || !package_platform);
bool already_installed = IsPackageInstalled(tix_directory_path, package_name);
bool already_installed =
IsPackageInstalled(tix_directory_path, package_name);
if ( already_installed && !reinstall )
errx(1, "error: package `%s' is already installed. Use --reinstall "
"to force reinstallation.", package_name);
@ -313,44 +333,51 @@ void InstallPackage(const char* tix_path)
fflush(stdout);
}
const char* data = modern ? "" : "data";
char* data_and_prefix = package_prefix && package_prefix[0] ?
print_string("data%s", package_prefix) :
strdup("data");
print_string("%s%s", data, package_prefix) :
strdup(data);
char* tixinfo_out_path = print_string("%s/tixinfo/%s", tix_directory_path, package_name);
int tixinfo_fd = open(tixinfo_out_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if ( tixinfo_fd < 0 )
err(1, "%s", tixinfo_out_path);
TarExtractFileToFD(tix_path, "tix/tixinfo", tixinfo_fd);
close(tixinfo_fd);
FILE* index_fp = TarOpenIndex(tix_path);
string_array_t files = string_array_make();
string_array_append_file(&files, index_fp);
qsort(files.strings, files.length, sizeof(char*), strcmp_indirect);
char* manifest_path = print_string("%s/manifest/%s", tix_directory_path, package_name);
FILE* manifest_fp = fopen(manifest_path, "w");
if ( !manifest_fp )
err(1, "%s", manifest_path);
for ( size_t i = 0; i < files.length; i++ )
if ( !modern )
{
char* str = files.strings[i];
if ( strncmp(str, "data", strlen("data")) != 0 )
continue;
str += strlen("data");
if ( str[0] && str[0] != '/' )
continue;
size_t len = strlen(str);
while ( 2 <= len && str[len-1] == '/' )
str[--len] = '\0';
if ( fprintf(manifest_fp, "%s\n", str) < 0 )
char* tixinfo_out_path =
print_string("%s/tixinfo/%s", tix_directory_path, package_name);
int tixinfo_fd =
open(tixinfo_out_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if ( tixinfo_fd < 0 )
err(1, "%s", tixinfo_out_path);
TarExtractFileToFD(tix_path, "tix/tixinfo", tixinfo_fd);
close(tixinfo_fd);
FILE* index_fp = TarOpenIndex(tix_path);
string_array_t files = string_array_make();
string_array_append_file(&files, index_fp);
qsort(files.strings, files.length, sizeof(char*), strcmp_indirect);
char* manifest_path =
print_string("%s/manifest/%s", tix_directory_path, package_name);
FILE* manifest_fp = fopen(manifest_path, "w");
if ( !manifest_fp )
err(1, "%s", manifest_path);
for ( size_t i = 0; i < files.length; i++ )
{
char* str = files.strings[i];
if ( strncmp(str, "data", strlen("data")) != 0 )
continue;
str += strlen("data");
if ( str[0] && str[0] != '/' )
continue;
size_t len = strlen(str);
while ( 2 <= len && str[len-1] == '/' )
str[--len] = '\0';
if ( fprintf(manifest_fp, "%s\n", str) < 0 )
err(1, "%s", manifest_path);
}
if ( ferror(manifest_fp) || fflush(manifest_fp) == EOF )
err(1, "%s", manifest_path);
fclose(manifest_fp);
string_array_reset(&files);
fclose(index_fp);
}
if ( ferror(manifest_fp) || fflush(manifest_fp) == EOF )
err(1, "%s", manifest_path);
fclose(manifest_fp);
string_array_reset(&files);
fclose(index_fp);
if ( fork_and_wait_or_death() )
{
@ -358,14 +385,14 @@ void InstallPackage(const char* tix_path)
const char* cmd_argv[] =
{
"tar",
print_string("--strip-components=%zu", num_strips),
"-C", collection,
"--extract",
"--file", tix_path,
"--keep-directory-symlink",
"--same-permissions",
"--no-same-owner",
data_and_prefix,
modern ? NULL : print_string("--strip-components=%zu", num_strips),
modern ? NULL : data_and_prefix,
NULL
};
execvp(cmd_argv[0], (char* const*) cmd_argv);
@ -373,7 +400,8 @@ void InstallPackage(const char* tix_path)
}
free(data_and_prefix);
if ( !already_installed )
// TODO: After releasing Sortix 1.1, delete generation 2 compatibility.
if ( generation <= 2 && !already_installed )
MarkPackageAsInstalled(tix_directory_path, package_name);
string_array_reset(&tixinfo);

View File

@ -1,5 +1,5 @@
#!/bin/sh
# Copyright (c) 2022 Jonas 'Sortie' Termansen.
# Copyright (c) 2022, 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
@ -304,6 +304,9 @@ desired_version() {(
if [ -f "$port.rmpatch" ]; then
stamp="$stamp.$(cat "$port.rmpatch" | sha256sum | grep -Eo '^[^ ]*')"
fi
if [ -f "$port.post-install" ]; then
stamp="$stamp.$(cat "$port.post-install" | sha256sum | grep -Eo '^[^ ]*')"
fi
DEVELOPMENT=$(tix-vars -d false "$port.port" DEVELOPMENT)
if [ "$DEVELOPMENT" = true ]; then
stamp="$stamp.development"
@ -428,12 +431,20 @@ strip_tix() {(
strip=${host+$host-}strip
dir=$(mktemp -d)
tar -C "$dir" -xf "$1"
$strip -d "$dir/data/bin/"* 2>/dev/null || true
$strip -d "$dir/data/lib/"* 2>/dev/null || true
$strip -d "$dir/data/libexec"* 2>/dev/null || true
$strip -d "$dir/data/libexec/git-core/"* 2>/dev/null || true
$strip -d "$dir/data/sbin/"* 2>/dev/null || true
(cd "$dir" && tar --numeric-owner --owner=0 --group=0 -cJf port.tar.tix.xz tix data)
# TODO: After releasing Sortix 1.1, remove the data directory compatibility.
if [ -e "$dir/data" ]; then
data_dir="$dir/data"
else
data_dir="$dir"
fi
$strip -d "$data_dir/bin/"* 2>/dev/null || true
$strip -d "$data_dir/lib/"* 2>/dev/null || true
$strip -d "$data_dir/libexec"* 2>/dev/null || true
$strip -d "$data_dir/libexec/git-core/"* 2>/dev/null || true
$strip -d "$data_dir/sbin/"* 2>/dev/null || true
(cd "$dir" &&
LC_ALL=C ls -A | grep -Ev '^tix$' |
tar --numeric-owner --owner=0 --group=0 -cJf port.tar.tix.xz tix -T -)
cp "$dir/port.tar.tix.xz" "$1"
rm -rf "$dir"
)}

View File

@ -25,6 +25,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2015, 2016, 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
@ -27,6 +27,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
@ -45,7 +46,6 @@ typedef struct
char* tixdb_path;
string_array_t coll_conf;
string_array_t repo_list;
string_array_t inst_list;
bool reinstall;
} params_t;
@ -92,20 +92,36 @@ string_array_t GetPackageDependencies(params_t* params, const char* pkg_name)
if ( !pkg_path )
err(1, "unable to locate package `%s'", pkg_name);
const char* tixinfo_path = "tix/tixinfo";
// TODO: After releasing Sortix 1.1, delete generation 2 compatibility.
bool modern = false;
const char* tixinfo_path = "tix/tixinfo/";
if ( !TarContainsFile(pkg_path, tixinfo_path) )
errx(1, "`%s' doesn't contain a `%s' file", pkg_path, tixinfo_path);
{
const char* tixinfo_path_old = "tix/tixinfo";
if ( !TarContainsFile(pkg_path, tixinfo_path_old) )
errx(1, "`%s' doesn't contain a `%s' directory", pkg_path,
tixinfo_path);
tixinfo_path = tixinfo_path_old;
modern = false;
}
string_array_t tixinfo = string_array_make();
FILE* tixinfo_fp = TarOpenFile(pkg_path, tixinfo_path);
dictionary_append_file(&tixinfo, tixinfo_fp);
switch ( variables_append_file(&tixinfo, tixinfo_fp) )
{
case -1: err(1, "%s: %s", pkg_path, tixinfo_path);
case -2: errx(1, "%s: %s: Syntax error", pkg_path, tixinfo_path);
}
fclose(tixinfo_fp);
VerifyTixInformation(&tixinfo, pkg_path);
const char* deps = dictionary_get_def(&tixinfo, "pkg.runtime-deps", "");
const char* deps = dictionary_get_def(&tixinfo, modern ? "RUNTIME_DEPS" :
"pkg.runtime-deps", "");
string_array_append_token_string(&ret, deps);
const char* alias = dictionary_get_def(&tixinfo, "pkg.alias-of", "");
const char* alias = dictionary_get_def(&tixinfo, modern ? "ALIAS_OF" :
"pkg.alias-of", "");
string_array_append_token_string(&ret, alias);
string_array_reset(&tixinfo);
@ -224,23 +240,22 @@ int main(int argc, char* argv[])
char* coll_conf_path = join_paths(params.tixdb_path, "collection.conf");
params.coll_conf = string_array_make();
if ( !dictionary_append_file_path(&params.coll_conf, coll_conf_path) )
err(1, "`%s'", coll_conf_path);
switch ( variables_append_file_path(&params.coll_conf, coll_conf_path) )
{
case -1: err(1, "%s", coll_conf_path);
case -2: errx(2, "%s: Syntax error", coll_conf_path);
}
VerifyTixCollectionConfiguration(&params.coll_conf, coll_conf_path);
free(coll_conf_path);
// TODO: Decide the fate of repository.list.
char* repo_list_path = join_paths(params.tixdb_path, "repository.list");
params.repo_list = string_array_make();
if ( !string_array_append_file_path(&params.repo_list, repo_list_path) )
if ( !string_array_append_file_path(&params.repo_list, repo_list_path) &&
errno != ENOENT )
err(1, "`%s'", repo_list_path);
free(repo_list_path);
char* inst_list_path = join_paths(params.tixdb_path, "installed.list");
params.inst_list = string_array_make();
if ( !string_array_append_file_path(&params.inst_list, inst_list_path) )
err(1, "`%s'", inst_list_path);
free(inst_list_path);
if ( argc == 1 )
errx(1, "error: no command specified.");
@ -252,10 +267,16 @@ int main(int argc, char* argv[])
string_array_t work = string_array_make();
char* tixinfo_dir = join_paths(params.tixdb_path, "tixinfo");
if ( !tixinfo_dir )
err(1, "malloc");
for ( int i = 2; i < argc; i++ )
{
const char* pkg_name = argv[i];
if ( string_array_contains(&params.inst_list, pkg_name) )
char* tixinfo = join_paths(tixinfo_dir, pkg_name);
bool installed = !access(tixinfo, F_OK);
free(tixinfo);
if ( installed )
{
if ( params.reinstall )
{
@ -268,6 +289,7 @@ int main(int argc, char* argv[])
GetPackageRecursiveDependencies(&params, &work, pkg_name);
}
free(tixinfo_dir);
for ( size_t i = 0; i < work.length; i++ )
InstallPackageOfName(&params, work.strings[i]);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, 2016, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2015, 2016, 2022, 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
@ -20,7 +20,7 @@
#ifndef UTIL_H
#define UTIL_H
#define DEFAULT_GENERATION "2"
#define DEFAULT_GENERATION "3"
extern char** environ;
@ -326,34 +326,6 @@ void dictionary_normalize_entry(char* entry)
entry[output_off] = '\0';
}
void dictionary_append_file(string_array_t* sa, FILE* fp)
{
char* entry = NULL;
size_t entry_size = 0;
ssize_t entry_length;
while ( 0 < (entry_length = getline(&entry, &entry_size, fp)) )
{
if ( entry[entry_length-1] == '\n' )
entry[--entry_length] = '\0';
dictionary_normalize_entry(entry);
if ( entry[0] == '#' )
continue;
string_array_append(sa, entry);
}
free(entry);
assert(!ferror(fp));
}
bool dictionary_append_file_path(string_array_t* sa, const char* path)
{
FILE* fp = fopen(path, "r");
if ( !fp )
return false;
dictionary_append_file(sa, fp);
fclose(fp);
return true;
}
bool is_identifier_char(char c)
{
return ('a' <= c && c <= 'z') ||
@ -595,10 +567,24 @@ const char* getenv_def(const char* var, const char* def)
int mkdir_p(const char* path, mode_t mode)
{
int saved_errno = errno;
if ( mkdir(path, mode) != 0 && errno != EEXIST )
return -1;
errno = saved_errno;
return 0;
if ( !mkdir(path, mode) )
return 0;
if ( errno == ENOENT )
{
char* prev = strdup(path);
if ( !prev )
return -1;
int status = mkdir_p(dirname(prev), mode | 0500);
free(prev);
if ( status < 0 )
return -1;
errno = saved_errno;
if ( !mkdir(path, mode) )
return 0;
}
if ( errno == EEXIST )
return errno = saved_errno, 0;
return -1;
}
static void compact_arguments(int* argc, char*** argv)
@ -925,23 +911,39 @@ void VerifyCommandLineCollection(char** collection)
void VerifyTixCollectionConfiguration(string_array_t* info, const char* path)
{
// TODO: After releasing Sortix 1.1, remove generation 2 compatibility.
const char* tix_version = dictionary_get(info, "tix.version");
if ( !tix_version )
errx(1, "error: `%s': no `tix.version' variable declared", path);
if ( atoi(tix_version) != 1 )
errx(1, "error: `%s': tix version `%s' not supported", path,
tix_version);
const char* tix_class = dictionary_get(info, "tix.class");
if ( !tix_class )
errx(1, "error: `%s': no `tix.class' variable declared", path);
if ( strcmp(tix_class, "collection") != 0 )
errx(1, "error: `%s': error: unexpected tix class `%s'.", path,
tix_class);
if ( !(dictionary_get(info, "collection.prefix")) )
errx(1, "error: `%s': no `collection.prefix' variable declared", path);
if ( !(dictionary_get(info, "collection.platform")) )
errx(1, "error: `%s': no `collection.platform' variable declared",
path);
if ( tix_version )
{
if ( !tix_version )
errx(1, "error: `%s': no `tix.version' variable declared", path);
if ( atoi(tix_version) != 1 )
errx(1, "error: `%s': tix version `%s' not supported", path,
tix_version);
const char* tix_class = dictionary_get(info, "tix.class");
if ( !tix_class )
errx(1, "error: `%s': no `tix.class' variable declared", path);
if ( strcmp(tix_class, "collection") != 0 )
errx(1, "error: `%s': error: unexpected tix class `%s'.", path,
tix_class);
if ( !(dictionary_get(info, "collection.prefix")) )
errx(1, "error: `%s': no `collection.prefix' variable declared",
path);
if ( !(dictionary_get(info, "collection.platform")) )
errx(1, "error: `%s': no `collection.platform' variable declared",
path);
return;
}
const char* version = dictionary_get(info, "TIX_COLLECTION_VERSION");
if ( !version )
errx(1, "%s: Mandatory TIX_COLLECTION_VERSION was not set", path);
if ( atoi(version) != 3 )
errx(1, "%s: Unsupported: TIX_COLLECTION_VERSION: %s", path, version);
if ( !(dictionary_get(info, "PREFIX")) )
errx(1, "%s: Mandatory PREFIX was not set", path);
if ( !(dictionary_get(info, "PLATFORM")) )
errx(1, "%s: Mandatory PLATFORM was not set", path);
}
static pid_t original_pid;
@ -1032,6 +1034,37 @@ void fprint_shell_variable_assignment(FILE* fp, const char* variable, const char
}
}
bool needs_single_quote(const char* string)
{
for ( size_t i = 0; string[i]; i++ )
{
char c = string[i];
if ( !(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
('0' <= c && c <= '9') ||
c == '/' || c == '_' || c == '.' || c == '+' || c == ':' ||
c == '%' || c == '$' || c == '{' || c == '}' || c == '-') )
return true;
}
return false;
}
void fwrite_variable(FILE* fp, const char* key, const char* value)
{
fprintf(fp, "%s=", key);
if ( !needs_single_quote(value) )
fprintf(fp, "%s\n", value);
else
{
fputc('\'', fp);
for ( size_t i = 0; value[i]; i++ )
if ( value[i] == '\'' )
fprintf(fp, "'\\''");
else
fputc(value[i], fp);
fputs("'\n", fp);
}
}
bool is_success_exit_status(int status)
{
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
@ -1149,6 +1182,7 @@ int recovery_execvp(const char* path, char* const* argv)
}
printf("\n");
fflush(stdout);
if ( recovery_configure_state(false) == RECOVERY_STATE_PRINT_COMMAND )
_exit(0);