Add init groups.

Every process now has an init process like it has a session, and each
session belong to an init. Orphaned processes are reparented to its init
process. All descendent processes are SIGKILL'd when an init process exits
and creating additional processes/threads fails.

Add setinit(2) for becoming the init process for your child processes and
add getinit(2) for locating your init process.

Add TIOCSCTTY force flag that releases a terminal from its current session
and makes it the controlling terminal for the current session. This ioctl
is essential to transferring the controlling terminal to a nested init,
which has its own session.

Add TIOCUCTTY that releases the terminal as the controlling terminal for
its current session.

Remove INIT_PID as it is replaced by getinit(2).
This commit is contained in:
Jonas 'Sortie' Termansen 2024-06-15 22:34:51 +00:00
parent 09ca6ea01e
commit 6e51c1ae51
28 changed files with 377 additions and 90 deletions

View File

@ -232,7 +232,7 @@ sysroot-system: sysroot-fsh sysroot-base-headers
echo 'ID=sortix' && \
echo 'VERSION_ID="$(VERSION)"' && \
echo 'PRETTY_NAME="Sortix $(VERSION)"' && \
echo 'SORTIX_ABI=2.0' && \
echo 'SORTIX_ABI=2.1' && \
true) > "$(SYSROOT)/etc/sortix-release"
echo /etc/sortix-release >> "$(SYSROOT)/tix/manifest/system"
ln -sf sortix-release "$(SYSROOT)/etc/os-release"

View File

@ -213,12 +213,9 @@ daemon is meant to start the installation's local daemon requirements.
.Sh ENVIRONMENT
.Nm
sets the following environment variables.
.Bl -tag -width "INIT_PID"
.Bl -tag -width "LOGNAME"
.It Ev HOME
root's home directory
.It Ev INIT_PID
.Nm Ns 's
process id
.It Ev LOGNAME
root
.It Ev PATH

View File

@ -2532,7 +2532,6 @@ static void daemon_start(struct daemon* daemon)
char ppid_str[sizeof(pid_t) * 3];
snprintf(ppid_str, sizeof(ppid_str), "%" PRIiPID, ppid);
if ( (!daemon->need_tty && setenv("READYFD", "3", 1)) < 0 ||
setenv("INIT_PID", ppid_str, 1) < 0 ||
setenv("LOGNAME", pwd->pw_name, 1) < 0 ||
setenv("USER", pwd->pw_name, 1) < 0 ||
setenv("HOME", home, 1) < 0 ||
@ -2628,7 +2627,6 @@ static void daemon_start(struct daemon* daemon)
// TODO: Also unset other things.
if ( !daemon->need_tty )
unsetenv("READYFD");
unsetenv("INIT_PID");
unsetenv("LOGNAME");
unsetenv("USER");
unsetenv("HOME");
@ -4302,9 +4300,12 @@ int main(int argc, char* argv[])
}
// Prevent recursive init without care.
if ( getenv("INIT_PID") )
if ( getinit(0) != getpid() )
fatal("System is already managed by an init process");
if ( !isatty(0) || !isatty(1) || !isatty(2) )
fatal("stdin, stdout, and stderr must be the terminal");
// Register handler that shuts down the system when init exits.
if ( atexit(niht) != 0 )
fatal("atexit: %m");
@ -4460,6 +4461,9 @@ int main(int argc, char* argv[])
chain_location_dev_made = true;
close(new_dev_fd);
close(old_dev_fd);
int tty_fd = open("/dev/tty", O_RDWR | O_CLOEXEC);
if ( tty_fd < 0 )
fatal("/dev/tty: %m");
// TODO: Forward the early init log to the chain init.
// Run the chain booted operating system.
pid_t child_pid = fork();
@ -4472,6 +4476,10 @@ int main(int argc, char* argv[])
fatal("chroot: %s: %m", chain_location);
if ( chdir("/") < 0 )
fatal("chdir: %s: %m", chain_location);
if ( setinit() < 0 )
fatal("setinit: %m");
if ( ioctl(tty_fd, TIOCSCTTY, 1) < 0 )
fatal("ioctl: TIOCSCTTY: %m");
const char* program = next_argv[0];
char verbose_opt[] = {'-', "sqv"[verbosity], '\0'};
// Chain boot the operating system upgrade if needed.
@ -4502,6 +4510,9 @@ int main(int argc, char* argv[])
}
sigprocmask(SIG_BLOCK, &handled_signals, NULL);
forward_signal_pid = -1; // Racy with waitpid.
if ( ioctl(tty_fd, TIOCSCTTY, 1) < 0 )
fatal("ioctl: TIOCSCTTY: %m");
close(tty_fd);
if ( WIFEXITED(status) )
return WEXITSTATUS(status);
else if ( WIFSIGNALED(status) )

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017 Jonas 'Sortie' Termansen.
* Copyright (c) 2016, 2017, 2024 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
@ -39,6 +39,7 @@
#define TIOCGNAME __IOCTL(6, __IOCTL_TYPE_PTR)
#define TIOCGPTN __IOCTL(7, __IOCTL_TYPE_PTR)
#define TIOCGDISPLAYS __IOCTL(8, __IOCTL_TYPE_PTR)
#define TIOCUCTTY __IOCTL(9, __IOCTL_TYPE_INT)
#define IOC_TYPE(x) ((x) >> 0 & 0xFF)
#define IOC_TYPE_BLOCK_DEVICE 1

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2016, 2021 Jonas 'Sortie' Termansen.
* Copyright (c) 2011-2016, 2021, 2024 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
@ -124,12 +124,17 @@ public:
Process* sessionprev;
Process* sessionnext;
Process* sessionfirst;
Process* init;
Process* initprev;
Process* initnext;
Process* initfirst;
kthread_mutex_t childlock;
kthread_mutex_t parentlock;
kthread_cond_t zombiecond;
bool iszombie;
bool nozombify;
bool limbo;
bool is_init_exiting;
int exit_code;
public:
@ -178,6 +183,7 @@ public:
int prot);
void GroupRemoveMember(Process* child);
void SessionRemoveMember(Process* child);
void InitRemoveMember(Process* child);
public:
Process* Fork();

View File

@ -41,8 +41,6 @@ void SetThreadState(Thread* thread, ThreadState state, bool wake_only = false);
void SetSignalPending(Thread* thread, unsigned long is_pending);
ThreadState GetThreadState(Thread* thread);
void SetIdleThread(Thread* thread);
void SetInitProcess(Process* init);
Process* GetInitProcess();
Process* GetKernelProcess();
void InterruptYieldCPU(struct interrupt_context* intctx, void* user);
void ThreadExitCPU(struct interrupt_context* intctx, void* user);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2016, 2021, 2022, 2023 Jonas 'Sortie' Termansen.
* Copyright (c) 2011-2016, 2021-2024 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
@ -97,6 +97,7 @@ int sys_getentropy(void*, size_t);
uid_t sys_geteuid(void);
gid_t sys_getgid(void);
int sys_gethostname(char*, size_t);
pid_t sys_getinit(pid_t);
size_t sys_getpagesize(void);
int sys_getpeername(int, void*, size_t*);
pid_t sys_getpgid(pid_t);
@ -151,6 +152,7 @@ int sys_setegid(gid_t);
int sys_seteuid(uid_t);
int sys_setgid(gid_t);
int sys_sethostname(const char*, size_t);
int sys_setinit(void);
int sys_setpgid(pid_t, pid_t);
int sys_setpriority(int, id_t, int);
pid_t sys_setsid(void);

View File

@ -190,6 +190,8 @@
#define SYSCALL_SETDNSCONFIG 167
#define SYSCALL_FUTEX 168
#define SYSCALL_MEMUSAGE 169
#define SYSCALL_MAX_NUM 170 /* index of highest constant + 1 */
#define SYSCALL_GETINIT 170
#define SYSCALL_SETINIT 171
#define SYSCALL_MAX_NUM 172 /* index of highest constant + 1 */
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2018, 2021-2023 Jonas 'Sortie' Termansen.
* Copyright (c) 2011-2018, 2021-2024 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
@ -381,6 +381,10 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo_p)
system->sessionprev = NULL;
system->sessionnext = NULL;
system->sessionfirst = system;
system->init = NULL;
system->initprev = NULL;
system->initnext = NULL;
system->initfirst = NULL;
if ( !(system->program_image_path = String::Clone("<kernel process>")) )
Panic("Unable to clone string for system process name");
@ -676,6 +680,10 @@ static void BootThread(void* /*user*/)
init->sessionprev = NULL;
init->sessionnext = NULL;
init->sessionfirst = init;
init->init = init;
init->initprev = NULL;
init->initnext = NULL;
init->initfirst = init;
kthread_mutex_unlock(&process_family_lock);
// TODO: Why don't we fork from pid=0 and this is done for us?
@ -685,7 +693,6 @@ static void BootThread(void* /*user*/)
mtable.Reset();
init->BootstrapDirectories(droot);
init->addrspace = initaddrspace;
Scheduler::SetInitProcess(init);
Thread* initthread = RunKernelThread(init, InitThread, NULL, "main");
if ( !initthread )

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2016, 2021-2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2011-2016, 2021-2024 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
@ -73,8 +73,6 @@ kthread_mutex_t process_family_lock = KTHREAD_MUTEX_INITIALIZER;
// The system is shutting down and creation of additional processes and threads
// should be prevented. Protected by process_family_lock.
static bool is_init_exiting = false;
Process::Process()
{
program_image_path = NULL;
@ -130,10 +128,15 @@ Process::Process()
sessionprev = NULL;
sessionnext = NULL;
sessionfirst = NULL;
init = NULL;
initprev = NULL;
initnext = NULL;
initfirst = NULL;
zombiecond = KTHREAD_COND_INITIALIZER;
iszombie = false;
nozombify = false;
limbo = false;
is_init_exiting = false;
exit_code = -1;
firstthread = NULL;
@ -168,9 +171,11 @@ Process::~Process() // process_family_lock taken
alarm_timer.Detach();
delete[] program_image_path;
assert(!zombiechild);
assert(!init);
assert(!session);
assert(!group);
assert(!parent);
assert(!initfirst);
assert(!sessionfirst);
assert(!groupfirst);
assert(!firstchild);
@ -208,9 +213,6 @@ void Process::BootstrapDirectories(Ref<Descriptor> root)
void Process::OnLastThreadExit()
{
Process* init = Scheduler::GetInitProcess();
assert(init);
// Child processes can't be reparented away if we're init. The system is
// about to shut down, so broadcast SIGKILL every process and wait for every
// single process to exit. The operating system is finished when init has
@ -221,14 +223,21 @@ void Process::OnLastThreadExit()
// Forbid any more processes and threads from being created, so this
// loop will always terminate.
is_init_exiting = true;
kthread_mutex_lock(&ptrlock);
for ( pid_t pid = ptable->Next(0); 0 < pid; pid = ptable->Next(pid) )
Process* process = firstchild;
while ( process )
{
Process* process = ptable->Get(pid);
if ( process->pid != 0 && process != init )
if ( process->pid != 0 )
process->DeliverSignal(SIGKILL);
if ( process->init == process )
process->is_init_exiting = true;
if ( process->firstchild )
process = process->firstchild;
while ( process && process != this && !process->nextsibling )
process = process->parent;
if ( process == this )
break;
process = process->nextsibling;
}
kthread_mutex_unlock(&ptrlock);
// NotifyChildExit always signals zombiecond for init when
// is_init_exiting is true.
while ( firstchild )
@ -342,12 +351,10 @@ void Process::LastPrayer()
iszombie = true;
// Init is nice and will gladly raise our orphaned children and zombies.
Process* init = Scheduler::GetInitProcess();
assert(init);
// Child processes can't be reparented away if we're init. OnLastThreadExit
// must have already killed all the child processes and prevented more from
// being created.
assert(init);
if ( init == this )
{
assert(is_init_exiting);
@ -386,6 +393,9 @@ void Process::LastPrayer()
// Remove ourself from our session.
if ( session )
session->SessionRemoveMember(this);
// Remove ourself from our init.
if ( init )
init->InitRemoveMember(this);
bool zombify = !nozombify;
@ -403,7 +413,7 @@ void Process::WaitedFor() // process_family_lock taken
{
parent = NULL;
limbo = false;
if ( groupfirst || sessionfirst )
if ( groupfirst || sessionfirst || initfirst )
limbo = true;
if ( !limbo )
delete this;
@ -460,9 +470,23 @@ void Process::SessionRemoveMember(Process* child) // process_family_lock taken
delete this;
}
void Process::InitRemoveMember(Process* child) // process_family_lock taken
{
assert(child->init == this);
if ( child->initprev )
child->initprev->initnext = child->initnext;
else
initfirst = child->initnext;
if ( child->initnext )
child->initnext->initprev = child->initprev;
child->init = NULL;
if ( IsLimboDone() )
delete this;
}
bool Process::IsLimboDone() // process_family_lock taken
{
return limbo && !groupfirst && !sessionfirst;
return limbo && !groupfirst && !sessionfirst && !initfirst;
}
// process_family_lock taken
@ -491,7 +515,7 @@ void Process::NotifyChildExit(Process* child, bool zombify)
// when init is exiting, because OnLastThreadExit needs to be able to catch
// every child exiting.
DeliverSignal(SIGCHLD);
if ( zombify || (is_init_exiting && Scheduler::GetInitProcess() == this) )
if ( zombify || is_init_exiting )
kthread_cond_broadcast(&zombiecond);
}
@ -704,7 +728,7 @@ Process* Process::Fork()
kthread_mutex_lock(&process_family_lock);
// Forbid the creation of new processes if init has exited.
if ( is_init_exiting )
if ( init->is_init_exiting )
{
kthread_mutex_unlock(&process_family_lock);
clone->AbortConstruction();
@ -741,6 +765,13 @@ Process* Process::Fork()
session->sessionfirst->sessionprev = clone;
session->sessionfirst = clone;
// Add the new process to the current init.
clone->init = init;
clone->initprev = NULL;
if ( (clone->initnext = init->initfirst) )
init->initfirst->initprev = clone;
init->initfirst = clone;
kthread_mutex_unlock(&process_family_lock);
// Initialize everything that is safe and can't fail.
@ -1487,14 +1518,12 @@ pid_t sys_tfork(int flags, struct tfork* user_regs)
stack_aligned = (stack_aligned + 16) & ~(stack_alignment-1);
stack_aligned_size &= 0xFFFFFFF0;
Process* parent_process = CurrentProcess();
Process* child_process;
if ( making_thread )
child_process = CurrentProcess();
else if ( !(child_process = CurrentProcess()->Fork()) )
{
delete[] newkernelstack;
return -1;
}
child_process = parent_process;
else if ( !(child_process = parent_process->Fork()) )
return delete[] newkernelstack, -1;
struct thread_registers cpuregs;
memset(&cpuregs, 0, sizeof(cpuregs));
@ -1550,7 +1579,7 @@ pid_t sys_tfork(int flags, struct tfork* user_regs)
// Forbid the creation of new threads if init has exited.
ScopedLock process_family_lock_lock(&process_family_lock);
if ( is_init_exiting )
if ( child_process->init->is_init_exiting )
return errno = EPERM, -1;
// If the thread could not be created, make the process commit suicide
@ -1604,7 +1633,8 @@ pid_t sys_getpgid(pid_t pid)
pid_t sys_getsid(pid_t pid)
{
ScopedLock lock(&process_family_lock);
Process* process = !pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid);
Process* process =
!pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid);
if ( !process )
return errno = ESRCH, -1;
if ( !process->session )
@ -1612,6 +1642,16 @@ pid_t sys_getsid(pid_t pid)
return process->session->pid;
}
pid_t sys_getinit(pid_t pid)
{
ScopedLock lock(&process_family_lock);
Process* process =
!pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid);
if ( !process->init )
return errno = ESRCH, -1;
return process->init->pid;
}
int sys_setpgid(pid_t pid, pid_t pgid)
{
if ( pid < 0 || pgid < 0 )
@ -1710,6 +1750,49 @@ pid_t sys_setsid(void)
return process->pid;
}
int sys_setinit(void)
{
Process* process = CurrentProcess();
ScopedLock lock(&process_family_lock);
// Test if already a process group leader.
if ( process->group == process )
return errno = EPERM, -1;
// Remove the process from its current process group.
if ( process->group )
process->group->GroupRemoveMember(process);
// Remove the process from its current session.
if ( process->session )
process->session->SessionRemoveMember(process);
// Remove the process from its current init.
if ( process->init )
process->init->InitRemoveMember(process);
// Insert the process into its new init.
process->initprev = NULL;
process->initnext = NULL;
process->initfirst = process;
process->init = process;
// Insert the process into its new session.
process->sessionprev = NULL;
process->sessionnext = NULL;
process->sessionfirst = process;
process->session = process;
// Insert the process into its new process group.
process->groupprev = NULL;
process->groupnext = NULL;
process->groupfirst = process;
process->group = process;
return process->pid;
}
size_t sys_getpagesize(void)
{
return Page::Size();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2016, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2015, 2016, 2022, 2024 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
@ -110,11 +110,21 @@ int sys_psctl(pid_t pid, int request, void* ptr)
psst.sid_next = -1;
}
psst.sid_first = process->sessionfirst ? process->sessionfirst->pid : -1;
// TODO: Implement init groupings.
psst.init = 1;
psst.init_prev = ptable->Prev(pid);
psst.init_next = ptable->Next(pid);
psst.init_first = pid == 1 ? 1 : -1;
if ( process->init )
{
Process* init = process->init;
psst.init = init->pid;
psst.init_prev = process->initprev ? process->initprev->pid : -1;
psst.init_next = process->initnext ? process->initnext->pid : -1;
}
else
{
psst.init = -1;
psst.init_prev = -1;
psst.init_next = -1;
}
psst.init_first = process->initfirst ? process->initfirst->pid : -1;
kthread_mutex_lock(&process->idlock);
psst.uid = process->uid;
psst.euid = process->euid;

View File

@ -268,7 +268,6 @@ static void SwitchRegisters(struct interrupt_context* intctx,
static Thread* idle_thread;
static Thread* first_runnable_thread;
static Thread* true_current_thread;
static Process* init_process;
static void SwitchThread(struct interrupt_context* intctx,
Thread* old_thread,
@ -407,16 +406,6 @@ void SetIdleThread(Thread* thread)
true_current_thread = thread;
}
void SetInitProcess(Process* init)
{
init_process = init;
}
Process* GetInitProcess()
{
return init_process;
}
Process* GetKernelProcess()
{
if ( !idle_thread )

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2016, 2021-2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2011-2016, 2021-2024 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
@ -204,6 +204,8 @@ void* syscall_list[SYSCALL_MAX_NUM + 1] =
[SYSCALL_SETDNSCONFIG] = (void*) sys_setdnsconfig,
[SYSCALL_FUTEX] = (void*) sys_futex,
[SYSCALL_MEMUSAGE] = (void*) sys_memusage,
[SYSCALL_GETINIT] = (void*) sys_getinit,
[SYSCALL_SETINIT] = (void*) sys_setinit,
[SYSCALL_MAX_NUM] = (void*) sys_bad_syscall,
};
} /* extern "C" */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2021 Jonas 'Sortie' Termansen.
* Copyright (c) 2012-2016, 2021, 2024 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
@ -852,12 +852,23 @@ int TTY::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
return errno = EIO, -1;
if ( cmd == TIOCSCTTY )
{
// TODO: After releasing Sortix 1.1, restore the invalid arguments check
// that is temporarily omitted since some Sortix 1.1 commits invoke the
// ioctl without an argument which was accidentally undefined. For now
// the kernel should be able to largely run older userspaces without
// issue, however terminal(1) did this which was fairly essential.
//if ( ((int) arg) & ~1 )
// return errno = EINVAL, -1;
bool force = arg & 1;
if ( !force && 0 <= sid )
return errno = EPERM, -1;
ScopedLock family_lock(&process_family_lock);
if ( 0 <= sid )
return errno = EPERM, -1;
Process* process = CurrentProcess();
if ( !process->sessionfirst )
if ( !force && !process->sessionfirst )
return errno = EPERM, -1;
Process* session = process->session;
// TODO: Don't do this if the sesion already has a tty.
Process* group = process->group;
if ( (ctx->dflags & (O_READ | O_WRITE)) != (O_READ | O_WRITE) )
return errno = EPERM, -1;
Ref<Vnode> vnode(new Vnode(Ref<Inode>(this), Ref<Vnode>(NULL), 0, 0));
@ -866,11 +877,34 @@ int TTY::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
Ref<Descriptor> desc(new Descriptor(vnode, O_READ | O_WRITE));
if ( !desc )
return -1;
sid = process->pid;
foreground_pgid = process->pid;
process->SetTTY(desc);
if ( 0 <= sid )
{
Process* owner = process->GetPTable()->Get(sid);
if ( owner )
owner->SetTTY(Ref<Descriptor>());
// TODO: SIGHUP?
}
sid = session->pid;
foreground_pgid = group->pid;
session->SetTTY(desc);
return 0;
}
else if ( cmd == TIOCUCTTY )
{
if ( ((int) arg) & ~1 )
return errno = EINVAL, -1;
if ( 0 <= sid )
{
ScopedLock family_lock(&process_family_lock);
Process* owner = CurrentProcess()->GetPTable()->Get(sid);
// TODO: If !(arg & 1) fail if not the right session owner?
if ( owner )
owner->SetTTY(Ref<Descriptor>());
// TODO: SIGHUP?
}
sid = -1;
foreground_pgid = -1;
}
else if ( cmd == TIOCSPTLCK )
{
// TODO: Figure out what locked ptys are and implement it if sensible.

View File

@ -713,6 +713,7 @@ unistd/getentropy.o \
unistd/geteuid.o \
unistd/getgid.o \
unistd/gethostname.o \
unistd/getinit.o \
unistd/getlogin.o \
unistd/getlogin_r.o \
unistd/getpagesize.o \
@ -741,6 +742,7 @@ unistd/setegid.o \
unistd/seteuid.o \
unistd/setgid.o \
unistd/sethostname.o \
unistd/setinit.o \
unistd/setpgid.o \
unistd/setsid.o \
unistd/setuid.o \
@ -779,6 +781,8 @@ MANPAGES2=\
scram/scram.2 \
sys/dnsconfig/getdnsconfig.2 \
sys/dnsconfig/setdnsconfig.2 \
unistd/setinit.2 \
unistd/getinit.2 \
MANPAGES3=\
time/add_leap_seconds.3 \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
* Copyright (c) 2011-2016, 2024 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
@ -562,8 +562,10 @@ int exit_thread(int, int, const struct exit_thread*);
int fchdirat(int, const char*);
int fchroot(int);
int fchrootat(int, const char*);
pid_t getinit(pid_t);
int memstat(size_t* memused, size_t* memtotal);
int mkpartition(int fd, off_t start, off_t length);
pid_t setinit(void);
pid_t sfork(int flags);
pid_t tfork(int flags, struct tfork* regs);
int truncateat(int dirfd, const char*, off_t);

1
libc/unistd/getinit.2 Symbolic link
View File

@ -0,0 +1 @@
setinit.2

29
libc/unistd/getinit.c Normal file
View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 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.
*
* unistd/getinit.c
* Get the current init.
*/
#include <sys/syscall.h>
#include <unistd.h>
DEFN_SYSCALL1(pid_t, sys_getinit, SYSCALL_GETINIT, pid_t);
pid_t getinit(pid_t pid)
{
return sys_getinit(pid);
}

75
libc/unistd/setinit.2 Normal file
View File

@ -0,0 +1,75 @@
.Dd June 18, 2024
.Dt SETINIT 2
.Os
.Sh NAME
.Nm setinit
.Nd become and locate init
.Sh SYNOPSIS
.In unistd.h
.Ft int
.Fn getinit "pid_t pid"
.Ft int
.Fn setinit void
.Sh DESCRIPTION
.Fn setinit
sets the current process as the init process for itself and its subsequently
created descendant processes.
.Fn setinit
runs
.Xr setsid 2
to create a new session (and process group) and can fail for the same reasons as
.Xr setsid 2 .
.Pp
.Fn getinit
returns the init process for the process specified in
.Fa pid ,
or the current process if
.Fa pid
is zero.
.Pp
Orphaned descendant processes are reparented to their init process.
If an init process exits, all descendant processes atomically receive the
.Dv SIGKILL
signal and become unable to create new processes and threads.
.Sh RETURN VALUES
.Fn setinit
returns the pid of the init process (the current process) on success, or -1 on
error and
.Va error
is set appropriately.
.Pp
.Fn getinit
returns the returns the pid of the init process, or -1 on
error and
.Va error
is set appropriately.
.Sh ERRORS
.Fn setinit
will fail if:
.Bl -tag -width "12345678"
.It Er EPERM
The process is already a process group leader, a session leader, or an init
process.
.El
.Pp
.Fn getinit
will fail if:
.Bl -tag -width "12345678"
.It Er ESRCH
The process specified in
.Fa pid
does not exist.
.El
.Sh SEE ALSO
.Xr getpgrp 2 ,
.Xr getsid 2 ,
.Xr psctl 2 ,
.Xr setpgrp 2 ,
.Xr setsid 2 ,
.Xr init 8
.Sh HISTORY
The
.Fn getinit
and
.Fn setinit
system calls originally appeared in Sortix 1.1.

29
libc/unistd/setinit.c Normal file
View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 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.
*
* unistd/setinit.c
* Become init.
*/
#include <sys/syscall.h>
#include <unistd.h>
DEFN_SYSCALL0(pid_t, sys_setinit, SYSCALL_SETINIT);
pid_t setinit(void)
{
return sys_setinit();
}

View File

@ -69,6 +69,21 @@ releasing Sortix x.y, foo." to allow the maintainer to easily
.Xr grep 1
for it after a release.
.Sh CHANGES
.Ss Add init groups
The
.Xr setinit 2
and
.Xr getinit 2
system calls have been added for nested init groups.
The
.Dv TIOCSCTTY
.Xr ioctl 2
for acquiring a controlling terminal has gained a force flag essential to
transferring terminals into nested sessions, and the new
.Dv TIOCUCTTY
.Xr ioctl 2
releases a controlling terminal.
This is a minor compatible ABI change.
.Ss Add tix-repository(8)
The new
.Xr tix-repository 8

View File

@ -1751,7 +1751,6 @@ int main(void)
unmount_all_but_root();
unsetenv("SYSINSTALL_TARGET");
unsetenv("SHLVL");
unsetenv("INIT_PID");
exit(execute((const char*[]) { "chroot", "-d", fs,
"/sbin/init", NULL }, "f"));
}

View File

@ -1210,7 +1210,7 @@ int main(int argc, char* argv[])
warn("setsid");
_exit(1);
}
if ( ioctl(slave_fd, TIOCSCTTY) < 0 )
if ( ioctl(slave_fd, TIOCSCTTY, 0) < 0 )
{
warn("ioctl: TIOCSCTTY");
_exit(1);

View File

@ -71,7 +71,7 @@ int main(int argc, char* argv[])
}
if ( setsid() < 0 )
err(1, "setsid");
if ( ioctl(tty, TIOCSCTTY) < 0 )
if ( ioctl(tty, TIOCSCTTY, 0) < 0 )
err(1, "ioctl: TIOCSCTTY");
if ( close(0) < 0 || close(1) < 0 || close(2) < 0 )
err(1, "close");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2021, 2022, 2024 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
@ -23,6 +23,7 @@
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
@ -38,11 +39,7 @@ int main(int argc, char* argv[])
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"));
pid_t init_pid = getinit(0);
if ( kill(init_pid, SIGQUIT) < 0 )
err(1, "kill: %" PRIdPID, init_pid);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2021, 2022, 2024 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
@ -23,6 +23,7 @@
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
@ -38,11 +39,7 @@ int main(int argc, char* argv[])
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"));
pid_t init_pid = getinit(0);
if ( kill(init_pid, SIGTERM) < 0 )
err(1, "kill: %" PRIdPID, init_pid);

View File

@ -288,7 +288,7 @@ int main(int argc, char* argv[])
warn("setsid");
_exit(1);
}
if ( ioctl(slave_fd, TIOCSCTTY) < 0 )
if ( ioctl(slave_fd, TIOCSCTTY, 0) < 0 )
{
warn("ioctl: TIOCSCTTY");
_exit(1);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022 Jonas 'Sortie' Termansen.
* Copyright (c) 2021, 2022, 2024 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
@ -23,6 +23,7 @@
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
@ -38,11 +39,7 @@ int main(int argc, char* argv[])
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"));
pid_t init_pid = getinit(0);
if ( kill(init_pid, SIGINT) < 0 )
err(1, "kill: %" PRIdPID, init_pid);