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 2d221e1ff1
commit d07beee30a
25 changed files with 273 additions and 89 deletions

View file

@ -232,7 +232,7 @@ sysroot-system: sysroot-fsh sysroot-base-headers
echo 'ID=sortix' && \ echo 'ID=sortix' && \
echo 'VERSION_ID="$(VERSION)"' && \ echo 'VERSION_ID="$(VERSION)"' && \
echo 'PRETTY_NAME="Sortix $(VERSION)"' && \ echo 'PRETTY_NAME="Sortix $(VERSION)"' && \
echo 'SORTIX_ABI=2.0' && \ echo 'SORTIX_ABI=2.1' && \
true) > "$(SYSROOT)/etc/sortix-release" true) > "$(SYSROOT)/etc/sortix-release"
echo /etc/sortix-release >> "$(SYSROOT)/tix/manifest/system" echo /etc/sortix-release >> "$(SYSROOT)/tix/manifest/system"
ln -sf sortix-release "$(SYSROOT)/etc/os-release" 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 .Sh ENVIRONMENT
.Nm .Nm
sets the following environment variables. sets the following environment variables.
.Bl -tag -width "INIT_PID" .Bl -tag -width "LOGNAME"
.It Ev HOME .It Ev HOME
root's home directory root's home directory
.It Ev INIT_PID
.Nm Ns 's
process id
.It Ev LOGNAME .It Ev LOGNAME
root root
.It Ev PATH .It Ev PATH

View file

@ -2532,7 +2532,6 @@ static void daemon_start(struct daemon* daemon)
char ppid_str[sizeof(pid_t) * 3]; char ppid_str[sizeof(pid_t) * 3];
snprintf(ppid_str, sizeof(ppid_str), "%" PRIiPID, ppid); snprintf(ppid_str, sizeof(ppid_str), "%" PRIiPID, ppid);
if ( (!daemon->need_tty && setenv("READYFD", "3", 1)) < 0 || if ( (!daemon->need_tty && setenv("READYFD", "3", 1)) < 0 ||
setenv("INIT_PID", ppid_str, 1) < 0 ||
setenv("LOGNAME", pwd->pw_name, 1) < 0 || setenv("LOGNAME", pwd->pw_name, 1) < 0 ||
setenv("USER", pwd->pw_name, 1) < 0 || setenv("USER", pwd->pw_name, 1) < 0 ||
setenv("HOME", home, 1) < 0 || setenv("HOME", home, 1) < 0 ||
@ -2628,7 +2627,6 @@ static void daemon_start(struct daemon* daemon)
// TODO: Also unset other things. // TODO: Also unset other things.
if ( !daemon->need_tty ) if ( !daemon->need_tty )
unsetenv("READYFD"); unsetenv("READYFD");
unsetenv("INIT_PID");
unsetenv("LOGNAME"); unsetenv("LOGNAME");
unsetenv("USER"); unsetenv("USER");
unsetenv("HOME"); unsetenv("HOME");
@ -4299,9 +4297,12 @@ int main(int argc, char* argv[])
} }
// Prevent recursive init without care. // Prevent recursive init without care.
if ( getenv("INIT_PID") ) if ( getinit() != getpid() )
fatal("System is already managed by an init process"); 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. // Register handler that shuts down the system when init exits.
if ( atexit(niht) != 0 ) if ( atexit(niht) != 0 )
fatal("atexit: %m"); fatal("atexit: %m");
@ -4457,6 +4458,9 @@ int main(int argc, char* argv[])
chain_location_dev_made = true; chain_location_dev_made = true;
close(new_dev_fd); close(new_dev_fd);
close(old_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. // TODO: Forward the early init log to the chain init.
// Run the chain booted operating system. // Run the chain booted operating system.
pid_t child_pid = fork(); pid_t child_pid = fork();
@ -4469,6 +4473,10 @@ int main(int argc, char* argv[])
fatal("chroot: %s: %m", chain_location); fatal("chroot: %s: %m", chain_location);
if ( chdir("/") < 0 ) if ( chdir("/") < 0 )
fatal("chdir: %s: %m", chain_location); 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]; const char* program = next_argv[0];
char verbose_opt[] = {'-', "sqv"[verbosity], '\0'}; char verbose_opt[] = {'-', "sqv"[verbosity], '\0'};
// Chain boot the operating system upgrade if needed. // Chain boot the operating system upgrade if needed.
@ -4499,6 +4507,9 @@ int main(int argc, char* argv[])
} }
sigprocmask(SIG_BLOCK, &handled_signals, NULL); sigprocmask(SIG_BLOCK, &handled_signals, NULL);
forward_signal_pid = -1; // Racy with waitpid. forward_signal_pid = -1; // Racy with waitpid.
if ( ioctl(tty_fd, TIOCSCTTY, 1) < 0 )
fatal("ioctl: TIOCSCTTY: %m");
close(tty_fd);
if ( WIFEXITED(status) ) if ( WIFEXITED(status) )
return WEXITSTATUS(status); return WEXITSTATUS(status);
else if ( WIFSIGNALED(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 * 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
@ -39,6 +39,7 @@
#define TIOCGNAME __IOCTL(6, __IOCTL_TYPE_PTR) #define TIOCGNAME __IOCTL(6, __IOCTL_TYPE_PTR)
#define TIOCGPTN __IOCTL(7, __IOCTL_TYPE_PTR) #define TIOCGPTN __IOCTL(7, __IOCTL_TYPE_PTR)
#define TIOCGDISPLAYS __IOCTL(8, __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(x) ((x) >> 0 & 0xFF)
#define IOC_TYPE_BLOCK_DEVICE 1 #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 * 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
@ -124,12 +124,17 @@ public:
Process* sessionprev; Process* sessionprev;
Process* sessionnext; Process* sessionnext;
Process* sessionfirst; Process* sessionfirst;
Process* init;
Process* initprev;
Process* initnext;
Process* initfirst;
kthread_mutex_t childlock; kthread_mutex_t childlock;
kthread_mutex_t parentlock; kthread_mutex_t parentlock;
kthread_cond_t zombiecond; kthread_cond_t zombiecond;
bool iszombie; bool iszombie;
bool nozombify; bool nozombify;
bool limbo; bool limbo;
bool is_init_exiting;
int exit_code; int exit_code;
public: public:
@ -178,6 +183,7 @@ public:
int prot); int prot);
void GroupRemoveMember(Process* child); void GroupRemoveMember(Process* child);
void SessionRemoveMember(Process* child); void SessionRemoveMember(Process* child);
void InitRemoveMember(Process* child);
public: public:
Process* Fork(); 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); void SetSignalPending(Thread* thread, unsigned long is_pending);
ThreadState GetThreadState(Thread* thread); ThreadState GetThreadState(Thread* thread);
void SetIdleThread(Thread* thread); void SetIdleThread(Thread* thread);
void SetInitProcess(Process* init);
Process* GetInitProcess();
Process* GetKernelProcess(); Process* GetKernelProcess();
void InterruptYieldCPU(struct interrupt_context* intctx, void* user); void InterruptYieldCPU(struct interrupt_context* intctx, void* user);
void ThreadExitCPU(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 * 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
@ -97,6 +97,7 @@ int sys_getentropy(void*, size_t);
uid_t sys_geteuid(void); uid_t sys_geteuid(void);
gid_t sys_getgid(void); gid_t sys_getgid(void);
int sys_gethostname(char*, size_t); int sys_gethostname(char*, size_t);
pid_t sys_getinit(void);
size_t sys_getpagesize(void); size_t sys_getpagesize(void);
int sys_getpeername(int, void*, size_t*); int sys_getpeername(int, void*, size_t*);
pid_t sys_getpgid(pid_t); pid_t sys_getpgid(pid_t);
@ -151,6 +152,7 @@ int sys_setegid(gid_t);
int sys_seteuid(uid_t); int sys_seteuid(uid_t);
int sys_setgid(gid_t); int sys_setgid(gid_t);
int sys_sethostname(const char*, size_t); int sys_sethostname(const char*, size_t);
int sys_setinit(void);
int sys_setpgid(pid_t, pid_t); int sys_setpgid(pid_t, pid_t);
int sys_setpriority(int, id_t, int); int sys_setpriority(int, id_t, int);
pid_t sys_setsid(void); pid_t sys_setsid(void);

View file

@ -190,6 +190,8 @@
#define SYSCALL_SETDNSCONFIG 167 #define SYSCALL_SETDNSCONFIG 167
#define SYSCALL_FUTEX 168 #define SYSCALL_FUTEX 168
#define SYSCALL_MEMUSAGE 169 #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 #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 * 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
@ -381,6 +381,10 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo_p)
system->sessionprev = NULL; system->sessionprev = NULL;
system->sessionnext = NULL; system->sessionnext = NULL;
system->sessionfirst = system; system->sessionfirst = system;
system->init = NULL;
system->initprev = NULL;
system->initnext = NULL;
system->initfirst = NULL;
if ( !(system->program_image_path = String::Clone("<kernel process>")) ) if ( !(system->program_image_path = String::Clone("<kernel process>")) )
Panic("Unable to clone string for system process name"); Panic("Unable to clone string for system process name");
@ -676,6 +680,10 @@ static void BootThread(void* /*user*/)
init->sessionprev = NULL; init->sessionprev = NULL;
init->sessionnext = NULL; init->sessionnext = NULL;
init->sessionfirst = init; init->sessionfirst = init;
init->init = init;
init->initprev = NULL;
init->initnext = NULL;
init->initfirst = init;
kthread_mutex_unlock(&process_family_lock); kthread_mutex_unlock(&process_family_lock);
// TODO: Why don't we fork from pid=0 and this is done for us? // 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(); mtable.Reset();
init->BootstrapDirectories(droot); init->BootstrapDirectories(droot);
init->addrspace = initaddrspace; init->addrspace = initaddrspace;
Scheduler::SetInitProcess(init);
Thread* initthread = RunKernelThread(init, InitThread, NULL, "main"); Thread* initthread = RunKernelThread(init, InitThread, NULL, "main");
if ( !initthread ) 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 * 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
@ -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 // The system is shutting down and creation of additional processes and threads
// should be prevented. Protected by process_family_lock. // should be prevented. Protected by process_family_lock.
static bool is_init_exiting = false;
Process::Process() Process::Process()
{ {
program_image_path = NULL; program_image_path = NULL;
@ -130,10 +128,15 @@ Process::Process()
sessionprev = NULL; sessionprev = NULL;
sessionnext = NULL; sessionnext = NULL;
sessionfirst = NULL; sessionfirst = NULL;
init = NULL;
initprev = NULL;
initnext = NULL;
initfirst = NULL;
zombiecond = KTHREAD_COND_INITIALIZER; zombiecond = KTHREAD_COND_INITIALIZER;
iszombie = false; iszombie = false;
nozombify = false; nozombify = false;
limbo = false; limbo = false;
is_init_exiting = false;
exit_code = -1; exit_code = -1;
firstthread = NULL; firstthread = NULL;
@ -168,9 +171,11 @@ Process::~Process() // process_family_lock taken
alarm_timer.Detach(); alarm_timer.Detach();
delete[] program_image_path; delete[] program_image_path;
assert(!zombiechild); assert(!zombiechild);
assert(!init);
assert(!session); assert(!session);
assert(!group); assert(!group);
assert(!parent); assert(!parent);
assert(!initfirst);
assert(!sessionfirst); assert(!sessionfirst);
assert(!groupfirst); assert(!groupfirst);
assert(!firstchild); assert(!firstchild);
@ -208,9 +213,6 @@ void Process::BootstrapDirectories(Ref<Descriptor> root)
void Process::OnLastThreadExit() void Process::OnLastThreadExit()
{ {
Process* init = Scheduler::GetInitProcess();
assert(init);
// Child processes can't be reparented away if we're init. The system is // 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 // 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 // single process to exit. The operating system is finished when init has
@ -221,14 +223,12 @@ void Process::OnLastThreadExit()
// Forbid any more processes and threads from being created, so this // Forbid any more processes and threads from being created, so this
// loop will always terminate. // loop will always terminate.
is_init_exiting = true; is_init_exiting = true;
kthread_mutex_lock(&ptrlock); for ( Process* process = initfirst; process;
for ( pid_t pid = ptable->Next(0); 0 < pid; pid = ptable->Next(pid) ) process = process->initnext )
{ {
Process* process = ptable->Get(pid); if ( process->pid != 0 && process != this )
if ( process->pid != 0 && process != init )
process->DeliverSignal(SIGKILL); process->DeliverSignal(SIGKILL);
} }
kthread_mutex_unlock(&ptrlock);
// NotifyChildExit always signals zombiecond for init when // NotifyChildExit always signals zombiecond for init when
// is_init_exiting is true. // is_init_exiting is true.
while ( firstchild ) while ( firstchild )
@ -342,12 +342,10 @@ void Process::LastPrayer()
iszombie = true; iszombie = true;
// Init is nice and will gladly raise our orphaned children and zombies. // 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 // Child processes can't be reparented away if we're init. OnLastThreadExit
// must have already killed all the child processes and prevented more from // must have already killed all the child processes and prevented more from
// being created. // being created.
assert(init);
if ( init == this ) if ( init == this )
{ {
assert(is_init_exiting); assert(is_init_exiting);
@ -386,6 +384,9 @@ void Process::LastPrayer()
// Remove ourself from our session. // Remove ourself from our session.
if ( session ) if ( session )
session->SessionRemoveMember(this); session->SessionRemoveMember(this);
// Remove ourself from our init.
if ( init )
init->InitRemoveMember(this);
bool zombify = !nozombify; bool zombify = !nozombify;
@ -403,7 +404,7 @@ void Process::WaitedFor() // process_family_lock taken
{ {
parent = NULL; parent = NULL;
limbo = false; limbo = false;
if ( groupfirst || sessionfirst ) if ( groupfirst || sessionfirst || initfirst )
limbo = true; limbo = true;
if ( !limbo ) if ( !limbo )
delete this; delete this;
@ -460,9 +461,23 @@ void Process::SessionRemoveMember(Process* child) // process_family_lock taken
delete this; 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 bool Process::IsLimboDone() // process_family_lock taken
{ {
return limbo && !groupfirst && !sessionfirst; return limbo && !groupfirst && !sessionfirst && !initfirst;
} }
// process_family_lock taken // process_family_lock taken
@ -491,7 +506,7 @@ void Process::NotifyChildExit(Process* child, bool zombify)
// when init is exiting, because OnLastThreadExit needs to be able to catch // when init is exiting, because OnLastThreadExit needs to be able to catch
// every child exiting. // every child exiting.
DeliverSignal(SIGCHLD); DeliverSignal(SIGCHLD);
if ( zombify || (is_init_exiting && Scheduler::GetInitProcess() == this) ) if ( zombify || is_init_exiting )
kthread_cond_broadcast(&zombiecond); kthread_cond_broadcast(&zombiecond);
} }
@ -704,7 +719,7 @@ Process* Process::Fork()
kthread_mutex_lock(&process_family_lock); kthread_mutex_lock(&process_family_lock);
// Forbid the creation of new processes if init has exited. // 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); kthread_mutex_unlock(&process_family_lock);
clone->AbortConstruction(); clone->AbortConstruction();
@ -741,6 +756,13 @@ Process* Process::Fork()
session->sessionfirst->sessionprev = clone; session->sessionfirst->sessionprev = clone;
session->sessionfirst = 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); kthread_mutex_unlock(&process_family_lock);
// Initialize everything that is safe and can't fail. // Initialize everything that is safe and can't fail.
@ -1487,14 +1509,12 @@ pid_t sys_tfork(int flags, struct tfork* user_regs)
stack_aligned = (stack_aligned + 16) & ~(stack_alignment-1); stack_aligned = (stack_aligned + 16) & ~(stack_alignment-1);
stack_aligned_size &= 0xFFFFFFF0; stack_aligned_size &= 0xFFFFFFF0;
Process* parent_process = CurrentProcess();
Process* child_process; Process* child_process;
if ( making_thread ) if ( making_thread )
child_process = CurrentProcess(); child_process = parent_process;
else if ( !(child_process = CurrentProcess()->Fork()) ) else if ( !(child_process = parent_process->Fork()) )
{ return delete[] newkernelstack, -1;
delete[] newkernelstack;
return -1;
}
struct thread_registers cpuregs; struct thread_registers cpuregs;
memset(&cpuregs, 0, sizeof(cpuregs)); memset(&cpuregs, 0, sizeof(cpuregs));
@ -1550,7 +1570,7 @@ pid_t sys_tfork(int flags, struct tfork* user_regs)
// Forbid the creation of new threads if init has exited. // Forbid the creation of new threads if init has exited.
ScopedLock process_family_lock_lock(&process_family_lock); ScopedLock process_family_lock_lock(&process_family_lock);
if ( is_init_exiting ) if ( child_process->init->is_init_exiting )
return errno = EPERM, -1; return errno = EPERM, -1;
// If the thread could not be created, make the process commit suicide // If the thread could not be created, make the process commit suicide
@ -1612,6 +1632,15 @@ pid_t sys_getsid(pid_t pid)
return process->session->pid; return process->session->pid;
} }
pid_t sys_getinit(void)
{
ScopedLock lock(&process_family_lock);
Process* process = CurrentProcess();
if ( !process->init )
return errno = ESRCH, -1;
return process->init->pid;
}
int sys_setpgid(pid_t pid, pid_t pgid) int sys_setpgid(pid_t pid, pid_t pgid)
{ {
if ( pid < 0 || pgid < 0 ) if ( pid < 0 || pgid < 0 )
@ -1710,6 +1739,49 @@ pid_t sys_setsid(void)
return process->pid; 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) size_t sys_getpagesize(void)
{ {
return Page::Size(); 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 * 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
@ -110,11 +110,21 @@ int sys_psctl(pid_t pid, int request, void* ptr)
psst.sid_next = -1; psst.sid_next = -1;
} }
psst.sid_first = process->sessionfirst ? process->sessionfirst->pid : -1; psst.sid_first = process->sessionfirst ? process->sessionfirst->pid : -1;
// TODO: Implement init groupings.
psst.init = 1; if ( process->init )
psst.init_prev = ptable->Prev(pid); {
psst.init_next = ptable->Next(pid); Process* init = process->init;
psst.init_first = pid == 1 ? 1 : -1; 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); kthread_mutex_lock(&process->idlock);
psst.uid = process->uid; psst.uid = process->uid;
psst.euid = process->euid; psst.euid = process->euid;

View file

@ -268,7 +268,6 @@ static void SwitchRegisters(struct interrupt_context* intctx,
static Thread* idle_thread; static Thread* idle_thread;
static Thread* first_runnable_thread; static Thread* first_runnable_thread;
static Thread* true_current_thread; static Thread* true_current_thread;
static Process* init_process;
static void SwitchThread(struct interrupt_context* intctx, static void SwitchThread(struct interrupt_context* intctx,
Thread* old_thread, Thread* old_thread,
@ -407,16 +406,6 @@ void SetIdleThread(Thread* thread)
true_current_thread = thread; true_current_thread = thread;
} }
void SetInitProcess(Process* init)
{
init_process = init;
}
Process* GetInitProcess()
{
return init_process;
}
Process* GetKernelProcess() Process* GetKernelProcess()
{ {
if ( !idle_thread ) 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 * 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
@ -204,6 +204,8 @@ void* syscall_list[SYSCALL_MAX_NUM + 1] =
[SYSCALL_SETDNSCONFIG] = (void*) sys_setdnsconfig, [SYSCALL_SETDNSCONFIG] = (void*) sys_setdnsconfig,
[SYSCALL_FUTEX] = (void*) sys_futex, [SYSCALL_FUTEX] = (void*) sys_futex,
[SYSCALL_MEMUSAGE] = (void*) sys_memusage, [SYSCALL_MEMUSAGE] = (void*) sys_memusage,
[SYSCALL_GETINIT] = (void*) sys_getinit,
[SYSCALL_SETINIT] = (void*) sys_setinit,
[SYSCALL_MAX_NUM] = (void*) sys_bad_syscall, [SYSCALL_MAX_NUM] = (void*) sys_bad_syscall,
}; };
} /* extern "C" */ } /* 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 * 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
@ -852,12 +852,23 @@ int TTY::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
return errno = EIO, -1; return errno = EIO, -1;
if ( cmd == TIOCSCTTY ) 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); ScopedLock family_lock(&process_family_lock);
if ( 0 <= sid )
return errno = EPERM, -1;
Process* process = CurrentProcess(); Process* process = CurrentProcess();
if ( !process->sessionfirst ) if ( !force && !process->sessionfirst )
return errno = EPERM, -1; 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) ) if ( (ctx->dflags & (O_READ | O_WRITE)) != (O_READ | O_WRITE) )
return errno = EPERM, -1; return errno = EPERM, -1;
Ref<Vnode> vnode(new Vnode(Ref<Inode>(this), Ref<Vnode>(NULL), 0, 0)); 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)); Ref<Descriptor> desc(new Descriptor(vnode, O_READ | O_WRITE));
if ( !desc ) if ( !desc )
return -1; return -1;
sid = process->pid; if ( 0 <= sid )
foreground_pgid = process->pid; {
process->SetTTY(desc); 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; 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 ) else if ( cmd == TIOCSPTLCK )
{ {
// TODO: Figure out what locked ptys are and implement it if sensible. // 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/geteuid.o \
unistd/getgid.o \ unistd/getgid.o \
unistd/gethostname.o \ unistd/gethostname.o \
unistd/getinit.o \
unistd/getlogin.o \ unistd/getlogin.o \
unistd/getlogin_r.o \ unistd/getlogin_r.o \
unistd/getpagesize.o \ unistd/getpagesize.o \
@ -741,6 +742,7 @@ unistd/setegid.o \
unistd/seteuid.o \ unistd/seteuid.o \
unistd/setgid.o \ unistd/setgid.o \
unistd/sethostname.o \ unistd/sethostname.o \
unistd/setinit.o \
unistd/setpgid.o \ unistd/setpgid.o \
unistd/setsid.o \ unistd/setsid.o \
unistd/setuid.o \ unistd/setuid.o \

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 * 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
@ -562,8 +562,10 @@ int exit_thread(int, int, const struct exit_thread*);
int fchdirat(int, const char*); int fchdirat(int, const char*);
int fchroot(int); int fchroot(int);
int fchrootat(int, const char*); int fchrootat(int, const char*);
pid_t getinit(void);
int memstat(size_t* memused, size_t* memtotal); int memstat(size_t* memused, size_t* memtotal);
int mkpartition(int fd, off_t start, off_t length); int mkpartition(int fd, off_t start, off_t length);
pid_t setinit(void);
pid_t sfork(int flags); pid_t sfork(int flags);
pid_t tfork(int flags, struct tfork* regs); pid_t tfork(int flags, struct tfork* regs);
int truncateat(int dirfd, const char*, off_t); int truncateat(int dirfd, const char*, off_t);

30
libc/unistd/getinit.c Normal file
View file

@ -0,0 +1,30 @@
/*
* 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_SYSCALL0(pid_t, sys_getinit, SYSCALL_GETINIT);
// TODO: Should this accept a pid like getsid?
pid_t getinit(void)
{
return sys_getinit();
}

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

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

View file

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

View file

@ -71,7 +71,7 @@ int main(int argc, char* argv[])
} }
if ( setsid() < 0 ) if ( setsid() < 0 )
err(1, "setsid"); err(1, "setsid");
if ( ioctl(tty, TIOCSCTTY) < 0 ) if ( ioctl(tty, TIOCSCTTY, 0) < 0 )
err(1, "ioctl: TIOCSCTTY"); err(1, "ioctl: TIOCSCTTY");
if ( close(0) < 0 || close(1) < 0 || close(2) < 0 ) if ( close(0) < 0 || close(1) < 0 || close(2) < 0 )
err(1, "close"); 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 * 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
@ -23,6 +23,7 @@
#include <getopt.h> #include <getopt.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
@ -38,11 +39,7 @@ int main(int argc, char* argv[])
if ( optind < argc ) if ( optind < argc )
errx(1, "extra operand: %s", argv[optind]); errx(1, "extra operand: %s", argv[optind]);
pid_t init_pid = 1; pid_t init_pid = getinit();
// 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 ) if ( kill(init_pid, SIGQUIT) < 0 )
err(1, "kill: %" PRIdPID, init_pid); 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 * 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
@ -23,6 +23,7 @@
#include <getopt.h> #include <getopt.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
@ -38,11 +39,7 @@ int main(int argc, char* argv[])
if ( optind < argc ) if ( optind < argc )
errx(1, "extra operand: %s", argv[optind]); errx(1, "extra operand: %s", argv[optind]);
pid_t init_pid = 1; pid_t init_pid = getinit();
// 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 ) if ( kill(init_pid, SIGTERM) < 0 )
err(1, "kill: %" PRIdPID, init_pid); err(1, "kill: %" PRIdPID, init_pid);

View file

@ -288,7 +288,7 @@ int main(int argc, char* argv[])
warn("setsid"); warn("setsid");
_exit(1); _exit(1);
} }
if ( ioctl(slave_fd, TIOCSCTTY) < 0 ) if ( ioctl(slave_fd, TIOCSCTTY, 0) < 0 )
{ {
warn("ioctl: TIOCSCTTY"); warn("ioctl: TIOCSCTTY");
_exit(1); _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 * 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
@ -23,6 +23,7 @@
#include <getopt.h> #include <getopt.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
@ -38,11 +39,7 @@ int main(int argc, char* argv[])
if ( optind < argc ) if ( optind < argc )
errx(1, "extra operand: %s", argv[optind]); errx(1, "extra operand: %s", argv[optind]);
pid_t init_pid = 1; pid_t init_pid = getinit();
// 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 ) if ( kill(init_pid, SIGINT) < 0 )
err(1, "kill: %" PRIdPID, init_pid); err(1, "kill: %" PRIdPID, init_pid);