mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 01:07:35 +00:00
Kernel: PID/PGID typing
This compiles, and fixes two bugs: - setpgid() confusion (see previous commit) - tcsetpgrp() now allows to set a non-empty process group even if the group leader has already died. This makes Serenity slightly more POSIX-compatible.
This commit is contained in:
parent
f5744a6f2f
commit
7bdf54c837
7 changed files with 53 additions and 46 deletions
|
@ -822,9 +822,9 @@ Optional<KBuffer> procfs$all(InodeIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
process_object.add("pid", process.pid().value());
|
process_object.add("pid", process.pid().value());
|
||||||
process_object.add("pgid", process.tty() ? process.tty()->pgid() : 0);
|
process_object.add("pgid", process.tty() ? process.tty()->pgid().value() : 0);
|
||||||
process_object.add("pgp", process.pgid());
|
process_object.add("pgp", process.pgid().value());
|
||||||
process_object.add("sid", process.sid());
|
process_object.add("sid", process.sid().value());
|
||||||
process_object.add("uid", process.uid());
|
process_object.add("uid", process.uid());
|
||||||
process_object.add("gid", process.gid());
|
process_object.add("gid", process.gid());
|
||||||
process_object.add("ppid", process.ppid().value());
|
process_object.add("ppid", process.ppid().value());
|
||||||
|
|
|
@ -100,7 +100,8 @@ ProcessID Process::allocate_pid()
|
||||||
// Overflow is UB, and negative PIDs wreck havoc.
|
// Overflow is UB, and negative PIDs wreck havoc.
|
||||||
// TODO: Handle PID overflow
|
// TODO: Handle PID overflow
|
||||||
// For example: Use an Atomic<u32>, mask the most significant bit,
|
// For example: Use an Atomic<u32>, mask the most significant bit,
|
||||||
// retry if PID is already taken as a PID, taken as a TID, or zero.
|
// retry if PID is already taken as a PID, taken as a TID,
|
||||||
|
// takes as a PGID, taken as a SID, or zero.
|
||||||
return next_pid.fetch_add(1, AK::MemoryOrder::memory_order_acq_rel);
|
return next_pid.fetch_add(1, AK::MemoryOrder::memory_order_acq_rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,11 +153,14 @@ public:
|
||||||
const PageDirectory& page_directory() const { return *m_page_directory; }
|
const PageDirectory& page_directory() const { return *m_page_directory; }
|
||||||
|
|
||||||
static RefPtr<Process> from_pid(ProcessID);
|
static RefPtr<Process> from_pid(ProcessID);
|
||||||
|
static SessionID get_sid_from_pgid(ProcessGroupID pgid);
|
||||||
|
|
||||||
const String& name() const { return m_name; }
|
const String& name() const { return m_name; }
|
||||||
ProcessID pid() const { return m_pid; }
|
ProcessID pid() const { return m_pid; }
|
||||||
pid_t sid() const { return m_sid; }
|
SessionID sid() const { return m_sid; }
|
||||||
pid_t pgid() const { return m_pgid; }
|
bool is_session_leader() const { return m_sid.value() == m_pid.value(); }
|
||||||
|
ProcessGroupID pgid() const { return m_pgid; }
|
||||||
|
bool is_group_leader() const { return m_pgid.value() == m_pid.value(); }
|
||||||
const FixedArray<gid_t>& extra_gids() const { return m_extra_gids; }
|
const FixedArray<gid_t>& extra_gids() const { return m_extra_gids; }
|
||||||
uid_t euid() const { return m_euid; }
|
uid_t euid() const { return m_euid; }
|
||||||
gid_t egid() const { return m_egid; }
|
gid_t egid() const { return m_egid; }
|
||||||
|
@ -179,7 +182,7 @@ public:
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
static void for_each(Callback);
|
static void for_each(Callback);
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
static void for_each_in_pgrp(pid_t, Callback);
|
static void for_each_in_pgrp(ProcessGroupID, Callback);
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_child(Callback);
|
void for_each_child(Callback);
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
|
@ -617,8 +620,8 @@ private:
|
||||||
String m_name;
|
String m_name;
|
||||||
|
|
||||||
ProcessID m_pid { 0 };
|
ProcessID m_pid { 0 };
|
||||||
pid_t m_sid { 0 };
|
SessionID m_sid { 0 };
|
||||||
pid_t m_pgid { 0 };
|
ProcessGroupID m_pgid { 0 };
|
||||||
|
|
||||||
uid_t m_euid { 0 };
|
uid_t m_euid { 0 };
|
||||||
gid_t m_egid { 0 };
|
gid_t m_egid { 0 };
|
||||||
|
@ -772,7 +775,7 @@ inline void Process::for_each_thread(Callback callback) const
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
inline void Process::for_each_in_pgrp(pid_t pgid, Callback callback)
|
inline void Process::for_each_in_pgrp(ProcessGroupID pgid, Callback callback)
|
||||||
{
|
{
|
||||||
ASSERT_INTERRUPTS_DISABLED();
|
ASSERT_INTERRUPTS_DISABLED();
|
||||||
ScopedSpinLock lock(g_processes_lock);
|
ScopedSpinLock lock(g_processes_lock);
|
||||||
|
|
|
@ -52,7 +52,8 @@ KResult Process::do_killpg(pid_t pgrp, int signal)
|
||||||
// Send the signal to all processes in the given group.
|
// Send the signal to all processes in the given group.
|
||||||
if (pgrp == 0) {
|
if (pgrp == 0) {
|
||||||
// Send the signal to our own pgrp.
|
// Send the signal to our own pgrp.
|
||||||
pgrp = pgid();
|
// FIXME: PIF/PGID INCOMPLETE
|
||||||
|
pgrp = pgid().value();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool group_was_empty = true;
|
bool group_was_empty = true;
|
||||||
|
|
|
@ -33,14 +33,14 @@ pid_t Process::sys$getsid(pid_t pid)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(proc);
|
REQUIRE_PROMISE(proc);
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
return m_sid;
|
return m_sid.value();
|
||||||
ScopedSpinLock lock(g_processes_lock);
|
ScopedSpinLock lock(g_processes_lock);
|
||||||
auto process = Process::from_pid(pid);
|
auto process = Process::from_pid(pid);
|
||||||
if (!process)
|
if (!process)
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
if (m_sid != process->m_sid)
|
if (m_sid != process->m_sid)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
return process->m_sid;
|
return process->m_sid.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t Process::sys$setsid()
|
pid_t Process::sys$setsid()
|
||||||
|
@ -48,44 +48,49 @@ pid_t Process::sys$setsid()
|
||||||
REQUIRE_PROMISE(proc);
|
REQUIRE_PROMISE(proc);
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
bool found_process_with_same_pgid_as_my_pid = false;
|
bool found_process_with_same_pgid_as_my_pid = false;
|
||||||
// FIXME: PID/PGID ISSUE?
|
|
||||||
Process::for_each_in_pgrp(pid().value(), [&](auto&) {
|
Process::for_each_in_pgrp(pid().value(), [&](auto&) {
|
||||||
found_process_with_same_pgid_as_my_pid = true;
|
found_process_with_same_pgid_as_my_pid = true;
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
});
|
});
|
||||||
if (found_process_with_same_pgid_as_my_pid)
|
if (found_process_with_same_pgid_as_my_pid)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
// Create a new Session and a new ProcessGroup.
|
||||||
m_sid = m_pid.value();
|
m_sid = m_pid.value();
|
||||||
m_pgid = m_pid.value();
|
m_pgid = m_pid.value();
|
||||||
m_tty = nullptr;
|
m_tty = nullptr;
|
||||||
return m_sid;
|
return m_sid.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t Process::sys$getpgid(pid_t pid)
|
pid_t Process::sys$getpgid(pid_t pid)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(proc);
|
REQUIRE_PROMISE(proc);
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
return m_pgid;
|
return m_pgid.value();
|
||||||
ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle
|
ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle
|
||||||
auto process = Process::from_pid(pid);
|
auto process = Process::from_pid(pid);
|
||||||
if (!process)
|
if (!process)
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
return process->m_pgid;
|
return process->m_pgid.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t Process::sys$getpgrp()
|
pid_t Process::sys$getpgrp()
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(stdio);
|
REQUIRE_PROMISE(stdio);
|
||||||
return m_pgid;
|
return m_pgid.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
static pid_t get_sid_from_pgid(pid_t pgid)
|
SessionID Process::get_sid_from_pgid(ProcessGroupID pgid)
|
||||||
{
|
{
|
||||||
|
// FIXME: This xor sys$setsid() uses the wrong locking mechanism.
|
||||||
ScopedSpinLock lock(g_processes_lock);
|
ScopedSpinLock lock(g_processes_lock);
|
||||||
auto group_leader = Process::from_pid(pgid);
|
|
||||||
if (!group_leader)
|
SessionID sid { -1 };
|
||||||
return -1;
|
Process::for_each_in_pgrp(pgid, [&](auto& process) {
|
||||||
return group_leader->sid();
|
sid = process.sid();
|
||||||
|
return IterationDecision::Break;
|
||||||
|
});
|
||||||
|
|
||||||
|
return sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
|
int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
|
||||||
|
@ -105,7 +110,7 @@ int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
|
||||||
// of the calling process or of a child process of the calling process.
|
// of the calling process or of a child process of the calling process.
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
}
|
}
|
||||||
if (process->pid() == process->sid()) {
|
if (process->is_session_leader()) {
|
||||||
// The process indicated by the pid argument is a session leader.
|
// The process indicated by the pid argument is a session leader.
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
@ -116,10 +121,9 @@ int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: PID/PGID INCOMPLETE
|
ProcessGroupID new_pgid = specified_pgid ? ProcessGroupID(specified_pgid) : process->m_pid.value();
|
||||||
pid_t new_pgid = specified_pgid ? specified_pgid : process->m_pid.value();
|
SessionID current_sid = sid();
|
||||||
pid_t current_sid = get_sid_from_pgid(process->m_pgid);
|
SessionID new_sid = get_sid_from_pgid(new_pgid);
|
||||||
pid_t new_sid = get_sid_from_pgid(new_pgid);
|
|
||||||
if (current_sid != new_sid) {
|
if (current_sid != new_sid) {
|
||||||
// Can't move a process between sessions.
|
// Can't move a process between sessions.
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
|
@ -159,6 +159,7 @@ void TTY::emit(u8 ch)
|
||||||
if (auto parent = Process::from_pid(m_process->ppid()))
|
if (auto parent = Process::from_pid(m_process->ppid()))
|
||||||
(void)parent->send_signal(SIGCHLD, m_process);
|
(void)parent->send_signal(SIGCHLD, m_process);
|
||||||
}
|
}
|
||||||
|
// TODO: Else send it to the session leader maybe?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,7 +254,7 @@ void TTY::generate_signal(int signal)
|
||||||
return;
|
return;
|
||||||
if (should_flush_on_signal())
|
if (should_flush_on_signal())
|
||||||
flush_input();
|
flush_input();
|
||||||
dbg() << tty_name() << ": Send signal " << signal << " to everyone in pgrp " << pgid();
|
dbg() << tty_name() << ": Send signal " << signal << " to everyone in pgrp " << pgid().value();
|
||||||
InterruptDisabler disabler; // FIXME: Iterate over a set of process handles instead?
|
InterruptDisabler disabler; // FIXME: Iterate over a set of process handles instead?
|
||||||
Process::for_each_in_pgrp(pgid(), [&](auto& process) {
|
Process::for_each_in_pgrp(pgid(), [&](auto& process) {
|
||||||
dbg() << tty_name() << ": Send signal " << signal << " to " << process;
|
dbg() << tty_name() << ": Send signal " << signal << " to " << process;
|
||||||
|
@ -291,7 +292,6 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(tty);
|
REQUIRE_PROMISE(tty);
|
||||||
auto& current_process = *Process::current();
|
auto& current_process = *Process::current();
|
||||||
pid_t pgid;
|
|
||||||
termios* user_termios;
|
termios* user_termios;
|
||||||
winsize* user_winsize;
|
winsize* user_winsize;
|
||||||
|
|
||||||
|
@ -304,23 +304,21 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
||||||
#endif
|
#endif
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case TIOCGPGRP:
|
case TIOCGPGRP:
|
||||||
return this->pgid();
|
return this->pgid().value();
|
||||||
case TIOCSPGRP:
|
case TIOCSPGRP: {
|
||||||
pgid = static_cast<pid_t>(arg);
|
ProcessGroupID pgid = static_cast<pid_t>(arg);
|
||||||
if (pgid <= 0)
|
if (pgid <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
{
|
InterruptDisabler disabler;
|
||||||
InterruptDisabler disabler;
|
auto process = Process::from_pid(pgid.value());
|
||||||
auto process = Process::from_pid(pgid);
|
SessionID new_sid = process ? process->sid() : Process::get_sid_from_pgid(pgid);
|
||||||
if (!process)
|
if (!new_sid || new_sid != current_process.sid())
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (pgid != process->pgid())
|
if (process && pgid != process->pgid())
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (current_process.sid() != process->sid())
|
m_process = process ? process->make_weak_ptr() : WeakPtr<Process>();
|
||||||
return -EPERM;
|
|
||||||
m_process = process->make_weak_ptr();
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
case TCGETS: {
|
case TCGETS: {
|
||||||
user_termios = reinterpret_cast<termios*>(arg);
|
user_termios = reinterpret_cast<termios*>(arg);
|
||||||
if (!current_process.validate_write(user_termios, sizeof(termios)))
|
if (!current_process.validate_write(user_termios, sizeof(termios)))
|
||||||
|
@ -395,7 +393,7 @@ void TTY::hang_up()
|
||||||
generate_signal(SIGHUP);
|
generate_signal(SIGHUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t TTY::pgid() const
|
ProcessGroupID TTY::pgid() const
|
||||||
{
|
{
|
||||||
return m_process ? m_process->pgid() : 0;
|
return m_process ? m_process->pgid() : 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
unsigned short rows() const { return m_rows; }
|
unsigned short rows() const { return m_rows; }
|
||||||
unsigned short columns() const { return m_columns; }
|
unsigned short columns() const { return m_columns; }
|
||||||
|
|
||||||
pid_t pgid() const;
|
ProcessGroupID pgid() const;
|
||||||
|
|
||||||
void set_termios(const termios&);
|
void set_termios(const termios&);
|
||||||
bool should_generate_signals() const { return m_termios.c_lflag & ISIG; }
|
bool should_generate_signals() const { return m_termios.c_lflag & ISIG; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue