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:
parent
09ca6ea01e
commit
6e51c1ae51
28 changed files with 377 additions and 90 deletions
2
Makefile
2
Makefile
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
17
init/init.c
17
init/init.c
|
@ -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) )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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" */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
1
libc/unistd/getinit.2
Symbolic link
|
@ -0,0 +1 @@
|
|||
setinit.2
|
29
libc/unistd/getinit.c
Normal file
29
libc/unistd/getinit.c
Normal 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
75
libc/unistd/setinit.2
Normal 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
29
libc/unistd/setinit.c
Normal 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();
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue