1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:07:45 +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:
Ben Wiederhake 2020-08-08 22:04:20 +02:00 committed by Andreas Kling
parent f5744a6f2f
commit 7bdf54c837
7 changed files with 53 additions and 46 deletions

View file

@ -822,9 +822,9 @@ Optional<KBuffer> procfs$all(InodeIdentifier)
}
process_object.add("pid", process.pid().value());
process_object.add("pgid", process.tty() ? process.tty()->pgid() : 0);
process_object.add("pgp", process.pgid());
process_object.add("sid", process.sid());
process_object.add("pgid", process.tty() ? process.tty()->pgid().value() : 0);
process_object.add("pgp", process.pgid().value());
process_object.add("sid", process.sid().value());
process_object.add("uid", process.uid());
process_object.add("gid", process.gid());
process_object.add("ppid", process.ppid().value());

View file

@ -100,7 +100,8 @@ ProcessID Process::allocate_pid()
// Overflow is UB, and negative PIDs wreck havoc.
// TODO: Handle PID overflow
// 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);
}

View file

@ -153,11 +153,14 @@ public:
const PageDirectory& page_directory() const { return *m_page_directory; }
static RefPtr<Process> from_pid(ProcessID);
static SessionID get_sid_from_pgid(ProcessGroupID pgid);
const String& name() const { return m_name; }
ProcessID pid() const { return m_pid; }
pid_t sid() const { return m_sid; }
pid_t pgid() const { return m_pgid; }
SessionID sid() const { return m_sid; }
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; }
uid_t euid() const { return m_euid; }
gid_t egid() const { return m_egid; }
@ -179,7 +182,7 @@ public:
template<typename Callback>
static void for_each(Callback);
template<typename Callback>
static void for_each_in_pgrp(pid_t, Callback);
static void for_each_in_pgrp(ProcessGroupID, Callback);
template<typename Callback>
void for_each_child(Callback);
template<typename Callback>
@ -617,8 +620,8 @@ private:
String m_name;
ProcessID m_pid { 0 };
pid_t m_sid { 0 };
pid_t m_pgid { 0 };
SessionID m_sid { 0 };
ProcessGroupID m_pgid { 0 };
uid_t m_euid { 0 };
gid_t m_egid { 0 };
@ -772,7 +775,7 @@ inline void Process::for_each_thread(Callback callback) const
}
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();
ScopedSpinLock lock(g_processes_lock);

View file

@ -52,7 +52,8 @@ KResult Process::do_killpg(pid_t pgrp, int signal)
// Send the signal to all processes in the given group.
if (pgrp == 0) {
// Send the signal to our own pgrp.
pgrp = pgid();
// FIXME: PIF/PGID INCOMPLETE
pgrp = pgid().value();
}
bool group_was_empty = true;

View file

@ -33,14 +33,14 @@ pid_t Process::sys$getsid(pid_t pid)
{
REQUIRE_PROMISE(proc);
if (pid == 0)
return m_sid;
return m_sid.value();
ScopedSpinLock lock(g_processes_lock);
auto process = Process::from_pid(pid);
if (!process)
return -ESRCH;
if (m_sid != process->m_sid)
return -EPERM;
return process->m_sid;
return process->m_sid.value();
}
pid_t Process::sys$setsid()
@ -48,44 +48,49 @@ pid_t Process::sys$setsid()
REQUIRE_PROMISE(proc);
InterruptDisabler disabler;
bool found_process_with_same_pgid_as_my_pid = false;
// FIXME: PID/PGID ISSUE?
Process::for_each_in_pgrp(pid().value(), [&](auto&) {
found_process_with_same_pgid_as_my_pid = true;
return IterationDecision::Break;
});
if (found_process_with_same_pgid_as_my_pid)
return -EPERM;
// Create a new Session and a new ProcessGroup.
m_sid = m_pid.value();
m_pgid = m_pid.value();
m_tty = nullptr;
return m_sid;
return m_sid.value();
}
pid_t Process::sys$getpgid(pid_t pid)
{
REQUIRE_PROMISE(proc);
if (pid == 0)
return m_pgid;
return m_pgid.value();
ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle
auto process = Process::from_pid(pid);
if (!process)
return -ESRCH;
return process->m_pgid;
return process->m_pgid.value();
}
pid_t Process::sys$getpgrp()
{
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);
auto group_leader = Process::from_pid(pgid);
if (!group_leader)
return -1;
return group_leader->sid();
SessionID sid { -1 };
Process::for_each_in_pgrp(pgid, [&](auto& process) {
sid = process.sid();
return IterationDecision::Break;
});
return sid;
}
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.
return -ESRCH;
}
if (process->pid() == process->sid()) {
if (process->is_session_leader()) {
// The process indicated by the pid argument is a session leader.
return -EPERM;
}
@ -116,10 +121,9 @@ int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
return -EPERM;
}
// FIXME: PID/PGID INCOMPLETE
pid_t new_pgid = specified_pgid ? specified_pgid : process->m_pid.value();
pid_t current_sid = get_sid_from_pgid(process->m_pgid);
pid_t new_sid = get_sid_from_pgid(new_pgid);
ProcessGroupID new_pgid = specified_pgid ? ProcessGroupID(specified_pgid) : process->m_pid.value();
SessionID current_sid = sid();
SessionID new_sid = get_sid_from_pgid(new_pgid);
if (current_sid != new_sid) {
// Can't move a process between sessions.
return -EPERM;

View file

@ -159,6 +159,7 @@ void TTY::emit(u8 ch)
if (auto parent = Process::from_pid(m_process->ppid()))
(void)parent->send_signal(SIGCHLD, m_process);
}
// TODO: Else send it to the session leader maybe?
return;
}
}
@ -253,7 +254,7 @@ void TTY::generate_signal(int signal)
return;
if (should_flush_on_signal())
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?
Process::for_each_in_pgrp(pgid(), [&](auto& process) {
dbg() << tty_name() << ": Send signal " << signal << " to " << process;
@ -291,7 +292,6 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
{
REQUIRE_PROMISE(tty);
auto& current_process = *Process::current();
pid_t pgid;
termios* user_termios;
winsize* user_winsize;
@ -304,23 +304,21 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
#endif
switch (request) {
case TIOCGPGRP:
return this->pgid();
case TIOCSPGRP:
pgid = static_cast<pid_t>(arg);
return this->pgid().value();
case TIOCSPGRP: {
ProcessGroupID pgid = static_cast<pid_t>(arg);
if (pgid <= 0)
return -EINVAL;
{
InterruptDisabler disabler;
auto process = Process::from_pid(pgid);
if (!process)
auto process = Process::from_pid(pgid.value());
SessionID new_sid = process ? process->sid() : Process::get_sid_from_pgid(pgid);
if (!new_sid || new_sid != current_process.sid())
return -EPERM;
if (pgid != process->pgid())
if (process && pgid != process->pgid())
return -EPERM;
if (current_process.sid() != process->sid())
return -EPERM;
m_process = process->make_weak_ptr();
}
m_process = process ? process->make_weak_ptr() : WeakPtr<Process>();
return 0;
}
case TCGETS: {
user_termios = reinterpret_cast<termios*>(arg);
if (!current_process.validate_write(user_termios, sizeof(termios)))
@ -395,7 +393,7 @@ void TTY::hang_up()
generate_signal(SIGHUP);
}
pid_t TTY::pgid() const
ProcessGroupID TTY::pgid() const
{
return m_process ? m_process->pgid() : 0;
}

View file

@ -50,7 +50,7 @@ public:
unsigned short rows() const { return m_rows; }
unsigned short columns() const { return m_columns; }
pid_t pgid() const;
ProcessGroupID pgid() const;
void set_termios(const termios&);
bool should_generate_signals() const { return m_termios.c_lflag & ISIG; }