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 '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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
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];
|
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");
|
||||||
|
@ -4302,9 +4300,12 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent recursive init without care.
|
// Prevent recursive init without care.
|
||||||
if ( getenv("INIT_PID") )
|
if ( getinit(0) != 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");
|
||||||
|
@ -4460,6 +4461,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();
|
||||||
|
@ -4472,6 +4476,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.
|
||||||
|
@ -4502,6 +4510,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) )
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(pid_t);
|
||||||
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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
|
@ -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,21 @@ 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);
|
Process* process = firstchild;
|
||||||
for ( pid_t pid = ptable->Next(0); 0 < pid; pid = ptable->Next(pid) )
|
while ( process )
|
||||||
{
|
{
|
||||||
Process* process = ptable->Get(pid);
|
if ( process->pid != 0 )
|
||||||
if ( process->pid != 0 && process != init )
|
|
||||||
process->DeliverSignal(SIGKILL);
|
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
|
// NotifyChildExit always signals zombiecond for init when
|
||||||
// is_init_exiting is true.
|
// is_init_exiting is true.
|
||||||
while ( firstchild )
|
while ( firstchild )
|
||||||
|
@ -342,12 +351,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 +393,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 +413,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 +470,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 +515,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 +728,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 +765,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 +1518,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 +1579,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
|
||||||
|
@ -1604,7 +1633,8 @@ pid_t sys_getpgid(pid_t pid)
|
||||||
pid_t sys_getsid(pid_t pid)
|
pid_t sys_getsid(pid_t pid)
|
||||||
{
|
{
|
||||||
ScopedLock lock(&process_family_lock);
|
ScopedLock lock(&process_family_lock);
|
||||||
Process* process = !pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid);
|
Process* process =
|
||||||
|
!pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid);
|
||||||
if ( !process )
|
if ( !process )
|
||||||
return errno = ESRCH, -1;
|
return errno = ESRCH, -1;
|
||||||
if ( !process->session )
|
if ( !process->session )
|
||||||
|
@ -1612,6 +1642,16 @@ pid_t sys_getsid(pid_t pid)
|
||||||
return process->session->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)
|
int sys_setpgid(pid_t pid, pid_t pgid)
|
||||||
{
|
{
|
||||||
if ( pid < 0 || pgid < 0 )
|
if ( pid < 0 || pgid < 0 )
|
||||||
|
@ -1710,6 +1750,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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
|
@ -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" */
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 \
|
||||||
|
@ -779,6 +781,8 @@ MANPAGES2=\
|
||||||
scram/scram.2 \
|
scram/scram.2 \
|
||||||
sys/dnsconfig/getdnsconfig.2 \
|
sys/dnsconfig/getdnsconfig.2 \
|
||||||
sys/dnsconfig/setdnsconfig.2 \
|
sys/dnsconfig/setdnsconfig.2 \
|
||||||
|
unistd/setinit.2 \
|
||||||
|
unistd/getinit.2 \
|
||||||
|
|
||||||
MANPAGES3=\
|
MANPAGES3=\
|
||||||
time/add_leap_seconds.3 \
|
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
|
* 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(pid_t);
|
||||||
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);
|
||||||
|
|
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
|
.Xr grep 1
|
||||||
for it after a release.
|
for it after a release.
|
||||||
.Sh CHANGES
|
.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)
|
.Ss Add tix-repository(8)
|
||||||
The new
|
The new
|
||||||
.Xr tix-repository 8
|
.Xr tix-repository 8
|
||||||
|
|
|
@ -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"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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(0);
|
||||||
// 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);
|
||||||
|
|
||||||
|
|
|
@ -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(0);
|
||||||
// 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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(0);
|
||||||
// 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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue