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
|
||||||
mkdir -p $(LIVE_INITRD).d/etc
|
mkdir -p $(LIVE_INITRD).d/etc
|
||||||
mkdir -p $(LIVE_INITRD).d/etc/init
|
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:0:root:/root:sh" > $(LIVE_INITRD).d/etc/passwd
|
||||||
echo "root::0:root" > $(LIVE_INITRD).d/etc/group
|
echo "root::0:root" > $(LIVE_INITRD).d/etc/group
|
||||||
mkdir -p $(LIVE_INITRD).d/home
|
mkdir -p $(LIVE_INITRD).d/home
|
||||||
|
|
|
@ -720,6 +720,18 @@ void TerminationHandler(int)
|
||||||
should_terminate = true;
|
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,
|
int fsmarshall_main(const char* argv0,
|
||||||
const char* mount_path,
|
const char* mount_path,
|
||||||
bool foreground,
|
bool foreground,
|
||||||
|
@ -756,6 +768,8 @@ int fsmarshall_main(const char* argv0,
|
||||||
exit(0);
|
exit(0);
|
||||||
setpgid(0, 0);
|
setpgid(0, 0);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
ready();
|
||||||
|
|
||||||
dev->SpawnSyncThread();
|
dev->SpawnSyncThread();
|
||||||
|
|
||||||
|
|
262
init/init.8
262
init/init.8
|
@ -6,16 +6,27 @@
|
||||||
.Nd system initialization
|
.Nd system initialization
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm init
|
.Nm init
|
||||||
.Op Fl \-target Ns "=" Ns Ar init-target
|
.Op Fl qsv
|
||||||
|
.Op Fl \-target Ns "=" Ns Ar default-daemon
|
||||||
.Op Fl \-
|
.Op Fl \-
|
||||||
.Op Ar chain-init ...
|
.Op Ar chain-init ...
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
is the first program run after system startup and is responsible for
|
is the first program run after system startup and is responsible for
|
||||||
initializing the operating system and starting the specified
|
initializing the operating system.
|
||||||
.Ar init-target .
|
.Pp
|
||||||
This is normally a login screen, a root shell, or a dedicated special purpose
|
Each
|
||||||
program.
|
.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
|
.Pp
|
||||||
The
|
The
|
||||||
.Xr kernel 7
|
.Xr kernel 7
|
||||||
|
@ -34,56 +45,30 @@ If the system is installed on a harddisk, then the initrd is a minimal system
|
||||||
made with
|
made with
|
||||||
.Xr update-initrd 8
|
.Xr update-initrd 8
|
||||||
that will search for the actual root filesystem and chain init it.
|
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
|
The next stage init will recognize itself as the intended system and complete
|
||||||
system startup.
|
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:
|
|
||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width "single-user" -compact -offset indent
|
The options are as follows:
|
||||||
.It Sy chain
|
.Bl -tag -width "12345678"
|
||||||
mount real root filesystem and run its
|
.It Fl q , \-quiet
|
||||||
.Nm .
|
Write status updates to the terminal only about failed daemons.
|
||||||
.It Sy chain-merge
|
This behavior is the default.
|
||||||
like
|
.It Fl s , \-silent
|
||||||
.Sy chain
|
Never write status updates about daemons to the terminal.
|
||||||
but run
|
.It Fl t , \-target Ns "=" Ns Ar default-daemon
|
||||||
.Pa /sysmerge/sbin/init
|
Boot
|
||||||
with the
|
.Ar default-daemon
|
||||||
.Sy merge
|
as the target.
|
||||||
target.
|
The
|
||||||
.It Sy merge
|
.Sy default
|
||||||
finish a
|
daemon configuration is changed to only require the
|
||||||
.Xr sysmerge 8
|
.Ar default-daemon
|
||||||
upgrade and then execute the real
|
dependency with the
|
||||||
.Nm
|
.Sy exit-only
|
||||||
with its default target.
|
flag.
|
||||||
.It Sy multi-user
|
.It Fl v , \-verbose
|
||||||
boot to
|
Write all status updates about daemons starting and stopping to the terminal
|
||||||
.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).
|
|
||||||
.El
|
.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
|
.Ss Cleanup of /tmp and /var/run
|
||||||
.Nm
|
.Nm
|
||||||
deletes everything inside of
|
deletes everything inside of
|
||||||
|
@ -104,23 +89,24 @@ will scan every block device for valid partition tables and create the
|
||||||
corresponding partition devices in
|
corresponding partition devices in
|
||||||
.Pa /dev .
|
.Pa /dev .
|
||||||
.Ss Chain Initialization
|
.Ss Chain Initialization
|
||||||
The
|
If the target is
|
||||||
.Sy chain
|
.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
|
.Pa /etc/fstab
|
||||||
(see
|
(see
|
||||||
.Xr fstab 5 )
|
.Xr fstab 5 ) .
|
||||||
and runs the next
|
This configuration file is a copy of the real file made by
|
||||||
.Nm
|
|
||||||
program.
|
|
||||||
This is used by
|
|
||||||
.Xr update-initrd 8
|
.Xr update-initrd 8
|
||||||
to make a bootstrap
|
when it makes the bootstrap
|
||||||
.Xr initrd 7 .
|
.Xr initrd 7 .
|
||||||
.Pp
|
.Pp
|
||||||
Every block device and partition is scanned to determine if it is the root
|
The root filesystem is found by searching each block device and partition.
|
||||||
filesystem.
|
It is checked for consistency if necessary and mounted read-only if the check
|
||||||
It is checked for consistency if necessary.
|
fails.
|
||||||
It is mounted at
|
It is mounted at
|
||||||
.Pa /tmp/fs.XXXXXX
|
.Pa /tmp/fs.XXXXXX
|
||||||
and the
|
and the
|
||||||
|
@ -133,6 +119,34 @@ Finally the
|
||||||
program (or
|
program (or
|
||||||
.Ar chain-init
|
.Ar chain-init
|
||||||
if specified) of the target root filesystem is run inside a chroot.
|
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
|
.Ss Configuration
|
||||||
Once the
|
Once the
|
||||||
.Nm
|
.Nm
|
||||||
|
@ -150,46 +164,52 @@ set keyboard layout (see
|
||||||
set graphics resolution (see
|
set graphics resolution (see
|
||||||
.Xr videomode 5 )
|
.Xr videomode 5 )
|
||||||
.El
|
.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
|
.Ss Merge
|
||||||
The
|
If the target is
|
||||||
.Sy merge
|
.Sy merge ,
|
||||||
target completes a delayed system upgrade by invoking the
|
then a delayed system upgrade is completed by invoking
|
||||||
.Xr sysmerge 8
|
.Xr sysmerge 8
|
||||||
at
|
at
|
||||||
.Pa /sysmerge/sbin/sysmerge
|
.Pa /sysmerge/sbin/sysmerge
|
||||||
with the
|
with the
|
||||||
.Ar --booting
|
.Ar --booting
|
||||||
option.
|
option.
|
||||||
|
.Pp
|
||||||
If the upgrade succeeds, the temporary
|
If the upgrade succeeds, the temporary
|
||||||
.Nm
|
.Pa /sysmerge/sbin/init
|
||||||
deinitializes the system and invokes the real (now upgraded)
|
deinitializes the system and invokes the real (now upgraded)
|
||||||
.Nm
|
.Pa /sbin/init ,
|
||||||
which will restart system initialization in the normal fashion.
|
which will restart system initialization in the normal fashion.
|
||||||
.Ss Session
|
.Ss Daemons
|
||||||
Finally
|
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
|
.Nm
|
||||||
will start the target program according to its initialization target.
|
exits with the same error code and the kernel shuts down the machine.
|
||||||
This will be a login screen, a root shell, or something else.
|
The
|
||||||
If the process exits abnormally
|
.Sy default
|
||||||
.Nm
|
daemon is meant to be a virtual daemon depending on a single top level daemon
|
||||||
will automatically restart it.
|
(the target), which provide the desired operating system functionality
|
||||||
.Nm
|
(e.g. booting to a single user shell or a multi user login screen).
|
||||||
will exit with the same exit status as the process if it exits normally.
|
.Pp
|
||||||
The kernel decides whether to power off, reboot or halt based on this exit
|
The daemons are configured per
|
||||||
status.
|
.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
|
.Sh ENVIRONMENT
|
||||||
.Nm
|
.Nm
|
||||||
sets the following environment variables.
|
sets the following environment variables.
|
||||||
|
@ -213,21 +233,47 @@ root
|
||||||
.Sh FILES
|
.Sh FILES
|
||||||
.Bl -tag -width "/boot/random.seed" -compact
|
.Bl -tag -width "/boot/random.seed" -compact
|
||||||
.It Pa /boot/random.seed
|
.It Pa /boot/random.seed
|
||||||
initial kernel entropy
|
Initial kernel entropy
|
||||||
.It Pa /etc/init/target
|
.It Pa /etc/init/
|
||||||
default initialization target
|
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
|
.It Pa /etc/fstab
|
||||||
filesystem table (see
|
Filesystem table (see
|
||||||
.Xr fstab 5 )
|
.Xr fstab 5 )
|
||||||
.It Pa /etc/hostname
|
.It Pa /etc/hostname
|
||||||
hostname (see
|
Hostname (see
|
||||||
.Xr hostname 5 )
|
.Xr hostname 5 )
|
||||||
.It Pa /etc/kblayout
|
.It Pa /etc/kblayout
|
||||||
keyboard layout (see
|
Keyboard layout (see
|
||||||
.Xr kblayout 5 )
|
.Xr kblayout 5 )
|
||||||
.It Pa /etc/videomode
|
.It Pa /etc/videomode
|
||||||
graphics resolution (see
|
Graphics resolution (see
|
||||||
.Xr videomode 5 )
|
.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
|
.El
|
||||||
.Sh EXIT STATUS
|
.Sh EXIT STATUS
|
||||||
.Nm
|
.Nm
|
||||||
|
@ -243,10 +289,26 @@ exits with the same exit status as its target session if it terminates normally.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr fstab 5 ,
|
.Xr fstab 5 ,
|
||||||
.Xr hostname 5 ,
|
.Xr hostname 5 ,
|
||||||
|
.Xr init 5 ,
|
||||||
.Xr kblayout 5 ,
|
.Xr kblayout 5 ,
|
||||||
.Xr videomode 5 ,
|
.Xr videomode 5 ,
|
||||||
|
.Xr daemon 7 ,
|
||||||
.Xr initrd 7 ,
|
.Xr initrd 7 ,
|
||||||
.Xr kernel 7 ,
|
.Xr kernel 7 ,
|
||||||
|
.Xr halt 8 ,
|
||||||
.Xr login 8 ,
|
.Xr login 8 ,
|
||||||
|
.Xr poweroff 8 ,
|
||||||
|
.Xr reboot 8 ,
|
||||||
.Xr sysmerge 8 ,
|
.Xr sysmerge 8 ,
|
||||||
.Xr update-initrd 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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -47,18 +47,15 @@ static bool array_add(void*** array_ptr,
|
||||||
|
|
||||||
if ( *used_ptr == *length_ptr )
|
if ( *used_ptr == *length_ptr )
|
||||||
{
|
{
|
||||||
// TODO: Avoid overflow.
|
size_t length = *length_ptr;
|
||||||
size_t new_length = 2 * *length_ptr;
|
if ( !length )
|
||||||
if ( !new_length )
|
length = 4;
|
||||||
new_length = 16;
|
void** new_array = reallocarray(array, length, 2 * sizeof(void*));
|
||||||
// TODO: Avoid overflow and use reallocarray.
|
|
||||||
size_t new_size = new_length * sizeof(void*);
|
|
||||||
void** new_array = (void**) realloc(array, new_size);
|
|
||||||
if ( !new_array )
|
if ( !new_array )
|
||||||
return false;
|
return false;
|
||||||
array = new_array;
|
array = new_array;
|
||||||
memcpy(array_ptr, &array, sizeof(array)); // Strict aliasing.
|
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.
|
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);
|
exit(0);
|
||||||
if ( !strcmp(textbox_username.text, "reboot") )
|
if ( !strcmp(textbox_username.text, "reboot") )
|
||||||
exit(1);
|
exit(1);
|
||||||
|
if ( !strcmp(textbox_username.text, "halt") )
|
||||||
|
exit(2);
|
||||||
state->stage = STAGE_PASSWORD;
|
state->stage = STAGE_PASSWORD;
|
||||||
textbox_reset(&textbox_password);
|
textbox_reset(&textbox_password);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -44,6 +44,8 @@ alias for poweroff
|
||||||
exit asking for powering off the computer
|
exit asking for powering off the computer
|
||||||
.It reboot
|
.It reboot
|
||||||
exit asking for rebooting the computer
|
exit asking for rebooting the computer
|
||||||
|
.It halt
|
||||||
|
exit asking for halting the computer
|
||||||
.El
|
.El
|
||||||
.Sh SECURITY
|
.Sh SECURITY
|
||||||
There is currently no method to confirm the login screen is in fact real other
|
There is currently no method to confirm the login screen is in fact real other
|
||||||
|
|
|
@ -349,6 +349,8 @@ int textual(void)
|
||||||
exit(0);
|
exit(0);
|
||||||
if ( !strcmp(username, "reboot") )
|
if ( !strcmp(username, "reboot") )
|
||||||
exit(1);
|
exit(1);
|
||||||
|
if ( !strcmp(username, "halt") )
|
||||||
|
exit(2);
|
||||||
|
|
||||||
if ( settermmode(0, pw_termmode) < 0 )
|
if ( settermmode(0, pw_termmode) < 0 )
|
||||||
err(2, "settermmode");
|
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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -49,18 +49,15 @@ bool array_add(void*** array_ptr,
|
||||||
|
|
||||||
if ( *used_ptr == *length_ptr )
|
if ( *used_ptr == *length_ptr )
|
||||||
{
|
{
|
||||||
// TODO: Avoid overflow.
|
size_t length = *length_ptr;
|
||||||
size_t new_length = 2 * *length_ptr;
|
if ( !length )
|
||||||
if ( !new_length )
|
length = 4;
|
||||||
new_length = 16;
|
void** new_array = reallocarray(array, length, 2 * sizeof(void*));
|
||||||
// TODO: Avoid overflow and use reallocarray.
|
|
||||||
size_t new_size = new_length * sizeof(void*);
|
|
||||||
void** new_array = (void**) realloc(array, new_size);
|
|
||||||
if ( !new_array )
|
if ( !new_array )
|
||||||
return false;
|
return false;
|
||||||
array = new_array;
|
array = new_array;
|
||||||
memcpy(array_ptr, &array, sizeof(array)); // Strict aliasing.
|
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.
|
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
|
.Xr grep 1
|
||||||
for it after a release.
|
for it after a release.
|
||||||
.Sh CHANGES
|
.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
|
.Ss Add ports to the Sortix repository
|
||||||
The ports have been moved from the porttix/srctix repositories into the
|
The ports have been moved from the porttix/srctix repositories into the
|
||||||
.Pa ports/
|
.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
|
If you did not accept the bootloader, you will need to manually configure a
|
||||||
bootloader to boot the new operating system.
|
bootloader to boot the new operating system.
|
||||||
.Pp
|
.Pp
|
||||||
You will be given the choice between powering off the system, rebooting it, or
|
You will be given the choice between powering off the system, rebooting it,
|
||||||
directly booting the new system.
|
halting it, or directly booting the new system.
|
||||||
|
.Pp
|
||||||
The last option will directly boot the new system in a chroot while the live
|
The last option will directly boot the new system in a chroot while the live
|
||||||
environment remains in the background.
|
environment remains in the background.
|
||||||
If you invoked
|
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
|
Upon boot of the new system it will be configured in multi-user mode and you
|
||||||
will be presented with a login screen.
|
will be presented with a login screen.
|
||||||
Authenticate as one of the local users and you will be given a shell.
|
Authenticate as one of the local users and you will be given a shell.
|
||||||
|
.Pp
|
||||||
To power off the computer login as user
|
To power off the computer login as user
|
||||||
.Sy poweroff
|
.Sy poweroff
|
||||||
and to reboot the computer login as user
|
or run
|
||||||
.Sy reboot .
|
.Xr poweroff 8
|
||||||
|
after logging in.
|
||||||
|
To reboot the computer login as user
|
||||||
|
.Sy reboot
|
||||||
|
or run
|
||||||
|
.Xr reboot 8
|
||||||
|
after logging in.
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Xr user-guide 7
|
.Xr user-guide 7
|
||||||
|
|
|
@ -46,7 +46,9 @@ is the modern replacement with nanosecond precision.
|
||||||
is the standard replacement.
|
is the standard replacement.
|
||||||
.Ss daemon
|
.Ss daemon
|
||||||
Daemons should not background by double forking but rather stay in the
|
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 .
|
.Xr init 8 .
|
||||||
.Ss __dead
|
.Ss __dead
|
||||||
.Dv noreturn
|
.Dv noreturn
|
||||||
|
|
|
@ -24,17 +24,16 @@ This is
|
||||||
if the system is booted in multi-user mode.
|
if the system is booted in multi-user mode.
|
||||||
This is a root shell if booted in single-user mode.
|
This is a root shell if booted in single-user mode.
|
||||||
.Pp
|
.Pp
|
||||||
To power off from the login screen, login as user
|
To power off the computer login as user
|
||||||
.Sy poweroff .
|
.Sy poweroff
|
||||||
To reboot, login as user
|
or run
|
||||||
.Sy reboot .
|
.Xr poweroff 8
|
||||||
.Pp
|
after logging in.
|
||||||
To power off from a single-user boot root shell, run
|
To reboot the computer login as user
|
||||||
.Sy exit 0
|
.Sy reboot
|
||||||
in the shell.
|
or run
|
||||||
To reboot, run
|
.Xr reboot 8
|
||||||
.Sy exit 1
|
after logging in.
|
||||||
in the shell.
|
|
||||||
.Ss Keyboard Layout
|
.Ss Keyboard Layout
|
||||||
The kernel has a default US keyboard layout compiled into it.
|
The kernel has a default US keyboard layout compiled into it.
|
||||||
.Pp
|
.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-random-seed
|
||||||
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-tix-manifest-mode
|
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-tix-manifest-mode
|
||||||
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-leaked-files
|
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-leaked-files
|
||||||
|
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-init
|
||||||
|
|
||||||
sysinstall: $(SYSINSTALL_OBJS)
|
sysinstall: $(SYSINSTALL_OBJS)
|
||||||
$(CC) $(SYSINSTALL_OBJS) -o $@ -lmount
|
$(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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -198,25 +198,29 @@ bool fsck(struct filesystem* fs)
|
||||||
const char* bdev_path = path_of_blockdevice(fs->bdev);
|
const char* bdev_path = path_of_blockdevice(fs->bdev);
|
||||||
printf("%s: Repairing filesystem due to inconsistency...\n", bdev_path);
|
printf("%s: Repairing filesystem due to inconsistency...\n", bdev_path);
|
||||||
assert(fs->fsck);
|
assert(fs->fsck);
|
||||||
pid_t child_pid = fork();
|
pid_t pid = fork();
|
||||||
if ( child_pid < 0 )
|
if ( pid < 0 )
|
||||||
{
|
{
|
||||||
warn("%s: Mandatory repair failed: fork", bdev_path);
|
warn("%s: Mandatory repair failed: fork", bdev_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( child_pid == 0 )
|
if ( pid == 0 )
|
||||||
{
|
{
|
||||||
execlp(fs->fsck, fs->fsck, "-fp", "--", bdev_path, (const char*) NULL);
|
execlp(fs->fsck, fs->fsck, "-fp", "--", bdev_path, (const char*) NULL);
|
||||||
warn("%s: Failed to load filesystem checker: %s", bdev_path, fs->fsck);
|
warn("%s: Failed to load filesystem checker: %s", bdev_path, fs->fsck);
|
||||||
_Exit(127);
|
_Exit(127);
|
||||||
}
|
}
|
||||||
int code;
|
int code;
|
||||||
if ( waitpid(child_pid, &code, 0) < 0 )
|
if ( waitpid(pid, &code, 0) < 0 )
|
||||||
{
|
|
||||||
warn("waitpid");
|
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,
|
warnx("%s: Mandatory repair failed: %s: %s", bdev_path,
|
||||||
fs->fsck, strsignal(WTERMSIG(code)));
|
fs->fsck, strsignal(WTERMSIG(code)));
|
||||||
else if ( !WIFEXITED(code) )
|
else if ( !WIFEXITED(code) )
|
||||||
|
@ -228,14 +232,9 @@ bool fsck(struct filesystem* fs)
|
||||||
else if ( WEXITSTATUS(code) & 2 )
|
else if ( WEXITSTATUS(code) & 2 )
|
||||||
warnx("%s: Mandatory repair: %s: %s", bdev_path,
|
warnx("%s: Mandatory repair: %s: %s", bdev_path,
|
||||||
fs->fsck, "System reboot is necessary");
|
fs->fsck, "System reboot is necessary");
|
||||||
else if ( WEXITSTATUS(code) != 0 && WEXITSTATUS(code) != 1 )
|
else
|
||||||
warnx("%s: Mandatory repair failed: %s: %s", bdev_path,
|
warnx("%s: Mandatory repair failed: %s: %s", bdev_path,
|
||||||
fs->fsck, "Filesystem checker was unsuccessful");
|
fs->fsck, "Filesystem checker was unsuccessful");
|
||||||
else
|
|
||||||
{
|
|
||||||
fs->flags &= ~(FILESYSTEM_FLAG_FSCK_SHOULD | FILESYSTEM_FLAG_FSCK_MUST);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,82 +337,106 @@ bool mountpoint_mount(struct mountpoint* mountpoint)
|
||||||
warnx("Failed to fsck %s", bdev_path);
|
warnx("Failed to fsck %s", bdev_path);
|
||||||
return false;
|
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* pretend_where = mountpoint->entry.fs_file;
|
||||||
const char* where = mountpoint->absolute;
|
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;
|
struct stat st;
|
||||||
if ( stat(where, &st) < 0 )
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
if ( (mountpoint->pid = fork()) < 0 )
|
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;
|
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 )
|
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,
|
execlp(fs->driver, fs->driver, "--foreground", bdev_path, where,
|
||||||
"--pretend-mount-path", pretend_where, (const char*) NULL);
|
"--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);
|
_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) )
|
||||||
if ( stat(where, &newst) < 0 )
|
|
||||||
{
|
{
|
||||||
warn("stat: %s", where);
|
if ( newst.st_dev != st.st_dev || newst.st_ino != st.st_ino )
|
||||||
if ( unmount(where, 0) < 0 && errno != ENOMOUNT )
|
return true;
|
||||||
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);
|
|
||||||
else
|
else
|
||||||
warnx("%s: Mount failed: %s: Exited with status %i", bdev_path,
|
warnx("Failed mount %s on %s: %s: "
|
||||||
fs->driver, WEXITSTATUS(code));
|
"No mounted filesystem appeared: %s",
|
||||||
return false;
|
bdev_path, pretend_where, fs->driver, where);
|
||||||
}
|
}
|
||||||
struct timespec delay = timespec_make(0, 50L * 1000L * 1000L);
|
else
|
||||||
nanosleep(&delay, NULL);
|
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)
|
void mountpoint_unmount(struct mountpoint* mountpoint)
|
||||||
|
|
|
@ -257,6 +257,45 @@ void upgrade_prepare(const struct release* old_release,
|
||||||
free(installed);
|
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,
|
void upgrade_finalize(const struct release* old_release,
|
||||||
|
|
|
@ -828,22 +828,24 @@ int main(void)
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
prompt(input, sizeof(input),
|
prompt(input, sizeof(input),
|
||||||
"Install " BRAND_DISTRIBUTION_NAME "? (yes/no/poweroff/reboot)",
|
"Install " BRAND_DISTRIBUTION_NAME "? "
|
||||||
"yes");
|
"(yes/no/poweroff/reboot/halt)", "yes");
|
||||||
if ( !strcasecmp(input, "yes") )
|
if ( !strcasecmp(input, "yes") )
|
||||||
break;
|
break;
|
||||||
else if ( !strcasecmp(input, "no") )
|
else if ( !strcasecmp(input, "no") )
|
||||||
{
|
{
|
||||||
text("Answer '!' to get a shell. Type !man to view the "
|
text("Answer '!' to get a shell. Type !man to view the "
|
||||||
"installation(7) manual page.\n");
|
"installation(7) manual page.\n");
|
||||||
text("Alternatively, you can answer 'poweroff' or 'reboot' to "
|
text("Alternatively, you can answer 'poweroff', 'reboot', or "
|
||||||
"cancel the installation.\n");
|
"'halt' to cancel the installation.\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if ( !strcasecmp(input, "poweroff") )
|
else if ( !strcasecmp(input, "poweroff") )
|
||||||
exit(0);
|
exit(0);
|
||||||
else if ( !strcasecmp(input, "reboot") )
|
else if ( !strcasecmp(input, "reboot") )
|
||||||
exit(1);
|
exit(1);
|
||||||
|
else if ( !strcasecmp(input, "halt") )
|
||||||
|
exit(2);
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1033,7 +1035,8 @@ int main(void)
|
||||||
else
|
else
|
||||||
warn("mkdir: etc/init");
|
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 "
|
text("Congratulations, the system is now functional! This is a good time "
|
||||||
"to do further customization of the system.\n\n");
|
"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 "
|
text("Upon boot, you'll be greeted with a login screen. Enter your "
|
||||||
"credentials to get a command line. Login as user 'poweroff' as "
|
"credentials to get a command line. Login as user 'poweroff' as "
|
||||||
"described in login(8) to power off the machine. After logging in, "
|
"described in login(8) to power off the machine or run poweroff(8). "
|
||||||
"type 'man user-guide' to view the introductory documentation.\n");
|
"After logging in, type 'man user-guide' to view the introductory "
|
||||||
|
"documentation.\n");
|
||||||
text("\n");
|
text("\n");
|
||||||
|
|
||||||
while ( true )
|
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") )
|
if ( !strcasecmp(input, "poweroff") )
|
||||||
exit(0);
|
exit(0);
|
||||||
if ( !strcasecmp(input, "reboot") )
|
if ( !strcasecmp(input, "reboot") )
|
||||||
exit(1);
|
exit(1);
|
||||||
|
if ( !strcasecmp(input, "halt") )
|
||||||
|
exit(2);
|
||||||
if ( !strcasecmp(input, "boot") )
|
if ( !strcasecmp(input, "boot") )
|
||||||
{
|
{
|
||||||
unmount_all_but_root();
|
unmount_all_but_root();
|
||||||
|
|
|
@ -775,7 +775,7 @@ int main(void)
|
||||||
while ( true )
|
while ( true )
|
||||||
{
|
{
|
||||||
promptx(input, sizeof(input),
|
promptx(input, sizeof(input),
|
||||||
"Upgrade? (yes/no/poweroff/reboot)", "yes", true);
|
"Upgrade? (yes/no/poweroff/reboot/halt)", "yes", true);
|
||||||
if ( !strcasecmp(input, "yes") )
|
if ( !strcasecmp(input, "yes") )
|
||||||
break;
|
break;
|
||||||
else if ( !strcasecmp(input, "no") )
|
else if ( !strcasecmp(input, "no") )
|
||||||
|
@ -784,14 +784,16 @@ int main(void)
|
||||||
"upgrade(7) manual page. You can edit the upgrade.conf(5) "
|
"upgrade(7) manual page. You can edit the upgrade.conf(5) "
|
||||||
"configuration file of the target system to change which "
|
"configuration file of the target system to change which "
|
||||||
"upgrade operations are performed.\n");
|
"upgrade operations are performed.\n");
|
||||||
text("Alternatively, you can answer 'poweroff' or 'reboot' to "
|
text("Alternatively, you can answer 'poweroff', 'reboot', or "
|
||||||
"cancel the upgrade.\n");
|
"'halt' or cancel the upgrade.\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if ( !strcasecmp(input, "poweroff") )
|
else if ( !strcasecmp(input, "poweroff") )
|
||||||
exit(0);
|
exit(0);
|
||||||
else if ( !strcasecmp(input, "reboot") )
|
else if ( !strcasecmp(input, "reboot") )
|
||||||
exit(1);
|
exit(1);
|
||||||
|
else if ( !strcasecmp(input, "halt") )
|
||||||
|
exit(2);
|
||||||
else if ( !strcasecmp(input, "!") )
|
else if ( !strcasecmp(input, "!") )
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
|
@ -928,10 +930,13 @@ int main(void)
|
||||||
|
|
||||||
while ( true )
|
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") )
|
if ( !strcasecmp(input, "poweroff") )
|
||||||
return 0;
|
return 0;
|
||||||
if ( !strcasecmp(input, "reboot") )
|
if ( !strcasecmp(input, "reboot") )
|
||||||
return 1;
|
return 1;
|
||||||
|
if ( !strcasecmp(input, "halt") )
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ default=
|
||||||
directory=
|
directory=
|
||||||
enable_append_title=true
|
enable_append_title=true
|
||||||
enable_src=
|
enable_src=
|
||||||
|
init_target=
|
||||||
liveconfig=
|
liveconfig=
|
||||||
operand=1
|
operand=1
|
||||||
random_seed=false
|
random_seed=false
|
||||||
|
@ -53,6 +54,8 @@ for argument do
|
||||||
--disable-src) enable_src=false ;;
|
--disable-src) enable_src=false ;;
|
||||||
--enable-append-title) enable_append_title=true ;;
|
--enable-append-title) enable_append_title=true ;;
|
||||||
--enable-src) enable_src=true ;;
|
--enable-src) enable_src=true ;;
|
||||||
|
--init-target=*) init_target=$parameter ;;
|
||||||
|
--init-target) previous_option=init_target ;;
|
||||||
--liveconfig=*) liveconfig=$parameter ;;
|
--liveconfig=*) liveconfig=$parameter ;;
|
||||||
--liveconfig) previous_option=liveconfig ;;
|
--liveconfig) previous_option=liveconfig ;;
|
||||||
--random-seed) random_seed=true ;;
|
--random-seed) random_seed=true ;;
|
||||||
|
@ -137,6 +140,13 @@ mkdir -p -- "$directory/boot/grub"
|
||||||
printf "base_menu_title=\"\$base_menu_title - \"'%s'\n" \
|
printf "base_menu_title=\"\$base_menu_title - \"'%s'\n" \
|
||||||
"$(printf '%s\n' "$append_title" | sed "s/'/'\\\\''/g")"
|
"$(printf '%s\n' "$append_title" | sed "s/'/'\\\\''/g")"
|
||||||
fi
|
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
|
if [ -e "$directory/boot/liveconfig.tar.xz" ]; then
|
||||||
printf 'function hook_initrd_post {\n'
|
printf 'function hook_initrd_post {\n'
|
||||||
printf ' echo -n "Loading /boot/liveconfig.tar.xz (%s) ... "\n' \
|
printf ' echo -n "Loading /boot/liveconfig.tar.xz (%s) ... "\n' \
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
.Op Fl \-disable-src
|
.Op Fl \-disable-src
|
||||||
.Op Fl \-enable-append-title
|
.Op Fl \-enable-append-title
|
||||||
.Op Fl \-enable-src
|
.Op Fl \-enable-src
|
||||||
|
.Op Fl \-init-target Ns = Ns Ar target
|
||||||
.Op Fl \-liveconfig Ns = Ns Ar liveconfig-directory
|
.Op Fl \-liveconfig Ns = Ns Ar liveconfig-directory
|
||||||
.Op Fl \-random-seed
|
.Op Fl \-random-seed
|
||||||
.Op Fl \-timeout Ns = Ns Ar boot-menu-timeout
|
.Op Fl \-timeout Ns = Ns Ar boot-menu-timeout
|
||||||
|
@ -110,6 +111,12 @@ by setting
|
||||||
.Sy enable_src
|
.Sy enable_src
|
||||||
GRUB variable to
|
GRUB variable to
|
||||||
.Sy true .
|
.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
|
.It Fl \-liveconfig Ns = Ns Ar liveconfig-directory
|
||||||
Overlay the
|
Overlay the
|
||||||
.Ar liveconfig-directory
|
.Ar liveconfig-directory
|
||||||
|
@ -222,6 +229,16 @@ bootloader menu timeout to 2 seconds:
|
||||||
tix-iso-bootconfig --default=1 --timeout=2 bootconfig
|
tix-iso-bootconfig --default=1 --timeout=2 bootconfig
|
||||||
tix-iso-add sortix.iso bootconfig
|
tix-iso-add sortix.iso bootconfig
|
||||||
.Ed
|
.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
|
.Ss Add to Bootloader Menu Title
|
||||||
To customize a release so the bootloader menu title is appended with a message
|
To customize a release so the bootloader menu title is appended with a message
|
||||||
of your choice:
|
of your choice:
|
||||||
|
@ -234,5 +251,6 @@ tix-iso-add sortix.iso bootconfig
|
||||||
.Xr kernel 7 ,
|
.Xr kernel 7 ,
|
||||||
.Xr release-iso-bootconfig 7 ,
|
.Xr release-iso-bootconfig 7 ,
|
||||||
.Xr release-iso-modification 7 ,
|
.Xr release-iso-modification 7 ,
|
||||||
|
.Xr init 8 ,
|
||||||
.Xr tix-iso-add 8 ,
|
.Xr tix-iso-add 8 ,
|
||||||
.Xr tix-iso-liveconfig 8
|
.Xr tix-iso-liveconfig 8
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/sh
|
#!/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
|
# Permission to use, copy, modify, and distribute this software for any
|
||||||
# purpose with or without fee is hereby granted, provided that the above
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
daemons=
|
||||||
directory=
|
directory=
|
||||||
hostname=
|
hostname=
|
||||||
kblayout=
|
kblayout=
|
||||||
|
@ -41,6 +42,8 @@ for argument do
|
||||||
|
|
||||||
case $dashdash$argument in
|
case $dashdash$argument in
|
||||||
--) dashdash=yes ;;
|
--) dashdash=yes ;;
|
||||||
|
--daemons=*) daemons=$parameter ;;
|
||||||
|
--daemons) previous_option=daemons ;;
|
||||||
--hostname=*) hostname=$parameter ;;
|
--hostname=*) hostname=$parameter ;;
|
||||||
--hostname) previous_option=hostname ;;
|
--hostname) previous_option=hostname ;;
|
||||||
--kblayout=*) kblayout=$parameter ;;
|
--kblayout=*) kblayout=$parameter ;;
|
||||||
|
@ -73,6 +76,15 @@ fi
|
||||||
|
|
||||||
mkdir -p "$directory"
|
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
|
if [ -n "$hostname" ]; then
|
||||||
mkdir -p -- "$directory/etc"
|
mkdir -p -- "$directory/etc"
|
||||||
printf "%s\n" "$hostname" > "$directory/etc/hostname"
|
printf "%s\n" "$hostname" > "$directory/etc/hostname"
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
.Nd generate additional live environment configuration for Sortix .iso releases
|
.Nd generate additional live environment configuration for Sortix .iso releases
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
|
.Op Fl \-daemons Ns = Ns Ar daemons
|
||||||
.Op Fl \-hostname Ns = Ns Ar hostname
|
.Op Fl \-hostname Ns = Ns Ar hostname
|
||||||
.Op Fl \-kblayout Ns = Ns Ar kblayout
|
.Op Fl \-kblayout Ns = Ns Ar kblayout
|
||||||
.Op Fl \-videomode Ns = Ns Ar videomode
|
.Op Fl \-videomode Ns = Ns Ar videomode
|
||||||
|
@ -43,6 +44,15 @@ installations made from inside it.
|
||||||
.Pp
|
.Pp
|
||||||
The options are as follows:
|
The options are as follows:
|
||||||
.Bl -tag -width "12345678"
|
.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
|
.It Fl \-hostname Ns = Ns Ar hostname
|
||||||
Set the live environment's hostname by writing
|
Set the live environment's hostname by writing
|
||||||
.Ar hostname
|
.Ar hostname
|
||||||
|
|
|
@ -77,9 +77,13 @@ mkdir "$tmp/etc"
|
||||||
cp "$sysroot/etc/fstab" "$tmp/etc/fstab"
|
cp "$sysroot/etc/fstab" "$tmp/etc/fstab"
|
||||||
mkdir "$tmp/etc/init"
|
mkdir "$tmp/etc/init"
|
||||||
if $sysmerge; then
|
if $sysmerge; then
|
||||||
echo chain-merge > "$tmp/etc/init/target"
|
cat > "$tmp/etc/init/default" << EOF
|
||||||
|
require chain-merge exit-code
|
||||||
|
EOF
|
||||||
else
|
else
|
||||||
echo chain > "$tmp/etc/init/target"
|
cat > "$tmp/etc/init/default" << EOF
|
||||||
|
require chain exit-code
|
||||||
|
EOF
|
||||||
fi
|
fi
|
||||||
mkdir -p "$sysroot/boot"
|
mkdir -p "$sysroot/boot"
|
||||||
mkinitrd --format=sortix-initrd-2 "$tmp" -o "$sysroot/boot/sortix.initrd" > /dev/null
|
mkinitrd --format=sortix-initrd-2 "$tmp" -o "$sysroot/boot/sortix.initrd" > /dev/null
|
||||||
|
|
|
@ -20,9 +20,10 @@ env
|
||||||
expr
|
expr
|
||||||
false
|
false
|
||||||
find
|
find
|
||||||
|
halt
|
||||||
head
|
head
|
||||||
id
|
|
||||||
help
|
help
|
||||||
|
id
|
||||||
kernelinfo
|
kernelinfo
|
||||||
kill
|
kill
|
||||||
ln
|
ln
|
||||||
|
@ -35,11 +36,13 @@ mv
|
||||||
nl
|
nl
|
||||||
pager
|
pager
|
||||||
passwd
|
passwd
|
||||||
|
poweroff
|
||||||
ps
|
ps
|
||||||
pstree
|
pstree
|
||||||
pwd
|
pwd
|
||||||
readlink
|
readlink
|
||||||
realpath
|
realpath
|
||||||
|
reboot
|
||||||
rm
|
rm
|
||||||
rmdir
|
rmdir
|
||||||
sleep
|
sleep
|
||||||
|
|
|
@ -31,6 +31,7 @@ env \
|
||||||
expr \
|
expr \
|
||||||
false \
|
false \
|
||||||
find \
|
find \
|
||||||
|
halt \
|
||||||
head \
|
head \
|
||||||
help \
|
help \
|
||||||
id \
|
id \
|
||||||
|
@ -71,6 +72,8 @@ uptime \
|
||||||
wc \
|
wc \
|
||||||
which \
|
which \
|
||||||
yes \
|
yes \
|
||||||
|
poweroff \
|
||||||
|
reboot \
|
||||||
|
|
||||||
BINARIES=\
|
BINARIES=\
|
||||||
$(BINARIES_EXCEPT_INSTALL) \
|
$(BINARIES_EXCEPT_INSTALL) \
|
||||||
|
@ -94,6 +97,9 @@ unmount \
|
||||||
|
|
||||||
MANPAGES8=\
|
MANPAGES8=\
|
||||||
chroot.8 \
|
chroot.8 \
|
||||||
|
halt.8 \
|
||||||
|
poweroff.8 \
|
||||||
|
reboot.8 \
|
||||||
unmount.8 \
|
unmount.8 \
|
||||||
|
|
||||||
all: $(BINARIES) $(SBINS)
|
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ä.
|
* Copyright (c) 2021 Juhani 'nortti' Krekelä.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
@ -27,49 +27,11 @@
|
||||||
|
|
||||||
#define ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0]))
|
#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)
|
static void suggest_logout(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, " Exiting your shell normally to logout.\n");
|
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
|
enum category
|
||||||
{
|
{
|
||||||
NONE,
|
NONE,
|
||||||
|
@ -79,7 +41,6 @@ enum category
|
||||||
MOUNT,
|
MOUNT,
|
||||||
PAGER,
|
PAGER,
|
||||||
POWEROFF,
|
POWEROFF,
|
||||||
REBOOT,
|
|
||||||
RW,
|
RW,
|
||||||
SHELL,
|
SHELL,
|
||||||
UNMOUNT,
|
UNMOUNT,
|
||||||
|
@ -122,12 +83,9 @@ struct command commands[] =
|
||||||
{PAGER, "more", NULL, NULL},
|
{PAGER, "more", NULL, NULL},
|
||||||
{PAGER, "pager", "system", NULL},
|
{PAGER, "pager", "system", NULL},
|
||||||
|
|
||||||
{POWEROFF, "halt", NULL, NULL},
|
{POWEROFF, "poweroff", "system", NULL},
|
||||||
{POWEROFF, "poweroff", NULL, suggest_poweroff},
|
|
||||||
{POWEROFF, "shutdown", NULL, NULL},
|
{POWEROFF, "shutdown", NULL, NULL},
|
||||||
|
|
||||||
{REBOOT, "reboot", NULL, suggest_reboot},
|
|
||||||
|
|
||||||
{RW, "dd", NULL, NULL},
|
{RW, "dd", NULL, NULL},
|
||||||
{RW, "rw", "system", 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