Compare commits
33 Commits
a1f7b508a1
...
3730c07330
Author | SHA1 | Date |
---|---|---|
Jonas 'Sortie' Termansen | 3730c07330 | |
Jonas 'Sortie' Termansen | 3b2685931b | |
Jonas 'Sortie' Termansen | 86acd95309 | |
Jonas 'Sortie' Termansen | 64c65ddba0 | |
Jonas 'Sortie' Termansen | 4552947ac9 | |
Jonas 'Sortie' Termansen | d22b3ddd15 | |
Jonas 'Sortie' Termansen | 0c82f0236a | |
Jonas 'Sortie' Termansen | fa53637420 | |
Jonas 'Sortie' Termansen | 9c27584adf | |
Jonas 'Sortie' Termansen | b93ce9f6d0 | |
Jonas 'Sortie' Termansen | ba51698db2 | |
Jonas 'Sortie' Termansen | be9d4bdf36 | |
Jonas 'Sortie' Termansen | f57ad489b6 | |
Jonas 'Sortie' Termansen | 956ec4355d | |
Jonas 'Sortie' Termansen | 76cf62062b | |
Jonas 'Sortie' Termansen | eab3628b2d | |
Jonas 'Sortie' Termansen | 74569706a5 | |
Jonas 'Sortie' Termansen | 27b7ad2fab | |
Jonas 'Sortie' Termansen | 77ac43ea39 | |
Jonas 'Sortie' Termansen | 80054fe389 | |
Jonas 'Sortie' Termansen | 348e89d5be | |
Jonas 'Sortie' Termansen | 5aa7e56123 | |
Jonas 'Sortie' Termansen | 26284dec59 | |
Jonas 'Sortie' Termansen | 3462079741 | |
Jonas 'Sortie' Termansen | 3a72e024de | |
Jonas 'Sortie' Termansen | c6f2dd602f | |
Jonas 'Sortie' Termansen | eaee5c4838 | |
Jonas 'Sortie' Termansen | 2abdecf59a | |
Jonas 'Sortie' Termansen | e9d9eabb6e | |
Jonas 'Sortie' Termansen | b029127df5 | |
Jonas 'Sortie' Termansen | c77745e447 | |
Juhani Krekelä | adcf11944f | |
Juhani Krekelä | 4657132716 |
|
@ -203,6 +203,9 @@ else
|
|||
fi
|
||||
set base_menu_title="Sortix \$version for \$machine"
|
||||
set menu_title="\$base_menu_title"
|
||||
set title_single_user='live environment'
|
||||
set title_sysinstall='new installation'
|
||||
set title_sysupgrade='upgrade existing installation'
|
||||
set timeout=10
|
||||
set default="0"
|
||||
if [ -e /boot/random.seed ]; then
|
||||
|
@ -223,6 +226,9 @@ export mount
|
|||
export chain
|
||||
export base_menu_title
|
||||
export menu_title
|
||||
export title_single_user
|
||||
export title_sysinstall
|
||||
export title_sysupgrade
|
||||
export timeout
|
||||
export default
|
||||
export no_random_seed
|
||||
|
@ -436,9 +442,9 @@ menu_title="\$base_menu_title"
|
|||
hook_menu_pre
|
||||
EOF
|
||||
|
||||
menuentry "live environment" '-- /sbin/init --target=single-user'
|
||||
menuentry "new installation" '-- /sbin/init --target=sysinstall'
|
||||
menuentry "upgrade existing installation" '-- /sbin/init --target=sysupgrade'
|
||||
menuentry "\$title_single_user" '-- /sbin/init --target=single-user'
|
||||
menuentry "\$title_sysinstall" '-- /sbin/init --target=sysinstall'
|
||||
menuentry "\$title_sysupgrade" '-- /sbin/init --target=sysupgrade'
|
||||
|
||||
cat << EOF
|
||||
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
.Nd disk editor
|
||||
.Sh SYNOPSIS
|
||||
.Nm disked
|
||||
.Op Fl in
|
||||
.Op Fl \-fstab Ns "=" Ns Ar path
|
||||
.Op Ar device
|
||||
.Op Ar command ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is an interactive program that manages partition tables.
|
||||
|
@ -19,17 +22,22 @@ supports the Master Boot Record and GUID Partition Table partitioning schemes.
|
|||
.Pp
|
||||
.Nm
|
||||
provides an interactive command line.
|
||||
Its prompt shows the currently selected device (defaulting to the first device
|
||||
alphabetically) or
|
||||
Its prompt shows the currently selected
|
||||
.Ar device
|
||||
(defaulting to the first device alphabetically if any) or
|
||||
.Li (disked)
|
||||
if none is selected.
|
||||
If a
|
||||
.Ar command
|
||||
is specified on the command line, then that command is run with its arguments
|
||||
non-interactively instead of reading from the standard input.
|
||||
.Pp
|
||||
Commands perform their actions when run rather than waiting for the user to
|
||||
write out changes.
|
||||
.Nm
|
||||
only creates partitions aligned to 1 MiB boundaries whose size is a multiple of
|
||||
1 MiB.
|
||||
Unused regions are aligned and those smaller than the alignment are not shown.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Fl \-fstab Ns "=" Ns Ar path
|
||||
|
@ -39,6 +47,17 @@ instead of
|
|||
.Pa /etc/fstab
|
||||
as
|
||||
.Xr fstab 5 .
|
||||
.It Fl i
|
||||
Run in interactive mode with prompt with line editing.
|
||||
Commands will ask for missing parameters.
|
||||
This is the default if the standard input and output are terminals and a
|
||||
.Ar command
|
||||
is not specified on the command line.
|
||||
.It Fl n
|
||||
Run in non-interactive mode reading commands from the standard input.
|
||||
Commands will not ask for missing parameters and
|
||||
.Nm
|
||||
will immediately exit unsuccessfully if any command fail.
|
||||
.El
|
||||
.Pp
|
||||
The following commands are supported:
|
||||
|
@ -78,14 +97,19 @@ Partitions are counted from 1.
|
|||
Display this manual page if no operands are given, otherwise run
|
||||
.Xr man 1
|
||||
with the given command line.
|
||||
.It Sy mkpart
|
||||
.It Sy mkpart Ar hole Ar offset Ar length Ar filesystem Ar mountpoint
|
||||
Create a partition on the current device.
|
||||
If the partition table has multiple unused regions
|
||||
.Pq holes ,
|
||||
.Nm
|
||||
asks you which one to use.
|
||||
You need to specify the offset into the hole where the partition is created and
|
||||
then the length of the partition.
|
||||
asks you which
|
||||
.Ar hole
|
||||
(counting from 1) to use.
|
||||
You need to specify the
|
||||
.Ar offset
|
||||
into the hole where the partition is created and
|
||||
then the
|
||||
.Ar length of the partition.
|
||||
See
|
||||
.Sx QUANTITIES
|
||||
below on the possible partition offset and length values.
|
||||
|
@ -106,7 +130,9 @@ Use the existing disk data.
|
|||
.El
|
||||
.Pp
|
||||
If you format a mountable filesystem, then you will be asked if you want to
|
||||
create a mountpoint for the partition, which will be added to
|
||||
create a
|
||||
.Ar mountpoint
|
||||
for the partition, which will be added to
|
||||
.Xr fstab 5 .
|
||||
.It Sy mktable Oo mbr "|" gpt Oc
|
||||
Create a partition table on the current device of the specified type.
|
||||
|
|
145
disked/disked.c
145
disked/disked.c
|
@ -240,6 +240,8 @@ static const char* device_name(const char* name)
|
|||
return name;
|
||||
}
|
||||
|
||||
static bool interactive;
|
||||
|
||||
static void display_rows_columns(char* (*format)(void*, size_t, size_t),
|
||||
void* ctx, size_t rows, size_t columns)
|
||||
{
|
||||
|
@ -395,6 +397,8 @@ static void prompt(char* buffer,
|
|||
const char* question,
|
||||
const char* answer)
|
||||
{
|
||||
if ( !interactive )
|
||||
errx(1, "Cannot ask question in non-interactive mode: %s", question);
|
||||
while ( true )
|
||||
{
|
||||
printf("\e[1m");
|
||||
|
@ -599,7 +603,6 @@ bool rewrite_finish(struct rewrite* rewr)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool interactive;
|
||||
static bool quitting;
|
||||
static struct harddisk** hds;
|
||||
static size_t hds_count;
|
||||
|
@ -1132,6 +1135,25 @@ static void switch_device(struct harddisk* hd)
|
|||
scan_device();
|
||||
}
|
||||
|
||||
static bool lookup_harddisk_by_string(struct harddisk** out,
|
||||
const char* argv0,
|
||||
const char* name)
|
||||
{
|
||||
for ( size_t i = 0; i < hds_count; i++ )
|
||||
{
|
||||
char buf[sizeof(i) * 3];
|
||||
snprintf(buf, sizeof(buf), "%zu", i);
|
||||
if ( strcmp(name, hds[i]->path) != 0 &&
|
||||
strcmp(name, device_name(hds[i]->path)) != 0 &&
|
||||
strcmp(name, buf) != 0 )
|
||||
continue;
|
||||
*out = hds[i];
|
||||
return true;
|
||||
}
|
||||
command_errorx("%s: No such device `%s'", argv0, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool lookup_partition_by_string(struct partition** out,
|
||||
const char* argv0,
|
||||
const char* numstr)
|
||||
|
@ -1573,8 +1595,6 @@ static char* display_hole_format(void* ctx, size_t row, size_t column)
|
|||
|
||||
static void on_mkpart(size_t argc, char** argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
size_t num_holes = 0;
|
||||
struct device_area* hole = NULL;
|
||||
for ( size_t i = 0; i < current_areas_count; i++ )
|
||||
|
@ -1598,8 +1618,11 @@ static void on_mkpart(size_t argc, char** argv)
|
|||
char answer[sizeof(size_t) * 3];
|
||||
while ( true )
|
||||
{
|
||||
prompt(answer, sizeof(answer),
|
||||
"Which hole to create the partition inside?", "1");
|
||||
if ( 2 <= argc )
|
||||
strlcpy(answer, argv[1], sizeof(answer));
|
||||
else
|
||||
prompt(answer, sizeof(answer),
|
||||
"Which hole to create the partition inside?", "1");
|
||||
char* end;
|
||||
unsigned long num = strtoul(answer, &end, 10);
|
||||
if ( *end || num_holes < num )
|
||||
|
@ -1618,7 +1641,8 @@ static void on_mkpart(size_t argc, char** argv)
|
|||
}
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
if ( argc < 2 )
|
||||
printf("\n");
|
||||
}
|
||||
unsigned int slot = 0;
|
||||
if ( current_pt_type == PARTITION_TABLE_TYPE_MBR && hole->inside_extended )
|
||||
|
@ -1678,54 +1702,68 @@ static void on_mkpart(size_t argc, char** argv)
|
|||
assert(start_str); // TODO: Error handling.
|
||||
char* length_str = format_bytes_amount((uintmax_t) hole->length);
|
||||
assert(length_str); // TODO: Error handling.
|
||||
printf("Creating partition inside hole at %s of length %s (100%%)\n",
|
||||
start_str, length_str);
|
||||
if ( argc < 3 )
|
||||
printf("Creating partition inside hole at %s of length %s (100%%)\n",
|
||||
start_str, length_str);
|
||||
free(start_str);
|
||||
free(length_str);
|
||||
off_t start;
|
||||
while ( true )
|
||||
{
|
||||
char answer[256];
|
||||
prompt(answer, sizeof(answer),
|
||||
"Free space before partition? (42%/15G/...)", "0%");
|
||||
if ( 3 <= argc )
|
||||
strlcpy(answer, argv[2], sizeof(answer));
|
||||
else
|
||||
prompt(answer, sizeof(answer),
|
||||
"Free space before partition? (42%/15G/...)", "0%");
|
||||
if ( !parse_disk_quantity(&start, answer, hole->length) )
|
||||
{
|
||||
fprintf(stderr, "Invalid quantity `%s'.\n", answer);
|
||||
command_errorx("%s: %s: Invalid quantity: %s",
|
||||
argv[0], device_name(current_hd->path), answer);
|
||||
continue;
|
||||
}
|
||||
if ( start == hole->length )
|
||||
{
|
||||
fprintf(stderr, "Answer was all free space, but need space for the "
|
||||
"partition itself.\n");
|
||||
command_errorx("%s: %s: Answer was all free space, but need space "
|
||||
"for the partition itself",
|
||||
argv[0], device_name(current_hd->path));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
if ( argc < 3 )
|
||||
printf("\n");
|
||||
off_t max_length = hole->length - start;
|
||||
off_t length;
|
||||
length_str = format_bytes_amount((uintmax_t) max_length);
|
||||
assert(length_str);
|
||||
printf("Partition size can be at most %s (100%%).\n", length_str);
|
||||
if ( argc < 4 )
|
||||
printf("Partition size can be at most %s (100%%).\n", length_str);
|
||||
free(length_str);
|
||||
while ( true )
|
||||
{
|
||||
char answer[256];
|
||||
prompt(answer, sizeof(answer),
|
||||
"Partition size? (42%/15G/...)", "100%");
|
||||
if ( 4 <= argc )
|
||||
strlcpy(answer, argv[3], sizeof(answer));
|
||||
else
|
||||
prompt(answer, sizeof(answer),
|
||||
"Partition size? (42%/15G/...)", "100%");
|
||||
if ( !parse_disk_quantity(&length, answer, max_length) )
|
||||
{
|
||||
fprintf(stderr, "Invalid quantity `%s'.\n", answer);
|
||||
command_errorx("%s: %s: Invalid quantity: %s",
|
||||
argv[0], device_name(current_hd->path), answer);
|
||||
continue;
|
||||
}
|
||||
if ( length == 0 )
|
||||
{
|
||||
fprintf(stderr, "Answer was zero (or rounded down to zero).\n");
|
||||
command_errorx("%s: %s: Length was zero (or rounded down to zero)",
|
||||
argv[0], device_name(current_hd->path));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
if ( argc < 4 )
|
||||
printf("\n");
|
||||
char fstype[256];
|
||||
while ( true )
|
||||
{
|
||||
|
@ -1736,13 +1774,17 @@ static void on_mkpart(size_t argc, char** argv)
|
|||
question = "Format a filesystem? (no/ext2/extended)";
|
||||
else if ( is_gpt )
|
||||
question = "Format a filesystem? (no/ext2/biosboot)";
|
||||
prompt(fstype, sizeof(fstype), question, "ext2");
|
||||
if ( 5 <= argc )
|
||||
strlcpy(fstype, argv[4], sizeof(fstype));
|
||||
else
|
||||
prompt(fstype, sizeof(fstype), question, "ext2");
|
||||
if ( strcmp(fstype, "no") != 0 &&
|
||||
strcmp(fstype, "ext2") != 0 &&
|
||||
(!is_mbr || strcmp(fstype, "extended") != 0) &&
|
||||
(!is_gpt || strcmp(fstype, "biosboot") != 0) )
|
||||
{
|
||||
fprintf(stderr, "Invalid filesystem choice `%s'.\n", fstype);
|
||||
command_errorx("%s: %s: Invalid filesystem choice: %s",
|
||||
argv[0], device_name(current_hd->path), fstype);
|
||||
continue;
|
||||
}
|
||||
if ( !strcmp(fstype, "extended") )
|
||||
|
@ -1762,27 +1804,27 @@ static void on_mkpart(size_t argc, char** argv)
|
|||
bool mountable = !strcmp(fstype, "ext2");
|
||||
while ( mountable )
|
||||
{
|
||||
prompt(mountpoint, sizeof(mountpoint),
|
||||
"Where to mount partition? (mountpoint or 'no')", "no");
|
||||
if ( 6 <= argc )
|
||||
strlcpy(mountpoint, argv[5], sizeof(mountpoint));
|
||||
else
|
||||
prompt(mountpoint, sizeof(mountpoint),
|
||||
"Where to mount partition? (mountpoint or 'no')", "no");
|
||||
if ( !strcmp(mountpoint, "no") )
|
||||
{
|
||||
mountpoint[0] = '\0';
|
||||
break;
|
||||
}
|
||||
if ( !strcmp(mountpoint, "mountpoint") )
|
||||
{
|
||||
printf("Then answer which mountpoint.\n");
|
||||
continue;
|
||||
}
|
||||
if ( !verify_mountpoint(mountpoint) )
|
||||
{
|
||||
fprintf(stderr, "Invalid mountpoint `%s'.\n", fstype);
|
||||
command_errorx("%s: %s: Invalid mountpoint: %s",
|
||||
argv[0], device_name(current_hd->path), mountpoint);
|
||||
continue;
|
||||
}
|
||||
simplify_mountpoint(mountpoint);
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
if ( mountable && argc < 6 )
|
||||
printf("\n");
|
||||
size_t renumbered_partitions = 0;
|
||||
if ( current_pt_type == PARTITION_TABLE_TYPE_MBR && hole->inside_extended )
|
||||
{
|
||||
|
@ -2696,14 +2738,8 @@ static const struct command commands[] =
|
|||
};
|
||||
static const size_t commands_count = sizeof(commands) / sizeof(commands[0]);
|
||||
|
||||
void execute(char* cmd)
|
||||
static void execute_argv(int argc, char** argv)
|
||||
{
|
||||
size_t argc = 0;
|
||||
char* argv[256];
|
||||
split_arguments(cmd, &argc, argv, 255);
|
||||
if ( argc < 1 )
|
||||
return;
|
||||
argv[argc] = NULL;
|
||||
for ( size_t i = 0; i < commands_count; i++ )
|
||||
{
|
||||
if ( strcmp(argv[0], commands[i].name) != 0 )
|
||||
|
@ -2738,6 +2774,17 @@ void execute(char* cmd)
|
|||
"Try `help' for more information.\n", argv[0]);
|
||||
}
|
||||
|
||||
static void execute(char* cmd)
|
||||
{
|
||||
size_t argc = 0;
|
||||
char* argv[256];
|
||||
split_arguments(cmd, &argc, argv, 255);
|
||||
if ( argc < 1 )
|
||||
return;
|
||||
argv[argc] = NULL;
|
||||
execute_argv(argc, argv);
|
||||
}
|
||||
|
||||
static void compact_arguments(int* argc, char*** argv)
|
||||
{
|
||||
for ( int i = 0; i < *argc; i++ )
|
||||
|
@ -2766,6 +2813,8 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
bool set_interactive = false;
|
||||
|
||||
const char* argv0 = argv[0];
|
||||
for ( int i = 1; i < argc; i++ )
|
||||
{
|
||||
|
@ -2780,6 +2829,8 @@ int main(int argc, char* argv[])
|
|||
char c;
|
||||
while ( (c = *++arg) ) switch ( c )
|
||||
{
|
||||
case 'i': interactive = true; set_interactive = true; break;
|
||||
case 'n': interactive = false; set_interactive = true; break;
|
||||
default:
|
||||
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
||||
help(stderr, argv0);
|
||||
|
@ -2813,20 +2864,30 @@ int main(int argc, char* argv[])
|
|||
|
||||
compact_arguments(&argc, &argv);
|
||||
|
||||
interactive = isatty(0) && isatty(1);
|
||||
if ( !set_interactive )
|
||||
interactive = isatty(0) && isatty(1) && argc < 3;
|
||||
|
||||
if ( !devices_open_all(&hds, &hds_count) )
|
||||
err(1, "iterating devices");
|
||||
|
||||
qsort(hds, hds_count, sizeof(struct harddisk*), harddisk_compare_path);
|
||||
|
||||
if ( 1 <= hds_count )
|
||||
if ( 2 <= argc )
|
||||
{
|
||||
struct harddisk* hd;
|
||||
if ( !lookup_harddisk_by_string(&hd, argv[0], argv[1]) )
|
||||
exit(1);
|
||||
switch_device(hd);
|
||||
}
|
||||
else if ( 1 <= hds_count )
|
||||
switch_device(hds[0]);
|
||||
|
||||
char* line = NULL;
|
||||
size_t line_size = 0;
|
||||
ssize_t line_length;
|
||||
while ( !quitting )
|
||||
if ( 3 <= argc )
|
||||
execute_argv(argc - 2, argv + 2);
|
||||
else while ( !quitting )
|
||||
{
|
||||
if ( interactive )
|
||||
{
|
||||
|
@ -2855,4 +2916,6 @@ int main(int argc, char* argv[])
|
|||
for ( size_t i = 0; i < hds_count; i++ )
|
||||
harddisk_close(hds[i]);
|
||||
free(hds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -217,7 +217,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/openssl/s_socket.c libssl/ap
|
|||
diff -Paur --no-dereference -- libssl.upstream/configure libssl/configure
|
||||
--- libssl.upstream/configure
|
||||
+++ libssl/configure
|
||||
@@ -11775,6 +11775,10 @@
|
||||
@@ -11779,6 +11779,10 @@
|
||||
HOST_OS=midipix
|
||||
CPPFLAGS="$CPPFLAGS -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_SOURCE -D_GNU_SOURCE"
|
||||
;;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
NAME=libssl
|
||||
BUILD_LIBRARIES=
|
||||
VERSION=3.7.1
|
||||
VERSION=3.7.2
|
||||
DISTNAME=libressl-$VERSION
|
||||
COMPRESSION=tar.gz
|
||||
ARCHIVE=$DISTNAME.$COMPRESSION
|
||||
SHA256SUM=98086961a2b8b657ed0fea3056fb2db14294b6bfa193c15a5236a0a35c843ded
|
||||
SHA256SUM=b06aa538fefc9c6b33c4db4931a09a5f52d9d2357219afcbff7d93fe12ebf6f7
|
||||
UPSTREAM_SITE=https://ftp.openbsd.org/pub/OpenBSD/LibreSSL
|
||||
UPSTREAM_ARCHIVE=$ARCHIVE
|
||||
LICENSE=OpenSSL
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
rm -rf -- 'include/openssl/opensslconf.h'
|
|
@ -1,4 +1,4 @@
|
|||
.Dd April 9, 2023
|
||||
.Dd April 23, 2023
|
||||
.Dt AUTOINSTALL.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -45,19 +45,31 @@ ask the question normally.
|
|||
Installations can be made fully non-interactive using
|
||||
.Sy accept_defaults .
|
||||
.Pp
|
||||
Each question has a counterpart question suffixed with
|
||||
.Sq "!"
|
||||
which contains a
|
||||
.Xr sh 1
|
||||
script that is executed before the question is asked.
|
||||
If the original question isn't answered, then the script's standard output
|
||||
is used as the answer to the original question.
|
||||
The installation aborts if the script exits unsuccessfully.
|
||||
These scripts are useful to customize the installation with arbitrary code.
|
||||
.Pp
|
||||
The questions in chronological order are as follows:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Sy accept_defaults Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||
Accept the default answer (if any) to questions that were not
|
||||
configured in
|
||||
.Nm .
|
||||
.Nm ?
|
||||
This feature makes installations entirely automated even if unexpected questions
|
||||
are asked, although the essential questions must be answered.
|
||||
.It Sy countdown Ns "=" Ns Ar seconds No ( default Li 10 )
|
||||
Count down for this many
|
||||
.Ar seconds
|
||||
with a warning that an automated installation is about to happen.
|
||||
The countdown happens if the
|
||||
with a warning that an automated installation is about to happen?
|
||||
The countdown happens if
|
||||
.Sy accept_defaults=yes
|
||||
or if the
|
||||
.Sy ready
|
||||
question is answered and either the
|
||||
.Sy disked
|
||||
|
@ -65,28 +77,234 @@ or
|
|||
.Sy confirm_install
|
||||
questions are answered.
|
||||
.It Sy ignore_missing_programs Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||
Ignore if the installer environment does not have the needed ports installed.
|
||||
Ignore if the installer environment does not have the needed ports installed?
|
||||
This situation ordinarily does not happen.
|
||||
ready
|
||||
.It Sy ready Ns "=" Ns Ar affirmation
|
||||
A human readable positive affirmation of your choice that you're ready to
|
||||
install, useful for fully automated installations.
|
||||
Are you ready to begin the installation process?
|
||||
This is a human readable positive affirmation of your choice that you're ready
|
||||
to install, useful for fully automated installations.
|
||||
Not answering this question is useful for semi-automated installations where one
|
||||
would acknowledge the installation before it's begun.
|
||||
It also provides the opportunity to escape to a shell before installing.
|
||||
.Pp
|
||||
The
|
||||
.Sy "ready!"
|
||||
question is convenient for running shell commands before the installation
|
||||
begins.
|
||||
.It Sy kblayout Ns "=" Ns Oo Sy default "|" Ar layout Oc ( default Sy default )
|
||||
Switch to this keyboard
|
||||
.Ar layout
|
||||
using
|
||||
.Xr chkblayout 1 .
|
||||
The choice is set as the system default in
|
||||
.Xr kblayout 5 .
|
||||
.Xr chkblayout 1 ?
|
||||
The choice is remembered as the
|
||||
.Xr kblayout 5
|
||||
system default.
|
||||
.It Sy videomode Ns "=" Ns Oo Sy no "|" Sy yes "|" Ar WIDTH Ns x Ns Ar HEIGHT Ns x Ns Ar BPP Oc ( default Sy yes )
|
||||
Interactively select a graphics resolution using
|
||||
.Xr chvideomode 1
|
||||
or non-interactively set it to the specified resolution.
|
||||
The choice is set as the system default in
|
||||
.Xr videomode 5 .
|
||||
or non-interactively set it to the specified resolution?
|
||||
The choice is remembered as the
|
||||
.Xr videomode 5
|
||||
system default.
|
||||
.Pp
|
||||
If the installation is non-interactive with
|
||||
.Sy accept_defaults=true ,
|
||||
then the default is instead
|
||||
.Sy no .
|
||||
.It Sy grub Ns "=" Ns Oo Sy no "|" Sy yes Oc
|
||||
Install the GRUB bootloader onto the device containing the
|
||||
.Pa /boot
|
||||
filesystem (if it exists, otherwise the root filesystem)?
|
||||
The default is
|
||||
.Sy yes
|
||||
if any existing installations are found with GRUB enabled or if no filesystems
|
||||
were found, otherwise the default is
|
||||
.Sy no .
|
||||
.Pp
|
||||
This is an essential question that must be answered for automatic installations.
|
||||
.It Sy grub_password Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||
Protect the bootloader with a password to avoid unauthorized root access via the
|
||||
advanced bootloader features?
|
||||
The standard bootloader menu options don't require a password.
|
||||
The password is set in the
|
||||
.Sy grub_password_hash
|
||||
question.
|
||||
.Pp
|
||||
If the installation is non-interactive with
|
||||
.Sy accept_defaults=true ,
|
||||
then the default is instead
|
||||
.Sy no
|
||||
if the
|
||||
.Sy grub_password_hash
|
||||
question is not answered.
|
||||
.It Sy grub_password_hash Ns "=" Ns Ar hash
|
||||
The bootloader password as hashed by the
|
||||
.Xr grub-mkpasswd-pbkdf2 1
|
||||
program?
|
||||
The password is asked interactively if this question is not answered.
|
||||
The choice is remembered in
|
||||
.Xr grubpw 5 .
|
||||
.Pp
|
||||
Although it's discouraged to place unhashed passwords in
|
||||
.Nm ,
|
||||
the
|
||||
.Sy "grub_password!"
|
||||
question could be answered with
|
||||
.Li "grub-mkpasswd-pbkdf2 -p password"
|
||||
to dynamically hash the bootloader password.
|
||||
.It Sy grub_password_empty Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||
Allow an insecure empty bootloader password typed interactively?
|
||||
.It Sy disked Ns "=" Ns Ar commands
|
||||
Commands to create partitions and filesystems with
|
||||
.Xr disked 8 ?
|
||||
The
|
||||
.Li ++=
|
||||
syntax is useful to append multiple lines to the
|
||||
.Sy disked
|
||||
answer.
|
||||
A root filesystem must be mounted in order to install the operating system.
|
||||
The mountpoints are remembered in
|
||||
.Xr fstab 5 .
|
||||
.Pp
|
||||
This is an essential question that must be answered for automatic installations.
|
||||
.Pp
|
||||
The
|
||||
.Sy "disked!"
|
||||
question is convenient for running shell commands before the partitioning step,
|
||||
or to generate dynamic partitioning commands on the standard output if the
|
||||
original
|
||||
.Sy disked
|
||||
question is unanswered.
|
||||
.It Sy missing_bios_boot_partition Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||
Attempt
|
||||
.Xr disked 8
|
||||
again if the GRUB bootloader is installed but the
|
||||
.Pa /boot
|
||||
directory's filesystem is inside a GPT partition table that doesn't have a
|
||||
biosboot partition?
|
||||
.It Sy confirm_install Ns "=" Ns Oo Sy no "|" Sy yes "|" Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt Oc ( default Sy yes )
|
||||
Install the operating system or abort the installation?
|
||||
This is the final confirmation before the operating system is installed, after
|
||||
the partitioning has taken place.
|
||||
.Pp
|
||||
The
|
||||
.Sy "confirm_install!"
|
||||
question is convenient for running shell commands before the installation step,
|
||||
after partitioning has happened, but before the filesystems are mounted.
|
||||
.It Sy hostname Ns "=" Ns Ar hostname
|
||||
Hostname for the installation?
|
||||
The choice is remembered in
|
||||
.Xr hostname 5 .
|
||||
.Pp
|
||||
This is an essential question that must be answered for automatic installations.
|
||||
If it isn't answered and
|
||||
.Sy accept_defaults=yes ,
|
||||
then the current (and likely default) hostname is used.
|
||||
.It Sy password_hash_root Ns "=" Ns Ar hash
|
||||
Password for the root user as hashed with
|
||||
.Xr crypt_newhash 2 ?
|
||||
The empty string sets the password to the empty string (insecure) and a literal
|
||||
.Sy x
|
||||
disables password login for root.
|
||||
The choice is remembered in
|
||||
.Xr passwd 5 .
|
||||
.Pp
|
||||
This is an essential question that must be answered for automatic installations.
|
||||
If it isn't answered and
|
||||
.Sy accept_defaults=yes ,
|
||||
then password login is disabled for root.
|
||||
.Pp
|
||||
Although it's discouraged to place unhashed passwords in
|
||||
.Nm ,
|
||||
the
|
||||
.Sy "password_hash_root!"
|
||||
question could be answered with
|
||||
.Li "echo password | passwd -H"
|
||||
to dynamically hash the root password.
|
||||
.It Sy password_hash_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||
Allow an insecure empty root password typed interactively?
|
||||
.It Sy copy_ssh_authorized_keys_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||
Copy the
|
||||
.Pa /root/.ssh/authorized_keys
|
||||
file (if it exists) into the installation?
|
||||
.It Sy copy_ssh_config_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||
Copy the
|
||||
.Pa /root/.ssh/config
|
||||
file (if it exists) into the installation?
|
||||
.It Sy copy_ssh_id_rsa_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||
Copy the
|
||||
.Pa /root/.ssh/id_rsa
|
||||
file (if it exists) into the installation?
|
||||
.It Sy copy_ssh_known_hosts_root Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||
Copy the
|
||||
.Pa /root/.ssh/known_hosts
|
||||
file (if it exists) into the installation?
|
||||
.It Sy empty_password Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||
Allow insecure empty passwords for regular users?
|
||||
.It Sy enable_gui Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||
Enable the
|
||||
.Xr display 1
|
||||
graphical user interface?
|
||||
The choice is remembered in
|
||||
.Xr session 5 .
|
||||
.It Sy enable_ntpd Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||
Automatically get time from the network using
|
||||
.Xr ntpd 8 ?
|
||||
Note this choice has privacy implications as the servers in
|
||||
.Xr ntpd.conf 5
|
||||
file will be contacted in the background.
|
||||
The choice is remembered in
|
||||
.Pa /etc/init/local
|
||||
per
|
||||
.Xr init 5 .
|
||||
.It Sy enable_sshd Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||
Enable the
|
||||
.Xr sshd 8
|
||||
secure shell server?
|
||||
The choice is remembered in
|
||||
.Pa /etc/init/local
|
||||
per
|
||||
.Xr init 5 .
|
||||
.It Sy copy_sshd_config Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||
Copy the
|
||||
.Pa /etc/sshd_config
|
||||
file (if it exists) into the installation?
|
||||
.It Sy enable_sshd_password Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||
Enable password authentication in the local
|
||||
.Xr sshd 8 ?
|
||||
The choice is remembered in
|
||||
.Xr sshd_config 5 .
|
||||
.Pp
|
||||
It's strongly encouraged to answer
|
||||
.Sy no
|
||||
and instead use public key authentication.
|
||||
The installation environment can be seeded with the ssh keys using the
|
||||
.Xr release-iso-modification 7
|
||||
procedure and the default answers will copy the keys into the installation.
|
||||
.It Sy enable_sshd_root_password Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy no )
|
||||
Enable ssh to the root user with password authentication?
|
||||
.It Sy copy_sshd_private_keys Ns "=" Ns Oo Sy no "|" Sy yes Oc ( default Sy yes )
|
||||
Copy the sshd private keys (if they exist) into the installation?
|
||||
These are
|
||||
.Pa /etc/ssh_host_ecdsa_key ,
|
||||
.Pa /etc/ssh_host_ed25519_key ,
|
||||
.Pa /etc/ssh_host_rsa_key .
|
||||
.It Sy finally Ns "=" Ns Oo Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt "|" Sy boot Oc ( default Sy boot )
|
||||
What action should be taken when the installation is finished?
|
||||
.Pp
|
||||
The
|
||||
.Sy "finally!"
|
||||
question is convenient for running shell commands once the installation is
|
||||
complete to customize the installation.
|
||||
The working directory is the root filesystem of the installation with all
|
||||
filesystems mounted.
|
||||
The
|
||||
.Li "chroot -d ."
|
||||
command is useful to
|
||||
.Xr chroot 8
|
||||
into the new root filesystem to run commands with the
|
||||
.Pa /dev
|
||||
filesystem mounted.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width "/etc/autoinstall.conf" -compact
|
||||
|
@ -94,23 +312,133 @@ The choice is set as the system default in
|
|||
Automatic installation configuration.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
.Bd -literal
|
||||
.Ss Fully automated installation
|
||||
To perform a fully automated installation with root login disabled, create
|
||||
.Pa autoinstall.conf :
|
||||
.Bd -literal -offset indentq
|
||||
accept_defaults=yes
|
||||
ready=Automatically
|
||||
kblayout=us
|
||||
videomode=1280x720x32
|
||||
grub=yes
|
||||
grub_password=no
|
||||
disked++=mktable mbr
|
||||
disked++=mkpart
|
||||
disked++=0%
|
||||
disked++=100%
|
||||
disked++=ext2
|
||||
disked++=/
|
||||
confirm_install=yes
|
||||
disked++=mkpart 1 0% 100% ext2 /
|
||||
hostname=dragon
|
||||
password_hash_root=
|
||||
finally=reboot
|
||||
password_hash_root=x
|
||||
.Ed
|
||||
.Pp
|
||||
Then follow
|
||||
.Xr release-iso-modification 7
|
||||
to configure the installation medium:
|
||||
.Bd -literal -offset indent
|
||||
tix-iso-liveconfig --autoinstall=autoinstall.conf liveconfig
|
||||
tix-iso-bootconfig \\
|
||||
--liveconfig=liveconfig --default=1 --random-seed \\
|
||||
bootconfig
|
||||
tix-iso-add sortix.iso bootconfig -o autosortix.iso
|
||||
.Ed
|
||||
.Pp
|
||||
The resulting
|
||||
.Pa autosortix.iso
|
||||
image will then automatically format the harddisk and install the operating
|
||||
system on whatever machine it is booted on.
|
||||
Take care.
|
||||
.Ss Setting passwords
|
||||
The
|
||||
.Xr grub-mkpasswd-pbkdf2 1
|
||||
command can be used to hash a GRUB password and
|
||||
.Xr passwd 1
|
||||
can be used to hash a user password:
|
||||
.Bd -literal -offset indent
|
||||
grub-mkpasswd-pbkdf2 -p bootloader-password
|
||||
echo root-password | passwd -H
|
||||
.Ed
|
||||
.Pp
|
||||
The hashes can then be inserted in
|
||||
.Nm :
|
||||
.Bd -literal -offset indent
|
||||
grub_password_hash=grub.pbkdf2.sha512.10000.68DA[...]
|
||||
password_hash_root=$2b$10$d/9pP1[...]
|
||||
.Ed
|
||||
.Pp
|
||||
Alternatively the passwords could be embedded in
|
||||
.Nm ,
|
||||
however beware that your
|
||||
.Nm
|
||||
file and the installation medium could leak:
|
||||
.Bd -literal -offset indent
|
||||
grub_password_hash!=grub-mkpasswd-pbkdf2 -p bootloader-password
|
||||
password_hash_root!=echo root-password | passwd -H
|
||||
.Ed
|
||||
.Ss Automatically install with sshd
|
||||
To automatically install the operating system with sshd enabled with keys and
|
||||
authorizations set up ahead of time, first create
|
||||
.Pa autoinstall.conf :
|
||||
.Bd -literal -offset indent
|
||||
accept_defaults=yes
|
||||
grub=yes
|
||||
disked++=mktable mbr
|
||||
disked++=mkpart 1 0% 100% ext2 /
|
||||
hostname=example.com
|
||||
password_hash_root=x
|
||||
enable_sshd=yes
|
||||
.Ed
|
||||
.Pp
|
||||
Then follow
|
||||
.Xr release-iso-modification 7
|
||||
to configure the installation medium with automated installation and sshd:
|
||||
.Bd -literal -offset indent
|
||||
tix-iso-liveconfig \\
|
||||
--autoinstall=autoinstall.conf \\
|
||||
--root-ssh-authorized-keys="$HOME/.ssh/id_rsa.pub" \\
|
||||
--sshd-keygen \\
|
||||
--sshd-key-known-hosts-file="$HOME/.ssh/known_hosts" \\
|
||||
--sshd-key-known-hosts-hosts="example.com example.com,192.0.2.1 192.0.2.1" \\
|
||||
liveconfig
|
||||
tix-iso-bootconfig \\
|
||||
--liveconfig=liveconfig --default=1 --random-seed \\
|
||||
bootconfig
|
||||
tix-iso-add sortix.iso bootconfig -o autosortix.iso
|
||||
.Ed
|
||||
.Pp
|
||||
To ssh into the installation after it has finished:
|
||||
.Bd -literal -offset indent
|
||||
ssh root@example.com
|
||||
.Ed
|
||||
.Pp
|
||||
The connection will be immediately trusted because the just-generated server
|
||||
keys were associated with the hostname in the
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
file.
|
||||
This step assumes the hostname (example.com in this example) resolves to the
|
||||
installation's IP address, otherwise the IP address can be used directly.
|
||||
If the IP address is known ahead of time, it should be inserted into the
|
||||
space delimited
|
||||
.Fl \-sshd-key-known-hosts-hosts
|
||||
list of host aliases.
|
||||
.Ss Automatically install into a virtual machine with sshd
|
||||
To automatically install into a qemu virtual machine, follow the above example
|
||||
but instead associate the server keys with your localhost and optionally use a
|
||||
.Pa known_hosts
|
||||
file per virtual machine.
|
||||
.Bd -literal -offset indent
|
||||
...
|
||||
--sshd-key-known-hosts-file="sortix.hdd.known_hosts" \\
|
||||
--sshd-key-known-hosts-hosts=127.0.0.1 \\
|
||||
...
|
||||
.Ed
|
||||
.Pp
|
||||
Create the harddisk and spawn the virtual machine and forward the local port
|
||||
2222 to the virtual machine's port 22.
|
||||
.Bd -literal -offset indent
|
||||
qemu-img create -f qcow2 sortix.hdd 1G
|
||||
qemu-system-x86_64 \\
|
||||
-vga std -m 1024 \\
|
||||
-hda sortix.hdd -cdrom autosortix.iso \\
|
||||
-device e1000,netdev=net0 \\
|
||||
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:2222-:22
|
||||
.Ed
|
||||
.Pp
|
||||
To ssh into the installation after it has finished:
|
||||
.Bd -literal -offset indent
|
||||
ssh -oUserKnownHostsFile=sortix.hdd.known_hosts -p 2222 root@127.0.0.1
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr autoupgrade.conf 5 ,
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
.Dd April 23, 2023
|
||||
.Dt AUTOUPGRADE.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm autoupgrade.conf
|
||||
.Nd automatic upgrade configuration
|
||||
.Sh SYNOPSIS
|
||||
.Nm /etc/autoupgrade.conf
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
configures
|
||||
.Xr sysupgrade 8
|
||||
to do an automatic operating system
|
||||
.Xr upgrade 7 .
|
||||
.Pp
|
||||
The system administrator can automate operating system upgrades by
|
||||
following
|
||||
.Xr release-iso-modification 7
|
||||
to embed the
|
||||
.Pa /etc/autoupgrade.conf
|
||||
file into the release cdrom filesystem.
|
||||
New installations can similarly be automatically installed using
|
||||
.Xr autoinstall.conf 5 .
|
||||
.Pp
|
||||
Each line is formatted as
|
||||
.Ar question Ns = Ns Ar answer
|
||||
which provides an
|
||||
.Ar answer
|
||||
to a
|
||||
.Ar question
|
||||
asked during upgrading.
|
||||
Alternatively
|
||||
.Ar question Ns += Ns Ar answer
|
||||
appends to an existing answer (if any) separated by a space, and
|
||||
.Ar question Ns ++= Ns Ar answer
|
||||
appends another line to an existing answer (if any).
|
||||
Empty lines and lines starting with
|
||||
.Sq #
|
||||
are comments and are ignored.
|
||||
Otherwise whitespace is significant.
|
||||
The empty answer accepts the default answer (if any) and is different from no
|
||||
answer, which makes
|
||||
.Xr sysupgrade 8
|
||||
ask the question normally.
|
||||
Upgrades can be made fully non-interactive using
|
||||
.Sy accept_defaults .
|
||||
.Pp
|
||||
Each question has a counterpart question suffixed with
|
||||
.Sq "!"
|
||||
which contains a
|
||||
.Xr sh 1
|
||||
script that is executed before the question is asked.
|
||||
If the original question isn't answered, then the script's standard output
|
||||
is used as the answer to the original question.
|
||||
The upgrade aborts if the script exits unsuccessfully.
|
||||
These scripts are useful to customize the upgrades with arbitrary code.
|
||||
.Pp
|
||||
The questions in chronological order are as follows:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Sy accept_defaults Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||
Accept the default answer (if any) to questions that were not
|
||||
configured in
|
||||
.Nm ?
|
||||
This feature makes upgrades entirely automated even if unexpected questions
|
||||
are asked, although the essential questions must be answered.
|
||||
.It Sy countdown Ns "=" Ns Ar seconds No ( default Li 10 )
|
||||
Count down for this many
|
||||
.Ar seconds
|
||||
with a warning that an automated upgrade is about to happen?
|
||||
The countdown happens if
|
||||
.Sy accept_defaults=yes
|
||||
or if the
|
||||
.Sy ready
|
||||
and
|
||||
.Sy confirm_upgrrade
|
||||
questions are answered.
|
||||
.It Sy ignore_missing_programs Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||
Ignore if the upgrader environment does not have the needed ports installed?
|
||||
This situation ordinarily does not happen.
|
||||
.It Sy ready Ns "=" Ns Ar affirmation
|
||||
Are you ready to begin the upgrade process?
|
||||
This is a human readable positive affirmation of your choice that you're ready
|
||||
to upgrade, useful for fully automated upgrades.
|
||||
Not answering this question is useful for semi-automated upgrades where one
|
||||
would acknowledge the upgrades before it's begun.
|
||||
It also provides the opportunity to escape to a shell before upgrading.
|
||||
.Pp
|
||||
The
|
||||
.Sy "ready!"
|
||||
question is convenient for running shell commands before the upgrade begins.
|
||||
.It Sy kblayout Ns "=" Ns Oo Sy default "|" Ar layout Oc ( default Sy default )
|
||||
Switch to this keyboard
|
||||
.Ar layout
|
||||
using
|
||||
.Xr chkblayout 1 ?
|
||||
.It Sy videomode Ns "=" Ns Oo Sy no "|" Sy yes "|" Ar WIDTH Ns x Ns Ar HEIGHT Ns x Ns Ar BPP Oc ( default Sy yes )
|
||||
Interactively select a graphics resolution using
|
||||
.Xr chvideomode 1
|
||||
or non-interactively set it to the specified resolution?
|
||||
.Pp
|
||||
If the upgrade is non-interactive with
|
||||
.Sy accept_defaults=true ,
|
||||
then the default is instead
|
||||
.Sy no .
|
||||
.It Sy run_installer_instead Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy yes )
|
||||
Run the
|
||||
.Xr sysinstall 8
|
||||
installer instead if no installations were found?
|
||||
.Pp
|
||||
This answer is useful combined with
|
||||
.Xr autoinstall.conf 5
|
||||
to either install or upgrade the operating system, regardless of what is already
|
||||
installed on the machine.
|
||||
.It Sy which_installaton Ns "=" Ns Ar block-device
|
||||
The name of the
|
||||
.Ar block-device
|
||||
containing the root filesystem to upgrade?
|
||||
This question is only asked if multiple installations were found.
|
||||
.It Sy switch_architecture Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||
Switch the installation to another architecture?
|
||||
.Pp
|
||||
Such upgrades are not supported and may corrupt the installation.
|
||||
.It Sy downgrade_release Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||
Downgrade the installation to an earlier release?
|
||||
.Pp
|
||||
Such upgrades are not supported and may corrupt the installation.
|
||||
.It Sy skip_release Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||
Skip upgrading to a release that ordinarily must be upgraded to first?
|
||||
.Pp
|
||||
Such upgrades are not supported and may corrupt the installation.
|
||||
.It Sy downgrade_abi Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy no )
|
||||
Downgrade the installation to an earlier ABI?
|
||||
.Pp
|
||||
Such upgrades are not supported and may corrupt the installation.
|
||||
.It Sy cancel_pending_sysmerge Ns "=" Ns Oo Sy no "|" yes Oc ( default Sy yes )
|
||||
Cancel an existing pending
|
||||
.Xr sysmerge 8
|
||||
upgrade?
|
||||
.It Sy confirm_upgrade Ns "=" Ns Oo Sy no "|" Sy yes "|" Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt Oc ( default Sy yes )
|
||||
Upgrade the operating system or abort the upgrade?
|
||||
This is the final confirmation before the operating system is upgraded.
|
||||
.Pp
|
||||
The
|
||||
.Sy "confirm_upgrade!"
|
||||
question is convenient for running shell commands before the upgrade step.
|
||||
The working directory is the root filesystem of the installation with all
|
||||
filesystems mounted.
|
||||
Note how
|
||||
.Xr chroot 8
|
||||
command may not work as intended at this point since the ABI may have
|
||||
incompatibly changed.
|
||||
.It Sy finally Ns "=" Ns Oo Sy exit "|" Sy poweroff "|" Sy reboot "|" Sy halt "|" Sy boot Oc ( default Sy boot )
|
||||
What action should be taken when the upgrade is finished?
|
||||
.Pp
|
||||
The
|
||||
.Sy "finally!"
|
||||
question is convenient for running shell commands once the upgrade is
|
||||
complete to customize the upgraded installation.
|
||||
The working directory is the root filesystem of the installation with all
|
||||
filesystems mounted.
|
||||
The
|
||||
.Li "chroot -d ."
|
||||
command is useful to
|
||||
.Xr chroot 8
|
||||
into the root filesystem to run commands with the
|
||||
.Pa /dev
|
||||
filesystem mounted.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width "/etc/autoupgrade.conf" -compact
|
||||
.It Pa /etc/autoupgrade.conf
|
||||
Automatic upgrade configuration.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
.Ss Fully automated upgrade
|
||||
To perform a fully automated upgrade with, create
|
||||
.Pa autoupgrade.conf :
|
||||
.Bd -literal -offset indent
|
||||
accept_defaults=yes
|
||||
.Ed
|
||||
.Pp
|
||||
Then follow
|
||||
.Xr release-iso-modification 7
|
||||
to configure the upgrade medium:
|
||||
.Bd -literal -offset indent
|
||||
tix-iso-liveconfig --autoupgrade=autoupgrade.conf liveconfig
|
||||
tix-iso-bootconfig \\
|
||||
--liveconfig=liveconfig --default=1 --random-seed \\
|
||||
bootconfig
|
||||
tix-iso-add sortix.iso bootconfig -o autosortix.iso
|
||||
.Ed
|
||||
.Pp
|
||||
The resulting
|
||||
.Pa autosortix.iso
|
||||
image will then automatically upgrade the operating system on whatever machine
|
||||
it is booted on.
|
||||
.Sh SEE ALSO
|
||||
.Xr autoinstall.conf 5 ,
|
||||
.Xr upgrade.conf 5 ,
|
||||
.Xr release-iso-modification 7 ,
|
||||
.Xr upgrade 7 ,
|
||||
.Xr sysupgrade 8 ,
|
||||
.Xr tix 8
|
|
@ -319,6 +319,15 @@ variable) is automatically selected.
|
|||
If set to 0, the default menu entry is loaded instantaneously.
|
||||
The timeout is disabled if set to -1.
|
||||
(Default: 10)
|
||||
.It Sy title_single_user
|
||||
The menu title for the single-user selection.
|
||||
(Default: live environment)
|
||||
.It Sy title_sysinstall
|
||||
The menu title for the sysinstall selection.
|
||||
(Default: new installation)
|
||||
.It Sy title_sysupgrade
|
||||
The menu title for the sysupgrade selection.
|
||||
(Default: upgrade existing installation)
|
||||
.It Sy tix_ Ns Ar $port
|
||||
A copy of the binary package is stored in
|
||||
.Pa /repository
|
||||
|
|
|
@ -74,7 +74,7 @@ sysupgrade: $(SYSUPGRADE_OBJS)
|
|||
sysinstall.o: $(SYSINSTALL_DEPS:=.h)
|
||||
sysmerge.o: $(SYSMERGE_DEPS:=.h)
|
||||
sysupgrade.o: $(SYSUPGRADE_DEPS:=.h)
|
||||
autoconf.o: autoconf.h
|
||||
autoconf.o: autoconf.h execute.h
|
||||
conf.o: conf.h
|
||||
devices.o: devices.h
|
||||
execute.o: execute.h
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "autoconf.h"
|
||||
#include "execute.h"
|
||||
|
||||
static char** keyvalues = NULL;
|
||||
static size_t keyvalues_used = 0;
|
||||
|
@ -34,6 +35,23 @@ static size_t keyvalues_length = 0;
|
|||
|
||||
bool has_autoconf = false;
|
||||
|
||||
bool autoconf_has(const char* name)
|
||||
{
|
||||
if ( !name )
|
||||
return false;
|
||||
size_t len = strlen(name);
|
||||
for ( size_t i = 0; i < keyvalues_used; i++ )
|
||||
{
|
||||
if ( strncmp(keyvalues[i], name, len) )
|
||||
continue;
|
||||
if ( keyvalues[i][len] == '=' )
|
||||
return true;
|
||||
if ( keyvalues[i][len] == '!' && keyvalues[i][len + 1] == '=' )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* autoconf_get(const char* name)
|
||||
{
|
||||
if ( !name )
|
||||
|
@ -45,6 +63,36 @@ const char* autoconf_get(const char* name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
char* autoconf_eval(const char* name)
|
||||
{
|
||||
if ( !name )
|
||||
return NULL;
|
||||
char* shname;
|
||||
if ( asprintf(&shname, "%s!", name) < 0 )
|
||||
err(1, "malloc");
|
||||
const char* script;
|
||||
char* output = NULL;
|
||||
if ( (script = autoconf_get(shname)) )
|
||||
{
|
||||
char** out_ptr = autoconf_get(name) ? NULL : &output;
|
||||
execute((const char*[]) { "sh", "-c", script, NULL }, "efo", out_ptr);
|
||||
if ( out_ptr )
|
||||
{
|
||||
size_t len = strlen(output);
|
||||
if ( len && output[len - 1] == '\n' )
|
||||
output[len - 1] = '\0';
|
||||
}
|
||||
}
|
||||
free(shname);
|
||||
if ( autoconf_get(name) )
|
||||
{
|
||||
free(output);
|
||||
if ( !(output = strdup(autoconf_get(name))) )
|
||||
err(1, "malloc");
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
bool autoconf_set(const char* name, const char* value)
|
||||
{
|
||||
char* keyvalue;
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
extern bool has_autoconf;
|
||||
|
||||
bool autoconf_has(const char* name);
|
||||
const char* autoconf_get(const char* name);
|
||||
char* autoconf_eval(const char* name);
|
||||
bool autoconf_set(const char* name, const char* value);
|
||||
void autoconf_load(const char* path);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2016, 2017, 2021 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2015, 2016, 2017, 2021, 2023 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -24,6 +24,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -36,6 +37,7 @@ int execute(const char* const* argv, const char* flags, ...)
|
|||
bool foreground = false;
|
||||
bool gid_set = false;
|
||||
const char* input = NULL;
|
||||
char** output = NULL;
|
||||
bool raw_exit_code = false;
|
||||
bool uid_set = false;
|
||||
bool quiet = false;
|
||||
|
@ -53,6 +55,7 @@ int execute(const char* const* argv, const char* flags, ...)
|
|||
case 'f': foreground = true; break;
|
||||
case 'g': gid_set = true; gid = va_arg(ap, gid_t); break;
|
||||
case 'i': input = va_arg(ap, const char*); break;
|
||||
case 'o': output = va_arg(ap, char**); break;
|
||||
case 'r': raw_exit_code = true; break;
|
||||
case 'u': uid_set = true; uid = va_arg(ap, uid_t); break;
|
||||
case 'q': quiet = true; break;
|
||||
|
@ -66,6 +69,15 @@ int execute(const char* const* argv, const char* flags, ...)
|
|||
sigemptyset(&sigttou);
|
||||
sigaddset(&sigttou, SIGTTOU);
|
||||
}
|
||||
int output_pipes[2] = {-1, -1};
|
||||
if ( output && pipe(output_pipes) < 0 )
|
||||
{
|
||||
if ( !quiet_stderr )
|
||||
warn("pipe: %s", argv[0]);
|
||||
if ( exit_on_failure )
|
||||
(_exit_instead ? _exit : exit)(2);
|
||||
return -1;
|
||||
}
|
||||
pid_t child_pid = fork();
|
||||
if ( child_pid < 0 )
|
||||
{
|
||||
|
@ -95,8 +107,8 @@ int execute(const char* const* argv, const char* flags, ...)
|
|||
}
|
||||
if ( input )
|
||||
{
|
||||
int pipes[2];
|
||||
if ( pipe(pipes) < 0 )
|
||||
int input_pipes[2];
|
||||
if ( pipe(input_pipes) < 0 )
|
||||
{
|
||||
if ( !quiet_stderr )
|
||||
warn("pipe: %s", argv[0]);
|
||||
|
@ -111,11 +123,11 @@ int execute(const char* const* argv, const char* flags, ...)
|
|||
}
|
||||
else if ( input_pid == 0 )
|
||||
{
|
||||
close(pipes[0]);
|
||||
close(input_pipes[0]);
|
||||
size_t left = strlen(input);
|
||||
while ( *input )
|
||||
{
|
||||
ssize_t written = write(pipes[1], input, left);
|
||||
ssize_t written = write(input_pipes[1], input, left);
|
||||
if ( written <= 0 )
|
||||
break;
|
||||
input += written;
|
||||
|
@ -123,10 +135,17 @@ int execute(const char* const* argv, const char* flags, ...)
|
|||
}
|
||||
_exit(0);
|
||||
}
|
||||
close(pipes[1]);
|
||||
close(input_pipes[1]);
|
||||
close(0);
|
||||
dup2(pipes[0], 0);
|
||||
close(pipes[0]);
|
||||
dup2(input_pipes[0], 0);
|
||||
close(input_pipes[0]);
|
||||
}
|
||||
if ( output )
|
||||
{
|
||||
close(output_pipes[0]);
|
||||
close(1);
|
||||
dup2(output_pipes[1], 1);
|
||||
close(output_pipes[1]);
|
||||
}
|
||||
if ( quiet )
|
||||
{
|
||||
|
@ -148,6 +167,49 @@ int execute(const char* const* argv, const char* flags, ...)
|
|||
warn("%s", argv[0]);
|
||||
_exit(127);
|
||||
}
|
||||
bool success = true;
|
||||
if ( output )
|
||||
{
|
||||
close(output_pipes[1]);
|
||||
char* out;
|
||||
size_t out_size;
|
||||
FILE* out_fp = open_memstream(&out, &out_size);
|
||||
if ( out_fp )
|
||||
{
|
||||
char buf[4096];
|
||||
ssize_t amount = 0;
|
||||
while ( 0 < (amount = read(output_pipes[0], buf, sizeof(buf))) )
|
||||
{
|
||||
if ( fwrite(buf, 1, amount, out_fp) != (size_t) amount )
|
||||
{
|
||||
if ( !quiet_stderr )
|
||||
warn("fwrite to memstream");
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( success && fclose(out_fp) == EOF )
|
||||
{
|
||||
if ( !quiet_stderr )
|
||||
warn("fclose of memstream");
|
||||
success = false;
|
||||
}
|
||||
close(output_pipes[0]);
|
||||
if ( !success )
|
||||
{
|
||||
free(out);
|
||||
*output = NULL;
|
||||
}
|
||||
else
|
||||
*output = out;
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
if ( !quiet_stderr )
|
||||
warn("open_memstream");
|
||||
}
|
||||
}
|
||||
int code;
|
||||
waitpid(child_pid, &code, 0);
|
||||
if ( foreground )
|
||||
|
@ -158,11 +220,13 @@ int execute(const char* const* argv, const char* flags, ...)
|
|||
}
|
||||
if ( exit_on_failure )
|
||||
{
|
||||
if ( !WIFEXITED(code) || WEXITSTATUS(code) != 0 )
|
||||
if ( !success || !WIFEXITED(code) || WEXITSTATUS(code) != 0 )
|
||||
(_exit_instead ? _exit : exit)(2);
|
||||
}
|
||||
int exit_status;
|
||||
if ( WIFEXITED(code) )
|
||||
if ( !success )
|
||||
exit_status = 2;
|
||||
else if ( WIFEXITED(code) )
|
||||
exit_status = WEXITSTATUS(code);
|
||||
else
|
||||
exit_status = 128 + WTERMSIG(code);
|
||||
|
|
|
@ -161,6 +161,7 @@ void promptx(char* buffer,
|
|||
const char* answer,
|
||||
bool catch_if_shell)
|
||||
{
|
||||
char* autoconf_answer = autoconf_eval(autoconf_name);
|
||||
while ( true )
|
||||
{
|
||||
printf("\e[1m");
|
||||
|
@ -171,12 +172,11 @@ void promptx(char* buffer,
|
|||
else
|
||||
printf(" ");
|
||||
fflush(stdout);
|
||||
const char* autoconf_value = autoconf_get(autoconf_name);
|
||||
const char* accept_defaults = autoconf_get("accept_defaults");
|
||||
const char* automatic_answer = NULL;
|
||||
if ( autoconf_value )
|
||||
if ( autoconf_answer )
|
||||
{
|
||||
automatic_answer = autoconf_value;
|
||||
automatic_answer = autoconf_answer;
|
||||
if ( !automatic_answer[0] )
|
||||
automatic_answer = answer;
|
||||
}
|
||||
|
@ -184,10 +184,12 @@ void promptx(char* buffer,
|
|||
automatic_answer = answer;
|
||||
if ( automatic_answer )
|
||||
{
|
||||
printf("\e[93m");
|
||||
printf("%s\n", automatic_answer);
|
||||
printf("\e[22m");
|
||||
printf("\e[m");
|
||||
fflush(stdout);
|
||||
strlcpy(buffer, automatic_answer, buffer_size);
|
||||
free(autoconf_answer);
|
||||
return;
|
||||
}
|
||||
fgets(buffer, buffer_size, stdin);
|
||||
|
@ -221,6 +223,7 @@ void promptx(char* buffer,
|
|||
}
|
||||
break;
|
||||
}
|
||||
free(autoconf_answer);
|
||||
}
|
||||
|
||||
void password(char* buffer,
|
||||
|
|
|
@ -432,17 +432,27 @@ int main(void)
|
|||
|
||||
autoconf_load("/etc/autoinstall.conf");
|
||||
|
||||
char* accepts_defaults = autoconf_eval("accept_defaults");
|
||||
bool non_interactive = accepts_defaults &&
|
||||
!strcasecmp(accepts_defaults, "yes");
|
||||
free(accepts_defaults);
|
||||
|
||||
static char input[256];
|
||||
|
||||
textf("Hello and welcome to the " BRAND_DISTRIBUTION_NAME " " VERSIONSTR ""
|
||||
" installer for %s.\n\n", uts.machine);
|
||||
|
||||
if ( autoconf_get("ready") &&
|
||||
(autoconf_get("disked") || autoconf_get("confirm_install")) )
|
||||
if ( non_interactive ||
|
||||
(autoconf_has("ready") &&
|
||||
(autoconf_has("disked") || autoconf_has("confirm_install"))) )
|
||||
{
|
||||
int countdown = 10;
|
||||
if ( autoconf_get("countdown") )
|
||||
countdown = atoi(autoconf_get("countdown"));
|
||||
if ( autoconf_has("countdown") )
|
||||
{
|
||||
char* string = autoconf_eval("countdown");
|
||||
countdown = atoi(string);
|
||||
free(string);
|
||||
}
|
||||
sigset_t old_set;
|
||||
sigset_t new_set;
|
||||
sigemptyset(&new_set);
|
||||
|
@ -519,11 +529,10 @@ int main(void)
|
|||
};
|
||||
size_t num_readies = sizeof(readies) / sizeof(readies[0]);
|
||||
const char* ready = readies[arc4random_uniform(num_readies)];
|
||||
if ( autoconf_get("disked") )
|
||||
if ( autoconf_has("disked") )
|
||||
text("Warning: This installer will perform automatic harddisk "
|
||||
"partitioning!\n");
|
||||
if ( autoconf_get("confirm_install") &&
|
||||
!strcasecmp(autoconf_get("confirm_install"), "yes") )
|
||||
if ( autoconf_has("confirm_install") )
|
||||
text("Warning: This installer will automatically install an operating "
|
||||
"system!\n");
|
||||
prompt(input, sizeof(input), "ready", "Ready?", ready);
|
||||
|
@ -647,7 +656,7 @@ int main(void)
|
|||
good = true;
|
||||
}
|
||||
}
|
||||
const char* def = good ? "no" : "yes";
|
||||
const char* def = non_interactive || good ? "no" : "yes";
|
||||
while ( true )
|
||||
{
|
||||
prompt(input, sizeof(input), "videomode",
|
||||
|
@ -729,17 +738,21 @@ int main(void)
|
|||
text("\n");
|
||||
while ( true )
|
||||
{
|
||||
const char* def =
|
||||
non_interactive &&
|
||||
!autoconf_has("grub_password_hash") ? "no" : "yes";
|
||||
prompt(accept_grub_password, sizeof(accept_grub_password),
|
||||
"grub_password",
|
||||
"Password protect interactive bootloader? (yes/no)", "yes");
|
||||
"Password protect interactive bootloader? (yes/no)", def);
|
||||
if ( strcasecmp(accept_grub_password, "no") == 0 ||
|
||||
strcasecmp(accept_grub_password, "yes") == 0 )
|
||||
break;
|
||||
}
|
||||
if ( autoconf_get("grub_password_hash") )
|
||||
if ( autoconf_has("grub_password_hash") )
|
||||
{
|
||||
const char* hash = autoconf_get("grub_password_hash");
|
||||
char* hash = autoconf_eval("grub_password_hash");
|
||||
install_configurationf("grubpw", "w", "%s\n", hash);
|
||||
free(hash);
|
||||
}
|
||||
else while ( !strcasecmp(accept_grub_password, "yes") )
|
||||
{
|
||||
|
@ -810,15 +823,17 @@ int main(void)
|
|||
text("Type man to display the disked(8) man page.\n");
|
||||
not_first = true;
|
||||
const char* argv[] = { "disked", "--fstab=fstab", NULL };
|
||||
const char* disked_input = autoconf_get("disked");
|
||||
char* disked_input = autoconf_eval("disked");
|
||||
if ( execute(argv, "fi", disked_input) != 0 )
|
||||
{
|
||||
free(disked_input);
|
||||
// TODO: We also end up here on SIGINT.
|
||||
// TODO: Offer a shell here instead of failing?
|
||||
warnx("partitioning failed");
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
free(disked_input);
|
||||
free_mountpoints(mountpoints, mountpoints_used);
|
||||
mountpoints = NULL;
|
||||
mountpoints_used = 0;
|
||||
|
@ -1052,6 +1067,8 @@ int main(void)
|
|||
else while ( true )
|
||||
{
|
||||
char defhost[HOST_NAME_MAX + 1] = "";
|
||||
if ( non_interactive )
|
||||
gethostname(defhost, sizeof(defhost));
|
||||
FILE* defhost_fp = fopen("etc/hostname", "r");
|
||||
if ( defhost_fp )
|
||||
{
|
||||
|
@ -1086,9 +1103,11 @@ int main(void)
|
|||
{
|
||||
textf("Root account already exists, skipping creating it.\n");
|
||||
}
|
||||
else if ( autoconf_get("password_hash_root") )
|
||||
else if ( non_interactive || autoconf_has("password_hash_root") )
|
||||
{
|
||||
const char* hash = autoconf_get("password_hash_root");
|
||||
char* hash = autoconf_eval("password_hash_root");
|
||||
if ( !hash && !(hash = strdup("x")) )
|
||||
err(2, "malloc");
|
||||
if ( !install_configurationf("etc/passwd", "a",
|
||||
"root:%s:0:0:root:/root:sh\n"
|
||||
"include /etc/default/passwd.d/*\n", hash) )
|
||||
|
@ -1100,6 +1119,7 @@ int main(void)
|
|||
err(2, "etc/passwd");
|
||||
install_skel("/root", 0, 0);
|
||||
textf("Group '%s' added to /etc/group.\n", "root");
|
||||
free(hash);
|
||||
}
|
||||
else while ( true )
|
||||
{
|
||||
|
|
|
@ -368,6 +368,11 @@ int main(void)
|
|||
|
||||
autoconf_load("/etc/autoupgrade.conf");
|
||||
|
||||
char* accepts_defaults = autoconf_eval("accept_defaults");
|
||||
bool non_interactive = accepts_defaults &&
|
||||
!strcasecmp(accepts_defaults, "yes");
|
||||
free(accepts_defaults);
|
||||
|
||||
struct utsname uts;
|
||||
uname(&uts);
|
||||
|
||||
|
@ -376,12 +381,16 @@ int main(void)
|
|||
textf("Hello and welcome to the " BRAND_DISTRIBUTION_NAME " " VERSIONSTR ""
|
||||
" upgrader for %s.\n\n", uts.machine);
|
||||
|
||||
if ( autoconf_get("ready") ||
|
||||
autoconf_get("confirm_upgrade") )
|
||||
if ( autoconf_has("ready") ||
|
||||
autoconf_has("confirm_upgrade") )
|
||||
{
|
||||
int countdown = 10;
|
||||
if ( autoconf_get("countdown") )
|
||||
countdown = atoi(autoconf_get("countdown"));
|
||||
if ( autoconf_has("countdown") )
|
||||
{
|
||||
char* string = autoconf_eval("countdown");
|
||||
countdown = atoi(string);
|
||||
free(string);
|
||||
}
|
||||
sigset_t old_set;
|
||||
sigset_t new_set;
|
||||
sigemptyset(&new_set);
|
||||
|
@ -451,7 +460,7 @@ int main(void)
|
|||
};
|
||||
size_t num_readies = sizeof(readies) / sizeof(readies[0]);
|
||||
const char* ready = readies[arc4random_uniform(num_readies)];
|
||||
if ( autoconf_get("confirm_upgrade") )
|
||||
if ( autoconf_has("confirm_upgrade") )
|
||||
text("Warning: This upgrader will automatically upgrade an operating "
|
||||
"system!\n");
|
||||
prompt(input, sizeof(input), "ready", "Ready?", ready);
|
||||
|
@ -532,7 +541,7 @@ int main(void)
|
|||
good = true;
|
||||
}
|
||||
}
|
||||
const char* def = good ? "no" : "yes";
|
||||
const char* def = non_interactive || good ? "no" : "yes";
|
||||
while ( true )
|
||||
{
|
||||
prompt(input, sizeof(input), "videomode",
|
||||
|
@ -592,7 +601,7 @@ int main(void)
|
|||
execlp("sysinstall", "sysinstall", (const char*) NULL);
|
||||
err(2, "sysinstall");
|
||||
}
|
||||
continue;
|
||||
errx(2, "Upgrade aborted since no installations were found");
|
||||
}
|
||||
|
||||
while ( true )
|
||||
|
|
|
@ -133,7 +133,15 @@ if $random_seed; then
|
|||
fi
|
||||
fi
|
||||
|
||||
has_autoinstall=false
|
||||
has_autoupgrade=false
|
||||
if [ -n "$liveconfig" ]; then
|
||||
if [ -e "$liveconfig/etc/autoinstall.conf" ]; then
|
||||
has_autoinstall=true
|
||||
fi
|
||||
if [ -e "$liveconfig/etc/autoupgrade.conf" ]; then
|
||||
has_autoupgrade=true
|
||||
fi
|
||||
mkdir -p -- "$directory/boot"
|
||||
(cd "$liveconfig" && tar -c -f- -- *) > "$directory/boot/liveconfig.tar"
|
||||
rm -f -- "$directory/boot/liveconfig.tar.xz"
|
||||
|
@ -150,6 +158,12 @@ mkdir -p -- "$directory/boot/grub"
|
|||
if [ -n "$timeout" ]; then
|
||||
printf 'timeout="%s"\n' "$timeout"
|
||||
fi
|
||||
if $has_autoinstall; then
|
||||
echo "title_sysinstall='***AUTOMATIC INSTALLATION***'"
|
||||
fi
|
||||
if $has_autoupgrade; then
|
||||
echo "title_sysupgrade='***AUTOMATIC UPGRADE***'"
|
||||
fi
|
||||
print_enable_default_bool "$enable_dhclient" dhclient dhclient
|
||||
print_enable_default_bool "$enable_gui" gui gui
|
||||
print_enable_default "$enable_network_drivers" network_drivers network-drivers
|
||||
|
|
|
@ -238,6 +238,13 @@ GRUB module is loaded and an
|
|||
hook is emitted that loads
|
||||
.Pa output-directory/boot/liveconfig.tar.xz
|
||||
as a multiboot module.
|
||||
.Pp
|
||||
If the liveconfig contains
|
||||
.Xr autoinstall.conf 5
|
||||
or
|
||||
.Xr autoupgrade.conf 5 ,
|
||||
the menu titles are modified to loudly warn they will automatically
|
||||
install/upgrade the operating system.
|
||||
.It Fl \-random-seed
|
||||
Copy 256 bytes of randomness from
|
||||
.Pa /dev/urandom
|
||||
|
|
|
@ -317,7 +317,7 @@ diff_package() {(
|
|||
base=$(basename -- "$port")
|
||||
if [ -e "$base.upstream" ]; then
|
||||
announce "diff $base.upstream $base"
|
||||
diff -Paur --no-dereference -- "$base.upstream" "$base" |
|
||||
LC_ALL=C diff -Paur --no-dereference -- "$base.upstream" "$base" |
|
||||
sed -E -e '/^Only in.*$/d' -e 's/^((---|\+\+\+)[^\t]+)\t.*/\1/' \
|
||||
> "$base.patch"
|
||||
if [ ! -s "$base.patch" ]; then rm "$base.patch"; fi
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
.Nd change user password
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl H
|
||||
.Op Fl c Ar cipher
|
||||
.Op Ar user
|
||||
.Sh DESCRIPTION
|
||||
|
@ -19,6 +20,11 @@ The options are as follows:
|
|||
.It Fl c Ar cipher
|
||||
Hash the password using the specified
|
||||
.Ar cipher .
|
||||
.It Fl H
|
||||
Read a password from the standard input and write the
|
||||
.Xr crypt_newpass 3
|
||||
hash to the standard output.
|
||||
The password database is unchanged.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width "/etc/passwd" -compact
|
||||
|
|
109
utils/passwd.c
109
utils/passwd.c
|
@ -34,79 +34,67 @@
|
|||
static void password(char* buffer,
|
||||
size_t buffer_size,
|
||||
const char* whose,
|
||||
const char* question)
|
||||
const char* question,
|
||||
bool require_tty)
|
||||
{
|
||||
if ( !isatty(0) )
|
||||
bool is_tty = isatty(0);
|
||||
if ( !require_tty && is_tty )
|
||||
errx(1, "Input is not a terminal");
|
||||
unsigned int termmode;
|
||||
gettermmode(0, &termmode);
|
||||
settermmode(0, termmode & ~TERMMODE_ECHO);
|
||||
if ( whose )
|
||||
printf("%s's ", whose);
|
||||
printf("%s ", question);
|
||||
fflush(stdout);
|
||||
fflush(stdin);
|
||||
unsigned int termmode = 0;
|
||||
if ( is_tty )
|
||||
{
|
||||
gettermmode(0, &termmode);
|
||||
settermmode(0, termmode & ~TERMMODE_ECHO);
|
||||
if ( whose )
|
||||
printf("%s's ", whose);
|
||||
printf("%s ", question);
|
||||
fflush(stdout);
|
||||
fflush(stdin);
|
||||
}
|
||||
// TODO: This may leave a copy of the password in the stdio buffer.
|
||||
fgets(buffer, buffer_size, stdin);
|
||||
fflush(stdin);
|
||||
printf("\n");
|
||||
if ( is_tty )
|
||||
{
|
||||
fflush(stdin);
|
||||
printf("\n");
|
||||
settermmode(0, termmode);
|
||||
}
|
||||
size_t buffer_length = strlen(buffer);
|
||||
if ( buffer_length && buffer[buffer_length-1] == '\n' )
|
||||
buffer[--buffer_length] = '\0';
|
||||
settermmode(0, termmode);
|
||||
}
|
||||
|
||||
static void compact_arguments(int* argc, char*** argv)
|
||||
{
|
||||
for ( int i = 0; i < *argc; i++ )
|
||||
{
|
||||
while ( i < *argc && !(*argv)[i] )
|
||||
{
|
||||
for ( int n = i; n < *argc; n++ )
|
||||
(*argv)[n] = (*argv)[n+1];
|
||||
(*argc)--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* cipher = "blowfish,a";
|
||||
bool hash_password = false;
|
||||
|
||||
for ( int i = 1; i < argc; i++ )
|
||||
int opt;
|
||||
while ( (opt = getopt(argc, argv, "c:H")) != -1 )
|
||||
{
|
||||
const char* arg = argv[i];
|
||||
if ( arg[0] != '-' || !arg[1] )
|
||||
continue;
|
||||
argv[i] = NULL;
|
||||
if ( !strcmp(arg, "--") )
|
||||
break;
|
||||
if ( arg[1] != '-' )
|
||||
switch ( opt )
|
||||
{
|
||||
char c;
|
||||
while ( (c = *++arg) ) switch ( c )
|
||||
{
|
||||
case 'c':
|
||||
if ( !*(cipher = arg + 1) )
|
||||
{
|
||||
if ( i + 1 == argc )
|
||||
errx(125, "option requires an argument -- 'c'");
|
||||
cipher = argv[i+1];
|
||||
argv[++i] = NULL;
|
||||
}
|
||||
arg = "c";
|
||||
break;
|
||||
default:
|
||||
errx(1, "unknown option -- '%c'", c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errx(1, "unrecognized option: %s", arg);
|
||||
case 'c': cipher = optarg; break;
|
||||
case 'H': hash_password = true; break;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
compact_arguments(&argc, &argv);
|
||||
if ( hash_password )
|
||||
{
|
||||
if ( argc - optind )
|
||||
errx(1, "Unexpected extra operand");
|
||||
char pass[128];
|
||||
password(pass, sizeof(pass), NULL, "Enter password (will not echo)",
|
||||
false);
|
||||
fgets(pass, sizeof(pass), stdin);
|
||||
char newhash[128];
|
||||
if ( crypt_newhash(pass, cipher, newhash, sizeof(newhash)) < 0 )
|
||||
err(1, "crypt_newhash");
|
||||
if ( printf("%s\n", newhash) < 0 || fflush(stdout) == EOF )
|
||||
err(1, "stdout");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uid_t my_uid = getuid();
|
||||
char* my_username = getlogin();
|
||||
|
@ -116,9 +104,9 @@ int main(int argc, char* argv[])
|
|||
err(1, "stdup");
|
||||
|
||||
const char* username;
|
||||
if ( argc <= 1 )
|
||||
if ( argc - optind <= 1 )
|
||||
username = my_username;
|
||||
else if ( argc <= 2 )
|
||||
else if ( argc - optind <= 2 )
|
||||
username = argv[1];
|
||||
else
|
||||
errx(1, "Unexpected extra operand");
|
||||
|
@ -139,16 +127,17 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
char current[128];
|
||||
password(current, sizeof(current), pwd->pw_name,
|
||||
"current password (will not echo)");
|
||||
"current password (will not echo)", true);
|
||||
if ( crypt_checkpass(current, pwd->pw_passwd) < 0 )
|
||||
errx(1, "Wrong password for '%s'", pwd->pw_name);
|
||||
explicit_bzero(current, sizeof(current));
|
||||
}
|
||||
|
||||
char first[128];
|
||||
password(first, sizeof(first), NULL, "Enter new password (will not echo)");
|
||||
password(first, sizeof(first), NULL, "Enter new password (will not echo)",
|
||||
true);
|
||||
char second[128];
|
||||
password(second, sizeof(second), NULL, "Enter new password (again)");
|
||||
password(second, sizeof(second), NULL, "Enter new password (again)", true);
|
||||
if ( strcmp(first, second) != 0 )
|
||||
errx(1, "Passwords don't match");
|
||||
explicit_bzero(second, sizeof(second));
|
||||
|
|
Loading…
Reference in New Issue