mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 05:48:12 +00:00
Add some basic signal support.
It only works for sending a signal to a process that's in userspace code. We implement reception by synthesizing a PUSHA+PUSHF in the receiving process (operating on values in the TSS.) The TSS CS:EIP is then rerouted to the signal handler and a tiny return trampoline is constructed in a dedicated region in the receiving process. Also hacked up /bin/kill to be able to send arbitrary signals (kill -N PID)
This commit is contained in:
parent
52d502e11f
commit
153ea704af
13 changed files with 240 additions and 30 deletions
|
@ -218,6 +218,8 @@ Region* MemoryManager::region_from_laddr(Process& process, LinearAddress laddr)
|
||||||
if (region->contains(laddr))
|
if (region->contains(laddr))
|
||||||
return region.ptr();
|
return region.ptr();
|
||||||
}
|
}
|
||||||
|
kprintf("%s(%u) Couldn't find region for L%x\n", process.name().characters(), process.pid(), laddr.get());
|
||||||
|
process.dumpRegions();
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -731,17 +731,18 @@ void Process::sys$exit(int status)
|
||||||
switchNow();
|
switchNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::send_signal(int signal, Process* sender)
|
void Process::terminate_due_to_signal(int signal, Process* sender)
|
||||||
{
|
{
|
||||||
ASSERT_INTERRUPTS_DISABLED();
|
ASSERT_INTERRUPTS_DISABLED();
|
||||||
bool wasCurrent = current == sender;
|
bool wasCurrent = this == current;
|
||||||
|
|
||||||
set_state(Exiting);
|
set_state(Exiting);
|
||||||
s_processes->remove(this);
|
s_processes->remove(this);
|
||||||
|
|
||||||
notify_waiters(m_pid, 0, signal);
|
notify_waiters(m_pid, 0, signal);
|
||||||
|
|
||||||
if (wasCurrent) {
|
if (wasCurrent) {
|
||||||
kprintf("Current process committing suicide!\n");
|
kprintf("Current process (%u) committing suicide!\n", pid());
|
||||||
if (!scheduleNewProcess()) {
|
if (!scheduleNewProcess()) {
|
||||||
kprintf("Process::send_signal: Failed to schedule a new process :(\n");
|
kprintf("Process::send_signal: Failed to schedule a new process :(\n");
|
||||||
HANG;
|
HANG;
|
||||||
|
@ -752,6 +753,75 @@ void Process::send_signal(int signal, Process* sender)
|
||||||
switchNow();
|
switchNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Process::send_signal(int signal, Process* sender)
|
||||||
|
{
|
||||||
|
ASSERT_INTERRUPTS_DISABLED();
|
||||||
|
ASSERT(signal < 32);
|
||||||
|
|
||||||
|
// FIXME: Handle send_signal to self.
|
||||||
|
ASSERT(this != current);
|
||||||
|
|
||||||
|
auto& action = m_signal_action_data[signal];
|
||||||
|
// FIXME: Implement SA_SIGINFO signal handlers.
|
||||||
|
ASSERT(!(action.flags & SA_SIGINFO));
|
||||||
|
|
||||||
|
auto handler_laddr = action.handler_or_sigaction;
|
||||||
|
if (handler_laddr.is_null())
|
||||||
|
return terminate_due_to_signal(signal, sender);
|
||||||
|
|
||||||
|
word ret_cs = m_tss.cs;
|
||||||
|
dword ret_eip = m_tss.eip;
|
||||||
|
dword ret_eflags = m_tss.eflags;
|
||||||
|
|
||||||
|
if ((ret_cs & 3) == 0) {
|
||||||
|
// FIXME: Handle send_signal to process currently in kernel code.
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessPagingScope pagingScope(*this);
|
||||||
|
dword old_esp = m_tss.esp;
|
||||||
|
push_value_on_stack(ret_eip);
|
||||||
|
push_value_on_stack(ret_eflags);
|
||||||
|
push_value_on_stack(m_tss.eax);
|
||||||
|
push_value_on_stack(m_tss.ecx);
|
||||||
|
push_value_on_stack(m_tss.edx);
|
||||||
|
push_value_on_stack(m_tss.ebx);
|
||||||
|
push_value_on_stack(old_esp);
|
||||||
|
push_value_on_stack(m_tss.ebp);
|
||||||
|
push_value_on_stack(m_tss.esi);
|
||||||
|
push_value_on_stack(m_tss.edi);
|
||||||
|
m_tss.eax = (dword)signal;
|
||||||
|
m_tss.cs = 0x1b;
|
||||||
|
m_tss.eip = handler_laddr.get();
|
||||||
|
|
||||||
|
if (m_return_from_signal_trampoline.is_null()) {
|
||||||
|
auto* region = allocate_region(LinearAddress(), PAGE_SIZE, "signal_trampoline", true, true); // FIXME: Remap as read-only after setup.
|
||||||
|
m_return_from_signal_trampoline = region->linearAddress;
|
||||||
|
byte* code_ptr = m_return_from_signal_trampoline.asPtr();
|
||||||
|
*code_ptr++ = 0x61; // popa
|
||||||
|
*code_ptr++ = 0x9d; // popf
|
||||||
|
*code_ptr++ = 0xc3; // ret
|
||||||
|
*code_ptr++ = 0x0f; // ud2
|
||||||
|
*code_ptr++ = 0x0b;
|
||||||
|
}
|
||||||
|
|
||||||
|
push_value_on_stack(m_return_from_signal_trampoline.get());
|
||||||
|
|
||||||
|
dbgprintf("signal: %s(%u) sent %d to %s(%u)\n", sender->name().characters(), sender->pid(), signal, name().characters(), pid());
|
||||||
|
|
||||||
|
if (sender == this) {
|
||||||
|
yield();
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::push_value_on_stack(dword value)
|
||||||
|
{
|
||||||
|
m_tss.esp -= 4;
|
||||||
|
dword* stack_ptr = (dword*)m_tss.esp;
|
||||||
|
*stack_ptr = value;
|
||||||
|
}
|
||||||
|
|
||||||
void Process::processDidCrash(Process* crashedProcess)
|
void Process::processDidCrash(Process* crashedProcess)
|
||||||
{
|
{
|
||||||
ASSERT_INTERRUPTS_DISABLED();
|
ASSERT_INTERRUPTS_DISABLED();
|
||||||
|
@ -1183,12 +1253,6 @@ int Process::sys$isatty(int fd)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Unix::sighandler_t Process::sys$signal(int signum, Unix::sighandler_t handler)
|
|
||||||
{
|
|
||||||
dbgprintf("sys$signal: %d => L%x\n", signum, handler);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Process::sys$kill(pid_t pid, int signal)
|
int Process::sys$kill(pid_t pid, int signal)
|
||||||
{
|
{
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
|
@ -1466,3 +1530,26 @@ int Process::sys$dup2(int old_fd, int new_fd)
|
||||||
m_file_descriptors[new_fd] = handle;
|
m_file_descriptors[new_fd] = handle;
|
||||||
return new_fd;
|
return new_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Unix::sighandler_t Process::sys$signal(int signum, Unix::sighandler_t handler)
|
||||||
|
{
|
||||||
|
// FIXME: Fail with -EINVAL if attepmting to catch or ignore SIGKILL or SIGSTOP.
|
||||||
|
if (signum >= 32)
|
||||||
|
return (Unix::sighandler_t)-EINVAL;
|
||||||
|
dbgprintf("sys$signal: %d => L%x\n", signum, handler);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Process::sys$sigaction(int signum, const Unix::sigaction* act, Unix::sigaction* old_act)
|
||||||
|
{
|
||||||
|
// FIXME: Fail with -EINVAL if attepmting to change action for SIGKILL or SIGSTOP.
|
||||||
|
if (signum >= 32)
|
||||||
|
return -EINVAL;
|
||||||
|
VALIDATE_USER_READ(act, sizeof(Unix::sigaction));
|
||||||
|
InterruptDisabler disabler; // FIXME: This should use a narrower lock.
|
||||||
|
auto& action = m_signal_action_data[signum];
|
||||||
|
action.restorer = LinearAddress((dword)act->sa_restorer);
|
||||||
|
action.flags = act->sa_flags;
|
||||||
|
action.handler_or_sigaction = LinearAddress((dword)act->sa_sigaction);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,13 @@ class PageDirectory;
|
||||||
class Region;
|
class Region;
|
||||||
class Zone;
|
class Zone;
|
||||||
|
|
||||||
|
struct SignalActionData {
|
||||||
|
LinearAddress handler_or_sigaction;
|
||||||
|
dword mask { 0 };
|
||||||
|
int flags { 0 };
|
||||||
|
LinearAddress restorer;
|
||||||
|
};
|
||||||
|
|
||||||
class Process : public InlineLinkedListNode<Process> {
|
class Process : public InlineLinkedListNode<Process> {
|
||||||
friend class InlineLinkedListNode<Process>;
|
friend class InlineLinkedListNode<Process>;
|
||||||
public:
|
public:
|
||||||
|
@ -129,6 +136,7 @@ public:
|
||||||
int sys$getdtablesize();
|
int sys$getdtablesize();
|
||||||
int sys$dup(int oldfd);
|
int sys$dup(int oldfd);
|
||||||
int sys$dup2(int oldfd, int newfd);
|
int sys$dup2(int oldfd, int newfd);
|
||||||
|
int sys$sigaction(int signum, const Unix::sigaction* act, Unix::sigaction* old_act);
|
||||||
|
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
||||||
|
@ -162,6 +170,7 @@ public:
|
||||||
const FileHandle* file_descriptor(size_t i) const { return m_file_descriptors[i].ptr(); }
|
const FileHandle* file_descriptor(size_t i) const { return m_file_descriptors[i].ptr(); }
|
||||||
|
|
||||||
void send_signal(int signal, Process* sender);
|
void send_signal(int signal, Process* sender);
|
||||||
|
void terminate_due_to_signal(int signal, Process* sender);
|
||||||
|
|
||||||
Process* fork(RegisterDump&);
|
Process* fork(RegisterDump&);
|
||||||
int exec(const String& path, Vector<String>&& arguments, Vector<String>&& environment);
|
int exec(const String& path, Vector<String>&& arguments, Vector<String>&& environment);
|
||||||
|
@ -172,7 +181,7 @@ private:
|
||||||
|
|
||||||
Process(String&& name, uid_t, gid_t, pid_t parentPID, RingLevel, RetainPtr<VirtualFileSystem::Node>&& cwd = nullptr, RetainPtr<VirtualFileSystem::Node>&& executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr);
|
Process(String&& name, uid_t, gid_t, pid_t parentPID, RingLevel, RetainPtr<VirtualFileSystem::Node>&& cwd = nullptr, RetainPtr<VirtualFileSystem::Node>&& executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr);
|
||||||
|
|
||||||
void allocateLDT();
|
void push_value_on_stack(dword);
|
||||||
|
|
||||||
PageDirectory* m_page_directory { nullptr };
|
PageDirectory* m_page_directory { nullptr };
|
||||||
|
|
||||||
|
@ -205,6 +214,7 @@ private:
|
||||||
int m_waiteeStatus { 0 };
|
int m_waiteeStatus { 0 };
|
||||||
int m_fdBlockedOnRead { -1 };
|
int m_fdBlockedOnRead { -1 };
|
||||||
size_t m_max_open_file_descriptors { 16 };
|
size_t m_max_open_file_descriptors { 16 };
|
||||||
|
SignalActionData m_signal_action_data[32];
|
||||||
|
|
||||||
RetainPtr<VirtualFileSystem::Node> m_cwd;
|
RetainPtr<VirtualFileSystem::Node> m_cwd;
|
||||||
RetainPtr<VirtualFileSystem::Node> m_executable;
|
RetainPtr<VirtualFileSystem::Node> m_executable;
|
||||||
|
@ -221,6 +231,8 @@ private:
|
||||||
// FIXME: Implement some kind of ASLR?
|
// FIXME: Implement some kind of ASLR?
|
||||||
LinearAddress m_nextRegion;
|
LinearAddress m_nextRegion;
|
||||||
|
|
||||||
|
LinearAddress m_return_from_signal_trampoline;
|
||||||
|
|
||||||
pid_t m_parentPID { 0 };
|
pid_t m_parentPID { 0 };
|
||||||
|
|
||||||
static void notify_waiters(pid_t waitee, int exit_status, int signal);
|
static void notify_waiters(pid_t waitee, int exit_status, int signal);
|
||||||
|
|
|
@ -146,6 +146,8 @@ static DWORD handle(RegisterDump& regs, DWORD function, DWORD arg1, DWORD arg2,
|
||||||
return current->sys$dup((int)arg1);
|
return current->sys$dup((int)arg1);
|
||||||
case Syscall::Dup2:
|
case Syscall::Dup2:
|
||||||
return current->sys$dup2((int)arg1, (int)arg2);
|
return current->sys$dup2((int)arg1, (int)arg2);
|
||||||
|
case Syscall::Sigaction:
|
||||||
|
return current->sys$sigaction((int)arg1, (const Unix::sigaction*)arg2, (Unix::sigaction*)arg3);
|
||||||
default:
|
default:
|
||||||
kprintf("<%u> int0x80: Unknown function %x requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
kprintf("<%u> int0x80: Unknown function %x requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -56,6 +56,7 @@ enum Function {
|
||||||
Getdtablesize = 0x2024,
|
Getdtablesize = 0x2024,
|
||||||
Dup = 0x2025,
|
Dup = 0x2025,
|
||||||
Dup2 = 0x2026,
|
Dup2 = 0x2026,
|
||||||
|
Sigaction = 0x2027,
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
|
@ -22,5 +22,11 @@ sighandler_t signal(int signum, sighandler_t handler)
|
||||||
return old_handler;
|
return old_handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sigaction(int signum, const struct sigaction* act, struct sigaction* old_act)
|
||||||
|
{
|
||||||
|
int rc = Syscall::invoke(Syscall::Sigaction, (dword)signum, (dword)act, (dword)old_act);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,10 @@ typedef uint32_t sigset_t;
|
||||||
typedef void siginfo_t;
|
typedef void siginfo_t;
|
||||||
|
|
||||||
struct sigaction {
|
struct sigaction {
|
||||||
void (*sa_handler)(int);
|
union {
|
||||||
void (*sa_sigaction)(int, siginfo_t*, void*);
|
void (*sa_handler)(int);
|
||||||
|
void (*sa_sigaction)(int, siginfo_t*, void*);
|
||||||
|
};
|
||||||
sigset_t sa_mask;
|
sigset_t sa_mask;
|
||||||
int sa_flags;
|
int sa_flags;
|
||||||
void (*sa_restorer)(void);
|
void (*sa_restorer)(void);
|
||||||
|
@ -20,11 +22,16 @@ struct sigaction {
|
||||||
|
|
||||||
int kill(pid_t, int sig);
|
int kill(pid_t, int sig);
|
||||||
sighandler_t signal(int sig, sighandler_t);
|
sighandler_t signal(int sig, sighandler_t);
|
||||||
|
int sigaction(int signum, const struct sigaction* act, struct sigaction* old_act);
|
||||||
|
|
||||||
#define SIG_DFL ((__sighandler_t)0)
|
#define SIG_DFL ((__sighandler_t)0)
|
||||||
#define SIG_ERR ((__sighandler_t)-1)
|
#define SIG_ERR ((__sighandler_t)-1)
|
||||||
#define SIG_IGN ((__sighandler_t)1)
|
#define SIG_IGN ((__sighandler_t)1)
|
||||||
|
|
||||||
|
#define SA_NOCLDSTOP 1
|
||||||
|
#define SA_NOCLDWAIT 2
|
||||||
|
#define SA_SIGINFO 4
|
||||||
|
|
||||||
#define SIG_BLOCK 0
|
#define SIG_BLOCK 0
|
||||||
#define SIG_UNBLOCK 1
|
#define SIG_UNBLOCK 1
|
||||||
#define SIG_SETMASK 2
|
#define SIG_SETMASK 2
|
||||||
|
|
|
@ -5,15 +5,15 @@
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
void* malloc(size_t);
|
void* malloc(size_t) __MALLOC;
|
||||||
void free(void*);
|
void free(void*);
|
||||||
void* calloc(size_t nmemb, size_t);
|
void* calloc(size_t nmemb, size_t);
|
||||||
void* realloc(void *ptr, size_t);
|
void* realloc(void *ptr, size_t);
|
||||||
char* getenv(const char* name);
|
char* getenv(const char* name);
|
||||||
int atoi(const char*);
|
int atoi(const char*);
|
||||||
|
|
||||||
void exit(int status);
|
void exit(int status) __NORETURN;
|
||||||
void abort();
|
void abort() __NORETURN;
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#define ALWAYS_INLINE inline __attribute__ ((always_inline))
|
#define ALWAYS_INLINE inline __attribute__ ((always_inline))
|
||||||
#define __NORETURN __attribute__ ((noreturn))
|
#define __NORETURN __attribute__ ((noreturn))
|
||||||
|
#define __MALLOC __attribute__ ((malloc))
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#define __BEGIN_DECLS extern "C" {
|
#define __BEGIN_DECLS extern "C" {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#include <LibC/stdio.h>
|
#include <stdio.h>
|
||||||
#include <LibC/unistd.h>
|
#include <unistd.h>
|
||||||
#include <LibC/errno.h>
|
#include <errno.h>
|
||||||
#include <LibC/string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <LibC/unistd.h>
|
#include <unistd.h>
|
||||||
#include <LibC/stdio.h>
|
#include <stdio.h>
|
||||||
#include <LibC/signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
|
||||||
static unsigned parseUInt(const String& str, bool& ok)
|
static unsigned parseUInt(const String& str, bool& ok)
|
||||||
|
@ -18,20 +19,36 @@ static unsigned parseUInt(const String& str, bool& ok)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_usage_and_exit()
|
||||||
|
{
|
||||||
|
printf("usage: kill [-signal] <PID>\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
if (argc != 2 && argc != 3)
|
||||||
printf("usage: kill <PID>\n");
|
print_usage_and_exit();
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
bool ok;
|
bool ok;
|
||||||
unsigned value = parseUInt(argv[1], ok);
|
unsigned signum = SIGTERM;
|
||||||
|
int pid_argi = 1;
|
||||||
|
if (argc == 3) {
|
||||||
|
pid_argi = 2;
|
||||||
|
if (argv[1][0] != '-')
|
||||||
|
print_usage_and_exit();
|
||||||
|
signum = parseUInt(&argv[1][1], ok);
|
||||||
|
if (!ok) {
|
||||||
|
printf("%s is not a valid signal number\n", &argv[1][1]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned pid = parseUInt(argv[pid_argi], ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
printf("%s is not a valid PID\n", argv[1]);
|
printf("%s is not a valid PID\n", argv[pid_argi]);
|
||||||
return 2;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
kill((pid_t)value, SIGKILL);
|
kill((pid_t)pid, signum);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <LibC/stdlib.h>
|
#include <LibC/stdlib.h>
|
||||||
#include <LibC/utsname.h>
|
#include <LibC/utsname.h>
|
||||||
#include <LibC/pwd.h>
|
#include <LibC/pwd.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <AK/FileSystemPath.h>
|
#include <AK/FileSystemPath.h>
|
||||||
|
|
||||||
struct GlobalState {
|
struct GlobalState {
|
||||||
|
@ -32,6 +33,29 @@ static int sh_pwd(int, const char**)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void did_receive_signal(int signum)
|
||||||
|
{
|
||||||
|
printf("\nMy word, I've received a signal with number %d\n", signum);
|
||||||
|
//exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sh_busy(int, const char**)
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = did_receive_signal;
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sa.sa_mask = 0;
|
||||||
|
sa.sa_restorer = nullptr;
|
||||||
|
int rc = sigaction(SIGUSR1, &sa, nullptr);
|
||||||
|
assert(rc == 0);
|
||||||
|
printf("listening for SIGUSR1 while looping in userspace...\n");
|
||||||
|
for (;;) {
|
||||||
|
for (volatile int i = 0; i < 100000; ++i)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int sh_fork(int, const char**)
|
static int sh_fork(int, const char**)
|
||||||
{
|
{
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
@ -147,6 +171,10 @@ static bool handle_builtin(int argc, const char** argv, int& retval)
|
||||||
retval = sh_fef(argc, argv);
|
retval = sh_fef(argc, argv);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(argv[0], "busy")) {
|
||||||
|
retval = sh_busy(argc, argv);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (!strcmp(argv[0], "wt")) {
|
if (!strcmp(argv[0], "wt")) {
|
||||||
retval = sh_wt(argc, argv);
|
retval = sh_wt(argc, argv);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -20,9 +20,54 @@ typedef dword nlink_t;
|
||||||
typedef dword uid_t;
|
typedef dword uid_t;
|
||||||
typedef dword gid_t;
|
typedef dword gid_t;
|
||||||
|
|
||||||
|
#ifdef SERENITY
|
||||||
typedef void (*__sighandler_t)(int);
|
typedef void (*__sighandler_t)(int);
|
||||||
typedef __sighandler_t sighandler_t;
|
typedef __sighandler_t sighandler_t;
|
||||||
|
|
||||||
|
typedef dword sigset_t;
|
||||||
|
typedef void siginfo_t;
|
||||||
|
|
||||||
|
struct sigaction {
|
||||||
|
union {
|
||||||
|
void (*sa_handler)(int);
|
||||||
|
void (*sa_sigaction)(int, siginfo_t*, void*);
|
||||||
|
};
|
||||||
|
sigset_t sa_mask;
|
||||||
|
int sa_flags;
|
||||||
|
void (*sa_restorer)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SA_NOCLDSTOP 1
|
||||||
|
#define SA_NOCLDWAIT 2
|
||||||
|
#define SA_SIGINFO 4
|
||||||
|
|
||||||
|
#define SIG_BLOCK 0
|
||||||
|
#define SIG_UNBLOCK 1
|
||||||
|
#define SIG_SETMASK 2
|
||||||
|
|
||||||
|
#define SIGHUP 1
|
||||||
|
#define SIGINT 2
|
||||||
|
#define SIGQUIT 3
|
||||||
|
#define SIGILL 4
|
||||||
|
#define SIGTRAP 5
|
||||||
|
#define SIGABRT 6
|
||||||
|
#define SIGBUS 7
|
||||||
|
#define SIGFPE 8
|
||||||
|
#define SIGKILL 9
|
||||||
|
#define SIGUSR1 10
|
||||||
|
#define SIGSEGV 11
|
||||||
|
#define SIGUSR2 12
|
||||||
|
#define SIGPIPE 13
|
||||||
|
#define SIGALRM 14
|
||||||
|
#define SIGTERM 15
|
||||||
|
#define SIGCONT 18
|
||||||
|
#define SIGTSTP 20
|
||||||
|
#define SIGTTIN 21
|
||||||
|
#define SIGTTOU 22
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef SERENITY
|
#ifdef SERENITY
|
||||||
// FIXME: Support 64-bit offsets!
|
// FIXME: Support 64-bit offsets!
|
||||||
typedef signed_dword off_t;
|
typedef signed_dword off_t;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue