Compare commits
2 Commits
875030f3f3
...
71edc766e7
Author | SHA1 | Date |
---|---|---|
Jonas 'Sortie' Termansen | 71edc766e7 | |
Jonas 'Sortie' Termansen | f2d50bbf9c |
2
Makefile
2
Makefile
|
@ -441,7 +441,7 @@ $(LIVE_INITRD): sysroot
|
|||
mkdir -p $(LIVE_INITRD).d
|
||||
mkdir -p $(LIVE_INITRD).d/etc
|
||||
mkdir -p $(LIVE_INITRD).d/etc/init
|
||||
echo single-user > $(LIVE_INITRD).d/etc/init/target
|
||||
echo require single-user exit-code > $(LIVE_INITRD).d/etc/init/default
|
||||
echo "root::0:0:root:/root:sh" > $(LIVE_INITRD).d/etc/passwd
|
||||
echo "root::0:root" > $(LIVE_INITRD).d/etc/group
|
||||
mkdir -p $(LIVE_INITRD).d/home
|
||||
|
|
|
@ -720,6 +720,18 @@ void TerminationHandler(int)
|
|||
should_terminate = true;
|
||||
}
|
||||
|
||||
static void ready(void)
|
||||
{
|
||||
const char* readyfd_env = getenv("READYFD");
|
||||
if ( !readyfd_env )
|
||||
return;
|
||||
int readyfd = atoi(readyfd_env);
|
||||
char c = '\n';
|
||||
write(readyfd, &c, 1);
|
||||
close(readyfd);
|
||||
unsetenv("READYFD");
|
||||
}
|
||||
|
||||
int fsmarshall_main(const char* argv0,
|
||||
const char* mount_path,
|
||||
bool foreground,
|
||||
|
@ -756,6 +768,8 @@ int fsmarshall_main(const char* argv0,
|
|||
exit(0);
|
||||
setpgid(0, 0);
|
||||
}
|
||||
else
|
||||
ready();
|
||||
|
||||
dev->SpawnSyncThread();
|
||||
|
||||
|
|
262
init/init.8
262
init/init.8
|
@ -6,16 +6,27 @@
|
|||
.Nd system initialization
|
||||
.Sh SYNOPSIS
|
||||
.Nm init
|
||||
.Op Fl \-target Ns "=" Ns Ar init-target
|
||||
.Op Fl qsv
|
||||
.Op Fl \-target Ns "=" Ns Ar default-daemon
|
||||
.Op Fl \-
|
||||
.Op Ar chain-init ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is the first program run after system startup and is responsible for
|
||||
initializing the operating system and starting the specified
|
||||
.Ar init-target .
|
||||
This is normally a login screen, a root shell, or a dedicated special purpose
|
||||
program.
|
||||
initializing the operating system.
|
||||
.Pp
|
||||
Each
|
||||
.Xr daemon 7
|
||||
is started in order as its dependencies become ready per its
|
||||
.Xr init 5
|
||||
configuration.
|
||||
The
|
||||
.Sy default
|
||||
daemon is automatically started and its recursive dependencies constitute the
|
||||
operating system.
|
||||
The
|
||||
.Sy default
|
||||
daemon's single dependency is referred to as the target.
|
||||
.Pp
|
||||
The
|
||||
.Xr kernel 7
|
||||
|
@ -34,56 +45,30 @@ If the system is installed on a harddisk, then the initrd is a minimal system
|
|||
made with
|
||||
.Xr update-initrd 8
|
||||
that will search for the actual root filesystem and chain init it.
|
||||
The next stage init will recognize it as the intended system and complete the
|
||||
system startup.
|
||||
.Ss Initialization Target
|
||||
.Nm
|
||||
first determines its target from the
|
||||
.Fl \-target
|
||||
option if specified or
|
||||
.Pa /etc/init/target
|
||||
otherwise.
|
||||
Supported targets are:
|
||||
The next stage init will recognize itself as the intended system and complete
|
||||
the system startup.
|
||||
.Pp
|
||||
.Bl -tag -width "single-user" -compact -offset indent
|
||||
.It Sy chain
|
||||
mount real root filesystem and run its
|
||||
.Nm .
|
||||
.It Sy chain-merge
|
||||
like
|
||||
.Sy chain
|
||||
but run
|
||||
.Pa /sysmerge/sbin/init
|
||||
with the
|
||||
.Sy merge
|
||||
target.
|
||||
.It Sy merge
|
||||
finish a
|
||||
.Xr sysmerge 8
|
||||
upgrade and then execute the real
|
||||
.Nm
|
||||
with its default target.
|
||||
.It Sy multi-user
|
||||
boot to
|
||||
.Xr login 8 .
|
||||
.It Sy single-user
|
||||
boot to root shell without password (not secure).
|
||||
.It Sy sysinstall
|
||||
boot to operating system installer (not secure).
|
||||
.It Sy sysupgrade
|
||||
boot to operating system upgrader (not secure).
|
||||
The options are as follows:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Fl q , \-quiet
|
||||
Write status updates to the terminal only about failed daemons.
|
||||
This behavior is the default.
|
||||
.It Fl s , \-silent
|
||||
Never write status updates about daemons to the terminal.
|
||||
.It Fl t , \-target Ns "=" Ns Ar default-daemon
|
||||
Boot
|
||||
.Ar default-daemon
|
||||
as the target.
|
||||
The
|
||||
.Sy default
|
||||
daemon configuration is changed to only require the
|
||||
.Ar default-daemon
|
||||
dependency with the
|
||||
.Sy exit-only
|
||||
flag.
|
||||
.It Fl v , \-verbose
|
||||
Write all status updates about daemons starting and stopping to the terminal
|
||||
.El
|
||||
.Pp
|
||||
It is a full system compromise if unauthenticated users are able to boot the
|
||||
wrong target.
|
||||
The kernel command line can specify the path to
|
||||
.Nm
|
||||
and its arguments.
|
||||
Unprivileged users can change the kernel command line from the bootloader
|
||||
command line if it hasn't been password protected.
|
||||
Likewise unprivileged users can use their own replacement bootloader by booting
|
||||
a portable device under their control if the firmware configuration has not been
|
||||
password protected.
|
||||
.Ss Cleanup of /tmp and /var/run
|
||||
.Nm
|
||||
deletes everything inside of
|
||||
|
@ -104,23 +89,24 @@ will scan every block device for valid partition tables and create the
|
|||
corresponding partition devices in
|
||||
.Pa /dev .
|
||||
.Ss Chain Initialization
|
||||
The
|
||||
If the target is
|
||||
.Sy chain
|
||||
target mounts the root filesystem as in
|
||||
or
|
||||
.Sy chain-merge ,
|
||||
then the real operating system is chain initialized.
|
||||
.Pp
|
||||
The root filesystem is mounted per
|
||||
.Pa /etc/fstab
|
||||
(see
|
||||
.Xr fstab 5 )
|
||||
and runs the next
|
||||
.Nm
|
||||
program.
|
||||
This is used by
|
||||
.Xr fstab 5 ) .
|
||||
This configuration file is a copy of the real file made by
|
||||
.Xr update-initrd 8
|
||||
to make a bootstrap
|
||||
when it makes the bootstrap
|
||||
.Xr initrd 7 .
|
||||
.Pp
|
||||
Every block device and partition is scanned to determine if it is the root
|
||||
filesystem.
|
||||
It is checked for consistency if necessary.
|
||||
The root filesystem is found by searching each block device and partition.
|
||||
It is checked for consistency if necessary and mounted read-only if the check
|
||||
fails.
|
||||
It is mounted at
|
||||
.Pa /tmp/fs.XXXXXX
|
||||
and the
|
||||
|
@ -133,6 +119,34 @@ Finally the
|
|||
program (or
|
||||
.Ar chain-init
|
||||
if specified) of the target root filesystem is run inside a chroot.
|
||||
If the target is
|
||||
.Sy chain-merge ,
|
||||
then the
|
||||
.Fl \-target=merge
|
||||
option is passed to the next
|
||||
.Nm .
|
||||
.Ss Mountpoints
|
||||
.Nm
|
||||
mounts all the filesystems according to
|
||||
.Xr fstab 5 .
|
||||
The filesystems are checked for consistency if necessary and mounted read-only
|
||||
if the check fails.
|
||||
.Ss Logging
|
||||
Logging to
|
||||
.Pa /var/log
|
||||
begins once the filesystems are mounted and
|
||||
.Nm
|
||||
writes the log entries from early boot to its
|
||||
.Pa /var/log/init.log .
|
||||
.Ss Random Seed
|
||||
.Nm
|
||||
will write 256 bytes of randomness to
|
||||
.Pa /boot/random.seed ,
|
||||
which serves as the initial entropy for the
|
||||
.Xr kernel 7
|
||||
on the next boot.
|
||||
The file is also written on system shutdown where the system has the most
|
||||
entropy.
|
||||
.Ss Configuration
|
||||
Once the
|
||||
.Nm
|
||||
|
@ -150,46 +164,52 @@ set keyboard layout (see
|
|||
set graphics resolution (see
|
||||
.Xr videomode 5 )
|
||||
.El
|
||||
.Ss Mountpoints
|
||||
.Nm
|
||||
mounts all the filesystems according to
|
||||
.Xr fstab 5 .
|
||||
.Ss Random Seed
|
||||
.Nm
|
||||
will write 256 bytes of randomness to
|
||||
.Pa /boot/random.seed ,
|
||||
which serves as the initial entropy for the
|
||||
.Xr kernel 7
|
||||
on the next boot.
|
||||
The file is also written on system shutdown where the system has the most
|
||||
entropy.
|
||||
.Ss Merge
|
||||
The
|
||||
.Sy merge
|
||||
target completes a delayed system upgrade by invoking the
|
||||
If the target is
|
||||
.Sy merge ,
|
||||
then a delayed system upgrade is completed by invoking
|
||||
.Xr sysmerge 8
|
||||
at
|
||||
.Pa /sysmerge/sbin/sysmerge
|
||||
with the
|
||||
.Ar --booting
|
||||
option.
|
||||
.Pp
|
||||
If the upgrade succeeds, the temporary
|
||||
.Nm
|
||||
.Pa /sysmerge/sbin/init
|
||||
deinitializes the system and invokes the real (now upgraded)
|
||||
.Nm
|
||||
.Pa /sbin/init ,
|
||||
which will restart system initialization in the normal fashion.
|
||||
.Ss Session
|
||||
Finally
|
||||
.Ss Daemons
|
||||
The
|
||||
.Sy default
|
||||
.Xr daemon 7
|
||||
is started per its
|
||||
.Pa /etc/init/default
|
||||
.Xr init 5
|
||||
configuration file, which constitutes the operating system, and once it exits
|
||||
then
|
||||
.Nm
|
||||
will start the target program according to its initialization target.
|
||||
This will be a login screen, a root shell, or something else.
|
||||
If the process exits abnormally
|
||||
.Nm
|
||||
will automatically restart it.
|
||||
.Nm
|
||||
will exit with the same exit status as the process if it exits normally.
|
||||
The kernel decides whether to power off, reboot or halt based on this exit
|
||||
status.
|
||||
exits with the same error code and the kernel shuts down the machine.
|
||||
The
|
||||
.Sy default
|
||||
daemon is meant to be a virtual daemon depending on a single top level daemon
|
||||
(the target), which provide the desired operating system functionality
|
||||
(e.g. booting to a single user shell or a multi user login screen).
|
||||
.Pp
|
||||
The daemons are configured per
|
||||
.Xr init 5
|
||||
where
|
||||
.Pa /etc/init
|
||||
contains the installation's local configuration, which overrides the operating
|
||||
system's default configuration in
|
||||
.Pa /share/init .
|
||||
The daemons are started in order as their dependencies become ready and are
|
||||
stopped in order when they are no longer required.
|
||||
.Pp
|
||||
The
|
||||
.Sy local
|
||||
daemon is meant to start the installation's local daemon requirements.
|
||||
.Sh ENVIRONMENT
|
||||
.Nm
|
||||
sets the following environment variables.
|
||||
|
@ -213,21 +233,47 @@ root
|
|||
.Sh FILES
|
||||
.Bl -tag -width "/boot/random.seed" -compact
|
||||
.It Pa /boot/random.seed
|
||||
initial kernel entropy
|
||||
.It Pa /etc/init/target
|
||||
default initialization target
|
||||
Initial kernel entropy
|
||||
.It Pa /etc/init/
|
||||
Daemon configuration for the local system (first in search path) (see
|
||||
.Xr init 5 )
|
||||
.It Pa /etc/init/default
|
||||
Configuration for the default daemon (see
|
||||
.Xr init 5 )
|
||||
.It Pa /etc/fstab
|
||||
filesystem table (see
|
||||
Filesystem table (see
|
||||
.Xr fstab 5 )
|
||||
.It Pa /etc/hostname
|
||||
hostname (see
|
||||
Hostname (see
|
||||
.Xr hostname 5 )
|
||||
.It Pa /etc/kblayout
|
||||
keyboard layout (see
|
||||
Keyboard layout (see
|
||||
.Xr kblayout 5 )
|
||||
.It Pa /etc/videomode
|
||||
graphics resolution (see
|
||||
Graphics resolution (see
|
||||
.Xr videomode 5 )
|
||||
.It Pa /share/init/
|
||||
Default daemon configuration provided by the operating system (second in
|
||||
search path) (see
|
||||
.Xr init 5 )
|
||||
.It Pa /var/log/
|
||||
Daemon log files (see
|
||||
.Xr init 5 )
|
||||
.It Pa /var/log/init.log
|
||||
.Nm Ns 's
|
||||
own log.
|
||||
.El
|
||||
.Sh ASYNCHRONOUS EVENTS
|
||||
.Bl -tag -width "SIGUSR1"
|
||||
.It Dv SIGTERM
|
||||
Request system poweroff, normally sent by
|
||||
.Xr poweroff 8 .
|
||||
.It Dv SIGINT
|
||||
Request system reboot, normally sent by
|
||||
.Xr reboot 8 .
|
||||
.It Dv SIGQUIT
|
||||
Request system halt, normally sent by
|
||||
.Xr halt 8 .
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Nm
|
||||
|
@ -243,10 +289,26 @@ exits with the same exit status as its target session if it terminates normally.
|
|||
.Sh SEE ALSO
|
||||
.Xr fstab 5 ,
|
||||
.Xr hostname 5 ,
|
||||
.Xr init 5 ,
|
||||
.Xr kblayout 5 ,
|
||||
.Xr videomode 5 ,
|
||||
.Xr daemon 7 ,
|
||||
.Xr initrd 7 ,
|
||||
.Xr kernel 7 ,
|
||||
.Xr halt 8 ,
|
||||
.Xr login 8 ,
|
||||
.Xr poweroff 8 ,
|
||||
.Xr reboot 8 ,
|
||||
.Xr sysmerge 8 ,
|
||||
.Xr update-initrd 8
|
||||
.Sh SECURITY CONSIDERATIONS
|
||||
It is a full system compromise if unauthenticated users are able to boot the
|
||||
wrong target.
|
||||
The kernel command line can specify the path to
|
||||
.Nm
|
||||
and its arguments.
|
||||
Unprivileged users can change the kernel command line from the bootloader
|
||||
command line if it hasn't been password protected.
|
||||
Likewise unprivileged users can use their own replacement bootloader by booting
|
||||
a portable device under their control if the firmware configuration has not been
|
||||
password protected.
|
||||
|
|
3266
init/init.c
3266
init/init.c
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2015, 2022 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
|
||||
|
@ -47,18 +47,15 @@ static bool array_add(void*** array_ptr,
|
|||
|
||||
if ( *used_ptr == *length_ptr )
|
||||
{
|
||||
// TODO: Avoid overflow.
|
||||
size_t new_length = 2 * *length_ptr;
|
||||
if ( !new_length )
|
||||
new_length = 16;
|
||||
// TODO: Avoid overflow and use reallocarray.
|
||||
size_t new_size = new_length * sizeof(void*);
|
||||
void** new_array = (void**) realloc(array, new_size);
|
||||
size_t length = *length_ptr;
|
||||
if ( !length )
|
||||
length = 4;
|
||||
void** new_array = reallocarray(array, length, 2 * sizeof(void*));
|
||||
if ( !new_array )
|
||||
return false;
|
||||
array = new_array;
|
||||
memcpy(array_ptr, &array, sizeof(array)); // Strict aliasing.
|
||||
*length_ptr = new_length;
|
||||
*length_ptr = length * 2;
|
||||
}
|
||||
|
||||
memcpy(array + (*used_ptr)++, &value, sizeof(value)); // Strict aliasing.
|
||||
|
|
|
@ -636,6 +636,8 @@ static void keyboard_event(struct glogin* state, uint32_t codepoint)
|
|||
exit(0);
|
||||
if ( !strcmp(textbox_username.text, "reboot") )
|
||||
exit(1);
|
||||
if ( !strcmp(textbox_username.text, "halt") )
|
||||
exit(2);
|
||||
state->stage = STAGE_PASSWORD;
|
||||
textbox_reset(&textbox_password);
|
||||
break;
|
||||
|
|
|
@ -44,6 +44,8 @@ alias for poweroff
|
|||
exit asking for powering off the computer
|
||||
.It reboot
|
||||
exit asking for rebooting the computer
|
||||
.It halt
|
||||
exit asking for halting the computer
|
||||
.El
|
||||
.Sh SECURITY
|
||||
There is currently no method to confirm the login screen is in fact real other
|
||||
|
|
|
@ -349,6 +349,8 @@ int textual(void)
|
|||
exit(0);
|
||||
if ( !strcmp(username, "reboot") )
|
||||
exit(1);
|
||||
if ( !strcmp(username, "halt") )
|
||||
exit(2);
|
||||
|
||||
if ( settermmode(0, pw_termmode) < 0 )
|
||||
err(2, "settermmode");
|
||||
|
|
15
sh/util.c
15
sh/util.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2022 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
|
||||
|
@ -49,18 +49,15 @@ bool array_add(void*** array_ptr,
|
|||
|
||||
if ( *used_ptr == *length_ptr )
|
||||
{
|
||||
// TODO: Avoid overflow.
|
||||
size_t new_length = 2 * *length_ptr;
|
||||
if ( !new_length )
|
||||
new_length = 16;
|
||||
// TODO: Avoid overflow and use reallocarray.
|
||||
size_t new_size = new_length * sizeof(void*);
|
||||
void** new_array = (void**) realloc(array, new_size);
|
||||
size_t length = *length_ptr;
|
||||
if ( !length )
|
||||
length = 4;
|
||||
void** new_array = reallocarray(array, length, 2 * sizeof(void*));
|
||||
if ( !new_array )
|
||||
return false;
|
||||
array = new_array;
|
||||
memcpy(array_ptr, &array, sizeof(array)); // Strict aliasing.
|
||||
*length_ptr = new_length;
|
||||
*length_ptr = length * 2;
|
||||
}
|
||||
|
||||
memcpy(array + (*used_ptr)++, &value, sizeof(value)); // Strict aliasing.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
require time optional
|
|
@ -0,0 +1,8 @@
|
|||
require base no-await
|
||||
require local no-await
|
||||
|
||||
tty tty1
|
||||
need tty
|
||||
|
||||
exit-code-meaning poweroff-reboot
|
||||
exec login
|
|
@ -0,0 +1,2 @@
|
|||
require base no-await
|
||||
require local no-await exit-code
|
|
@ -0,0 +1,9 @@
|
|||
require base no-await
|
||||
require local no-await
|
||||
|
||||
tty tty1
|
||||
need tty
|
||||
|
||||
cd "$HOME"
|
||||
exit-code-meaning poweroff-reboot
|
||||
exec "$SHELL"
|
|
@ -0,0 +1,8 @@
|
|||
require base no-await
|
||||
require local no-await
|
||||
|
||||
tty tty1
|
||||
need tty
|
||||
|
||||
exec sysinstall
|
||||
exit-code-meaning poweroff-reboot
|
|
@ -0,0 +1,8 @@
|
|||
require base no-await
|
||||
require local no-await
|
||||
|
||||
tty tty1
|
||||
need tty
|
||||
|
||||
exec sysupgrade
|
||||
exit-code-meaning poweroff-reboot
|
|
@ -0,0 +1,587 @@
|
|||
.Dd July 29, 2018
|
||||
.Dt INIT 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm init
|
||||
.Nd system initialization configuration
|
||||
.Sh SYNOPSIS
|
||||
.Nm /etc/init/
|
||||
.Nm /share/init/
|
||||
.Sh DESCRIPTION
|
||||
.Xr init 8
|
||||
starts each
|
||||
.Xr daemon 7
|
||||
(system background process) according to the daemon's
|
||||
configuration file, which specifies the daemon's dependencies and how to run the
|
||||
daemon.
|
||||
.Pp
|
||||
Configuration files are searched for in the
|
||||
.Pa /etc/init/
|
||||
directory (local initialization configuration owned by the system administrator,
|
||||
which may be modified) and the
|
||||
.Pa /share/init/
|
||||
directory (default initialization configuration owned by the operating system,
|
||||
which should not be modified).
|
||||
The file name of each configuration file is that of the daemon without any file
|
||||
extension.
|
||||
For instance, the daemon
|
||||
.Sy exampled
|
||||
might come with the default configuration file
|
||||
.Pa /share/init/exampled
|
||||
that the system administrator can override in
|
||||
.Pa /etc/init/exampled .
|
||||
.Pp
|
||||
.Xr init 8
|
||||
initially starts the
|
||||
.Sy default
|
||||
daemon which is configured in
|
||||
.Pa /etc/init/default ,
|
||||
which then depends on the daemons constituting the operating system (which in
|
||||
turn depend on the
|
||||
.Sy local
|
||||
daemon).
|
||||
The
|
||||
.Pa /etc/init/default
|
||||
file also defines default settings such as logging that are implicitly inherited
|
||||
by all other deamons, as well as
|
||||
.Xr init 8 Ns 's
|
||||
own
|
||||
.Pa /var/log/init.log
|
||||
file.
|
||||
.Pp
|
||||
Local system daemons should be started by overriding the
|
||||
.Sy local
|
||||
daemon in
|
||||
.Pa /etc/init/local ,
|
||||
which then depends on the locally required daemons.
|
||||
System provided daemons can be customized by making
|
||||
.Pa /etc/init/exampled
|
||||
which starts with the
|
||||
.Sy furthermore
|
||||
statement to include the default
|
||||
.Pa /etc/share/exampled
|
||||
configuration and then change the desired properties.
|
||||
.Sh DAEMONS
|
||||
The
|
||||
.Sy default
|
||||
daemon should
|
||||
.Sy require
|
||||
exactly one top level daemon with
|
||||
.Sy exit-code
|
||||
and nothing else.
|
||||
.Pp
|
||||
The following daemons are top level daemons that start the operating system.
|
||||
They are mutually exclusive and only a single one should be depended on:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Sy multi-user
|
||||
Starts the operating system in the multi-user mode.
|
||||
It starts the
|
||||
.Sy login
|
||||
foreground daemon that provides a login screen and exits with login's exit code
|
||||
when login exits.
|
||||
This is a secure operating system mode where only authorized users have access.
|
||||
It depends on the
|
||||
.Sy base
|
||||
and
|
||||
.Sy local
|
||||
daemons.
|
||||
.It Sy no-user
|
||||
Starts the operating system in the no-user mode.
|
||||
This is a secure operating system mode where no user is granted access.
|
||||
Additional daemons can be started by configuring the
|
||||
.Sy local
|
||||
daemon.
|
||||
It depends on the
|
||||
.Sy base
|
||||
and
|
||||
.Sy local
|
||||
daemons.
|
||||
The dependency on
|
||||
.Sy local
|
||||
is marked
|
||||
.Sy exit-code ,
|
||||
letting the system administrator fully control the
|
||||
.Sy default
|
||||
daemon's exit code and when the system completes.
|
||||
.It Sy single-user
|
||||
Starts the operating system in the single user mode.
|
||||
This foreground daemon starts the
|
||||
.Sy sh
|
||||
program that directly provides a root shell and exits with the shell's exit code
|
||||
when the shell exits.
|
||||
This operating system mode is insecure because it boots straight to root access
|
||||
without a password.
|
||||
It depends on the
|
||||
.Sy base
|
||||
and
|
||||
.Sy local
|
||||
daemons.
|
||||
.It Sy sysinstall
|
||||
Starts the operating system installer.
|
||||
This foreground daemon starts the
|
||||
.Sy sysinstall
|
||||
program that provides the operating system installer and exits with the
|
||||
installer's exit code when the installer exits.
|
||||
This operating system mode is insecure because it boots straight to root access
|
||||
without a password.
|
||||
It depends on the
|
||||
.Sy base
|
||||
and
|
||||
.Sy local
|
||||
daemons.
|
||||
.It Sy sysupgrade
|
||||
Starts the operating system upgrader.
|
||||
This foreground daemon starts the
|
||||
.Sy sysupgrade
|
||||
program that provides the operating system upgrader and exits with the
|
||||
upgrader's exit code when the upgrader exits.
|
||||
This operating system mode is insecure because it boots straight to root access
|
||||
without a password.
|
||||
It depends on the
|
||||
.Sy base
|
||||
and
|
||||
.Sy local
|
||||
daemons.
|
||||
.El
|
||||
.Pp
|
||||
The following daemons are provided by the system:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Sy base
|
||||
Virtual daemon that depends on the core operating system daemons.
|
||||
It depends on the
|
||||
.Sy time
|
||||
daemon.
|
||||
.It Sy local
|
||||
Virtual daemon that starts daemons pertinent to the local system.
|
||||
The system provides a default implementation that does nothing.
|
||||
The system administrator is meant to override the daemon in
|
||||
.Pa /etc/init/local
|
||||
by depending on daemons outside of the base system that should run on the local
|
||||
system.
|
||||
.It Sy time
|
||||
Virtual daemon that becomes ready when the current date and time has been
|
||||
established.
|
||||
The system provides a default implementation that does nothing, as the base
|
||||
system does not contain a daemon that obtains the current date and time.
|
||||
The system administrator is meant to override the daemon in
|
||||
.Pa /etc/init/time
|
||||
by depending on a daemon that obtains the current date and time and sets the
|
||||
system time.
|
||||
Daemons can depend on this daemon if they need the current date and time to have
|
||||
been established before they start.
|
||||
.El
|
||||
.Sh FORMAT
|
||||
Daemon configuration files are processed line by line.
|
||||
Each line specifies a property of the daemon.
|
||||
Lines are tokenized like shell commands on white space with support for single
|
||||
qoutes, double quotes, and backslash escape sequences (\\\\, \\', \\", \\a, \\b,
|
||||
\\e, \\f, \\n, \\r, \\t, \\v).
|
||||
The # character starts a comment and the rest of the line is ignored.
|
||||
.Bl -tag -width "12345678"
|
||||
.It Sy cd Ar directory
|
||||
The working directory to run the deamon inside.
|
||||
(Default is
|
||||
.Pa / )
|
||||
.It Sy exec Ar command
|
||||
The command line that starts the daemon.
|
||||
The daemon becomes ready when it writes
|
||||
a newline to the file descriptor mentioned in the
|
||||
.Ev READYFD
|
||||
environment variable as described in
|
||||
.Xr daemon 7 .
|
||||
.Pp
|
||||
If this property isn't specified, then the daemon is a virtual daemon.
|
||||
Virtual deamons become ready when all their dependencies are ready and finish
|
||||
when all their dependencies are finished.
|
||||
Virtual daemons exit 0 (success) if every dependency finished successfully,
|
||||
otherwise they exit 3 (failed).
|
||||
.It Sy exit-code-meaning Oo Sy default "|" poweroff-reboot Oc
|
||||
This property specifies how to interpret the exit code.
|
||||
.Pp
|
||||
The
|
||||
.Sy default
|
||||
meaning is that exiting 0 is successful.
|
||||
Any other exit means the daemon failed.
|
||||
.Pp
|
||||
The
|
||||
.Sy poweroff-reboot
|
||||
meaning is that exiting 0 means the system should power off, exiting 1 means the
|
||||
system should reboot, exiting 2 means the system should halt, and any other exit
|
||||
means the daemon failed.
|
||||
.Pp
|
||||
Daemons are considered successful if they exit by
|
||||
.Sy SIGTERM
|
||||
if
|
||||
.Xr init 8
|
||||
stopped the daemon by sending
|
||||
.Sy SIGTERM.
|
||||
.It Sy furthermore
|
||||
The current daemon configuration file extends an existing daemon that is defined
|
||||
in a configuration file by the same name later in the search path.
|
||||
The later configuration file is included into the current configuration file.
|
||||
This statement can only be used once per configuration file, any subsequent uses
|
||||
are silently ignored, but it can be used recursively.
|
||||
Customizing an existing daemon should be done by adding a new daemon file
|
||||
earlier in the search path that starts with the
|
||||
.Sy furthermore
|
||||
statement, followed by additional configuration.
|
||||
.Pp
|
||||
This is not a property and cannot be
|
||||
.Sy unset .
|
||||
.It Sy log-control-messages Oo Sy false "|" true Oc
|
||||
Includes control messages such as the start and stop of the daemon and loss of
|
||||
log data.
|
||||
Control messages are inserted as entries from the daemon
|
||||
.Sy init .
|
||||
.Pp
|
||||
The default is
|
||||
.Sy true
|
||||
and is
|
||||
inherited from the
|
||||
.Sy default
|
||||
deamon.
|
||||
.It Sy log-file-mode Ar octal
|
||||
Sets the log file permissions to the
|
||||
.Ar octal
|
||||
mode with
|
||||
.Xr chmod 2 .
|
||||
.Pp
|
||||
The default value is
|
||||
.Sy 644
|
||||
and is inherited from the
|
||||
.Sy default
|
||||
deamon.
|
||||
.It Sy log-format Ar format
|
||||
Selects the
|
||||
.Ar format
|
||||
of the log:
|
||||
.Bl -tag -width "nanoseconds"
|
||||
.It Sy none
|
||||
The log is exactly as written by the daemon with no additional formatting.
|
||||
.It Sy seconds
|
||||
"YYYY-dd-mm HH:MM:SS +0000: "
|
||||
.Pp
|
||||
Each line is prefixed with a timestamp with second precision and the timezone
|
||||
offset.
|
||||
.It Sy nanoseconds
|
||||
"YYYY-dd-mm HH:MM:SS.nnnnnnnnn +0000: "
|
||||
.Pp
|
||||
Each line is prefixed with a timestamp with nanosecond precision and the
|
||||
timezone offset.
|
||||
.It Sy basic
|
||||
"YYYY-dd-mm HH:MM:SS.nnnnnnnnn +0000 daemon: "
|
||||
.Pp
|
||||
Each line is prefixed with a timestamp with nanosecond precision and the
|
||||
timezone offset followed by the name of the daemon.
|
||||
.It Sy full
|
||||
"YYYY-dd-mm HH:MM:SS.nnnnnnnnn +0000 hostname daemon: "
|
||||
.Pp
|
||||
Each line is prefixed with a timestamp with nanosecond precision and the
|
||||
timezone offset followed
|
||||
by the hostname and name of the daemon.
|
||||
.It Sy syslog
|
||||
"<ppp>1 YYYY-dd-mmTHH:MM:SS.uuuuuuZ hostname daemon pid - - "
|
||||
.Pp
|
||||
Each line is prefixed in the RFC 5424 syslog version 1 format with the priority,
|
||||
the timestamp with microsecond precision and the timezone offset, the hostname,
|
||||
the daemon name, and the process id.
|
||||
.El
|
||||
.Pp
|
||||
The default format is
|
||||
.Sy nanoseconds
|
||||
and is inherited from the
|
||||
.Sy default
|
||||
deamon.
|
||||
.It Sy log-line-size Ar line-size
|
||||
When using the
|
||||
.Sy rotate
|
||||
log method, log files are cut at newlines if the lines don't exceed
|
||||
.Ar line-size
|
||||
bytes.
|
||||
.Pp
|
||||
The default value is 4096 bytes and is inherited from the
|
||||
.Sy default
|
||||
deamon.
|
||||
.It Sy log-method Oo Sy none "|" append "|" rotate Oc
|
||||
Selects the method for logging:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Sy none
|
||||
Disable logging.
|
||||
.It Sy append
|
||||
Always append the log data to the log file without any rotation.
|
||||
For instance,
|
||||
.Pa exampled.log
|
||||
will contain all the log entries ever produced by the
|
||||
.Sy exampled
|
||||
daemon.
|
||||
.Pp
|
||||
This method does not lose log data but it will fail when filesystem space is
|
||||
exhausted.
|
||||
.It Sy rotate
|
||||
Append lines to the log file until it becomes too large, in which case the
|
||||
daemon's logs are rotated.
|
||||
.Pp
|
||||
Rotation is done by deleting the oldest log (if there are too many), each of the
|
||||
remaining log files are renamed with the subsequent number, and a new log file
|
||||
is begun.
|
||||
The logs are cut on a newline boundary if the lines doesn't exceed
|
||||
.Sy log-line-size .
|
||||
.Pp
|
||||
For instance,
|
||||
.Pa exampled.log.2
|
||||
is deleted,
|
||||
.Pa exampled.log.1
|
||||
becomes
|
||||
.Pa exampled.log.2 ,
|
||||
.Pa exampled.log.1
|
||||
becomes
|
||||
.Pa exampled.log.2 ,
|
||||
and a new
|
||||
.Pa exampled.log
|
||||
is begun.
|
||||
.Pp
|
||||
This method will lose old log data.
|
||||
.El
|
||||
.Pp
|
||||
The default format is
|
||||
.Sy rotate
|
||||
and is inherited from the
|
||||
.Sy default
|
||||
deamon.
|
||||
.It Sy log-rotate-on-start Oo Sy false "|" true Oc
|
||||
When starting the daemon, rotate the logs (when using the
|
||||
.Sy rotate
|
||||
log method) or empty the log (when using the
|
||||
.Sy append
|
||||
log method), such that the daemon starts out with a new log.
|
||||
.Pp
|
||||
The default value is
|
||||
.Sy false
|
||||
and is inherited from the
|
||||
.Sy default
|
||||
deamon.
|
||||
.It Sy log-size Ar size
|
||||
When using the
|
||||
.Sy rotate
|
||||
log method, keep each log file below
|
||||
.Ar size
|
||||
bytes.
|
||||
.Pp
|
||||
The default value is 1048576 bytes and is inherited from the
|
||||
.Sy default
|
||||
deamon.
|
||||
.It Sy need tty
|
||||
Specifies that the daemon is not a background daemon, but instead is the
|
||||
foreground daemon controlling the terminal in the
|
||||
.Sy tty
|
||||
property.
|
||||
The daemon is made a process group leader.
|
||||
The terminal's foreground process group is set to that of the daemon.
|
||||
The terminal is enabled by setting
|
||||
.Sy CREAD .
|
||||
The daemon is not logged, and the standard input, output, and error are instead
|
||||
connected to the terminal
|
||||
Foreground daemons are automatically considered ready and don't participate in
|
||||
the
|
||||
.Ev READYFD
|
||||
daemon readiness protocol.
|
||||
Upon exit, the original terminal settings are restored and
|
||||
.Xr init 8
|
||||
reclaims ownership of the terminal.
|
||||
.It Sy require Ar dependency Oo Ar flag ... Oc
|
||||
When the daemon is needed, start the
|
||||
.Ar dependency
|
||||
first.
|
||||
The daemon starts when all its dependencies have become ready or have finished.
|
||||
Dependencies are started in parallel whenever possible.
|
||||
If the daemon hasn't started yet, and any non-optional dependency finishes
|
||||
unsuccessfully, then the daemon doesn't start and instead directly finishes
|
||||
unsuccessfully.
|
||||
If the daemon has started, it is the daemon's responsibility to detect failures
|
||||
in its dependencies.
|
||||
.Pp
|
||||
The dependency can be customized with zero or more flags:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Sy exit-code
|
||||
If the daemon is a virtual daemon, then the daemon's exit code is that of the
|
||||
specific
|
||||
.Ar dependency
|
||||
rather than whether all dependencies succeeded.
|
||||
The daemon exits as soon as the
|
||||
.Ar dependency
|
||||
exits, rather than waiting for all dependencies to exit.
|
||||
The
|
||||
.Sy exit-code-meaning
|
||||
field is set to that of the dependency.
|
||||
.Sy exit-code
|
||||
can at most be used on a single dependency for a daemon.
|
||||
.It Sy no-await
|
||||
Don't wait for the
|
||||
.Ar dependency
|
||||
to become ready before starting this daemon.
|
||||
This flag is meant for dependencies that the daemon can make use of, but isn't
|
||||
essential to the daemon itself becoming ready.
|
||||
It shouldn't be used if the daemon polls for the the dependency to come online,
|
||||
as it is more efficient to only start the daemon once the dependency is ready.
|
||||
.It Sy optional
|
||||
Start the daemon even if the
|
||||
.Ar dependency
|
||||
fails.
|
||||
The dependency is assumed to exist and a warning occurs if it doesn't exist.
|
||||
.El
|
||||
.Pp
|
||||
Dependencies can be forgotten using
|
||||
.Sy unset require Ar dependency .
|
||||
Flags on a dependency can be be unset using
|
||||
.Sy unset require Ar dependency flag ... .
|
||||
.It Sy unset Ar property
|
||||
Reset the given property to its default value.
|
||||
.It Sy tty Ar device
|
||||
If the daemon is a foreground daemon
|
||||
.Sy ( need tty
|
||||
is set), then connect the daemon to the terminal named
|
||||
.Ar device .
|
||||
.Pp
|
||||
The default value is the terminal
|
||||
.Xr init 8
|
||||
is attached to, usually
|
||||
.Pa tty1 .
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
Daemons inherit their environment from
|
||||
.Xr init 8
|
||||
with this additional environment:
|
||||
.Bl -tag -width "READYFD"
|
||||
.It Ev READYFD
|
||||
Daemons signal they are ready by writing a newline to the file descriptor
|
||||
mentioned in the
|
||||
.Ev READYFD
|
||||
environment variable as described in
|
||||
.Xr daemon 7 .
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /share/init/default -compact
|
||||
.It Pa /etc/init/
|
||||
Daemon configuration for the local system (first in search path).
|
||||
.It Pa /etc/init/default
|
||||
The configuration file for the
|
||||
.Sy default
|
||||
daemon.
|
||||
.It Pa /etc/init/local
|
||||
The configuration file for the
|
||||
.Sy local
|
||||
daemon which depends on the installation's local daemons.
|
||||
.It Pa /share/init/
|
||||
Default daemon configuration provided by the operating system (second in search
|
||||
path).
|
||||
.It Pa /var/log/
|
||||
Daemon log files.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
.Ss Configuring a daemon to start on boot
|
||||
The local system can be configured to start the
|
||||
.Sy exampled
|
||||
daemon by creating
|
||||
.Pa /etc/init/local
|
||||
with the following contents:
|
||||
.Bd -literal
|
||||
require exampled optional
|
||||
.Ed
|
||||
.Pp
|
||||
Additional lines can be included for any daemon you wish to start.
|
||||
The
|
||||
.Sy optional
|
||||
flag means the
|
||||
.Sy local
|
||||
daemon doesn't fail if the daemon fails.
|
||||
The top level daemons
|
||||
.Sy ( multi-user , single-user , ... )
|
||||
fails if the
|
||||
.Sy local
|
||||
daemon fails, which will shut down the operating system.
|
||||
The
|
||||
.Sy optional
|
||||
flag should only be omitted if a local daemon is critical and the boot should
|
||||
fail if the daemon fails.
|
||||
.Ss Creating a new virtual daemon
|
||||
The
|
||||
.Sy exampled
|
||||
daemon, which depends on the
|
||||
.Sy food , bard ,
|
||||
and
|
||||
.Sy quxd
|
||||
daemons and whose program file is called
|
||||
.Pa exampled ,
|
||||
can then be configured by creating
|
||||
.Pa /etc/init/exampled
|
||||
with the following contents:
|
||||
.Bd -literal
|
||||
require food
|
||||
require bard
|
||||
require quxd
|
||||
exec exampled
|
||||
.Ed
|
||||
.Ss Changing the log format
|
||||
The default log format of daemons and
|
||||
.Xr init 8 Ns 's
|
||||
own can be set by setting the properties in
|
||||
.Pa /etc/init/default .
|
||||
A few examples:
|
||||
.Bd -literal
|
||||
log-format full
|
||||
log-method append
|
||||
.Ed
|
||||
.Pp
|
||||
Uses the
|
||||
.Sy full
|
||||
log format and grows the log without limit, never losing data unless the
|
||||
filesystem space is exhausted.
|
||||
.Bd -literal
|
||||
log-control-messages false
|
||||
log-format none
|
||||
log-method rotate
|
||||
log-rotate-on-start true
|
||||
.Ed
|
||||
.Pp
|
||||
Provides plain rotated log files, by disabling control messages from
|
||||
.Xr init 8
|
||||
about starting/stopping the daemon, turning off log metadata, and also rotates
|
||||
the log when the deamon is started.
|
||||
.Ss Configuring a multi-user system
|
||||
The system can be configured to boot into multi-user mode by creating
|
||||
.Pa /etc/init/default
|
||||
with the following contents:
|
||||
.Bd -literal
|
||||
require multi-user exit-code
|
||||
.Ed
|
||||
.Ss Configuring an unattended system
|
||||
A fully unattended system that only starts the base system and the
|
||||
.Sy exampled
|
||||
daemon, shutting down when the
|
||||
.Sy exampled
|
||||
daemon finishes, can be done by first creating
|
||||
.Pa /etc/init/default
|
||||
with the following contents:
|
||||
.Bd -literal
|
||||
require no-user exit-code
|
||||
.Ed
|
||||
.Pp
|
||||
And then secondly creating
|
||||
.Pa /etc/init/local
|
||||
with the following contents:
|
||||
.Bd -literal
|
||||
require exampled exit-code
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr daemon 7 ,
|
||||
.Xr init 8
|
||||
.Sh BUGS
|
||||
The control messages mentioned in
|
||||
.Sy log-control-messages
|
||||
aren't implemented yet.
|
||||
.Pp
|
||||
The
|
||||
.Sy tty
|
||||
property isn't implemented yet and must be
|
||||
.Pa tty1
|
||||
if set.
|
|
@ -0,0 +1,113 @@
|
|||
.Dd September 19, 2022
|
||||
.Dt DAEMON 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm daemon
|
||||
.Nd system background process
|
||||
.Sh DESCRIPTION
|
||||
A daemon is a system background process that performs a task or continuously
|
||||
provides a service.
|
||||
.Xr init 8
|
||||
starts daemons on system startup per the
|
||||
.Xr init 5
|
||||
configuration and stops them on system shutdown.
|
||||
.Pp
|
||||
Conventions for daemons have varied between traditional init systems and this
|
||||
document describes the modern design of daemons suitable for this operating
|
||||
system.
|
||||
Daemons should default to the behavior described below, or offer the behavior
|
||||
through options if they need to be compatible with historic default behavior.
|
||||
.Pp
|
||||
A daemon is implemented as a system program, usually in
|
||||
.Pa /sbin
|
||||
inside the appropriate prefix,
|
||||
whose name conventionally is the name of the service it implements plus the
|
||||
letter d (as opposed to a client program).
|
||||
Its runtime dependencies on other daemons are declared ahead of time in the
|
||||
init system's configuration, so the daemons can be started in the right order.
|
||||
.Pp
|
||||
The process will be started per the init system's configuration with the
|
||||
appropriate command line arguments, environment variables, working directory,
|
||||
user, group, and so on.
|
||||
.Pp
|
||||
The process must remain in the foreground such that
|
||||
.Xr init 8
|
||||
can manage its lifetime.
|
||||
It must not
|
||||
.Xr fork 2
|
||||
to become a background process and escape
|
||||
the init system.
|
||||
The process should have no need to escape the controlling terminal by starting a
|
||||
new session using
|
||||
.Xr setsid 2 .
|
||||
Daemons should not write a pid file but instead be administered through the init
|
||||
system.
|
||||
.Pp
|
||||
Logs should be written to the standard error as it is non-buffered and is meant
|
||||
to contain messages that are not process output.
|
||||
Alternatively logs may be written to the standard output.
|
||||
The standard output may be the same file description as the standard error.
|
||||
The standard input should not be used and will be
|
||||
.Pa /dev/null .
|
||||
The log entries should be formatted as plain line; or if the program wants to
|
||||
supply additional meta data, one of the log formats described in
|
||||
.Xr init 5
|
||||
or the syslog format.
|
||||
.Xr syslog 3
|
||||
is discouraged but may be used if the program has additional meta data.
|
||||
On this operating system,
|
||||
.Xr syslog 3
|
||||
will write the log entry to the standard error instead of sending it to a
|
||||
centralized log service, which is unreliable on other operating systems.
|
||||
Daemons should prefer letting the init system manage the log files but may
|
||||
provide their own logging as appropriate.
|
||||
.Pp
|
||||
The process may be executed as root per the init system configuration.
|
||||
Privileges should be dropped after acquiring the needed protected resources.
|
||||
The main loop should run with the least privileges required, ideally as another
|
||||
user, potentially in a
|
||||
.Xr chroot 2
|
||||
or sandboxed environment.
|
||||
.Pp
|
||||
Continuous daemons providing a service should signal their readiness once the
|
||||
main loop is serving requests, such that the init system will start dependent
|
||||
daemons.
|
||||
Unfortunately there is no portable convention and this operating system uses the
|
||||
.Ev READYFD
|
||||
environment variable containing a file descriptor pointing to a writing pipe,
|
||||
where the daemon must write a newline upon readiness.
|
||||
Alternatively closing the pipe is considered readiness as a discouraged
|
||||
fallback.
|
||||
.Pp
|
||||
The process must exit 0 if the daemon has concluded its work and exit non-zero
|
||||
in the case of errors.
|
||||
The daemon may be restarted by the init system
|
||||
upon error per the configuration.
|
||||
.Pp
|
||||
The process must exit unconditionally when sent
|
||||
.Dv SIGTERM
|
||||
and should gracefully conclude its work immediately and recursively terminate
|
||||
any child processes.
|
||||
In this case, dying by the
|
||||
.Dv SIGTERM
|
||||
signal is considered a successful exit.
|
||||
The process is killed with
|
||||
.Dv SIGKILL
|
||||
if it does not gracefully terminate within a high system-specific timeout.
|
||||
.Sh EXAMPLES
|
||||
A daemon can signal readiness using this utility function:
|
||||
.Bd -literal -offset indent
|
||||
static void ready(void) {
|
||||
const char *readyfd_env = getenv("READYFD");
|
||||
if ( !readyfd_env )
|
||||
return;
|
||||
int readyfd = atoi(readyfd_env);
|
||||
char c = '\n';
|
||||
write(readyfd, &c, 1);
|
||||
close(readyfd);
|
||||
unsetenv("READYFD");
|
||||
}
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr init 5 ,
|
||||
.Xr init 8
|
|
@ -69,6 +69,21 @@ releasing Sortix x.y, foo." to allow the maintainer to easily
|
|||
.Xr grep 1
|
||||
for it after a release.
|
||||
.Sh CHANGES
|
||||
.Ss Add daemon support to init(8)
|
||||
.Xr init 8
|
||||
has gained
|
||||
.Xr daemon 7
|
||||
support with the new
|
||||
.Xr init 5
|
||||
configuration format.
|
||||
.Pp
|
||||
The old
|
||||
.Pa /etc/init/target
|
||||
configuration file is replaced by the
|
||||
.Sy default
|
||||
daemon in
|
||||
.Pa /etc/init/default .
|
||||
An upgrade hook will migrate the configuration.
|
||||
.Ss Add ports to the Sortix repository
|
||||
The ports have been moved from the porttix/srctix repositories into the
|
||||
.Pa ports/
|
||||
|
|
|
@ -357,8 +357,9 @@ if applicable restore boot priorities in your firmware.
|
|||
If you did not accept the bootloader, you will need to manually configure a
|
||||
bootloader to boot the new operating system.
|
||||
.Pp
|
||||
You will be given the choice between powering off the system, rebooting it, or
|
||||
directly booting the new system.
|
||||
You will be given the choice between powering off the system, rebooting it,
|
||||
halting it, or directly booting the new system.
|
||||
.Pp
|
||||
The last option will directly boot the new system in a chroot while the live
|
||||
environment remains in the background.
|
||||
If you invoked
|
||||
|
@ -369,10 +370,17 @@ Otherwise the computer will power off when the chroot environment terminates.
|
|||
Upon boot of the new system it will be configured in multi-user mode and you
|
||||
will be presented with a login screen.
|
||||
Authenticate as one of the local users and you will be given a shell.
|
||||
.Pp
|
||||
To power off the computer login as user
|
||||
.Sy poweroff
|
||||
and to reboot the computer login as user
|
||||
.Sy reboot .
|
||||
or run
|
||||
.Xr poweroff 8
|
||||
after logging in.
|
||||
To reboot the computer login as user
|
||||
.Sy reboot
|
||||
or run
|
||||
.Xr reboot 8
|
||||
after logging in.
|
||||
.Pp
|
||||
The
|
||||
.Xr user-guide 7
|
||||
|
|
|
@ -46,7 +46,9 @@ is the modern replacement with nanosecond precision.
|
|||
is the standard replacement.
|
||||
.Ss daemon
|
||||
Daemons should not background by double forking but rather stay in the
|
||||
foreground and be managed by
|
||||
foreground as described in
|
||||
.Xr daemon 7
|
||||
and be managed by
|
||||
.Xr init 8 .
|
||||
.Ss __dead
|
||||
.Dv noreturn
|
||||
|
|
|
@ -24,17 +24,16 @@ This is
|
|||
if the system is booted in multi-user mode.
|
||||
This is a root shell if booted in single-user mode.
|
||||
.Pp
|
||||
To power off from the login screen, login as user
|
||||
.Sy poweroff .
|
||||
To reboot, login as user
|
||||
.Sy reboot .
|
||||
.Pp
|
||||
To power off from a single-user boot root shell, run
|
||||
.Sy exit 0
|
||||
in the shell.
|
||||
To reboot, run
|
||||
.Sy exit 1
|
||||
in the shell.
|
||||
To power off the computer login as user
|
||||
.Sy poweroff
|
||||
or run
|
||||
.Xr poweroff 8
|
||||
after logging in.
|
||||
To reboot the computer login as user
|
||||
.Sy reboot
|
||||
or run
|
||||
.Xr reboot 8
|
||||
after logging in.
|
||||
.Ss Keyboard Layout
|
||||
The kernel has a default US keyboard layout compiled into it.
|
||||
.Pp
|
||||
|
|
|
@ -54,6 +54,7 @@ install: all
|
|||
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-leaked-files
|
||||
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-init
|
||||
|
||||
sysinstall: $(SYSINSTALL_OBJS)
|
||||
$(CC) $(SYSINSTALL_OBJS) -o $@ -lmount
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2016, 2021 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2015, 2016, 2021, 2022 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
|
||||
|
@ -198,25 +198,29 @@ bool fsck(struct filesystem* fs)
|
|||
const char* bdev_path = path_of_blockdevice(fs->bdev);
|
||||
printf("%s: Repairing filesystem due to inconsistency...\n", bdev_path);
|
||||
assert(fs->fsck);
|
||||
pid_t child_pid = fork();
|
||||
if ( child_pid < 0 )
|
||||
pid_t pid = fork();
|
||||
if ( pid < 0 )
|
||||
{
|
||||
warn("%s: Mandatory repair failed: fork", bdev_path);
|
||||
return false;
|
||||
}
|
||||
if ( child_pid == 0 )
|
||||
if ( pid == 0 )
|
||||
{
|
||||
execlp(fs->fsck, fs->fsck, "-fp", "--", bdev_path, (const char*) NULL);
|
||||
warn("%s: Failed to load filesystem checker: %s", bdev_path, fs->fsck);
|
||||
_Exit(127);
|
||||
}
|
||||
int code;
|
||||
if ( waitpid(child_pid, &code, 0) < 0 )
|
||||
{
|
||||
if ( waitpid(pid, &code, 0) < 0 )
|
||||
warn("waitpid");
|
||||
return false;
|
||||
else if ( WIFEXITED(code) &&
|
||||
(WEXITSTATUS(code) == 0 || WEXITSTATUS(code) == 1) )
|
||||
{
|
||||
// Successfully checked filesystem.
|
||||
fs->flags &= ~(FILESYSTEM_FLAG_FSCK_SHOULD | FILESYSTEM_FLAG_FSCK_MUST);
|
||||
return true;
|
||||
}
|
||||
if ( WIFSIGNALED(code) )
|
||||
else if ( WIFSIGNALED(code) )
|
||||
warnx("%s: Mandatory repair failed: %s: %s", bdev_path,
|
||||
fs->fsck, strsignal(WTERMSIG(code)));
|
||||
else if ( !WIFEXITED(code) )
|
||||
|
@ -228,14 +232,9 @@ bool fsck(struct filesystem* fs)
|
|||
else if ( WEXITSTATUS(code) & 2 )
|
||||
warnx("%s: Mandatory repair: %s: %s", bdev_path,
|
||||
fs->fsck, "System reboot is necessary");
|
||||
else if ( WEXITSTATUS(code) != 0 && WEXITSTATUS(code) != 1 )
|
||||
else
|
||||
warnx("%s: Mandatory repair failed: %s: %s", bdev_path,
|
||||
fs->fsck, "Filesystem checker was unsuccessful");
|
||||
else
|
||||
{
|
||||
fs->flags &= ~(FILESYSTEM_FLAG_FSCK_SHOULD | FILESYSTEM_FLAG_FSCK_MUST);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -338,82 +337,106 @@ bool mountpoint_mount(struct mountpoint* mountpoint)
|
|||
warnx("Failed to fsck %s", bdev_path);
|
||||
return false;
|
||||
}
|
||||
if ( !fs->driver )
|
||||
{
|
||||
warnx("%s: Don't know how to mount a %s filesystem",
|
||||
bdev_path, fs->fstype_name);
|
||||
return false;
|
||||
}
|
||||
const char* pretend_where = mountpoint->entry.fs_file;
|
||||
const char* where = mountpoint->absolute;
|
||||
if ( !fs->driver )
|
||||
{
|
||||
warnx("Failed mounting %s on %s: "
|
||||
"Don't know how to mount a %s filesystem",
|
||||
bdev_path, pretend_where, fs->fstype_name);
|
||||
return false;
|
||||
}
|
||||
struct stat st;
|
||||
if ( stat(where, &st) < 0 )
|
||||
{
|
||||
warn("stat: %s", where);
|
||||
warn("Failed mounting %s on %s: stat: %s",
|
||||
bdev_path, pretend_where, where);
|
||||
return false;
|
||||
}
|
||||
int readyfds[2];
|
||||
if ( pipe(readyfds) < 0 )
|
||||
{
|
||||
warn("Failed mounting %s on %s: pipe", bdev_path, pretend_where);
|
||||
return false;
|
||||
}
|
||||
if ( (mountpoint->pid = fork()) < 0 )
|
||||
{
|
||||
warn("%s: Unable to mount: fork", bdev_path);
|
||||
warn("Failed mounting %s on %s: fork", bdev_path, pretend_where);
|
||||
close(readyfds[0]);
|
||||
close(readyfds[1]);
|
||||
return false;
|
||||
}
|
||||
// TODO: This design is broken. The filesystem should tell us when it is
|
||||
// ready instead of having to poll like this.
|
||||
if ( mountpoint->pid == 0 )
|
||||
{
|
||||
close(readyfds[0]);
|
||||
char readyfdstr[sizeof(int) * 3];
|
||||
snprintf(readyfdstr, sizeof(readyfdstr), "%d", readyfds[1]);
|
||||
if ( setenv("READYFD", readyfdstr, 1) < 0 )
|
||||
{
|
||||
warn("Failed mounting %s on %s: setenv",
|
||||
bdev_path, pretend_where);
|
||||
_exit(127);
|
||||
}
|
||||
execlp(fs->driver, fs->driver, "--foreground", bdev_path, where,
|
||||
"--pretend-mount-path", pretend_where, (const char*) NULL);
|
||||
warn("%s: Failed to load filesystem driver: %s", bdev_path, fs->driver);
|
||||
warn("Failed mount %s on %s: execvp: %s",
|
||||
bdev_path, pretend_where, fs->driver);
|
||||
_exit(127);
|
||||
}
|
||||
while ( true )
|
||||
close(readyfds[1]);
|
||||
char c;
|
||||
struct stat newst;
|
||||
ssize_t amount = read(readyfds[0], &c, 1);
|
||||
close(readyfds[0]);
|
||||
if ( 0 <= amount )
|
||||
{
|
||||
struct stat newst;
|
||||
if ( stat(where, &newst) < 0 )
|
||||
if ( !stat(where, &newst) )
|
||||
{
|
||||
warn("stat: %s", where);
|
||||
if ( unmount(where, 0) < 0 && errno != ENOMOUNT )
|
||||
warn("unmount: %s", where);
|
||||
else if ( errno == ENOMOUNT )
|
||||
kill(mountpoint->pid, SIGQUIT);
|
||||
int code;
|
||||
waitpid(mountpoint->pid, &code, 0);
|
||||
mountpoint->pid = -1;
|
||||
return false;
|
||||
}
|
||||
if ( newst.st_dev != st.st_dev || newst.st_ino != st.st_ino )
|
||||
break;
|
||||
int code;
|
||||
pid_t child = waitpid(mountpoint->pid, &code, WNOHANG);
|
||||
if ( child < 0 )
|
||||
{
|
||||
warn("waitpid");
|
||||
return false;
|
||||
}
|
||||
if ( child != 0 )
|
||||
{
|
||||
mountpoint->pid = -1;
|
||||
if ( WIFSIGNALED(code) )
|
||||
warnx("%s: Mount failed: %s: %s", bdev_path, fs->driver,
|
||||
strsignal(WTERMSIG(code)));
|
||||
else if ( !WIFEXITED(code) )
|
||||
warnx("%s: Mount failed: %s: %s", bdev_path, fs->driver,
|
||||
"Unexpected unusual termination");
|
||||
else if ( WEXITSTATUS(code) == 127 )
|
||||
warnx("%s: Mount failed: %s: %s", bdev_path, fs->driver,
|
||||
"Filesystem driver is absent");
|
||||
else if ( WEXITSTATUS(code) == 0 )
|
||||
warnx("%s: Mount failed: %s: Unexpected successful exit",
|
||||
bdev_path, fs->driver);
|
||||
if ( newst.st_dev != st.st_dev || newst.st_ino != st.st_ino )
|
||||
return true;
|
||||
else
|
||||
warnx("%s: Mount failed: %s: Exited with status %i", bdev_path,
|
||||
fs->driver, WEXITSTATUS(code));
|
||||
return false;
|
||||
warnx("Failed mount %s on %s: %s: "
|
||||
"No mounted filesystem appeared: %s",
|
||||
bdev_path, pretend_where, fs->driver, where);
|
||||
}
|
||||
struct timespec delay = timespec_make(0, 50L * 1000L * 1000L);
|
||||
nanosleep(&delay, NULL);
|
||||
else
|
||||
warn("Failed mounting %s on %s: %s, stat: %s",
|
||||
bdev_path, pretend_where, fs->driver, where);
|
||||
}
|
||||
return true;
|
||||
else
|
||||
warn("Failed mounting %s on %s: %s, Failed to read readiness",
|
||||
bdev_path, pretend_where, fs->driver);
|
||||
if ( unmount(where, 0) < 0 )
|
||||
{
|
||||
if ( errno != ENOMOUNT )
|
||||
warn("Failed mounting %s on %s: unmount: %s",
|
||||
bdev_path, pretend_where, where);
|
||||
kill(mountpoint->pid, SIGQUIT);
|
||||
}
|
||||
int code;
|
||||
pid_t child = waitpid(mountpoint->pid, &code, 0);
|
||||
mountpoint->pid = -1;
|
||||
if ( child < 0 )
|
||||
warn("Failed mounting %s on %s: %s: waitpid",
|
||||
bdev_path, pretend_where, fs->driver);
|
||||
else if ( WIFSIGNALED(code) )
|
||||
warnx("Failed mounting %s on %s: %s: %s",
|
||||
bdev_path, pretend_where, fs->driver,
|
||||
strsignal(WTERMSIG(code)));
|
||||
else if ( !WIFEXITED(code) )
|
||||
warnx("Failed mounting %s on %s: %s: Unexpected unusual termination",
|
||||
bdev_path, pretend_where, fs->driver);
|
||||
else if ( WEXITSTATUS(code) == 127 )
|
||||
warnx("Failed mounting %s on %s: %s: "
|
||||
"Filesystem driver could not be executed",
|
||||
bdev_path, pretend_where, fs->driver);
|
||||
else if ( WEXITSTATUS(code) == 0 )
|
||||
warnx("Failed mounting %s on %s: %s: Unexpected successful exit",
|
||||
bdev_path, pretend_where, fs->driver);
|
||||
else
|
||||
warnx("Failed mounting %s on %s: %s: Exited with status %i",
|
||||
bdev_path, pretend_where, fs->driver, WEXITSTATUS(code));
|
||||
return false;
|
||||
}
|
||||
|
||||
void mountpoint_unmount(struct mountpoint* mountpoint)
|
||||
|
|
|
@ -257,6 +257,45 @@ void upgrade_prepare(const struct release* old_release,
|
|||
free(installed);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: After releasing Sortix 1.1, remove this compatibility.
|
||||
if ( hook_needs_to_be_run(source_prefix, target_prefix, "sortix-1.1-init") )
|
||||
{
|
||||
char* init_target_path = join_paths(target_prefix, "/etc/init/target");
|
||||
char* init_default_path =
|
||||
join_paths(target_prefix, "/etc/init/default");
|
||||
if ( !init_target_path || !init_default_path )
|
||||
{
|
||||
warn("malloc");
|
||||
_exit(2);
|
||||
}
|
||||
char* line = read_string_file(init_target_path);
|
||||
if ( line )
|
||||
{
|
||||
printf(" - Converting /etc/init/target to /etc/init/default...\n");
|
||||
FILE* init_default_fp = fopen(init_default_path, "w");
|
||||
if ( !init_default_fp ||
|
||||
fprintf(init_default_fp, "require %s exit-code\n", line) < 0 ||
|
||||
fclose(init_default_fp) == EOF )
|
||||
{
|
||||
warn("%s", init_default_path);
|
||||
_exit(2);
|
||||
}
|
||||
free(line);
|
||||
if ( unlink(init_target_path) < 0 )
|
||||
{
|
||||
warn("unlink: %s", init_target_path);
|
||||
_exit(2);
|
||||
}
|
||||
}
|
||||
else if ( errno != ENOENT )
|
||||
{
|
||||
warn("%s", init_target_path);
|
||||
_exit(2);
|
||||
}
|
||||
free(init_target_path);
|
||||
free(init_default_path);
|
||||
}
|
||||
}
|
||||
|
||||
void upgrade_finalize(const struct release* old_release,
|
||||
|
|
|
@ -828,22 +828,24 @@ int main(void)
|
|||
while ( true )
|
||||
{
|
||||
prompt(input, sizeof(input),
|
||||
"Install " BRAND_DISTRIBUTION_NAME "? (yes/no/poweroff/reboot)",
|
||||
"yes");
|
||||
"Install " BRAND_DISTRIBUTION_NAME "? "
|
||||
"(yes/no/poweroff/reboot/halt)", "yes");
|
||||
if ( !strcasecmp(input, "yes") )
|
||||
break;
|
||||
else if ( !strcasecmp(input, "no") )
|
||||
{
|
||||
text("Answer '!' to get a shell. Type !man to view the "
|
||||
"installation(7) manual page.\n");
|
||||
text("Alternatively, you can answer 'poweroff' or 'reboot' to "
|
||||
"cancel the installation.\n");
|
||||
text("Alternatively, you can answer 'poweroff', 'reboot', or "
|
||||
"'halt' to cancel the installation.\n");
|
||||
continue;
|
||||
}
|
||||
else if ( !strcasecmp(input, "poweroff") )
|
||||
exit(0);
|
||||
else if ( !strcasecmp(input, "reboot") )
|
||||
exit(1);
|
||||
else if ( !strcasecmp(input, "halt") )
|
||||
exit(2);
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
@ -1033,7 +1035,8 @@ int main(void)
|
|||
else
|
||||
warn("mkdir: etc/init");
|
||||
}
|
||||
install_configurationf("etc/init/target", "w", "multi-user\n");
|
||||
install_configurationf("etc/init/default", "w",
|
||||
"require multi-user exit-code\n");
|
||||
|
||||
text("Congratulations, the system is now functional! This is a good time "
|
||||
"to do further customization of the system.\n\n");
|
||||
|
@ -1132,17 +1135,21 @@ int main(void)
|
|||
|
||||
text("Upon boot, you'll be greeted with a login screen. Enter your "
|
||||
"credentials to get a command line. Login as user 'poweroff' as "
|
||||
"described in login(8) to power off the machine. After logging in, "
|
||||
"type 'man user-guide' to view the introductory documentation.\n");
|
||||
"described in login(8) to power off the machine or run poweroff(8). "
|
||||
"After logging in, type 'man user-guide' to view the introductory "
|
||||
"documentation.\n");
|
||||
text("\n");
|
||||
|
||||
while ( true )
|
||||
{
|
||||
prompt(input, sizeof(input), "What now? (poweroff/reboot/boot)", "boot");
|
||||
prompt(input, sizeof(input),
|
||||
"What now? (poweroff/reboot/halt/boot)", "boot");
|
||||
if ( !strcasecmp(input, "poweroff") )
|
||||
exit(0);
|
||||
if ( !strcasecmp(input, "reboot") )
|
||||
exit(1);
|
||||
if ( !strcasecmp(input, "halt") )
|
||||
exit(2);
|
||||
if ( !strcasecmp(input, "boot") )
|
||||
{
|
||||
unmount_all_but_root();
|
||||
|
|
|
@ -775,7 +775,7 @@ int main(void)
|
|||
while ( true )
|
||||
{
|
||||
promptx(input, sizeof(input),
|
||||
"Upgrade? (yes/no/poweroff/reboot)", "yes", true);
|
||||
"Upgrade? (yes/no/poweroff/reboot/halt)", "yes", true);
|
||||
if ( !strcasecmp(input, "yes") )
|
||||
break;
|
||||
else if ( !strcasecmp(input, "no") )
|
||||
|
@ -784,14 +784,16 @@ int main(void)
|
|||
"upgrade(7) manual page. You can edit the upgrade.conf(5) "
|
||||
"configuration file of the target system to change which "
|
||||
"upgrade operations are performed.\n");
|
||||
text("Alternatively, you can answer 'poweroff' or 'reboot' to "
|
||||
"cancel the upgrade.\n");
|
||||
text("Alternatively, you can answer 'poweroff', 'reboot', or "
|
||||
"'halt' or cancel the upgrade.\n");
|
||||
continue;
|
||||
}
|
||||
else if ( !strcasecmp(input, "poweroff") )
|
||||
exit(0);
|
||||
else if ( !strcasecmp(input, "reboot") )
|
||||
exit(1);
|
||||
else if ( !strcasecmp(input, "halt") )
|
||||
exit(2);
|
||||
else if ( !strcasecmp(input, "!") )
|
||||
break;
|
||||
else
|
||||
|
@ -928,10 +930,13 @@ int main(void)
|
|||
|
||||
while ( true )
|
||||
{
|
||||
prompt(input, sizeof(input), "What now? (poweroff/reboot)", "reboot");
|
||||
prompt(input, sizeof(input),
|
||||
"What now? (poweroff/reboot/halt)", "reboot");
|
||||
if ( !strcasecmp(input, "poweroff") )
|
||||
return 0;
|
||||
if ( !strcasecmp(input, "reboot") )
|
||||
return 1;
|
||||
if ( !strcasecmp(input, "halt") )
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ default=
|
|||
directory=
|
||||
enable_append_title=true
|
||||
enable_src=
|
||||
init_target=
|
||||
liveconfig=
|
||||
operand=1
|
||||
random_seed=false
|
||||
|
@ -53,6 +54,8 @@ for argument do
|
|||
--disable-src) enable_src=false ;;
|
||||
--enable-append-title) enable_append_title=true ;;
|
||||
--enable-src) enable_src=true ;;
|
||||
--init-target=*) init_target=$parameter ;;
|
||||
--init-target) previous_option=init_target ;;
|
||||
--liveconfig=*) liveconfig=$parameter ;;
|
||||
--liveconfig) previous_option=liveconfig ;;
|
||||
--random-seed) random_seed=true ;;
|
||||
|
@ -137,6 +140,13 @@ mkdir -p -- "$directory/boot/grub"
|
|||
printf "base_menu_title=\"\$base_menu_title - \"'%s'\n" \
|
||||
"$(printf '%s\n' "$append_title" | sed "s/'/'\\\\''/g")"
|
||||
fi
|
||||
if [ -n "$init_target" ]; then
|
||||
printf 'function hook_menu_pre {\n'
|
||||
printf ' menuentry "Sortix (%s)" {\n' "$init_target"
|
||||
printf ' load_sortix -- /sbin/init --target=%s\n' "$init_target"
|
||||
printf ' }\n'
|
||||
printf '}\n'
|
||||
fi
|
||||
if [ -e "$directory/boot/liveconfig.tar.xz" ]; then
|
||||
printf 'function hook_initrd_post {\n'
|
||||
printf ' echo -n "Loading /boot/liveconfig.tar.xz (%s) ... "\n' \
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
.Op Fl \-disable-src
|
||||
.Op Fl \-enable-append-title
|
||||
.Op Fl \-enable-src
|
||||
.Op Fl \-init-target Ns = Ns Ar target
|
||||
.Op Fl \-liveconfig Ns = Ns Ar liveconfig-directory
|
||||
.Op Fl \-random-seed
|
||||
.Op Fl \-timeout Ns = Ns Ar boot-menu-timeout
|
||||
|
@ -110,6 +111,12 @@ by setting
|
|||
.Sy enable_src
|
||||
GRUB variable to
|
||||
.Sy true .
|
||||
.It Fl \-init-target Ns = Ns Ar target
|
||||
Add a new first menu entry that boots the
|
||||
.Ar target
|
||||
daemon as the
|
||||
.Xr init 8
|
||||
target.
|
||||
.It Fl \-liveconfig Ns = Ns Ar liveconfig-directory
|
||||
Overlay the
|
||||
.Ar liveconfig-directory
|
||||
|
@ -222,6 +229,16 @@ bootloader menu timeout to 2 seconds:
|
|||
tix-iso-bootconfig --default=1 --timeout=2 bootconfig
|
||||
tix-iso-add sortix.iso bootconfig
|
||||
.Ed
|
||||
.Ss Non-interactive Live Environment
|
||||
The interactive user environment can be disabled by setting the default
|
||||
.Xr init 8
|
||||
.Fl \-target
|
||||
to
|
||||
.Sy no-user :
|
||||
.Bd -literal
|
||||
tix-iso-bootconfig --init-target=no-user bootconfig
|
||||
tix-iso-add sortix.iso bootconfig
|
||||
.Ed
|
||||
.Ss Add to Bootloader Menu Title
|
||||
To customize a release so the bootloader menu title is appended with a message
|
||||
of your choice:
|
||||
|
@ -234,5 +251,6 @@ tix-iso-add sortix.iso bootconfig
|
|||
.Xr kernel 7 ,
|
||||
.Xr release-iso-bootconfig 7 ,
|
||||
.Xr release-iso-modification 7 ,
|
||||
.Xr init 8 ,
|
||||
.Xr tix-iso-add 8 ,
|
||||
.Xr tix-iso-liveconfig 8
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/sh
|
||||
# Copyright (c) 2017 Jonas 'Sortie' Termansen.
|
||||
# Copyright (c) 2017, 2022 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
|
||||
|
@ -18,6 +18,7 @@
|
|||
|
||||
set -e
|
||||
|
||||
daemons=
|
||||
directory=
|
||||
hostname=
|
||||
kblayout=
|
||||
|
@ -41,6 +42,8 @@ for argument do
|
|||
|
||||
case $dashdash$argument in
|
||||
--) dashdash=yes ;;
|
||||
--daemons=*) daemons=$parameter ;;
|
||||
--daemons) previous_option=daemons ;;
|
||||
--hostname=*) hostname=$parameter ;;
|
||||
--hostname) previous_option=hostname ;;
|
||||
--kblayout=*) kblayout=$parameter ;;
|
||||
|
@ -73,6 +76,15 @@ fi
|
|||
|
||||
mkdir -p "$directory"
|
||||
|
||||
|
||||
if [ -n "$daemons" ]; then
|
||||
mkdir -p -- "$directory/etc/init"
|
||||
true > "$directory/etc/init/local"
|
||||
for daemon in $daemons; do
|
||||
printf "require %s optional\n" "$daemon" >> "$directory/etc/init/local"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$hostname" ]; then
|
||||
mkdir -p -- "$directory/etc"
|
||||
printf "%s\n" "$hostname" > "$directory/etc/hostname"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
.Nd generate additional live environment configuration for Sortix .iso releases
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl \-daemons Ns = Ns Ar daemons
|
||||
.Op Fl \-hostname Ns = Ns Ar hostname
|
||||
.Op Fl \-kblayout Ns = Ns Ar kblayout
|
||||
.Op Fl \-videomode Ns = Ns Ar videomode
|
||||
|
@ -43,6 +44,15 @@ installations made from inside it.
|
|||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width "12345678"
|
||||
.It Fl \-daemons Ns = Ns Ar daemons
|
||||
Configures the
|
||||
.Sy local
|
||||
daemon to optionally depend on each of the
|
||||
.Ar daemons
|
||||
in
|
||||
.Pa output-directory/etc/init/local .
|
||||
(See
|
||||
.Xr init 5 )
|
||||
.It Fl \-hostname Ns = Ns Ar hostname
|
||||
Set the live environment's hostname by writing
|
||||
.Ar hostname
|
||||
|
|
|
@ -77,9 +77,13 @@ mkdir "$tmp/etc"
|
|||
cp "$sysroot/etc/fstab" "$tmp/etc/fstab"
|
||||
mkdir "$tmp/etc/init"
|
||||
if $sysmerge; then
|
||||
echo chain-merge > "$tmp/etc/init/target"
|
||||
cat > "$tmp/etc/init/default" << EOF
|
||||
require chain-merge exit-code
|
||||
EOF
|
||||
else
|
||||
echo chain > "$tmp/etc/init/target"
|
||||
cat > "$tmp/etc/init/default" << EOF
|
||||
require chain exit-code
|
||||
EOF
|
||||
fi
|
||||
mkdir -p "$sysroot/boot"
|
||||
mkinitrd --format=sortix-initrd-2 "$tmp" -o "$sysroot/boot/sortix.initrd" > /dev/null
|
||||
|
|
|
@ -20,9 +20,10 @@ env
|
|||
expr
|
||||
false
|
||||
find
|
||||
halt
|
||||
head
|
||||
id
|
||||
help
|
||||
id
|
||||
kernelinfo
|
||||
kill
|
||||
ln
|
||||
|
@ -35,11 +36,13 @@ mv
|
|||
nl
|
||||
pager
|
||||
passwd
|
||||
poweroff
|
||||
ps
|
||||
pstree
|
||||
pwd
|
||||
readlink
|
||||
realpath
|
||||
reboot
|
||||
rm
|
||||
rmdir
|
||||
sleep
|
||||
|
|
|
@ -31,6 +31,7 @@ env \
|
|||
expr \
|
||||
false \
|
||||
find \
|
||||
halt \
|
||||
head \
|
||||
help \
|
||||
id \
|
||||
|
@ -71,6 +72,8 @@ uptime \
|
|||
wc \
|
||||
which \
|
||||
yes \
|
||||
poweroff \
|
||||
reboot \
|
||||
|
||||
BINARIES=\
|
||||
$(BINARIES_EXCEPT_INSTALL) \
|
||||
|
@ -94,6 +97,9 @@ unmount \
|
|||
|
||||
MANPAGES8=\
|
||||
chroot.8 \
|
||||
halt.8 \
|
||||
poweroff.8 \
|
||||
reboot.8 \
|
||||
unmount.8 \
|
||||
|
||||
all: $(BINARIES) $(SBINS)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2013, 2015, 2016, 2021 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2021 Juhani 'nortti' Krekelä.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
|
@ -27,49 +27,11 @@
|
|||
|
||||
#define ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0]))
|
||||
|
||||
static const char* tty_name(void)
|
||||
{
|
||||
int tty_fd = open("/dev/tty", O_RDONLY);
|
||||
const char* result = NULL;
|
||||
if ( 0 <= tty_fd )
|
||||
{
|
||||
result = ttyname(tty_fd);
|
||||
close(tty_fd);
|
||||
}
|
||||
return result ? result : "/dev/tty";
|
||||
}
|
||||
|
||||
static void suggest_logout(void)
|
||||
{
|
||||
fprintf(stderr, " Exiting your shell normally to logout.\n");
|
||||
}
|
||||
|
||||
static void suggest_poweroff(void)
|
||||
{
|
||||
if ( strcmp(tty_name(), "/dev/tty1") != 0 )
|
||||
fprintf(stderr, " Powering off on /dev/tty1.\n");
|
||||
else if ( getenv("LOGIN_PID") )
|
||||
{
|
||||
fprintf(stderr, " Exiting your shell normally to logout.\n");
|
||||
fprintf(stderr, " Login as user 'poweroff' to power off computer.\n");
|
||||
}
|
||||
else
|
||||
fprintf(stderr, " Exiting your shell normally to poweroff.\n");
|
||||
}
|
||||
|
||||
static void suggest_reboot(void)
|
||||
{
|
||||
if ( strcmp(tty_name(), "/dev/tty1") != 0 )
|
||||
fprintf(stderr, " Rebooting on /dev/tty1.\n");
|
||||
else if ( getenv("LOGIN_PID") )
|
||||
{
|
||||
fprintf(stderr, " Exiting your shell normally to logout.\n");
|
||||
fprintf(stderr, " Login as user 'reboot' to reboot computer.\n");
|
||||
}
|
||||
else
|
||||
fprintf(stderr, " Exiting your shell with 'exit 1' to reboot.\n");
|
||||
}
|
||||
|
||||
enum category
|
||||
{
|
||||
NONE,
|
||||
|
@ -79,7 +41,6 @@ enum category
|
|||
MOUNT,
|
||||
PAGER,
|
||||
POWEROFF,
|
||||
REBOOT,
|
||||
RW,
|
||||
SHELL,
|
||||
UNMOUNT,
|
||||
|
@ -122,12 +83,9 @@ struct command commands[] =
|
|||
{PAGER, "more", NULL, NULL},
|
||||
{PAGER, "pager", "system", NULL},
|
||||
|
||||
{POWEROFF, "halt", NULL, NULL},
|
||||
{POWEROFF, "poweroff", NULL, suggest_poweroff},
|
||||
{POWEROFF, "poweroff", "system", NULL},
|
||||
{POWEROFF, "shutdown", NULL, NULL},
|
||||
|
||||
{REBOOT, "reboot", NULL, suggest_reboot},
|
||||
|
||||
{RW, "dd", NULL, NULL},
|
||||
{RW, "rw", "system", NULL},
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
.Dd December 13, 2021
|
||||
.Dt HALT 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm halt
|
||||
.Nd halt the computer
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
gracefully halts the computer by sending a request to the appropriate
|
||||
.Xr init 8
|
||||
process.
|
||||
.Sh EXIT STATUS
|
||||
.Nm
|
||||
will exit 0 on success and non-zero otherwise.
|
||||
.Sh SEE ALSO
|
||||
.Xr init 8 ,
|
||||
.Xr poweroff 8 ,
|
||||
.Xr reboot 8
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2022 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.
|
||||
*
|
||||
* halt.c
|
||||
* Halts the computer.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
while ( (opt = getopt(argc, argv, "")) != -1 )
|
||||
{
|
||||
switch ( opt )
|
||||
{
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( optind < argc )
|
||||
errx(1, "extra operand: %s", argv[optind]);
|
||||
|
||||
pid_t init_pid = 1;
|
||||
// TODO: Use a more reliable getinit() approach that also works in sshd.
|
||||
if ( getenv("INIT_PID") )
|
||||
init_pid = atoll(getenv("INIT_PID"));
|
||||
|
||||
if ( kill(init_pid, SIGQUIT) < 0 )
|
||||
err(1, "kill: %" PRIdPID, init_pid);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
.Dd December 13, 2021
|
||||
.Dt POWEROFF 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm poweroff
|
||||
.Nd power off the computer
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
gracefully powers off the computer by sending a request to the appropriate
|
||||
.Xr init 8
|
||||
process.
|
||||
.Sh EXIT STATUS
|
||||
.Nm
|
||||
will exit 0 on success and non-zero otherwise.
|
||||
.Sh SEE ALSO
|
||||
.Xr halt 8 ,
|
||||
.Xr init 8 ,
|
||||
.Xr reboot 8
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2022 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.
|
||||
*
|
||||
* poweroff.c
|
||||
* Powers off the computer.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
while ( (opt = getopt(argc, argv, "")) != -1 )
|
||||
{
|
||||
switch ( opt )
|
||||
{
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( optind < argc )
|
||||
errx(1, "extra operand: %s", argv[optind]);
|
||||
|
||||
pid_t init_pid = 1;
|
||||
// TODO: Use a more reliable getinit() approach that also works in sshd.
|
||||
if ( getenv("INIT_PID") )
|
||||
init_pid = atoll(getenv("INIT_PID"));
|
||||
|
||||
if ( kill(init_pid, SIGTERM) < 0 )
|
||||
err(1, "kill: %" PRIdPID, init_pid);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
.Dd December 13, 2021
|
||||
.Dt REBOOT 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm reboot
|
||||
.Nd reboot the computer
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
gracefully reboots the computer by sending a request to the appropriate
|
||||
.Xr init 8
|
||||
process.
|
||||
.Sh EXIT STATUS
|
||||
.Nm
|
||||
will exit 0 on success and non-zero otherwise.
|
||||
.Sh SEE ALSO
|
||||
.Xr halt 8 ,
|
||||
.Xr init 8 ,
|
||||
.Xr poweroff 8
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2022 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.
|
||||
*
|
||||
* reboot.c
|
||||
* Reboots the computer.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int opt;
|
||||
while ( (opt = getopt(argc, argv, "")) != -1 )
|
||||
{
|
||||
switch ( opt )
|
||||
{
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( optind < argc )
|
||||
errx(1, "extra operand: %s", argv[optind]);
|
||||
|
||||
pid_t init_pid = 1;
|
||||
// TODO: Use a more reliable getinit() approach that also works in sshd.
|
||||
if ( getenv("INIT_PID") )
|
||||
init_pid = atoll(getenv("INIT_PID"));
|
||||
|
||||
if ( kill(init_pid, SIGINT) < 0 )
|
||||
err(1, "kill: %" PRIdPID, init_pid);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue