Fix system upgrade leaking files.
This commit is contained in:
parent
29598b4fde
commit
cb590ff205
8
Makefile
8
Makefile
|
@ -74,6 +74,14 @@ all: sysroot
|
||||||
sysmerge: sysroot
|
sysmerge: sysroot
|
||||||
sysmerge "$(SYSROOT)"
|
sysmerge "$(SYSROOT)"
|
||||||
|
|
||||||
|
.PHONY: sysmerge-full
|
||||||
|
sysmerge-full: sysroot
|
||||||
|
sysmerge --full "$(SYSROOT)"
|
||||||
|
|
||||||
|
.PHONY: sysmerge-full-wait
|
||||||
|
sysmerge-full-wait: sysroot
|
||||||
|
sysmerge --full --wait "$(SYSROOT)"
|
||||||
|
|
||||||
.PHONY: sysmerge-wait
|
.PHONY: sysmerge-wait
|
||||||
sysmerge-wait: sysroot
|
sysmerge-wait: sysroot
|
||||||
sysmerge --wait "$(SYSROOT)"
|
sysmerge --wait "$(SYSROOT)"
|
||||||
|
|
|
@ -71,6 +71,7 @@ This takes precedence over and disables the behavior described under
|
||||||
.Sy src .
|
.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.
|
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 src Ns "=" Ns Oo Sy no "|" yes Oc (default Sy no ) .
|
||||||
Place the new source code in
|
Place the new source code in
|
||||||
.Pa /src
|
.Pa /src
|
||||||
|
|
|
@ -121,10 +121,22 @@ and place it in the current directory as
|
||||||
Upgrade the current operating system using the sysroot after making the
|
Upgrade the current operating system using the sysroot after making the
|
||||||
.Sy all
|
.Sy all
|
||||||
target.
|
target.
|
||||||
|
.It Sy sysmerge-full
|
||||||
|
Like
|
||||||
|
.Sy sysmerge
|
||||||
|
but do a full operating system upgrade that uninstalls ports not present in the
|
||||||
|
sysroot using
|
||||||
|
.Fl \-full .
|
||||||
|
.It Sy sysmerge-full-wait
|
||||||
|
The combination of
|
||||||
|
.Sy sysmerge-full
|
||||||
|
and
|
||||||
|
.Sy sysmerge-full-wait .
|
||||||
.It Sy sysmerge-wait
|
.It Sy sysmerge-wait
|
||||||
Like
|
Like
|
||||||
.Sy sysmerge
|
.Sy sysmerge
|
||||||
but delay the upgrade until the next boot.
|
but delay the upgrade until the next boot using
|
||||||
|
.Fl \-wait .
|
||||||
.It Sy sysroot-base-headers
|
.It Sy sysroot-base-headers
|
||||||
Create the sysroot and install only the headers of the standard library and
|
Create the sysroot and install only the headers of the standard library and
|
||||||
kernel into it.
|
kernel into it.
|
||||||
|
@ -190,6 +202,16 @@ For instance, to build and install libc, run as root:
|
||||||
make install
|
make install
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
|
Note the individual makefiles only install the new system files and leak any
|
||||||
|
files that don't exist anymore; and they also don't run any upgrade hooks to
|
||||||
|
migrate the current system.
|
||||||
|
This mechanism isn't supported unless you are building the same source code as
|
||||||
|
the current operating system.
|
||||||
|
The global
|
||||||
|
.Sy sysmerge
|
||||||
|
makefile targets should be used instead as the supported mechanism for operating
|
||||||
|
system upgrades.
|
||||||
|
.Pp
|
||||||
System libraries are statically linked and you will have to relink programs with
|
System libraries are statically linked and you will have to relink programs with
|
||||||
the new library for changes to take effect.
|
the new library for changes to take effect.
|
||||||
Building the whole operating system from the root makefile ensures components
|
Building the whole operating system from the root makefile ensures components
|
||||||
|
|
|
@ -69,6 +69,26 @@ releasing Sortix x.y, foo." to allow the maintainer to easily
|
||||||
.Xr grep 1
|
.Xr grep 1
|
||||||
for it after a release.
|
for it after a release.
|
||||||
.Sh CHANGES
|
.Sh CHANGES
|
||||||
|
.Ss Fix system upgrade leaking files
|
||||||
|
.Xr sysupgrade 8
|
||||||
|
and
|
||||||
|
.Xr sysmerge 8
|
||||||
|
will now delete files that no longer exist in the new system and ports.
|
||||||
|
However, files may already have leaked if a 1.0 installation was upgraded to
|
||||||
|
a development build prior to this change.
|
||||||
|
An upgrade hook will delete any well known leaked files.
|
||||||
|
.Pp
|
||||||
|
Note:
|
||||||
|
You must use the
|
||||||
|
.Fl \-wait
|
||||||
|
option to do a two-stage upgrade if doing a
|
||||||
|
.Xr sysmerge 8
|
||||||
|
upgrade from an installation prior to this change to a version after this
|
||||||
|
change.
|
||||||
|
This requirement is because the old
|
||||||
|
.Xr sysmerge 8
|
||||||
|
will leak files and the upgrade hook only deal with well known files as of this
|
||||||
|
change, and doesn't handle future changes.
|
||||||
.Ss Fix /tix/manifest permissions in installations
|
.Ss Fix /tix/manifest permissions in installations
|
||||||
The
|
The
|
||||||
.Pa /tix/manifest
|
.Pa /tix/manifest
|
||||||
|
|
|
@ -134,6 +134,10 @@ all.
|
||||||
You can configure which ports gets loaded using the bootloader menu.
|
You can configure which ports gets loaded using the bootloader menu.
|
||||||
The base system is rather lean and can be made quite small.
|
The base system is rather lean and can be made quite small.
|
||||||
You need some ports to complete an installation.
|
You need some ports to complete an installation.
|
||||||
|
Only the selected ports are loaded into the live environment and installed onto
|
||||||
|
the new installation.
|
||||||
|
If upgrading an existing installation, then any ports not loaded will be removed
|
||||||
|
from the installation being upgraded.
|
||||||
.Ss Installer
|
.Ss Installer
|
||||||
This guide assumes you selected the operating system installation option in the
|
This guide assumes you selected the operating system installation option in the
|
||||||
bootloader.
|
bootloader.
|
||||||
|
|
|
@ -122,7 +122,8 @@ changes.
|
||||||
.It
|
.It
|
||||||
Updating the system.
|
Updating the system.
|
||||||
.It
|
.It
|
||||||
Updating the ports.
|
Updating the ports, installing any new ports, and removing any ports that
|
||||||
|
don't exist anymore or weren't loaded.
|
||||||
.It
|
.It
|
||||||
Updating the source code.
|
Updating the source code.
|
||||||
.It
|
.It
|
||||||
|
|
|
@ -24,12 +24,13 @@ hooks.o \
|
||||||
interactive.o \
|
interactive.o \
|
||||||
manifest.o \
|
manifest.o \
|
||||||
release.o \
|
release.o \
|
||||||
|
string_array.o \
|
||||||
|
|
||||||
OBJS=$(MAIN_OBJS) $(UTIL_OBJS)
|
OBJS=$(MAIN_OBJS) $(UTIL_OBJS)
|
||||||
|
|
||||||
SYSINSTALL_DEPS=conf devices execute fileops interactive manifest release
|
SYSINSTALL_DEPS=conf devices execute fileops interactive manifest release string_array
|
||||||
SYSMERGE_DEPS=conf fileops execute hooks manifest release
|
SYSMERGE_DEPS=conf fileops execute hooks manifest release string_array
|
||||||
SYSUPGRADE_DEPS=conf devices execute fileops hooks interactive manifest release
|
SYSUPGRADE_DEPS=conf devices execute fileops hooks interactive manifest release string_array
|
||||||
|
|
||||||
SYSINSTALL_OBJS:=sysinstall.o $(SYSINSTALL_DEPS:=.o)
|
SYSINSTALL_OBJS:=sysinstall.o $(SYSINSTALL_DEPS:=.o)
|
||||||
SYSMERGE_OBJS:=sysmerge.o $(SYSMERGE_DEPS:=.o)
|
SYSMERGE_OBJS:=sysmerge.o $(SYSMERGE_DEPS:=.o)
|
||||||
|
@ -52,6 +53,7 @@ install: all
|
||||||
# TODO: After releasing Sortix 1.1, remove this compatibility.
|
# TODO: After releasing Sortix 1.1, remove this compatibility.
|
||||||
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-random-seed
|
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-random-seed
|
||||||
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-tix-manifest-mode
|
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-tix-manifest-mode
|
||||||
|
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-leaked-files
|
||||||
|
|
||||||
sysinstall: $(SYSINSTALL_OBJS)
|
sysinstall: $(SYSINSTALL_OBJS)
|
||||||
$(CC) $(SYSINSTALL_OBJS) -o $@ -lmount
|
$(CC) $(SYSINSTALL_OBJS) -o $@ -lmount
|
||||||
|
@ -71,10 +73,11 @@ sysupgrade.o: $(SYSUPGRADE_DEPS:=.h)
|
||||||
conf.o: conf.h
|
conf.o: conf.h
|
||||||
devices.o: devices.h
|
devices.o: devices.h
|
||||||
execute.o: execute.h
|
execute.o: execute.h
|
||||||
fileops.o: fileops.h
|
fileops.o: fileops.h string_array.h
|
||||||
hooks.o: fileops.h release.h
|
string_array.o: string_array.h
|
||||||
|
hooks.o: fileops.h manifest.h release.h string_array.h
|
||||||
interactive.o: interactive.h execute.h
|
interactive.o: interactive.h execute.h
|
||||||
manifest.o: manifest.h execute.h fileops.h
|
manifest.o: manifest.h fileops.h string_array.h
|
||||||
release.o: release.h
|
release.o: release.h
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2016, 2017 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2015, 2016, 2017, 2020 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "fileops.h"
|
#include "fileops.h"
|
||||||
|
#include "string_array.h"
|
||||||
|
|
||||||
char* join_paths(const char* a, const char* b)
|
char* join_paths(const char* a, const char* b)
|
||||||
{
|
{
|
||||||
|
@ -176,3 +177,45 @@ char* read_string_file(const char* path)
|
||||||
content[amount] = '\0';
|
content[amount] = '\0';
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char** read_lines_file(const char* path, size_t* out_count)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(path, "r");
|
||||||
|
if ( !fp )
|
||||||
|
return NULL;
|
||||||
|
size_t count;
|
||||||
|
size_t length;
|
||||||
|
char** lines;
|
||||||
|
if ( !string_array_init(&lines, &count, &length) )
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
char* line = NULL;
|
||||||
|
size_t line_size = 0;
|
||||||
|
ssize_t line_length;
|
||||||
|
while ( 0 < (errno = 0, line_length = getline(&line, &line_size, fp)) )
|
||||||
|
{
|
||||||
|
if ( line[line_length-1] == '\n' )
|
||||||
|
line[--line_length] = '\0';
|
||||||
|
if ( !string_array_append_nodup(&lines, &count, &length, line) )
|
||||||
|
{
|
||||||
|
free(line);
|
||||||
|
string_array_free(&lines, &count, &length);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
line = NULL;
|
||||||
|
line_size = 0;
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
if ( ferror(fp) )
|
||||||
|
{
|
||||||
|
string_array_free(&lines, &count, &length);
|
||||||
|
fclose(fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
*out_count = count;
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2015, 2016, 2020 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -26,5 +26,6 @@ int access_or_die(const char* path, int mode);
|
||||||
void mkdir_or_chmod_or_die(const char* path, mode_t mode);
|
void mkdir_or_chmod_or_die(const char* path, mode_t mode);
|
||||||
void write_random_seed(const char* path);
|
void write_random_seed(const char* path);
|
||||||
char* read_string_file(const char* path);
|
char* read_string_file(const char* path);
|
||||||
|
char** read_lines_file(const char* path, size_t* out_count);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
2003
sysinstall/hooks.c
2003
sysinstall/hooks.c
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2018 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2015, 2018, 2020, 2021 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -27,27 +27,85 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "execute.h"
|
|
||||||
#include "fileops.h"
|
#include "fileops.h"
|
||||||
#include "manifest.h"
|
#include "manifest.h"
|
||||||
|
#include "string_array.h"
|
||||||
|
|
||||||
bool has_manifest(const char* manifest)
|
bool has_manifest(const char* manifest)
|
||||||
{
|
{
|
||||||
char* path;
|
char* path = join_paths("/tix/manifest", manifest);
|
||||||
if ( asprintf(&path, "/tix/manifest/%s", manifest) < 0 )
|
if ( !path )
|
||||||
{
|
{
|
||||||
warn("asprintf");
|
warn("asprintf");
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
bool result = access(path, F_OK) == 0;
|
bool result = access_or_die(path, F_OK) == 0;
|
||||||
free(path);
|
free(path);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char** read_manifest(const char* path, size_t* out_count)
|
||||||
|
{
|
||||||
|
char** files = read_lines_file(path, out_count);
|
||||||
|
if ( !files )
|
||||||
|
return NULL;
|
||||||
|
// TODO: Remove this compatibility after releasing Sortix 1.1. The manifests
|
||||||
|
// in Sortix 1.0 have spurious trailing slashes due to a bug in the
|
||||||
|
// kernel binary package extractor. Remove them here to normalize the
|
||||||
|
// manifests.
|
||||||
|
for ( size_t i = 0; i < *out_count; i++ )
|
||||||
|
{
|
||||||
|
char* file = files[i];
|
||||||
|
size_t len = strlen(file);
|
||||||
|
if ( 2 <= len && file[len - 1] == '/' )
|
||||||
|
file[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
string_array_sort_strcmp(files, *out_count);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unlink_rename_conflict(const char* path)
|
||||||
|
{
|
||||||
|
if ( !unlink(path) || errno == ENOENT )
|
||||||
|
return;
|
||||||
|
if ( errno != EISDIR )
|
||||||
|
{
|
||||||
|
warn("unlink: %s", path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
if ( !rmdir(path) )
|
||||||
|
return;
|
||||||
|
if ( errno != ENOTEMPTY && errno != EEXIST )
|
||||||
|
{
|
||||||
|
warn("rmdir: %s", path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
char* conflict;
|
||||||
|
if ( asprintf(&conflict, "%s.conflict.XXXXXX", path) < 0 )
|
||||||
|
{
|
||||||
|
warn("malloc");
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
if ( !mkdtemp(conflict) )
|
||||||
|
{
|
||||||
|
warn("mkdtemp: %s.conflict.XXXXXX", path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
if ( rename(path, conflict) < 0 )
|
||||||
|
{
|
||||||
|
warn("rename: %s -> %s", path, conflict);
|
||||||
|
rmdir(conflict);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
printf("warning: Moving conflicting directory %s to %s\n", path, conflict);
|
||||||
|
free(conflict);
|
||||||
|
}
|
||||||
|
|
||||||
struct hardlink
|
struct hardlink
|
||||||
{
|
{
|
||||||
dev_t dev;
|
dev_t dev;
|
||||||
|
@ -57,9 +115,10 @@ struct hardlink
|
||||||
|
|
||||||
void install_manifest(const char* manifest,
|
void install_manifest(const char* manifest,
|
||||||
const char* from_prefix,
|
const char* from_prefix,
|
||||||
const char* to_prefix)
|
const char* to_prefix,
|
||||||
|
const char* const* preserved,
|
||||||
|
size_t preserved_count)
|
||||||
{
|
{
|
||||||
printf(" - Installing %s...\n", manifest);
|
|
||||||
struct hardlink* hardlinks = NULL;
|
struct hardlink* hardlinks = NULL;
|
||||||
size_t hardlinks_used = 0;
|
size_t hardlinks_used = 0;
|
||||||
size_t hardlinks_length = 0;
|
size_t hardlinks_length = 0;
|
||||||
|
@ -71,52 +130,141 @@ void install_manifest(const char* manifest,
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
mode_t old_umask = umask(0000);
|
mode_t old_umask = umask(0000);
|
||||||
|
// Read the input and output manifests if they exist. Consider a manifest
|
||||||
|
// that doesn't exist as being empty.
|
||||||
char* inmanifest;
|
char* inmanifest;
|
||||||
if ( asprintf(&inmanifest, "%s/tix/manifest/%s", from_prefix, manifest) < 0 )
|
|
||||||
{
|
|
||||||
warn("asprintf");
|
|
||||||
_exit(2);
|
|
||||||
}
|
|
||||||
char* outmanifest;
|
char* outmanifest;
|
||||||
if ( asprintf(&outmanifest, "%s/tix/manifest/%s", to_prefix, manifest) < 0 )
|
char* outnewmanifest;
|
||||||
|
if ( asprintf(&inmanifest, "%s/tix/manifest/%s", from_prefix,
|
||||||
|
manifest) < 0 ||
|
||||||
|
asprintf(&outmanifest, "%s/tix/manifest/%s", to_prefix,
|
||||||
|
manifest) < 0 ||
|
||||||
|
asprintf(&outnewmanifest, "%s/tix/manifest/%s.new", to_prefix,
|
||||||
|
manifest) < 0 )
|
||||||
{
|
{
|
||||||
warn("asprintf");
|
warn("malloc");
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
FILE* fpin = fopen(inmanifest, "r");
|
bool in_exists = !access_or_die(inmanifest, F_OK);
|
||||||
if ( !fpin )
|
bool out_exists = !access_or_die(outmanifest, F_OK);
|
||||||
|
const char* action = in_exists && out_exists ? "Upgrading" :
|
||||||
|
in_exists ? "Installing" :
|
||||||
|
"Uninstalling";
|
||||||
|
printf(" - %s %s...\n", action, manifest);
|
||||||
|
char** empty = (char*[]){};
|
||||||
|
char** in_files = empty;
|
||||||
|
size_t in_files_count = 0;
|
||||||
|
if ( in_exists &&
|
||||||
|
!(in_files = read_manifest(inmanifest, &in_files_count)) )
|
||||||
{
|
{
|
||||||
warn("%s", inmanifest);
|
warn("%s", inmanifest);
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
FILE* fpout = fopen(outmanifest, "w");
|
char** out_files = empty;
|
||||||
if ( !fpout )
|
size_t out_files_count = 0;
|
||||||
|
if ( out_exists &&
|
||||||
|
!(out_files = read_manifest(outmanifest, &out_files_count)) )
|
||||||
{
|
{
|
||||||
warn("%s", outmanifest);
|
warn("%s", outmanifest);
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
char* line = NULL;
|
// Directories to be cleaned up afterwards when they might be empty.
|
||||||
size_t line_size = 0;
|
size_t rmdirs_count;
|
||||||
ssize_t line_length;
|
size_t rmdirs_length;
|
||||||
while ( 0 < (line_length = getline(&line, &line_size, fpin)) )
|
char** rmdirs;
|
||||||
|
if ( !string_array_init(&rmdirs, &rmdirs_count, &rmdirs_length) )
|
||||||
{
|
{
|
||||||
if ( line[line_length-1] == '\n' )
|
warn("malloc");
|
||||||
line[--line_length] = '\0';
|
_exit(2);
|
||||||
if ( fprintf(fpout, "%s\n", line) < 0 )
|
}
|
||||||
|
// Find the differences by mutually iterating the manifests in sorted
|
||||||
|
// order.
|
||||||
|
size_t in_i = 0;
|
||||||
|
size_t out_i = 0;
|
||||||
|
while ( in_i < in_files_count || out_i < out_files_count )
|
||||||
|
{
|
||||||
|
const char* in = in_i < in_files_count ? in_files[in_i] : NULL;
|
||||||
|
const char* out = out_i < out_files_count ? out_files[out_i] : NULL;
|
||||||
|
if ( !in || (out && strcmp(in, out) > 0) )
|
||||||
{
|
{
|
||||||
warn("write: %s", outmanifest);
|
out_i++;
|
||||||
_exit(2);
|
const char* path = out;
|
||||||
}
|
char* out_path = join_paths(to_prefix, path);
|
||||||
if ( line[0] != '/' )
|
if ( !out_path )
|
||||||
|
{
|
||||||
|
warn("asprintf");
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
// Don't delete a path if it will be added in later by another
|
||||||
|
// manifest. This supports files moving from one manifest to another
|
||||||
|
// and directories only being cleaned up when no manifest mentions
|
||||||
|
// them.
|
||||||
|
if ( string_array_contains_bsearch_strcmp(preserved,
|
||||||
|
preserved_count, path) )
|
||||||
|
{
|
||||||
|
// Handle a directory becoming a symbolic link, which will be
|
||||||
|
// renamed to a conflict directory and replaced with a symbolic
|
||||||
|
// link, but we must take care not to delete anything through
|
||||||
|
// the symbolic link. This case happens if the directory becomes
|
||||||
|
// a symlink in another manifest.
|
||||||
|
struct stat outst;
|
||||||
|
if ( !lstat(out_path, &outst) )
|
||||||
|
{
|
||||||
|
if ( S_ISLNK(outst.st_mode) )
|
||||||
|
{
|
||||||
|
size_t path_length = strlen(path);
|
||||||
|
while ( out_i < out_files_count &&
|
||||||
|
!strncmp(path, out_files[out_i], path_length) &&
|
||||||
|
out_files[out_i][path_length] == '/' )
|
||||||
|
out_i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( errno != ENOENT && errno != ENOTDIR )
|
||||||
|
{
|
||||||
|
warn("%s", out_path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
free(out_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( unlink(out_path) < 0 )
|
||||||
|
{
|
||||||
|
if ( errno == EISDIR )
|
||||||
|
{
|
||||||
|
if ( rmdir(out_path) < 0 )
|
||||||
|
{
|
||||||
|
if ( errno == ENOTEMPTY || errno == EEXIST )
|
||||||
|
{
|
||||||
|
if ( !string_array_append(&rmdirs, &rmdirs_count,
|
||||||
|
&rmdirs_length, path) )
|
||||||
|
{
|
||||||
|
warn("malloc");
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( errno != ENOENT )
|
||||||
|
{
|
||||||
|
warn("unlink: %s", out_path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( errno != ENOENT )
|
||||||
|
{
|
||||||
|
warn("unlink: %s", out_path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(out_path);
|
||||||
continue;
|
continue;
|
||||||
char* in_path;
|
|
||||||
if ( asprintf(&in_path, "%s%s", from_prefix, line) < 0 )
|
|
||||||
{
|
|
||||||
warn("asprintf");
|
|
||||||
_exit(2);
|
|
||||||
}
|
}
|
||||||
char* out_path = line;
|
in_i++;
|
||||||
if ( asprintf(&out_path, "%s%s", to_prefix, line) < 0 )
|
if ( out && !strcmp(in, out) )
|
||||||
|
out_i++;
|
||||||
|
const char* path = in;
|
||||||
|
char* in_path = join_paths(from_prefix, path);
|
||||||
|
char* out_path = join_paths(to_prefix, path);
|
||||||
|
if ( !in_path || !out_path )
|
||||||
{
|
{
|
||||||
warn("asprintf");
|
warn("asprintf");
|
||||||
_exit(2);
|
_exit(2);
|
||||||
|
@ -141,7 +289,7 @@ void install_manifest(const char* manifest,
|
||||||
}
|
}
|
||||||
if ( hardlink )
|
if ( hardlink )
|
||||||
{
|
{
|
||||||
unlink(out_path);
|
unlink_rename_conflict(out_path);
|
||||||
if ( link(hardlink->path, out_path) < 0 )
|
if ( link(hardlink->path, out_path) < 0 )
|
||||||
{
|
{
|
||||||
warn("link: %s -> %s", hardlink->path, out_path);
|
warn("link: %s -> %s", hardlink->path, out_path);
|
||||||
|
@ -150,23 +298,38 @@ void install_manifest(const char* manifest,
|
||||||
}
|
}
|
||||||
else if ( S_ISDIR(inst.st_mode) )
|
else if ( S_ISDIR(inst.st_mode) )
|
||||||
{
|
{
|
||||||
if ( mkdir(out_path, inst.st_mode & 07777) < 0 && errno != EEXIST )
|
if ( unlink(out_path) < 0 && errno != ENOENT && errno != EISDIR )
|
||||||
{
|
{
|
||||||
warn("mkdir: %s", out_path);
|
warn("unlink: %s", out_path);
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
|
if ( mkdir(out_path, inst.st_mode & 07777) < 0 )
|
||||||
|
{
|
||||||
|
if ( errno == EEXIST )
|
||||||
|
{
|
||||||
|
if ( chmod(out_path, inst.st_mode & 07777) < 0 )
|
||||||
|
{
|
||||||
|
warn("chmod: %s", out_path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
warn("mkdir: %s", out_path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ( S_ISREG(inst.st_mode) )
|
else if ( S_ISREG(inst.st_mode) )
|
||||||
{
|
{
|
||||||
|
unlink_rename_conflict(out_path);
|
||||||
int in_fd = open(in_path, O_RDONLY);
|
int in_fd = open(in_path, O_RDONLY);
|
||||||
if ( in_fd < 0 )
|
if ( in_fd < 0 )
|
||||||
{
|
{
|
||||||
warn("%s", in_path);
|
warn("%s", in_path);
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
unlink(out_path);
|
int out_fd = open(out_path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
|
||||||
int out_fd = open(out_path, O_WRONLY | O_CREAT | O_TRUNC,
|
|
||||||
inst.st_mode & 07777);
|
inst.st_mode & 07777);
|
||||||
if ( out_fd < 0 )
|
if ( out_fd < 0 )
|
||||||
{
|
{
|
||||||
|
@ -183,7 +346,8 @@ void install_manifest(const char* manifest,
|
||||||
}
|
}
|
||||||
if ( amount == 0 )
|
if ( amount == 0 )
|
||||||
break;
|
break;
|
||||||
if ( writeall(out_fd, buffer, (size_t) amount) < (size_t) amount )
|
if ( writeall(out_fd, buffer, (size_t) amount) <
|
||||||
|
(size_t) amount )
|
||||||
{
|
{
|
||||||
warn("write: %s", out_path);
|
warn("write: %s", out_path);
|
||||||
_exit(2);
|
_exit(2);
|
||||||
|
@ -195,17 +359,17 @@ void install_manifest(const char* manifest,
|
||||||
{
|
{
|
||||||
if ( hardlinks_used == hardlinks_length )
|
if ( hardlinks_used == hardlinks_length )
|
||||||
{
|
{
|
||||||
// TODO: Multiplication overflow.
|
size_t new_length = hardlinks_length ? hardlinks_length : 8;
|
||||||
size_t new_length = hardlinks_length ? 2 * hardlinks_length : 16;
|
struct hardlink* new_hardlinks =
|
||||||
struct hardlink* new_hardlinks = (struct hardlink*)
|
reallocarray(hardlinks, new_length,
|
||||||
reallocarray(hardlinks, new_length, sizeof(struct hardlink));
|
2 * sizeof(struct hardlink));
|
||||||
if ( !new_hardlinks )
|
if ( !new_hardlinks )
|
||||||
{
|
{
|
||||||
warn("malloc");
|
warn("malloc");
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
hardlinks = new_hardlinks;
|
hardlinks = new_hardlinks;
|
||||||
hardlinks_length = new_length;
|
hardlinks_length = 2 * new_length;
|
||||||
}
|
}
|
||||||
hardlinks[hardlinks_used].ino = inst.st_ino;
|
hardlinks[hardlinks_used].ino = inst.st_ino;
|
||||||
hardlinks[hardlinks_used].dev = inst.st_dev;
|
hardlinks[hardlinks_used].dev = inst.st_dev;
|
||||||
|
@ -226,12 +390,22 @@ void install_manifest(const char* manifest,
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
buffer[amount] = '\0';
|
buffer[amount] = '\0';
|
||||||
unlink(out_path);
|
unlink_rename_conflict(out_path);
|
||||||
if ( symlink(buffer, out_path) < 0 && errno != EEXIST )
|
if ( symlink(buffer, out_path) < 0 && errno != EEXIST )
|
||||||
{
|
{
|
||||||
warn("symlink: %s", out_path);
|
warn("symlink: %s", out_path);
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
|
// Handle a directory becoming a symbolic link, which will be
|
||||||
|
// renamed to a conflict directory and replaced with a symbolic
|
||||||
|
// link, but we must take care not to delete anything through
|
||||||
|
// the symbolic link. This case happens if the directory becomes a
|
||||||
|
// symlink in the same manifest.
|
||||||
|
size_t path_length = strlen(path);
|
||||||
|
while ( out_i < out_files_count &&
|
||||||
|
!strncmp(path, out_files[out_i], path_length) &&
|
||||||
|
out_files[out_i][path_length] == '/' )
|
||||||
|
out_i++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -241,20 +415,218 @@ void install_manifest(const char* manifest,
|
||||||
free(in_path);
|
free(in_path);
|
||||||
free(out_path);
|
free(out_path);
|
||||||
}
|
}
|
||||||
free(line);
|
// Delete directories that might not be empty in backwards order to ensure
|
||||||
if ( ferror(fpin) )
|
// subdirectories are deleted before their parent directories.
|
||||||
|
for ( size_t i = rmdirs_count; i; i-- )
|
||||||
{
|
{
|
||||||
warn("%s", inmanifest);
|
const char* path = rmdirs[i - 1];
|
||||||
|
char* out_path;
|
||||||
|
if ( asprintf(&out_path, "%s%s", to_prefix, path) < 0 )
|
||||||
|
{
|
||||||
|
warn("asprintf");
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
if ( rmdir(out_path) < 0 &&
|
||||||
|
errno != ENOTEMPTY && errno != EEXIST && errno != ENOENT )
|
||||||
|
{
|
||||||
|
warn("unlink: %s", out_path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
free(out_path);
|
||||||
|
(void) path;
|
||||||
|
}
|
||||||
|
string_array_free(&rmdirs, &rmdirs_count, &rmdirs_length);
|
||||||
|
if ( in_exists )
|
||||||
|
{
|
||||||
|
if ( unlink(outnewmanifest) < 0 && errno != ENOENT )
|
||||||
|
{
|
||||||
|
warn("unlink: %s", outnewmanifest);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
mode_t temp_umask = umask(0022);
|
||||||
|
FILE* fp = fopen(outnewmanifest, "w");
|
||||||
|
if ( !fp )
|
||||||
|
{
|
||||||
|
warn("%s", outnewmanifest);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
umask(temp_umask);
|
||||||
|
for ( size_t i = 0; i < in_files_count; i++ )
|
||||||
|
{
|
||||||
|
const char* path = in_files[i];
|
||||||
|
if ( fputs(path, fp) == EOF || fputc('\n', fp) == EOF )
|
||||||
|
{
|
||||||
|
warn("%s", outnewmanifest);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( fclose(fp) == EOF )
|
||||||
|
{
|
||||||
|
warn("%s", outnewmanifest);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
if ( rename(outnewmanifest, outmanifest) < 0 )
|
||||||
|
{
|
||||||
|
warn("rename: %s -> %s", outnewmanifest, outmanifest);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( out_exists )
|
||||||
|
{
|
||||||
|
if ( unlink(outmanifest) < 0 && errno != ENOENT )
|
||||||
|
{
|
||||||
|
warn("unlink: %s", outmanifest);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write out the new manifests atomically 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,
|
||||||
|
manifest) < 0 ||
|
||||||
|
asprintf(&out_tixinfo, "%s/tix/tixinfo/%s", to_prefix,
|
||||||
|
manifest) < 0 )
|
||||||
|
{
|
||||||
|
warn("malloc");
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
fclose(fpin);
|
// Update or delete the tixinfo accordingly.
|
||||||
if ( fclose(fpout) == EOF )
|
bool is_tix = !access_or_die(in_tixinfo, F_OK);
|
||||||
|
if ( is_tix )
|
||||||
{
|
{
|
||||||
warn("close: %s", outmanifest);
|
int in_fd = open(in_tixinfo, O_RDONLY);
|
||||||
|
if ( in_fd < 0 )
|
||||||
|
{
|
||||||
|
warn("%s", in_tixinfo);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
unlink(out_tixinfo);
|
||||||
|
int out_fd = open(out_tixinfo, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
if ( out_fd < 0 )
|
||||||
|
{
|
||||||
|
warn("%s", out_tixinfo);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
ssize_t amount = read(in_fd, buffer, buffer_size);
|
||||||
|
if ( amount < 0 )
|
||||||
|
{
|
||||||
|
warn("read: %s", in_tixinfo);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
if ( amount == 0 )
|
||||||
|
break;
|
||||||
|
if ( writeall(out_fd, buffer, (size_t) amount) < (size_t) amount )
|
||||||
|
{
|
||||||
|
warn("write: %s", out_tixinfo);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(out_fd);
|
||||||
|
close(in_fd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( unlink(out_tixinfo) < 0 && errno != ENOENT )
|
||||||
|
{
|
||||||
|
warn("unlink: %s", out_tixinfo);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
_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++ )
|
||||||
|
free(in_files[i]);
|
||||||
|
free(in_files);
|
||||||
|
}
|
||||||
|
if ( out_files != empty )
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; i < out_files_count; i++ )
|
||||||
|
free(out_files[i]);
|
||||||
|
free(out_files);
|
||||||
|
}
|
||||||
free(inmanifest);
|
free(inmanifest);
|
||||||
free(outmanifest);
|
free(outmanifest);
|
||||||
|
free(outnewmanifest);
|
||||||
umask(old_umask);
|
umask(old_umask);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
for ( size_t i = 0; i < hardlinks_used; i++ )
|
for ( size_t i = 0; i < hardlinks_used; i++ )
|
||||||
|
@ -262,148 +634,152 @@ void install_manifest(const char* manifest,
|
||||||
free(hardlinks);
|
free(hardlinks);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_installed(const char* path, const char* package)
|
void install_manifests(const char* const* manifests,
|
||||||
|
size_t manifests_count,
|
||||||
|
const char* from_prefix,
|
||||||
|
const char* to_prefix)
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(path, "r");
|
// Load all the paths mentioned in the new set of manifests, which are used
|
||||||
if ( !fp )
|
// to ensure no files and directories are deleted part way if they are moved
|
||||||
|
// from one manifest to another.
|
||||||
|
printf(" - Loading manifests...\n");
|
||||||
|
size_t all_count;
|
||||||
|
size_t all_length;
|
||||||
|
char** all;
|
||||||
|
if ( !string_array_init(&all, &all_count, &all_length) )
|
||||||
{
|
{
|
||||||
if ( errno != ENOENT )
|
warn("malloc");
|
||||||
warn("%s", path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
char* line = NULL;
|
|
||||||
size_t line_size = 0;
|
|
||||||
ssize_t line_length;
|
|
||||||
while ( 0 < (line_length = getline(&line, &line_size, fp)) )
|
|
||||||
{
|
|
||||||
if ( line[line_length-1] == '\n' )
|
|
||||||
line[--line_length] = '\0';
|
|
||||||
if ( !strcmp(line, package) )
|
|
||||||
{
|
|
||||||
free(line);
|
|
||||||
fclose(fp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( ferror(fp) )
|
|
||||||
warn("%s", path);
|
|
||||||
free(line);
|
|
||||||
fclose(fp);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* shell_single_quote(const char* string)
|
|
||||||
{
|
|
||||||
char* result;
|
|
||||||
size_t result_size;
|
|
||||||
FILE* fp = open_memstream(&result, &result_size);
|
|
||||||
if (!fp)
|
|
||||||
return NULL;
|
|
||||||
fputc('\'', fp);
|
|
||||||
for ( size_t i = 0; string[i]; i++ )
|
|
||||||
{
|
|
||||||
if ( string[i] == '\'' )
|
|
||||||
fputs("\'\\\'\'", fp);
|
|
||||||
else
|
|
||||||
fputc((unsigned char) string[i], fp);
|
|
||||||
}
|
|
||||||
fputc('\'', fp);
|
|
||||||
fflush(fp);
|
|
||||||
int waserr = ferror(fp);
|
|
||||||
fclose(fp);
|
|
||||||
if (waserr) {
|
|
||||||
free(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* sort_file_cmd(const char* file)
|
|
||||||
{
|
|
||||||
char* file_esc = shell_single_quote(file);
|
|
||||||
if ( !file_esc )
|
|
||||||
return NULL;
|
|
||||||
char* cmd;
|
|
||||||
if ( asprintf(&cmd, "sort -- %s", file_esc) < 0 )
|
|
||||||
{
|
|
||||||
free(file_esc);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
free(file_esc);
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void install_ports(const char* from_prefix, const char* to_prefix)
|
|
||||||
{
|
|
||||||
char* inst_in_path;
|
|
||||||
char* inst_out_path;
|
|
||||||
if ( asprintf(&inst_in_path, "%s/tix/installed.list", from_prefix) < 0 ||
|
|
||||||
asprintf(&inst_out_path, "%s/tix/installed.list", to_prefix) < 0 )
|
|
||||||
{
|
|
||||||
warn("asprintf");
|
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
if ( access_or_die(inst_in_path, F_OK) < 0 )
|
for ( size_t i = 0; i < manifests_count; i++ )
|
||||||
{
|
{
|
||||||
free(inst_in_path);
|
// Read the input manifests if they exist. Consider a manifest that
|
||||||
free(inst_out_path);
|
// doesn't exist as being empty.
|
||||||
return;
|
const char* manifest = manifests[i];
|
||||||
}
|
char* inmanifest;
|
||||||
char* cmd = sort_file_cmd(inst_in_path);
|
if ( asprintf(&inmanifest, "%s/tix/manifest/%s", from_prefix,
|
||||||
if ( !cmd )
|
manifest) < 0 )
|
||||||
{
|
|
||||||
warn("sort_file_cmd");
|
|
||||||
_exit(2);
|
|
||||||
}
|
|
||||||
FILE* fp = popen(cmd, "r");
|
|
||||||
if ( !fp )
|
|
||||||
{
|
|
||||||
warn("%s", cmd);
|
|
||||||
_exit(2);
|
|
||||||
}
|
|
||||||
char* line = NULL;
|
|
||||||
size_t line_size = 0;
|
|
||||||
ssize_t line_length;
|
|
||||||
while ( 0 < (line_length = getline(&line, &line_size, fp)) )
|
|
||||||
{
|
|
||||||
if ( line[line_length-1] == '\n' )
|
|
||||||
line[--line_length] = '\0';
|
|
||||||
if ( !check_installed(inst_out_path, line) )
|
|
||||||
{
|
|
||||||
FILE* inst_out_fp = fopen(inst_out_path, "a");
|
|
||||||
if ( !inst_out_fp ||
|
|
||||||
fprintf(inst_out_fp, "%s\n", line) < 0 ||
|
|
||||||
fflush(inst_out_fp) == EOF )
|
|
||||||
{
|
|
||||||
warn("%s", inst_out_path);
|
|
||||||
pclose(fp);
|
|
||||||
_exit(2);
|
|
||||||
}
|
|
||||||
fclose(inst_out_fp);
|
|
||||||
}
|
|
||||||
char* tixinfo_in;
|
|
||||||
char* tixinfo_out;
|
|
||||||
if ( asprintf(&tixinfo_in, "%s/tix/tixinfo/%s", from_prefix, line) < 0 ||
|
|
||||||
asprintf(&tixinfo_out, "%s/tix/tixinfo/%s", to_prefix, line) < 0 )
|
|
||||||
{
|
{
|
||||||
warn("asprintf");
|
warn("asprintf");
|
||||||
pclose(fp);
|
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
execute((const char*[]) { "cp", "--", tixinfo_in, tixinfo_out, NULL }, "_e");
|
char** empty = (char*[]){};
|
||||||
free(tixinfo_in);
|
char** in_files = empty;
|
||||||
free(tixinfo_out);
|
size_t in_files_count = 0;
|
||||||
install_manifest(line, from_prefix, to_prefix);
|
if ( !access_or_die(inmanifest, F_OK) &&
|
||||||
|
!(in_files = read_manifest(inmanifest, &in_files_count)) )
|
||||||
|
{
|
||||||
|
warn("%s", inmanifest);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
// Directories can appear in multiple manifests, so keep track of all
|
||||||
|
// input paths so we later can find duplicates.
|
||||||
|
for ( size_t i = 0; i < in_files_count; i++ )
|
||||||
|
{
|
||||||
|
if ( !string_array_append(&all, &all_count, &all_length,
|
||||||
|
in_files[i]) )
|
||||||
|
{
|
||||||
|
warn("malloc");
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( in_files != empty )
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; i < in_files_count; i++ )
|
||||||
|
free(in_files[i]);
|
||||||
|
free(in_files);
|
||||||
|
}
|
||||||
|
free(inmanifest);
|
||||||
}
|
}
|
||||||
free(line);
|
string_array_sort_strcmp(all, all_count);
|
||||||
if ( ferror(fp) )
|
all_count = string_array_deduplicate(all, all_count);
|
||||||
|
for ( size_t i = 0; i < manifests_count; i++ )
|
||||||
|
install_manifest(manifests[i], from_prefix, to_prefix,
|
||||||
|
(const char* const*) all, all_count);
|
||||||
|
string_array_free(&all, &all_count, &all_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
char** read_installed_list(const char* prefix, size_t* out_count)
|
||||||
|
{
|
||||||
|
char* path;
|
||||||
|
if ( asprintf(&path, "%s/tix/installed.list", prefix) < 0 )
|
||||||
{
|
{
|
||||||
warn("%s", cmd);
|
warn("malloc");
|
||||||
pclose(fp);
|
|
||||||
_exit(2);
|
_exit(2);
|
||||||
}
|
}
|
||||||
pclose(fp);
|
char** installed;
|
||||||
free(cmd);
|
size_t installed_count;
|
||||||
free(inst_in_path);
|
if ( !access_or_die(path, F_OK) )
|
||||||
free(inst_out_path);
|
{
|
||||||
|
if ( !(installed = read_lines_file(path, &installed_count)) )
|
||||||
|
{
|
||||||
|
warn("%s", path);
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
string_array_sort_strcmp(installed, installed_count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
installed = malloc(1);
|
||||||
|
if ( !installed )
|
||||||
|
{
|
||||||
|
warn("malloc");
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
installed_count = 0;
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
|
*out_count = installed_count;
|
||||||
|
return installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void install_manifests_detect(const char* from_prefix,
|
||||||
|
const char* to_prefix,
|
||||||
|
bool system,
|
||||||
|
bool detect_from,
|
||||||
|
bool detect_to)
|
||||||
|
{
|
||||||
|
char** manifests;
|
||||||
|
size_t manifests_count;
|
||||||
|
size_t manifests_length;
|
||||||
|
string_array_init(&manifests, &manifests_count, &manifests_length);
|
||||||
|
if ( system &&
|
||||||
|
!string_array_append(&manifests, &manifests_count, &manifests_length,
|
||||||
|
"system") )
|
||||||
|
{
|
||||||
|
warn("malloc");
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
size_t system_offset = system ? 1 : 0;
|
||||||
|
const char* prefixes[] =
|
||||||
|
{
|
||||||
|
detect_from ? from_prefix : NULL,
|
||||||
|
detect_to ? to_prefix : NULL,
|
||||||
|
};
|
||||||
|
for ( size_t i = 0; i < sizeof(prefixes) / sizeof(prefixes[0]); i++ )
|
||||||
|
{
|
||||||
|
const char* prefix = prefixes[i];
|
||||||
|
if ( !prefix )
|
||||||
|
continue;
|
||||||
|
size_t installed_count;
|
||||||
|
char** installed = read_installed_list(prefix, &installed_count);
|
||||||
|
for ( size_t i = 0; i < installed_count; i++ )
|
||||||
|
{
|
||||||
|
if ( !string_array_append(&manifests, &manifests_count,
|
||||||
|
&manifests_length, installed[i]) )
|
||||||
|
{
|
||||||
|
warn("malloc");
|
||||||
|
_exit(2);
|
||||||
|
}
|
||||||
|
free(installed[i]);
|
||||||
|
}
|
||||||
|
free(installed);
|
||||||
|
}
|
||||||
|
// Keep the system manifest first and otherwise sort and deduplicate.
|
||||||
|
string_array_sort_strcmp(manifests + system_offset,
|
||||||
|
manifests_count - system_offset);
|
||||||
|
manifests_count = string_array_deduplicate(manifests, manifests_count);
|
||||||
|
install_manifests((const char* const*) manifests, manifests_count,
|
||||||
|
from_prefix, to_prefix);
|
||||||
|
string_array_free(&manifests, &manifests_count, &manifests_length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2015, 2016, 2020 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -21,10 +21,21 @@
|
||||||
#define MANIFEST_H
|
#define MANIFEST_H
|
||||||
|
|
||||||
bool has_manifest(const char* manifest);
|
bool has_manifest(const char* manifest);
|
||||||
|
char** read_manifest(const char* path, size_t* out_count);
|
||||||
void install_manifest(const char* manifest,
|
void install_manifest(const char* manifest,
|
||||||
const char* from_prefix,
|
const char* from_prefix,
|
||||||
const char* to_prefix);
|
const char* to_prefix,
|
||||||
bool check_installed(const char* path, const char* package);
|
const char* const* preserved,
|
||||||
void install_ports(const char* from_prefix, const char* to_prefix);
|
size_t preserved_count);
|
||||||
|
void install_manifests(const char* const* manifests,
|
||||||
|
size_t manifests_count,
|
||||||
|
const char* from_prefix,
|
||||||
|
const char* to_prefix);
|
||||||
|
char** read_installed_list(const char* prefix, size_t* out_count);
|
||||||
|
void install_manifests_detect(const char* from_prefix,
|
||||||
|
const char* to_prefix,
|
||||||
|
bool system,
|
||||||
|
bool detect_from,
|
||||||
|
bool detect_to);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.
|
||||||
|
*
|
||||||
|
* string_array.c
|
||||||
|
* String array utility functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "string_array.h"
|
||||||
|
|
||||||
|
bool string_array_init(char*** array, size_t* count, size_t* length)
|
||||||
|
{
|
||||||
|
*count = 0;
|
||||||
|
*length = 0;
|
||||||
|
size_t initial_length = 4;
|
||||||
|
if ( !(*array = calloc(initial_length, sizeof(char*))) )
|
||||||
|
return false;
|
||||||
|
*length = initial_length;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_array_free(char*** array, size_t* count, size_t* length)
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; i < *count; i++ )
|
||||||
|
free((*array)[i]);
|
||||||
|
free((*array));
|
||||||
|
*array = NULL;
|
||||||
|
*count = 0;
|
||||||
|
*length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_array_append_nodup(char*** array,
|
||||||
|
size_t* count,
|
||||||
|
size_t* length,
|
||||||
|
char* str)
|
||||||
|
{
|
||||||
|
if ( *count == *length )
|
||||||
|
{
|
||||||
|
char** new_array =
|
||||||
|
reallocarray(*array, *length, 2 * sizeof(char*));
|
||||||
|
if ( !new_array )
|
||||||
|
return false;
|
||||||
|
*array = new_array;
|
||||||
|
*length *= 2;
|
||||||
|
}
|
||||||
|
(*array)[(*count)++] = str;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_array_append(char*** array,
|
||||||
|
size_t* count,
|
||||||
|
size_t* length,
|
||||||
|
const char* str)
|
||||||
|
{
|
||||||
|
char* dup = strdup(str);
|
||||||
|
if ( !dup )
|
||||||
|
return false;
|
||||||
|
if ( !string_array_append_nodup(array, count, length, dup) )
|
||||||
|
{
|
||||||
|
free(dup);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int strcmp_indirect(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_array_sort_strcmp(char** array, size_t count)
|
||||||
|
{
|
||||||
|
qsort(array, count, sizeof(char*), strcmp_indirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int search_strcmp(const void* str_ptr, const void* elem_ptr)
|
||||||
|
{
|
||||||
|
const char* str = (const char*) str_ptr;
|
||||||
|
char* elem = *(char**) elem_ptr;
|
||||||
|
return strcmp(str, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_array_contains_bsearch_strcmp(const char* const* array,
|
||||||
|
size_t count,
|
||||||
|
const char* str)
|
||||||
|
{
|
||||||
|
return bsearch(str, array, count, sizeof(char*), search_strcmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t string_array_deduplicate(char** strings, size_t count)
|
||||||
|
{
|
||||||
|
size_t o = 0;
|
||||||
|
for ( size_t i = 0; i < count; i++ )
|
||||||
|
{
|
||||||
|
if ( !o || strcmp(strings[o - 1], strings[i]) != 0 )
|
||||||
|
strings[o++] = strings[i];
|
||||||
|
else
|
||||||
|
free(strings[i]);
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.
|
||||||
|
*
|
||||||
|
* string_array.h
|
||||||
|
* String array utility functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STRING_ARRAY_H
|
||||||
|
#define STRING_ARRAY_H
|
||||||
|
|
||||||
|
bool string_array_init(char*** array, size_t* count, size_t* length);
|
||||||
|
void string_array_free(char*** array, size_t* count, size_t* length);
|
||||||
|
bool string_array_append_nodup(char*** array,
|
||||||
|
size_t* count,
|
||||||
|
size_t* length,
|
||||||
|
char* str);
|
||||||
|
bool string_array_append(char*** array,
|
||||||
|
size_t* count,
|
||||||
|
size_t* length,
|
||||||
|
const char* str);
|
||||||
|
void string_array_sort_strcmp(char** array, size_t count);
|
||||||
|
bool string_array_contains_bsearch_strcmp(const char* const* array,
|
||||||
|
size_t count,
|
||||||
|
const char* str);
|
||||||
|
size_t string_array_deduplicate(char** strings, size_t count);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2016, 2020 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2015, 2016, 2020, 2021 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -884,40 +884,19 @@ int main(void)
|
||||||
if ( install_pid == 0 )
|
if ( install_pid == 0 )
|
||||||
{
|
{
|
||||||
printf(" - Populating root filesystem...\n");
|
printf(" - Populating root filesystem...\n");
|
||||||
umask(0000);
|
|
||||||
chmod(".", 0755);
|
chmod(".", 0755);
|
||||||
mkdir_or_chmod_or_die("bin", 0755);
|
|
||||||
mkdir_or_chmod_or_die("boot", 0755);
|
|
||||||
mkdir_or_chmod_or_die("dev", 0755);
|
|
||||||
mkdir_or_chmod_or_die("etc", 0755);
|
|
||||||
mkdir_or_chmod_or_die("etc/skel", 0755);
|
|
||||||
mkdir_or_chmod_or_die("etc/init", 0755);
|
|
||||||
mkdir_or_chmod_or_die("home", 0755);
|
|
||||||
mkdir_or_chmod_or_die("include", 0755);
|
|
||||||
mkdir_or_chmod_or_die("lib", 0755);
|
|
||||||
mkdir_or_chmod_or_die("mnt", 0755);
|
|
||||||
mkdir_or_chmod_or_die("root", 0700);
|
|
||||||
mkdir_or_chmod_or_die("sbin", 0755);
|
|
||||||
mkdir_or_chmod_or_die("share", 0755);
|
|
||||||
mkdir_or_chmod_or_die("tix", 0755);
|
|
||||||
mkdir_or_chmod_or_die("tix/manifest", 0755);
|
|
||||||
mkdir_or_chmod_or_die("tmp", 01777);
|
|
||||||
mkdir_or_chmod_or_die("var", 0755);
|
|
||||||
mkdir_or_chmod_or_die("var/empty", 0555);
|
|
||||||
umask(0022);
|
|
||||||
if ( access("tix/collection.conf", F_OK) < 0 )
|
if ( access("tix/collection.conf", F_OK) < 0 )
|
||||||
execute((const char*[]) { "tix-collection", ".", "create",
|
execute((const char*[]) { "tix-collection", ".", "create",
|
||||||
"--prefix=", NULL }, "_e");
|
"--prefix=", NULL }, "_e");
|
||||||
install_manifest("system", "", ".");
|
install_manifests_detect("", ".", true, true, true);
|
||||||
// TODO: Preserve the existing /src if it exists like in sysupgrade.
|
// TODO: Preserve the existing /src if it exists like in sysupgrade.
|
||||||
if ( has_manifest("src") )
|
if ( has_manifest("src") )
|
||||||
install_manifest("src", "", ".");
|
install_manifest("src", "", ".", (const char*[]){}, 0);
|
||||||
printf(" - Creating configuration files...\n");
|
printf(" - Creating configuration files...\n");
|
||||||
// TODO: Preserve mode/ownership/timestamps?
|
// TODO: Preserve mode/ownership/timestamps?
|
||||||
execute((const char*[]) { "cp", "-RTP", etc, "etc", NULL }, "_e");
|
execute((const char*[]) { "cp", "-RTP", etc, "etc", NULL }, "_e");
|
||||||
// TODO: Auto detect appropriate bcrypt rounds and set up etc/login.conf
|
// TODO: Auto detect appropriate bcrypt rounds and set up etc/login.conf
|
||||||
// and use those below instead of blowfish,a.
|
// and use those below instead of blowfish,a.
|
||||||
install_ports("", ".");
|
|
||||||
if ( access_or_die("boot/random.seed", F_OK) < 0 )
|
if ( access_or_die("boot/random.seed", F_OK) < 0 )
|
||||||
{
|
{
|
||||||
printf(" - Creating random seed...\n");
|
printf(" - Creating random seed...\n");
|
||||||
|
@ -991,6 +970,16 @@ int main(void)
|
||||||
}
|
}
|
||||||
text("\n");
|
text("\n");
|
||||||
|
|
||||||
|
if ( mkdir("root", 0700) < 0 )
|
||||||
|
{
|
||||||
|
if ( errno == EEXIST )
|
||||||
|
{
|
||||||
|
if ( chmod("root", 0700) < 0 )
|
||||||
|
warn("chmod: root");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
warn("mkdir: root");
|
||||||
|
}
|
||||||
if ( passwd_has_uid("etc/passwd", 0) ||
|
if ( passwd_has_uid("etc/passwd", 0) ||
|
||||||
passwd_has_name("etc/passwd", "root") )
|
passwd_has_name("etc/passwd", "root") )
|
||||||
{
|
{
|
||||||
|
@ -1036,6 +1025,16 @@ int main(void)
|
||||||
}
|
}
|
||||||
text("\n");
|
text("\n");
|
||||||
|
|
||||||
|
if ( mkdir("etc/init", 0755) < 0 )
|
||||||
|
{
|
||||||
|
if ( errno == EEXIST )
|
||||||
|
{
|
||||||
|
if ( chmod("etc/init", 0755) < 0 )
|
||||||
|
warn("chmod: etc/init");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
warn("mkdir: etc/init");
|
||||||
|
}
|
||||||
install_configurationf("etc/init/target", "w", "multi-user\n");
|
install_configurationf("etc/init/target", "w", "multi-user\n");
|
||||||
|
|
||||||
text("Congratulations, the system is now functional! This is a good time "
|
text("Congratulations, the system is now functional! This is a good time "
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
.Nd upgrade current operating system from a sysroot
|
.Nd upgrade current operating system from a sysroot
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm sysmerge
|
.Nm sysmerge
|
||||||
.Op Fl cw
|
.Op Fl cfw
|
||||||
.Op Fl \-booting
|
.Op Fl \-booting
|
||||||
.Op Fl \-hook-finalize
|
.Op Fl \-hook-finalize
|
||||||
.Op Fl \-hook-prepare
|
.Op Fl \-hook-prepare
|
||||||
|
@ -27,6 +27,7 @@ installs the
|
||||||
manifest from the tix repository in the
|
manifest from the tix repository in the
|
||||||
.Ar source
|
.Ar source
|
||||||
directory, as well as all the ports found.
|
directory, as well as all the ports found.
|
||||||
|
If a full upgrade is done, then all ports not found will be uninstalled.
|
||||||
Upgrade hooks will be run if further actions are needed to migrate the system to
|
Upgrade hooks will be run if further actions are needed to migrate the system to
|
||||||
the new version as described in
|
the new version as described in
|
||||||
.Xr following-development 7 .
|
.Xr following-development 7 .
|
||||||
|
@ -68,6 +69,10 @@ directory and restore the old
|
||||||
.Xr kernel 7
|
.Xr kernel 7
|
||||||
and
|
and
|
||||||
.Xr initrd 7 .
|
.Xr initrd 7 .
|
||||||
|
.It Fl f , Fl \-full
|
||||||
|
Full system upgrade that uninstalls ports not present in the
|
||||||
|
.Ar source
|
||||||
|
directory.
|
||||||
.It Fl \-hook-finalize
|
.It Fl \-hook-finalize
|
||||||
Run the post-upgrade hooks.
|
Run the post-upgrade hooks.
|
||||||
This is meant to be used by the old
|
This is meant to be used by the old
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, 2018, 2020 Jonas 'Sortie' Termansen.
|
* Copyright (c) 2016, 2018, 2020, 2021 Jonas 'Sortie' Termansen.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -73,6 +74,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
bool booting = false;
|
bool booting = false;
|
||||||
bool cancel = false;
|
bool cancel = false;
|
||||||
|
bool full = false;
|
||||||
bool hook_finalize = false;
|
bool hook_finalize = false;
|
||||||
bool hook_prepare = false;
|
bool hook_prepare = false;
|
||||||
bool wait = false;
|
bool wait = false;
|
||||||
|
@ -92,6 +94,7 @@ int main(int argc, char* argv[])
|
||||||
while ( (c = *++arg) ) switch ( c )
|
while ( (c = *++arg) ) switch ( c )
|
||||||
{
|
{
|
||||||
case 'c': cancel = true; break;
|
case 'c': cancel = true; break;
|
||||||
|
case 'f': full = true; break;
|
||||||
case 'w': wait = true; break;
|
case 'w': wait = true; break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
||||||
|
@ -107,6 +110,8 @@ int main(int argc, char* argv[])
|
||||||
booting = true;
|
booting = true;
|
||||||
else if ( !strcmp(arg, "--cancel") )
|
else if ( !strcmp(arg, "--cancel") )
|
||||||
cancel = true;
|
cancel = true;
|
||||||
|
else if ( !strcmp(arg, "--full") )
|
||||||
|
full = true;
|
||||||
else if ( !strcmp(arg, "--hook-finalize") )
|
else if ( !strcmp(arg, "--hook-finalize") )
|
||||||
hook_finalize = true;
|
hook_finalize = true;
|
||||||
else if ( !strcmp(arg, "--hook-prepare") )
|
else if ( !strcmp(arg, "--hook-prepare") )
|
||||||
|
@ -142,6 +147,7 @@ int main(int argc, char* argv[])
|
||||||
source = "/sysmerge";
|
source = "/sysmerge";
|
||||||
if ( 1 < argc )
|
if ( 1 < argc )
|
||||||
errx(2, "Unexpected extra operand `%s'", argv[1]);
|
errx(2, "Unexpected extra operand `%s'", argv[1]);
|
||||||
|
full = access_or_die("/sysmerge/tix/sysmerge.full", F_OK) == 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -307,13 +313,19 @@ int main(int argc, char* argv[])
|
||||||
execute((const char*[]) { "tix-collection", "/sysmerge", "create",
|
execute((const char*[]) { "tix-collection", "/sysmerge", "create",
|
||||||
NULL }, "e");
|
NULL }, "e");
|
||||||
}
|
}
|
||||||
install_manifest("system", source, target);
|
install_manifests_detect(source, target, true, true, full);
|
||||||
install_ports(source, target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( wait )
|
if ( wait )
|
||||||
{
|
{
|
||||||
printf(" - Scheduling upgrade on next boot...\n");
|
printf(" - Scheduling upgrade on next boot...\n");
|
||||||
|
if ( full )
|
||||||
|
{
|
||||||
|
int fd = open("/sysmerge/tix/sysmerge.full", O_WRONLY | O_CREAT);
|
||||||
|
if ( fd < 0 )
|
||||||
|
err(1, "/sysmerge/tix/sysmerge.full");
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
execute((const char*[]) { "cp", "/boot/sortix.bin",
|
execute((const char*[]) { "cp", "/boot/sortix.bin",
|
||||||
"/boot/sortix.bin.sysmerge.orig", NULL }, "e");
|
"/boot/sortix.bin.sysmerge.orig", NULL }, "e");
|
||||||
execute((const char*[]) { "cp", "/boot/sortix.initrd",
|
execute((const char*[]) { "cp", "/boot/sortix.initrd",
|
||||||
|
|
|
@ -803,13 +803,9 @@ int main(void)
|
||||||
if ( upgrade_pid == 0 )
|
if ( upgrade_pid == 0 )
|
||||||
{
|
{
|
||||||
umask(0022);
|
umask(0022);
|
||||||
// TODO: Use an upgrade manifest system that notices files that are now
|
|
||||||
// untracked or moved from one manifest to another.
|
|
||||||
if ( conf.system )
|
if ( conf.system )
|
||||||
{
|
|
||||||
upgrade_prepare(target_release, &new_release, "", ".");
|
upgrade_prepare(target_release, &new_release, "", ".");
|
||||||
install_manifest("system", "", ".");
|
install_manifests_detect("", ".", conf.system, conf.ports, conf.ports);
|
||||||
}
|
|
||||||
if ( has_manifest("src") )
|
if ( has_manifest("src") )
|
||||||
{
|
{
|
||||||
if ( conf.newsrc )
|
if ( conf.newsrc )
|
||||||
|
@ -824,7 +820,7 @@ int main(void)
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
install_manifest("src", "", ".");
|
install_manifest("src", "", ".", (const char*[]){}, 0);
|
||||||
if ( has_src )
|
if ( has_src )
|
||||||
{
|
{
|
||||||
if ( rename("src", "newsrc") < 0 )
|
if ( rename("src", "newsrc") < 0 )
|
||||||
|
@ -842,11 +838,9 @@ int main(void)
|
||||||
else if ( conf.src )
|
else if ( conf.src )
|
||||||
{
|
{
|
||||||
preserve_src("src");
|
preserve_src("src");
|
||||||
install_manifest("src", "", ".");
|
install_manifest("src", "", ".", (const char*[]){}, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( conf.ports )
|
|
||||||
install_ports("", ".");
|
|
||||||
if ( conf.system )
|
if ( conf.system )
|
||||||
upgrade_finalize(target_release, &new_release, "", ".");
|
upgrade_finalize(target_release, &new_release, "", ".");
|
||||||
if ( conf.system )
|
if ( conf.system )
|
||||||
|
|
Loading…
Reference in New Issue