mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add support for sessions.
This change refactors the process group implementation and adds support for sessions. The setsid(2) and getsid(2) system calls were added. psctl(2) now has PSCTL_TTYNAME, which lets you get the name of a process's terminal, and ps(1) now uses it. The initial terminal is now called /dev/tty1. /dev/tty is now a factory for the current terminal. A global lock now protects the process hierarchy which makes it safe to access other processes. This refactor removes potential vulnerabilities and increases system robustness. A number of terminal ioctls have been added. This is a compatible ABI change.
This commit is contained in:
parent
d529a1e332
commit
db7182ddc3
32 changed files with 817 additions and 346 deletions
2
Makefile
2
Makefile
|
@ -157,7 +157,7 @@ sysroot-system: sysroot-fsh sysroot-base-headers
|
|||
echo 'ID=sortix' && \
|
||||
echo 'VERSION_ID="$(VERSION)"' && \
|
||||
echo 'PRETTY_NAME="Sortix $(VERSION)"' && \
|
||||
echo 'SORTIX_ABI=0.1' && \
|
||||
echo 'SORTIX_ABI=0.2' && \
|
||||
true) > "$(SYSROOT)/etc/sortix-release"
|
||||
echo /etc/sortix-release >> "$(SYSROOT)/tix/manifest/system"
|
||||
ln -sf sortix-release "$(SYSROOT)/etc/os-release"
|
||||
|
|
|
@ -694,9 +694,13 @@ int Descriptor::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
|
|||
return vnode->tcgetwincurpos(ctx, wcp);
|
||||
}
|
||||
|
||||
int Descriptor::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
|
||||
int Descriptor::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
|
||||
{
|
||||
return vnode->tcgetwinsize(ctx, ws);
|
||||
int old_ctx_dflags = ctx->dflags;
|
||||
ctx->dflags = ContextFlags(old_ctx_dflags, dflags);
|
||||
int result = vnode->ioctl(ctx, cmd, arg);
|
||||
ctx->dflags = old_ctx_dflags;
|
||||
return result;
|
||||
}
|
||||
|
||||
int Descriptor::tcsetpgrp(ioctx_t* ctx, pid_t pgid)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <sortix/dirent.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/ioctl.h>
|
||||
#include <sortix/stat.h>
|
||||
#include <sortix/timespec.h>
|
||||
#include <sortix/winsize.h>
|
||||
|
@ -227,7 +228,7 @@ public:
|
|||
const char* filename);
|
||||
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
||||
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
|
||||
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
|
||||
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
|
||||
virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
|
||||
virtual pid_t tcgetpgrp(ioctx_t* ctx);
|
||||
virtual int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
|
@ -1227,23 +1228,27 @@ int Unode::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int Unode::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
|
||||
int Unode::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
|
||||
{
|
||||
Channel* channel = server->Connect(ctx);
|
||||
if ( !channel )
|
||||
return -1;
|
||||
int ret = -1;
|
||||
struct fsm_req_tcgetwinsize msg;
|
||||
struct fsm_resp_tcgetwinsize resp;
|
||||
msg.ino = ino;
|
||||
if ( SendMessage(channel, FSM_REQ_TCGETWINSIZE, &msg, sizeof(msg)) &&
|
||||
RecvMessage(channel, FSM_RESP_TCGETWINSIZE, &resp, sizeof(resp)) &&
|
||||
ctx->copy_to_dest(ws, &resp.size, sizeof(*ws)) )
|
||||
ret = 0;
|
||||
channel->KernelClose();
|
||||
return ret;
|
||||
if ( cmd == TIOCGWINSZ )
|
||||
{
|
||||
struct winsize* ws = (struct winsize*) arg;
|
||||
Channel* channel = server->Connect(ctx);
|
||||
if ( !channel )
|
||||
return -1;
|
||||
int ret = -1;
|
||||
struct fsm_req_tcgetwinsize msg;
|
||||
struct fsm_resp_tcgetwinsize resp;
|
||||
msg.ino = ino;
|
||||
if ( SendMessage(channel, FSM_REQ_TCGETWINSIZE, &msg, sizeof(msg)) &&
|
||||
RecvMessage(channel, FSM_RESP_TCGETWINSIZE, &resp, sizeof(resp)) &&
|
||||
ctx->copy_to_dest(ws, &resp.size, sizeof(*ws)) )
|
||||
ret = 0;
|
||||
channel->KernelClose();
|
||||
return ret;
|
||||
}
|
||||
return errno = ENOTTY, -1;
|
||||
}
|
||||
|
||||
int Unode::tcsetpgrp(ioctx_t* ctx, pid_t pgid)
|
||||
{
|
||||
Channel* channel = server->Connect(ctx);
|
||||
|
|
|
@ -32,5 +32,11 @@
|
|||
#define __IOCTL_TYPE(value) ((value) & __IOCTL_TYPE_MASK)
|
||||
|
||||
#define TIOCGWINSZ __IOCTL(1, __IOCTL_TYPE_PTR)
|
||||
#define TIOCSWINSZ __IOCTL(2, __IOCTL_TYPE_PTR)
|
||||
#define TIOCSCTTY __IOCTL(3, __IOCTL_TYPE_INT)
|
||||
#define TIOCSPTLCK __IOCTL(4, __IOCTL_TYPE_PTR)
|
||||
#define TIOCGPTLCK __IOCTL(5, __IOCTL_TYPE_PTR)
|
||||
#define TIOCGNAME __IOCTL(6, __IOCTL_TYPE_PTR)
|
||||
#define TIOCGPTN __IOCTL(7, __IOCTL_TYPE_PTR)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
int symlink(ioctx_t* ctx, const char* oldname, const char* filename);
|
||||
ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
||||
int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
|
||||
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
|
||||
int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
|
||||
int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
|
||||
pid_t tcgetpgrp(ioctx_t* ctx);
|
||||
int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
const char* filename) = 0;
|
||||
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz) = 0;
|
||||
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp) = 0;
|
||||
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws) = 0;
|
||||
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg) = 0;
|
||||
virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid) = 0;
|
||||
virtual pid_t tcgetpgrp(ioctx_t* ctx) = 0;
|
||||
virtual int settermmode(ioctx_t* ctx, unsigned mode) = 0;
|
||||
|
@ -181,7 +181,7 @@ public:
|
|||
const char* filename);
|
||||
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
||||
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
|
||||
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
|
||||
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
|
||||
virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
|
||||
virtual pid_t tcgetpgrp(ioctx_t* ctx);
|
||||
virtual int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 205, 2016 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
|
||||
|
@ -77,6 +77,7 @@ public:
|
|||
|
||||
private:
|
||||
kthread_mutex_t ptrlock;
|
||||
Ref<Descriptor> tty;
|
||||
Ref<Descriptor> root;
|
||||
Ref<Descriptor> cwd;
|
||||
Ref<MountTable> mtable;
|
||||
|
@ -101,38 +102,36 @@ public:
|
|||
Ref<DescriptorTable> GetDTable();
|
||||
Ref<MountTable> GetMTable();
|
||||
Ref<ProcessTable> GetPTable();
|
||||
Ref<Descriptor> GetTTY();
|
||||
Ref<Descriptor> GetRoot();
|
||||
Ref<Descriptor> GetCWD();
|
||||
Ref<Descriptor> GetDescriptor(int fd);
|
||||
void SetTTY(Ref<Descriptor> tty);
|
||||
void SetRoot(Ref<Descriptor> newroot);
|
||||
void SetCWD(Ref<Descriptor> newcwd);
|
||||
|
||||
public:
|
||||
// A process may only access its parent if parentlock is locked. A process
|
||||
// may only use its list of children if childlock is locked. A process may
|
||||
// not access its sibling processes.
|
||||
Process* parent;
|
||||
Process* prevsibling;
|
||||
Process* nextsibling;
|
||||
Process* firstchild;
|
||||
Process* zombiechild;
|
||||
Process* group;
|
||||
Process* groupprev;
|
||||
Process* groupnext;
|
||||
Process* groupfirst;
|
||||
Process* session;
|
||||
Process* sessionprev;
|
||||
Process* sessionnext;
|
||||
Process* sessionfirst;
|
||||
kthread_mutex_t childlock;
|
||||
kthread_mutex_t parentlock;
|
||||
kthread_cond_t zombiecond;
|
||||
bool iszombie;
|
||||
bool nozombify;
|
||||
bool limbo;
|
||||
int exit_code;
|
||||
|
||||
public:
|
||||
Process* group;
|
||||
Process* groupprev;
|
||||
Process* groupnext;
|
||||
Process* groupfirst;
|
||||
kthread_mutex_t groupchildlock;
|
||||
kthread_mutex_t groupparentlock;
|
||||
kthread_cond_t groupchildleft;
|
||||
bool grouplimbo;
|
||||
|
||||
public:
|
||||
Thread* firstthread;
|
||||
kthread_mutex_t threadlock;
|
||||
|
@ -165,13 +164,14 @@ public:
|
|||
pid_t Wait(pid_t pid, int* status, int options);
|
||||
bool DeliverSignal(int signum);
|
||||
bool DeliverGroupSignal(int signum);
|
||||
bool DeliverSessionSignal(int signum);
|
||||
void OnThreadDestruction(Thread* thread);
|
||||
pid_t GetParentProcessId();
|
||||
void AddChildProcess(Process* child);
|
||||
void ScheduleDeath();
|
||||
void AbortConstruction();
|
||||
bool MapSegment(struct segment* result, void* hint, size_t size, int flags,
|
||||
int prot);
|
||||
void GroupRemoveMember(Process* child);
|
||||
void SessionRemoveMember(Process* child);
|
||||
|
||||
public:
|
||||
Process* Fork();
|
||||
|
@ -180,19 +180,17 @@ private:
|
|||
void OnLastThreadExit();
|
||||
void LastPrayer();
|
||||
void WaitedFor();
|
||||
void NotifyMemberExit(Process* child);
|
||||
void NotifyChildExit(Process* child, bool zombify);
|
||||
void NotifyNewZombies();
|
||||
void DeleteTimers();
|
||||
|
||||
public:
|
||||
void NotifyLeftProcessGroup();
|
||||
bool IsLimboDone();
|
||||
|
||||
public:
|
||||
void ResetForExecute();
|
||||
|
||||
};
|
||||
|
||||
extern kthread_mutex_t process_family_lock;
|
||||
|
||||
Process* CurrentProcess();
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -100,6 +100,7 @@ pid_t sys_getpgid(pid_t);
|
|||
pid_t sys_getpid(void);
|
||||
pid_t sys_getppid(void);
|
||||
int sys_getpriority(int, id_t);
|
||||
pid_t sys_getsid(pid_t);
|
||||
int sys_getsockname(int, struct sockaddr*, socklen_t*);
|
||||
int sys_getsockopt(int, int, int, void*, size_t*);
|
||||
int sys_gettermmode(int, unsigned*);
|
||||
|
@ -146,6 +147,7 @@ int sys_setgid(gid_t);
|
|||
int sys_sethostname(const char*, size_t);
|
||||
int sys_setpgid(pid_t, pid_t);
|
||||
int sys_setpriority(int, id_t, int);
|
||||
pid_t sys_setsid(void);
|
||||
int sys_setsockopt(int, int, int, const void*, size_t);
|
||||
int sys_settermmode(int, unsigned);
|
||||
int sys_setuid(uid_t);
|
||||
|
|
|
@ -77,7 +77,7 @@ public:
|
|||
ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
|
||||
int fsbind(ioctx_t* ctx, Vnode* node, int flags);
|
||||
int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
|
||||
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
|
||||
int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
|
||||
int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
|
||||
pid_t tcgetpgrp(ioctx_t* ctx);
|
||||
int settermmode(ioctx_t* ctx, unsigned mode);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#if __USE_SORTIX || __USE_POSIX
|
||||
#define HOST_NAME_MAX 255
|
||||
#define TTY_NAME_MAX 32
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2015, 2016 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
|
||||
|
@ -97,4 +97,11 @@ struct psctl_program_path
|
|||
size_t size;
|
||||
};
|
||||
|
||||
#define PSCTL_TTYNAME __PSCTL(psctl_program_path, 5)
|
||||
struct psctl_ttyname
|
||||
{
|
||||
char* buffer;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 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
|
||||
|
@ -183,6 +183,8 @@
|
|||
#define SYSCALL_TCSENDBREAK 160
|
||||
#define SYSCALL_TCSETATTR 161
|
||||
#define SYSCALL_SCRAM 162
|
||||
#define SYSCALL_MAX_NUM 163 /* index of highest constant + 1 */
|
||||
#define SYSCALL_GETSID 163
|
||||
#define SYSCALL_SETSID 164
|
||||
#define SYSCALL_MAX_NUM 165 /* index of highest constant + 1 */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -298,10 +298,8 @@ int AbstractInode::tcgetwincurpos(ioctx_t* /*ctx*/, struct wincurpos* /*wcp*/)
|
|||
return errno = ENOTTY, -1;
|
||||
}
|
||||
|
||||
int AbstractInode::tcgetwinsize(ioctx_t* /*ctx*/, struct winsize* /*ws*/)
|
||||
int AbstractInode::ioctl(ioctx_t* /*ctx*/, int /*cmd*/, uintptr_t /*arg*/)
|
||||
{
|
||||
if ( inode_type == INODE_TYPE_TTY )
|
||||
return errno = EBADF, -1;
|
||||
return errno = ENOTTY, -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -371,13 +371,11 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg)
|
|||
|
||||
int sys_ioctl(int fd, int cmd, uintptr_t arg)
|
||||
{
|
||||
switch ( cmd )
|
||||
{
|
||||
case TIOCGWINSZ:
|
||||
return sys_tcgetwinsize(fd, (struct winsize*) arg);
|
||||
default:
|
||||
return errno = EINVAL, -1;
|
||||
}
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return desc->ioctl(&ctx, cmd, arg);
|
||||
}
|
||||
|
||||
ssize_t sys_readdirents(int fd, struct dirent* dirent, size_t size)
|
||||
|
@ -648,14 +646,9 @@ int sys_tcgetwincurpos(int fd, struct wincurpos* wcp)
|
|||
return desc->tcgetwincurpos(&ctx, wcp);
|
||||
}
|
||||
|
||||
|
||||
int sys_tcgetwinsize(int fd, struct winsize* ws)
|
||||
{
|
||||
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
|
||||
if ( !desc )
|
||||
return -1;
|
||||
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
||||
return desc->tcgetwinsize(&ctx, ws);
|
||||
return sys_ioctl(fd, TIOCGWINSZ, (uintptr_t) ws);
|
||||
}
|
||||
|
||||
int sys_tcsetpgrp(int fd, pid_t pgid)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 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
|
||||
|
@ -18,6 +18,7 @@
|
|||
* initial process from the init ramdisk, allowing a full operating system.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -342,6 +343,10 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo_p)
|
|||
system->groupprev = NULL;
|
||||
system->groupnext = NULL;
|
||||
system->groupfirst = system;
|
||||
system->session = system;
|
||||
system->sessionprev = NULL;
|
||||
system->sessionnext = NULL;
|
||||
system->sessionfirst = system;
|
||||
|
||||
if ( !(system->program_image_path = String::Clone("<kernel process>")) )
|
||||
Panic("Unable to clone string for system process name");
|
||||
|
@ -480,12 +485,20 @@ static void BootThread(void* /*user*/)
|
|||
// Initialize the PS/2 controller.
|
||||
PS2::Init(keyboard, mouse);
|
||||
|
||||
// Register the kernel terminal as /dev/tty.
|
||||
Ref<Inode> tty(new LogTerminal(slashdev->dev, 0666, 0, 0, keyboard, kblayout));
|
||||
// Register /dev/tty as the current-terminal factory.
|
||||
Ref<Inode> tty(new DevTTY(slashdev->dev, 0666, 0, 0));
|
||||
if ( !tty )
|
||||
Panic("Could not allocate a kernel terminal");
|
||||
Panic("Could not allocate a kernel terminal factory");
|
||||
if ( LinkInodeInDir(&ctx, slashdev, "tty", tty) != 0 )
|
||||
Panic("Unable to link /dev/tty to kernel terminal.");
|
||||
Panic("Unable to link /dev/tty to kernel terminal factory.");
|
||||
|
||||
// Register the kernel terminal as /dev/tty1.
|
||||
Ref<Inode> tty1(new LogTerminal(slashdev->dev, 0666, 0, 0,
|
||||
keyboard, kblayout, "tty1"));
|
||||
if ( !tty1 )
|
||||
Panic("Could not allocate a kernel terminal");
|
||||
if ( LinkInodeInDir(&ctx, slashdev, "tty1", tty1) != 0 )
|
||||
Panic("Unable to link /dev/tty1 to kernel terminal.");
|
||||
|
||||
// Register the mouse as /dev/mouse.
|
||||
Ref<Inode> mousedev(new PS2MouseDevice(slashdev->dev, 0666, 0, 0, mouse));
|
||||
|
@ -562,12 +575,24 @@ static void BootThread(void* /*user*/)
|
|||
Panic("Could not allocate init process");
|
||||
if ( (init->pid = (init->ptable = CurrentProcess()->ptable)->Allocate(init)) < 0 )
|
||||
Panic("Could not allocate init a pid");
|
||||
|
||||
kthread_mutex_lock(&process_family_lock);
|
||||
Process* kernel_process = CurrentProcess();
|
||||
init->parent = kernel_process;
|
||||
init->nextsibling = kernel_process->firstchild;
|
||||
init->prevsibling = NULL;
|
||||
if ( kernel_process->firstchild )
|
||||
kernel_process->firstchild->prevsibling = init;
|
||||
kernel_process->firstchild = init;
|
||||
init->group = init;
|
||||
init->groupprev = NULL;
|
||||
init->groupnext = NULL;
|
||||
init->groupfirst = init;
|
||||
|
||||
CurrentProcess()->AddChildProcess(init);
|
||||
init->session = init;
|
||||
init->sessionprev = NULL;
|
||||
init->sessionnext = NULL;
|
||||
init->sessionfirst = init;
|
||||
kthread_mutex_unlock(&process_family_lock);
|
||||
|
||||
// TODO: Why don't we fork from pid=0 and this is done for us?
|
||||
// TODO: Fork dtable and mtable, don't share them!
|
||||
|
@ -582,7 +607,7 @@ static void BootThread(void* /*user*/)
|
|||
if ( !initthread )
|
||||
Panic("Could not create init thread");
|
||||
|
||||
// Wait until init init is done and then shut down the computer.
|
||||
// Wait until init is done and then shut down the computer.
|
||||
int status;
|
||||
pid_t pid = CurrentProcess()->Wait(init->pid, &status, 0);
|
||||
if ( pid != init->pid )
|
||||
|
@ -618,6 +643,13 @@ static void InitThread(void* /*user*/)
|
|||
|
||||
Ref<DescriptorTable> dtable = process->GetDTable();
|
||||
|
||||
Ref<Descriptor> tty1 = root->open(&ctx, "/dev/tty1", O_READ | O_WRITE);
|
||||
if ( !tty1 )
|
||||
PanicF("/dev/tty1: %m");
|
||||
if ( tty1->ioctl(&ctx, TIOCSCTTY, 0) < 0 )
|
||||
PanicF("/dev/tty1: ioctl: TIOCSCTTY: %m");
|
||||
tty1.Reset();
|
||||
|
||||
Ref<Descriptor> tty_stdin = root->open(&ctx, "/dev/tty", O_READ);
|
||||
if ( !tty_stdin || dtable->Allocate(tty_stdin, 0) != 0 )
|
||||
Panic("Could not prepare stdin for initialization process");
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <wchar.h>
|
||||
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/ioctl.h>
|
||||
#include <sortix/keycodes.h>
|
||||
#include <sortix/poll.h>
|
||||
#include <sortix/signal.h>
|
||||
|
@ -107,8 +108,9 @@ static inline const struct kbkey_sequence* LookupKeystrokeSequence(int kbkey)
|
|||
}
|
||||
|
||||
LogTerminal::LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
|
||||
Keyboard* keyboard, KeyboardLayoutExecutor* kblayout)
|
||||
: TTY(dev, mode, owner, group)
|
||||
Keyboard* keyboard, KeyboardLayoutExecutor* kblayout,
|
||||
const char* name)
|
||||
: TTY(dev, 0, mode, owner, group, name)
|
||||
{
|
||||
this->keyboard = keyboard;
|
||||
this->kblayout = kblayout;
|
||||
|
@ -122,9 +124,16 @@ LogTerminal::~LogTerminal()
|
|||
delete kblayout;
|
||||
}
|
||||
|
||||
void LogTerminal::tty_output(const unsigned char* buffer, size_t length)
|
||||
{
|
||||
Log::PrintData(buffer, length);
|
||||
}
|
||||
|
||||
int LogTerminal::sync(ioctx_t* /*ctx*/)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
return Log::Sync() ? 0 : -1;
|
||||
}
|
||||
|
||||
|
@ -239,6 +248,9 @@ void LogTerminal::ProcessKeystroke(int kbkey)
|
|||
|
||||
ssize_t LogTerminal::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( !name )
|
||||
{
|
||||
static const char index[] = "kblayout\0";
|
||||
|
@ -251,7 +263,6 @@ ssize_t LogTerminal::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, siz
|
|||
}
|
||||
else if ( !strcmp(name, "kblayout") )
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
const uint8_t* data;
|
||||
size_t size;
|
||||
if ( !kblayout->Download(&data, &size) )
|
||||
|
@ -268,6 +279,9 @@ ssize_t LogTerminal::tcgetblob(ioctx_t* ctx, const char* name, void* buffer, siz
|
|||
|
||||
ssize_t LogTerminal::tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( !name )
|
||||
return errno = EPERM, -1;
|
||||
else if ( !strcmp(name, "kblayout") )
|
||||
|
@ -277,7 +291,6 @@ ssize_t LogTerminal::tcsetblob(ioctx_t* ctx, const char* name, const void* buffe
|
|||
return -1;
|
||||
if ( !ctx->copy_from_src(data, buffer, count) )
|
||||
return -1;
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( !kblayout->Upload(data, count) )
|
||||
return -1;
|
||||
delete[] data;
|
||||
|
@ -287,4 +300,40 @@ ssize_t LogTerminal::tcsetblob(ioctx_t* ctx, const char* name, const void* buffe
|
|||
return errno = ENOENT, -1;
|
||||
}
|
||||
|
||||
int LogTerminal::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
struct wincurpos retwcp;
|
||||
memset(&retwcp, 0, sizeof(retwcp));
|
||||
size_t cursor_column, cursor_row;
|
||||
Log::GetCursor(&cursor_column, &cursor_row);
|
||||
retwcp.wcp_col = cursor_column;
|
||||
retwcp.wcp_row = cursor_row;
|
||||
if ( !ctx->copy_to_dest(wcp, &retwcp, sizeof(retwcp)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LogTerminal::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( cmd == TIOCGWINSZ )
|
||||
{
|
||||
struct winsize* ws = (struct winsize*) arg;
|
||||
struct winsize retws;
|
||||
memset(&retws, 0, sizeof(retws));
|
||||
retws.ws_col = Log::Width();
|
||||
retws.ws_row = Log::Height();
|
||||
if ( !ctx->copy_to_dest(ws, &retws, sizeof(retws)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
lock.Reset();
|
||||
return TTY::ioctl(ctx, cmd, arg);
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -28,17 +28,23 @@ class LogTerminal : public TTY, public KeyboardOwner
|
|||
{
|
||||
public:
|
||||
LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
|
||||
Keyboard* keyboard, KeyboardLayoutExecutor* kblayout);
|
||||
Keyboard* keyboard, KeyboardLayoutExecutor* kblayout,
|
||||
const char* name);
|
||||
virtual ~LogTerminal();
|
||||
|
||||
public:
|
||||
virtual int sync(ioctx_t* ctx);
|
||||
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
|
||||
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
|
||||
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
|
||||
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
|
||||
|
||||
public:
|
||||
virtual void OnKeystroke(Keyboard* keyboard, void* user);
|
||||
|
||||
protected:
|
||||
virtual void tty_output(const unsigned char* buffer, size_t length);
|
||||
|
||||
private:
|
||||
void ProcessKeystroke(int kbkey);
|
||||
|
||||
|
|
|
@ -69,6 +69,8 @@
|
|||
|
||||
namespace Sortix {
|
||||
|
||||
kthread_mutex_t process_family_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
Process::Process()
|
||||
{
|
||||
program_image_path = NULL;
|
||||
|
@ -84,6 +86,7 @@ Process::Process()
|
|||
umask = 0022;
|
||||
|
||||
ptrlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
// tty set to null reference in the member constructor.
|
||||
// root set to null reference in the member constructor.
|
||||
// cwd set to null reference in the member constructor.
|
||||
// mtable set to null reference in the member constructor.
|
||||
|
@ -115,22 +118,19 @@ Process::Process()
|
|||
nextsibling = NULL;
|
||||
firstchild = NULL;
|
||||
zombiechild = NULL;
|
||||
childlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
parentlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
zombiecond = KTHREAD_COND_INITIALIZER;
|
||||
iszombie = false;
|
||||
nozombify = false;
|
||||
exit_code = -1;
|
||||
|
||||
group = NULL;
|
||||
groupprev = NULL;
|
||||
groupnext = NULL;
|
||||
groupfirst = NULL;
|
||||
|
||||
groupparentlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
groupchildlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
groupchildleft = KTHREAD_COND_INITIALIZER;
|
||||
grouplimbo = false;
|
||||
session = NULL;
|
||||
sessionprev = NULL;
|
||||
sessionnext = NULL;
|
||||
sessionfirst = NULL;
|
||||
zombiecond = KTHREAD_COND_INITIALIZER;
|
||||
iszombie = false;
|
||||
nozombify = false;
|
||||
limbo = false;
|
||||
exit_code = -1;
|
||||
|
||||
firstthread = NULL;
|
||||
threadlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
|
@ -153,12 +153,17 @@ Process::Process()
|
|||
alarm_timer.Attach(Time::GetClock(CLOCK_MONOTONIC));
|
||||
}
|
||||
|
||||
Process::~Process()
|
||||
Process::~Process() // process_family_lock taken
|
||||
{
|
||||
if ( alarm_timer.IsAttached() )
|
||||
alarm_timer.Detach();
|
||||
delete[] program_image_path;
|
||||
assert(!zombiechild);
|
||||
assert(!session);
|
||||
assert(!group);
|
||||
assert(!parent);
|
||||
assert(!sessionfirst);
|
||||
assert(!groupfirst);
|
||||
assert(!firstchild);
|
||||
assert(!addrspace);
|
||||
assert(!segments);
|
||||
|
@ -170,6 +175,7 @@ Process::~Process()
|
|||
assert(ptable);
|
||||
ptable->Free(pid);
|
||||
ptable.Reset();
|
||||
tty.Reset();
|
||||
}
|
||||
|
||||
void Process::BootstrapTables(Ref<DescriptorTable> dtable, Ref<MountTable> mtable)
|
||||
|
@ -280,6 +286,7 @@ void Process::LastPrayer()
|
|||
|
||||
ResetAddressSpace();
|
||||
|
||||
// tty is kept alive in session leader until no longer in limbo.
|
||||
if ( dtable ) dtable.Reset();
|
||||
if ( cwd ) cwd.Reset();
|
||||
if ( root ) root.Reset();
|
||||
|
@ -290,14 +297,15 @@ void Process::LastPrayer()
|
|||
Memory::DestroyAddressSpace(prevaddrspace);
|
||||
addrspace = 0;
|
||||
|
||||
ScopedLock family_lock(&process_family_lock);
|
||||
|
||||
iszombie = true;
|
||||
|
||||
// Init is nice and will gladly raise our orphaned children and zombies.
|
||||
Process* init = Scheduler::GetInitProcess();
|
||||
assert(init);
|
||||
kthread_mutex_lock(&childlock);
|
||||
while ( firstchild )
|
||||
{
|
||||
ScopedLock firstchildlock(&firstchild->parentlock);
|
||||
ScopedLock initlock(&init->childlock);
|
||||
Process* process = firstchild;
|
||||
firstchild = process->nextsibling;
|
||||
process->parent = init;
|
||||
|
@ -322,39 +330,32 @@ void Process::LastPrayer()
|
|||
zombie->nozombify = true;
|
||||
zombie->WaitedFor();
|
||||
}
|
||||
kthread_mutex_unlock(&childlock);
|
||||
|
||||
iszombie = true;
|
||||
// Remove ourself from our process group.
|
||||
if ( group )
|
||||
group->GroupRemoveMember(this);
|
||||
// Remove ourself from our session.
|
||||
if ( session )
|
||||
session->SessionRemoveMember(this);
|
||||
|
||||
bool zombify = !nozombify;
|
||||
|
||||
// Remove ourself from our process group.
|
||||
kthread_mutex_lock(&groupchildlock);
|
||||
if ( group )
|
||||
group->NotifyMemberExit(this);
|
||||
kthread_mutex_unlock(&groupchildlock);
|
||||
|
||||
// This class instance will be destroyed by our parent process when it
|
||||
// has received and acknowledged our death.
|
||||
kthread_mutex_lock(&parentlock);
|
||||
if ( parent )
|
||||
parent->NotifyChildExit(this, zombify);
|
||||
kthread_mutex_unlock(&parentlock);
|
||||
|
||||
// If nobody is waiting for us, then simply commit suicide.
|
||||
if ( !zombify )
|
||||
WaitedFor();
|
||||
}
|
||||
|
||||
void Process::WaitedFor()
|
||||
void Process::WaitedFor() // process_family_lock taken
|
||||
{
|
||||
kthread_mutex_lock(&parentlock);
|
||||
parent = NULL;
|
||||
kthread_mutex_unlock(&parentlock);
|
||||
kthread_mutex_lock(&groupparentlock);
|
||||
bool in_limbo = groupfirst && (grouplimbo = true);
|
||||
kthread_mutex_unlock(&groupparentlock);
|
||||
if ( !in_limbo )
|
||||
limbo = false;
|
||||
if ( groupfirst || sessionfirst )
|
||||
limbo = true;
|
||||
if ( !limbo )
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
@ -375,37 +376,48 @@ void Process::ResetAddressSpace()
|
|||
segments = NULL;
|
||||
}
|
||||
|
||||
void Process::NotifyMemberExit(Process* child)
|
||||
void Process::GroupRemoveMember(Process* child) // process_family_lock taken
|
||||
{
|
||||
assert(child->group == this);
|
||||
kthread_mutex_lock(&groupparentlock);
|
||||
if ( child->groupprev )
|
||||
child->groupprev->groupnext = child->groupnext;
|
||||
else
|
||||
groupfirst = child->groupnext;
|
||||
if ( child->groupnext )
|
||||
child->groupnext->groupprev = child->groupprev;
|
||||
kthread_cond_signal(&groupchildleft);
|
||||
kthread_mutex_unlock(&groupparentlock);
|
||||
|
||||
child->group = NULL;
|
||||
|
||||
NotifyLeftProcessGroup();
|
||||
if ( IsLimboDone() )
|
||||
delete this;
|
||||
}
|
||||
|
||||
void Process::NotifyLeftProcessGroup()
|
||||
void Process::SessionRemoveMember(Process* child) // process_family_lock taken
|
||||
{
|
||||
ScopedLock parentlock(&groupparentlock);
|
||||
if ( !grouplimbo || groupfirst )
|
||||
return;
|
||||
grouplimbo = false;
|
||||
delete this;
|
||||
assert(child->session == this);
|
||||
if ( child->sessionprev )
|
||||
child->sessionprev->sessionnext = child->sessionnext;
|
||||
else
|
||||
sessionfirst = child->sessionnext;
|
||||
if ( child->sessionnext )
|
||||
child->sessionnext->sessionprev = child->sessionprev;
|
||||
child->session = NULL;
|
||||
if ( !sessionfirst )
|
||||
{
|
||||
// Remove reference to tty when session is empty.
|
||||
ScopedLock lock(&ptrlock);
|
||||
tty.Reset();
|
||||
}
|
||||
if ( IsLimboDone() )
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool Process::IsLimboDone() // process_family_lock taken
|
||||
{
|
||||
return limbo && !groupfirst && !sessionfirst;
|
||||
}
|
||||
|
||||
// process_family_lock taken
|
||||
void Process::NotifyChildExit(Process* child, bool zombify)
|
||||
{
|
||||
kthread_mutex_lock(&childlock);
|
||||
|
||||
if ( child->prevsibling )
|
||||
child->prevsibling->nextsibling = child->nextsibling;
|
||||
if ( child->nextsibling )
|
||||
|
@ -424,17 +436,11 @@ void Process::NotifyChildExit(Process* child, bool zombify)
|
|||
zombiechild = child;
|
||||
}
|
||||
|
||||
kthread_mutex_unlock(&childlock);
|
||||
|
||||
if ( zombify )
|
||||
NotifyNewZombies();
|
||||
}
|
||||
|
||||
void Process::NotifyNewZombies()
|
||||
{
|
||||
ScopedLock lock(&childlock);
|
||||
DeliverSignal(SIGCHLD);
|
||||
kthread_cond_broadcast(&zombiecond);
|
||||
{
|
||||
DeliverSignal(SIGCHLD);
|
||||
kthread_cond_broadcast(&zombiecond);
|
||||
}
|
||||
}
|
||||
|
||||
pid_t Process::Wait(pid_t thepid, int* status_ptr, int options)
|
||||
|
@ -443,7 +449,7 @@ pid_t Process::Wait(pid_t thepid, int* status_ptr, int options)
|
|||
if ( thepid < -1 || thepid == 0 )
|
||||
return errno = ENOSYS, -1;
|
||||
|
||||
ScopedLock lock(&childlock);
|
||||
ScopedLock lock(&process_family_lock);
|
||||
|
||||
// A process can only wait if it has children.
|
||||
if ( !firstchild && !zombiechild )
|
||||
|
@ -475,7 +481,7 @@ pid_t Process::Wait(pid_t thepid, int* status_ptr, int options)
|
|||
break;
|
||||
if ( options & WNOHANG )
|
||||
return 0;
|
||||
if ( !kthread_cond_wait_signal(&zombiecond, &childlock) )
|
||||
if ( !kthread_cond_wait_signal(&zombiecond, &process_family_lock) )
|
||||
return errno = EINTR, -1;
|
||||
}
|
||||
|
||||
|
@ -536,21 +542,6 @@ void Process::ExitWithCode(int requested_exit_code)
|
|||
t->DeliverSignal(SIGKILL);
|
||||
}
|
||||
|
||||
void Process::AddChildProcess(Process* child)
|
||||
{
|
||||
ScopedLock mylock(&childlock);
|
||||
ScopedLock itslock(&child->parentlock);
|
||||
assert(!child->parent);
|
||||
assert(!child->nextsibling);
|
||||
assert(!child->prevsibling);
|
||||
child->parent = this;
|
||||
child->nextsibling = firstchild;
|
||||
child->prevsibling = NULL;
|
||||
if ( firstchild )
|
||||
firstchild->prevsibling = child;
|
||||
firstchild = child;
|
||||
}
|
||||
|
||||
Ref<MountTable> Process::GetMTable()
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
|
@ -572,6 +563,12 @@ Ref<ProcessTable> Process::GetPTable()
|
|||
return ptable;
|
||||
}
|
||||
|
||||
Ref<Descriptor> Process::GetTTY()
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
return tty;
|
||||
}
|
||||
|
||||
Ref<Descriptor> Process::GetRoot()
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
|
@ -586,6 +583,12 @@ Ref<Descriptor> Process::GetCWD()
|
|||
return cwd;
|
||||
}
|
||||
|
||||
void Process::SetTTY(Ref<Descriptor> newtty)
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
tty = newtty;
|
||||
}
|
||||
|
||||
void Process::SetRoot(Ref<Descriptor> newroot)
|
||||
{
|
||||
ScopedLock lock(&ptrlock);
|
||||
|
@ -611,19 +614,10 @@ Process* Process::Fork()
|
|||
{
|
||||
assert(CurrentProcess() == this);
|
||||
|
||||
// TODO: This adds the new process to the process table, but it's not ready
|
||||
// and functions that access this new process will be surprised that
|
||||
// it's not fully constructed and really bad things will happen.
|
||||
Process* clone = new Process;
|
||||
if ( !clone )
|
||||
return NULL;
|
||||
|
||||
if ( (clone->pid = (clone->ptable = ptable)->Allocate(clone)) < 0 )
|
||||
{
|
||||
delete clone;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct segment* clone_segments = NULL;
|
||||
|
||||
// Fork the segment list.
|
||||
|
@ -653,19 +647,38 @@ Process* Process::Fork()
|
|||
clone->segments_used = segments_used;
|
||||
clone->segments_length = segments_used;
|
||||
|
||||
kthread_mutex_lock(&process_family_lock);
|
||||
|
||||
if ( (clone->pid = (clone->ptable = ptable)->Allocate(clone)) < 0 )
|
||||
{
|
||||
kthread_mutex_unlock(&process_family_lock);
|
||||
clone->AbortConstruction();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Remember the relation to the child process.
|
||||
AddChildProcess(clone);
|
||||
clone->parent = this;
|
||||
clone->nextsibling = firstchild;
|
||||
clone->prevsibling = NULL;
|
||||
if ( firstchild )
|
||||
firstchild->prevsibling = clone;
|
||||
firstchild = clone;
|
||||
|
||||
// Add the new process to the current process group.
|
||||
kthread_mutex_lock(&groupchildlock);
|
||||
kthread_mutex_lock(&group->groupparentlock);
|
||||
clone->group = group;
|
||||
clone->groupprev = NULL;
|
||||
if ( (clone->groupnext = group->groupfirst) )
|
||||
group->groupfirst->groupprev = clone;
|
||||
group->groupfirst = clone;
|
||||
kthread_mutex_unlock(&group->groupparentlock);
|
||||
kthread_mutex_unlock(&groupchildlock);
|
||||
|
||||
// Add the new process to the current session.
|
||||
clone->session = session;
|
||||
clone->sessionprev = NULL;
|
||||
if ( (clone->sessionnext = session->sessionfirst) )
|
||||
session->sessionfirst->sessionprev = clone;
|
||||
session->sessionfirst = clone;
|
||||
|
||||
kthread_mutex_unlock(&process_family_lock);
|
||||
|
||||
// Initialize everything that is safe and can't fail.
|
||||
kthread_mutex_lock(&resource_limits_lock);
|
||||
|
@ -1495,36 +1508,42 @@ pid_t sys_getpid(void)
|
|||
return CurrentProcess()->pid;
|
||||
}
|
||||
|
||||
pid_t Process::GetParentProcessId()
|
||||
{
|
||||
ScopedLock lock(&parentlock);
|
||||
if( !parent )
|
||||
return 0;
|
||||
return parent->pid;
|
||||
}
|
||||
|
||||
pid_t sys_getppid(void)
|
||||
{
|
||||
return CurrentProcess()->GetParentProcessId();
|
||||
Process* process = CurrentProcess();
|
||||
ScopedLock lock(&process_family_lock);
|
||||
if ( !process->parent )
|
||||
return 0;
|
||||
return process->parent->pid;
|
||||
}
|
||||
|
||||
pid_t sys_getpgid(pid_t pid)
|
||||
{
|
||||
ScopedLock lock(&process_family_lock);
|
||||
Process* process = !pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid);
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
|
||||
// Prevent the process group from changing while we read it.
|
||||
ScopedLock childlock(&process->groupchildlock);
|
||||
assert(process->group);
|
||||
|
||||
if ( !process->group )
|
||||
return errno = ESRCH, -1;
|
||||
return process->group->pid;
|
||||
}
|
||||
|
||||
pid_t sys_getsid(pid_t pid)
|
||||
{
|
||||
ScopedLock lock(&process_family_lock);
|
||||
Process* process = !pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid);
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
if ( !process->session )
|
||||
return errno = ESRCH, -1;
|
||||
return process->session->pid;
|
||||
}
|
||||
|
||||
int sys_setpgid(pid_t pid, pid_t pgid)
|
||||
{
|
||||
// TODO: Prevent changing the process group of zombies and other volatile
|
||||
// things that are about to implode.
|
||||
if ( pid < 0 || pgid < 0 )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
// TODO: Either prevent changing the process group after an exec or provide
|
||||
// a version of this system call with a flags parameter that lets you
|
||||
// decide if you want this behavior. This will fix a race condition
|
||||
|
@ -1534,6 +1553,10 @@ int sys_setpgid(pid_t pid, pid_t pgid)
|
|||
// process group, and then the shell gets around to change the process
|
||||
// group. This probably unlikely, but correctness over all!
|
||||
|
||||
Process* current_process = CurrentProcess();
|
||||
|
||||
ScopedLock lock(&process_family_lock);
|
||||
|
||||
// Find the processes in question.
|
||||
Process* process = !pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid);
|
||||
if ( !process )
|
||||
|
@ -1542,47 +1565,78 @@ int sys_setpgid(pid_t pid, pid_t pgid)
|
|||
if ( !group )
|
||||
return errno = ESRCH, -1;
|
||||
|
||||
// Prevent the current group from being changed while we also change it
|
||||
ScopedLock childlock(&process->groupchildlock);
|
||||
assert(process->group);
|
||||
// The process must be this one or a direct child.
|
||||
if ( process != current_process && process->parent != current_process )
|
||||
return errno = EPERM, -1;
|
||||
// The process must be in this session.
|
||||
if ( process->session != current_process->session )
|
||||
return errno = EPERM, -1;
|
||||
// The new group must be in the same session as the process.
|
||||
if ( group->session != process->session )
|
||||
return errno = EPERM, -1;
|
||||
// The process must not be a process group leader.
|
||||
// TODO: Maybe POSIX actually allows this.
|
||||
if ( process->groupfirst )
|
||||
return errno = EPERM, -1;
|
||||
// The process must not be a session leader.
|
||||
if ( process->sessionfirst )
|
||||
return errno = EPERM, -1;
|
||||
// The group must either exist or be the process itself.
|
||||
if ( !group->groupfirst && group != process )
|
||||
return errno = EPERM, -1;
|
||||
|
||||
// Exit early if this is a noop.
|
||||
if ( process->group == group )
|
||||
return 0;
|
||||
|
||||
// Prevent changing the process group of a process group leader.
|
||||
if ( process->group == process )
|
||||
return errno = EPERM, -1;
|
||||
|
||||
// Remove the process from its current process group.
|
||||
kthread_mutex_lock(&process->group->groupparentlock);
|
||||
if ( process->groupprev )
|
||||
process->groupprev->groupnext = process->groupnext;
|
||||
else
|
||||
process->group->groupfirst = process->groupnext;
|
||||
if ( process->groupnext )
|
||||
process->groupnext->groupprev = process->groupprev;
|
||||
kthread_cond_signal(&process->group->groupchildleft);
|
||||
kthread_mutex_unlock(&process->group->groupparentlock);
|
||||
process->group->NotifyLeftProcessGroup();
|
||||
process->group = NULL;
|
||||
|
||||
// TODO: Somehow prevent joining a zombie group, or worse yet, one that is
|
||||
// currently being deleted by its parent!
|
||||
if ( process->group )
|
||||
process->group->GroupRemoveMember(process);
|
||||
|
||||
// Insert the process into its new process group.
|
||||
kthread_mutex_lock(&group->groupparentlock);
|
||||
process->groupprev = NULL;
|
||||
process->groupnext = group->groupfirst;
|
||||
if ( group->groupfirst )
|
||||
group->groupfirst->groupprev = process;
|
||||
group->groupfirst = process;
|
||||
process->group = group;
|
||||
kthread_mutex_unlock(&group->groupparentlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pid_t sys_setsid(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);
|
||||
|
||||
// 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)
|
||||
{
|
||||
return Page::Size();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2015, 2016 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
|
||||
|
@ -17,16 +17,23 @@
|
|||
* Process control interface.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(TTY_NAME_MAX)
|
||||
#include <sortix/limits.h>
|
||||
#endif
|
||||
#include <sortix/psctl.h>
|
||||
|
||||
#include <sortix/kernel/clock.h>
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
#include <sortix/kernel/ptable.h>
|
||||
|
@ -37,6 +44,7 @@ namespace Sortix {
|
|||
|
||||
int sys_psctl(pid_t pid, int request, void* ptr)
|
||||
{
|
||||
ScopedLock lock(&process_family_lock);
|
||||
Ref<ProcessTable> ptable = CurrentProcess()->GetPTable();
|
||||
if ( request == PSCTL_PREV_PID )
|
||||
{
|
||||
|
@ -52,7 +60,6 @@ int sys_psctl(pid_t pid, int request, void* ptr)
|
|||
resp.next_pid = ptable->Next(pid);
|
||||
return CopyToUser(ptr, &resp, sizeof(resp)) ? 0 : -1;
|
||||
}
|
||||
// TODO: Scoped lock that prevents zombies from terminating.
|
||||
Process* process = ptable->Get(pid);
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
|
@ -61,55 +68,48 @@ int sys_psctl(pid_t pid, int request, void* ptr)
|
|||
struct psctl_stat psst;
|
||||
memset(&psst, 0, sizeof(psst));
|
||||
psst.pid = pid;
|
||||
kthread_mutex_lock(&process->parentlock);
|
||||
if ( process->parent )
|
||||
{
|
||||
Process* parent = process->parent;
|
||||
psst.ppid = parent->pid;
|
||||
kthread_mutex_unlock(&process->parentlock);
|
||||
// TODO: Is there a risk of getting a new parent here?
|
||||
kthread_mutex_lock(&parent->childlock);
|
||||
psst.ppid_prev = process->prevsibling ? process->prevsibling->pid : -1;
|
||||
psst.ppid_next = process->nextsibling ? process->nextsibling->pid : -1;
|
||||
kthread_mutex_unlock(&parent->childlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
kthread_mutex_unlock(&process->parentlock);
|
||||
psst.ppid = -1;
|
||||
psst.ppid_prev = -1;
|
||||
psst.ppid_next = -1;
|
||||
}
|
||||
kthread_mutex_lock(&process->childlock);
|
||||
psst.ppid_first = process->firstchild ? process->firstchild->pid : -1;
|
||||
kthread_mutex_unlock(&process->childlock);
|
||||
kthread_mutex_lock(&process->groupparentlock);
|
||||
if ( process->group )
|
||||
{
|
||||
Process* group = process->group;
|
||||
psst.pgid = group->pid;
|
||||
kthread_mutex_unlock(&process->groupparentlock);
|
||||
// TODO: Is there a risk of getting a new group here?
|
||||
kthread_mutex_lock(&group->groupchildlock);
|
||||
psst.pgid_prev = process->groupprev ? process->groupprev->pid : -1;
|
||||
psst.pgid_next = process->groupnext ? process->groupnext->pid : -1;
|
||||
kthread_mutex_unlock(&group->groupchildlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
kthread_mutex_unlock(&process->groupparentlock);
|
||||
psst.pgid = -1;
|
||||
psst.pgid_prev = -1;
|
||||
psst.pgid_next = -1;
|
||||
}
|
||||
kthread_mutex_lock(&process->groupchildlock);
|
||||
psst.pgid_first = process->groupfirst ? process->groupfirst->pid : -1;
|
||||
kthread_mutex_unlock(&process->groupchildlock);
|
||||
// TODO: Implement sessions.
|
||||
psst.sid = 1;
|
||||
psst.sid_prev = ptable->Prev(pid);
|
||||
psst.sid_next = ptable->Next(pid);
|
||||
psst.sid_first = pid == 1 ? 1 : -1;
|
||||
if ( process->session )
|
||||
{
|
||||
Process* session = process->session;
|
||||
psst.sid = session->pid;
|
||||
psst.sid_prev = process->sessionprev ? process->sessionprev->pid : -1;
|
||||
psst.sid_next = process->sessionnext ? process->sessionnext->pid : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
psst.sid = -1;
|
||||
psst.sid_prev = -1;
|
||||
psst.sid_next = -1;
|
||||
}
|
||||
psst.sid_first = process->sessionfirst ? process->sessionfirst->pid : -1;
|
||||
// TODO: Implement init groupings.
|
||||
psst.init = 1;
|
||||
psst.init_prev = ptable->Prev(pid);
|
||||
|
@ -155,6 +155,34 @@ int sys_psctl(pid_t pid, int request, void* ptr)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
else if ( request == PSCTL_TTYNAME )
|
||||
{
|
||||
struct psctl_ttyname ctl;
|
||||
if ( !CopyFromUser(&ctl, ptr, sizeof(ctl)) )
|
||||
return -1;
|
||||
ioctx_t kctx; SetupKernelIOCtx(&kctx);
|
||||
if ( !process->session )
|
||||
return errno = ENOTTY, -1;
|
||||
Ref<Descriptor> tty = process->session->GetTTY();
|
||||
if ( !tty )
|
||||
return errno = ENOTTY, -1;
|
||||
char ttyname[TTY_NAME_MAX-5+1];
|
||||
if ( tty->ioctl(&kctx, TIOCGNAME, (uintptr_t) ttyname) < 0 )
|
||||
return -1;
|
||||
size_t size = strlen(ttyname) + 1;
|
||||
struct psctl_ttyname resp = ctl;
|
||||
resp.size = size;
|
||||
if ( !CopyToUser(ptr, &resp, sizeof(resp)) )
|
||||
return -1;
|
||||
if ( ctl.buffer )
|
||||
{
|
||||
if ( ctl.size < size )
|
||||
return errno = ERANGE, -1;
|
||||
if ( !CopyToUser(ctl.buffer, ttyname, size) )
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return errno = EINVAL, -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2013, 2014, 2016 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
|
||||
|
@ -36,8 +36,6 @@ static int GetProcessPriority(pid_t who)
|
|||
{
|
||||
if ( who < 0 )
|
||||
return errno = EINVAL, -1;
|
||||
// TODO: If who isn't the current process, then it could self-destruct at
|
||||
// any time while we use it; there is no safe way to do this yet.
|
||||
Process* process = who ? CurrentProcess()->GetPTable()->Get(who) : CurrentProcess();
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
|
@ -49,8 +47,6 @@ static int SetProcessPriority(pid_t who, int prio)
|
|||
{
|
||||
if ( who < 0 )
|
||||
return errno = EINVAL, -1;
|
||||
// TODO: If who isn't the current process, then it could self-destruct at
|
||||
// any time while we use it; there is no safe way to do this yet.
|
||||
Process* process = who ? CurrentProcess()->GetPTable()->Get(who) : CurrentProcess();
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
|
@ -61,24 +57,17 @@ static int SetProcessPriority(pid_t who, int prio)
|
|||
|
||||
static Process* CurrentProcessGroup()
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
ScopedLock lock(&process->groupchildlock);
|
||||
// TODO: The process group can change when this call returns, additionally
|
||||
// the current process leader could self-destruct.
|
||||
return process->group;
|
||||
return CurrentProcess()->group;
|
||||
}
|
||||
|
||||
static int GetProcessGroupPriority(pid_t who)
|
||||
{
|
||||
if ( who < 0 )
|
||||
return errno = EINVAL, -1;
|
||||
// TODO: If who isn't the current process, then it could self-destruct at
|
||||
// any time while we use it; there is no safe way to do this yet.
|
||||
Process* group = who ? CurrentProcess()->GetPTable()->Get(who) : CurrentProcessGroup();
|
||||
if ( !group )
|
||||
return errno = ESRCH, -1;
|
||||
int lowest = INT_MAX;
|
||||
ScopedLock group_parent_lock(&group->groupparentlock);
|
||||
for ( Process* process = group->groupfirst; process; process = process->groupnext )
|
||||
{
|
||||
ScopedLock lock(&process->nicelock);
|
||||
|
@ -92,12 +81,9 @@ static int SetProcessGroupPriority(pid_t who, int prio)
|
|||
{
|
||||
if ( who < 0 )
|
||||
return errno = EINVAL, -1;
|
||||
// TODO: If who isn't the current process, then it could self-destruct at
|
||||
// any time while we use it; there is no safe way to do this yet.
|
||||
Process* group = who ? CurrentProcess()->GetPTable()->Get(who) : CurrentProcessGroup();
|
||||
if ( !group )
|
||||
return errno = ESRCH, -1;
|
||||
ScopedLock group_parent_lock(&group->groupparentlock);
|
||||
for ( Process* process = group->groupfirst; process; process = process->groupnext )
|
||||
{
|
||||
ScopedLock lock(&process->nicelock);
|
||||
|
@ -108,20 +94,17 @@ static int SetProcessGroupPriority(pid_t who, int prio)
|
|||
|
||||
static int GetUserPriority(uid_t /*who*/)
|
||||
{
|
||||
// TODO: There is currently no easy way to iterate all processes without
|
||||
// dire race conditions being possible.
|
||||
return errno = ENOSYS, -1;
|
||||
}
|
||||
|
||||
static int SetUserPriority(uid_t /*who*/, int /*prio*/)
|
||||
{
|
||||
// TODO: There is currently no easy way to iterate all processes without
|
||||
// dire race conditions being possible.
|
||||
return errno = ENOSYS, -1;
|
||||
}
|
||||
|
||||
int sys_getpriority(int which, id_t who)
|
||||
{
|
||||
ScopedLock lock(&process_family_lock);
|
||||
switch ( which )
|
||||
{
|
||||
case PRIO_PROCESS: return GetProcessPriority(who);
|
||||
|
@ -133,6 +116,7 @@ int sys_getpriority(int which, id_t who)
|
|||
|
||||
int sys_setpriority(int which, id_t who, int prio)
|
||||
{
|
||||
ScopedLock lock(&process_family_lock);
|
||||
switch ( which )
|
||||
{
|
||||
case PRIO_PROCESS: return SetProcessPriority(who, prio);
|
||||
|
@ -151,8 +135,7 @@ int sys_prlimit(pid_t pid,
|
|||
return errno = EINVAL, -1;
|
||||
if ( resource < 0 || RLIMIT_NUM_DECLARED <= resource )
|
||||
return errno = EINVAL, -1;
|
||||
// TODO: If pid isn't the current process, then it could self-destruct at
|
||||
// any time while we use it; there is no safe way to do this yet.
|
||||
ScopedLock family_lock(&process_family_lock);
|
||||
Process* process = pid ? CurrentProcess()->GetPTable()->Get(pid) : CurrentProcess();
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
|
|
|
@ -279,7 +279,8 @@ int sys_kill(pid_t pid, int signum)
|
|||
// TODO: Implement that pid == -1 means all processes!
|
||||
bool process_group = pid < 0 ? (pid = -pid, true) : false;
|
||||
|
||||
// TODO: Race condition: The process could be deleted while we use it.
|
||||
ScopedLock lock(&process_family_lock);
|
||||
|
||||
Process* process = CurrentProcess()->GetPTable()->Get(pid);
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
|
@ -300,9 +301,8 @@ int sys_kill(pid_t pid, int signum)
|
|||
return errno = 0, 0;
|
||||
}
|
||||
|
||||
bool Process::DeliverGroupSignal(int signum)
|
||||
bool Process::DeliverGroupSignal(int signum) // process_family_lock held
|
||||
{
|
||||
ScopedLock lock(&groupparentlock);
|
||||
if ( !groupfirst )
|
||||
return errno = ESRCH, false;
|
||||
for ( Process* iter = groupfirst; iter; iter = iter->groupnext )
|
||||
|
@ -317,6 +317,22 @@ bool Process::DeliverGroupSignal(int signum)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Process::DeliverSessionSignal(int signum) // process_family_lock held
|
||||
{
|
||||
if ( !sessionfirst )
|
||||
return errno = ESRCH, false;
|
||||
for ( Process* iter = sessionfirst; iter; iter = iter->sessionnext )
|
||||
{
|
||||
int saved_errno = errno;
|
||||
if ( !iter->DeliverSignal(signum) && errno != ESIGPENDING )
|
||||
{
|
||||
// This is not currently an error condition.
|
||||
}
|
||||
errno = saved_errno;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Process::DeliverSignal(int signum)
|
||||
{
|
||||
ScopedLock lock(&threadlock);
|
||||
|
|
|
@ -197,6 +197,8 @@ void* syscall_list[SYSCALL_MAX_NUM + 1] =
|
|||
[SYSCALL_TCSENDBREAK] = (void*) sys_tcsendbreak,
|
||||
[SYSCALL_TCSETATTR] = (void*) sys_tcsetattr,
|
||||
[SYSCALL_SCRAM] = (void*) sys_scram,
|
||||
[SYSCALL_GETSID] = (void*) sys_getsid,
|
||||
[SYSCALL_SETSID] = (void*) sys_setsid,
|
||||
[SYSCALL_MAX_NUM] = (void*) sys_bad_syscall,
|
||||
};
|
||||
} /* extern "C" */
|
||||
|
|
271
kernel/tty.cpp
271
kernel/tty.cpp
|
@ -17,9 +17,11 @@
|
|||
* Terminal line discipline.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -28,6 +30,9 @@
|
|||
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/keycodes.h>
|
||||
#if !defined(TTY_NAME_MAX)
|
||||
#include <sortix/limits.h>
|
||||
#endif
|
||||
#include <sortix/poll.h>
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/stat.h>
|
||||
|
@ -35,6 +40,7 @@
|
|||
#include <sortix/termmode.h>
|
||||
#include <sortix/winsize.h>
|
||||
|
||||
#include <sortix/kernel/descriptor.h>
|
||||
#include <sortix/kernel/inode.h>
|
||||
#include <sortix/kernel/interlock.h>
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
|
@ -47,6 +53,7 @@
|
|||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/scheduler.h>
|
||||
#include <sortix/kernel/thread.h>
|
||||
#include <sortix/kernel/vnode.h>
|
||||
|
||||
#include "tty.h"
|
||||
|
||||
|
@ -79,13 +86,50 @@ static inline bool IsUTF8Continuation(unsigned char byte)
|
|||
return (byte & 0b11000000) == 0b10000000;
|
||||
}
|
||||
|
||||
TTY::TTY(dev_t dev, mode_t mode, uid_t owner, gid_t group)
|
||||
DevTTY::DevTTY(dev_t dev, mode_t mode, uid_t owner, gid_t group)
|
||||
{
|
||||
if ( !dev )
|
||||
dev = (dev_t) this;
|
||||
inode_type = INODE_TYPE_TTY;
|
||||
this->dev = dev;
|
||||
this->ino = (ino_t) this;
|
||||
this->type = S_IFFACTORY;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
this->stat_uid = owner;
|
||||
this->stat_gid = group;
|
||||
}
|
||||
|
||||
DevTTY::~DevTTY()
|
||||
{
|
||||
}
|
||||
|
||||
Ref<Inode> DevTTY::factory(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode)
|
||||
{
|
||||
(void) ctx;
|
||||
(void) filename;
|
||||
(void) flags;
|
||||
(void) mode;
|
||||
ScopedLock lock(&process_family_lock);
|
||||
Process* process = CurrentProcess();
|
||||
if ( !process->session )
|
||||
return errno = ENOTTY, Ref<Inode>(NULL);
|
||||
Ref<Descriptor> tty_desc = process->session->GetTTY();
|
||||
if ( !tty_desc )
|
||||
return errno = ENOTTY, Ref<Inode>(NULL);
|
||||
return tty_desc->vnode->inode;
|
||||
}
|
||||
|
||||
TTY::TTY(dev_t dev, ino_t ino, mode_t mode, uid_t owner, gid_t group,
|
||||
const char* name)
|
||||
{
|
||||
if ( !dev )
|
||||
dev = (dev_t) this;
|
||||
if ( !ino )
|
||||
ino = (ino_t) this;
|
||||
inode_type = INODE_TYPE_TTY;
|
||||
this->dev = dev;
|
||||
this->ino = ino;
|
||||
this->type = S_IFCHR;
|
||||
this->stat_mode = (mode & S_SETABLE) | this->type;
|
||||
this->stat_uid = owner;
|
||||
|
@ -109,10 +153,13 @@ TTY::TTY(dev_t dev, mode_t mode, uid_t owner, gid_t group)
|
|||
tio.c_cc[VWERASE] = CONTROL('W');
|
||||
tio.c_ispeed = B38400;
|
||||
tio.c_ospeed = B38400;
|
||||
this->termlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
this->datacond = KTHREAD_COND_INITIALIZER;
|
||||
this->numeofs = 0;
|
||||
this->foreground_pgid = 0;
|
||||
termlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
datacond = KTHREAD_COND_INITIALIZER;
|
||||
numeofs = 0;
|
||||
foreground_pgid = -1;
|
||||
sid = -1;
|
||||
hungup = false;
|
||||
snprintf(ttyname, sizeof(ttyname), "%s", name);
|
||||
}
|
||||
|
||||
TTY::~TTY()
|
||||
|
@ -122,8 +169,10 @@ TTY::~TTY()
|
|||
int TTY::settermmode(ioctx_t* /*ctx*/, unsigned int termmode)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( !RequireForeground(SIGTTOU) )
|
||||
return errno = EINTR, -1;
|
||||
return -1;
|
||||
if ( termmode & ~SUPPORTED_TERMMODES )
|
||||
return errno = EINVAL, -1;
|
||||
tcflag_t old_cflag = tio.c_cflag;
|
||||
|
@ -195,6 +244,8 @@ int TTY::settermmode(ioctx_t* /*ctx*/, unsigned int termmode)
|
|||
int TTY::gettermmode(ioctx_t* ctx, unsigned int* mode)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
unsigned int termmode = 0;
|
||||
if ( tio.c_lflag & ISORTIX_KBKEY )
|
||||
termmode |= TERMMODE_KBKEY;
|
||||
|
@ -225,46 +276,25 @@ int TTY::gettermmode(ioctx_t* ctx, unsigned int* mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int TTY::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
|
||||
int TTY::tcgetwincurpos(ioctx_t* /*ctx*/, struct wincurpos* /*wcp*/)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
struct wincurpos retwcp;
|
||||
memset(&retwcp, 0, sizeof(retwcp));
|
||||
size_t cursor_column, cursor_row;
|
||||
Log::GetCursor(&cursor_column, &cursor_row);
|
||||
retwcp.wcp_col = cursor_column;
|
||||
retwcp.wcp_row = cursor_row;
|
||||
if ( !ctx->copy_to_dest(wcp, &retwcp, sizeof(retwcp)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TTY::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
struct winsize retws;
|
||||
memset(&retws, 0, sizeof(retws));
|
||||
retws.ws_col = Log::Width();
|
||||
retws.ws_row = Log::Height();
|
||||
if ( !ctx->copy_to_dest(ws, &retws, sizeof(retws)) )
|
||||
return -1;
|
||||
return 0;
|
||||
return errno = ENOTSUP, -1;
|
||||
}
|
||||
|
||||
int TTY::tcsetpgrp(ioctx_t* /*ctx*/, pid_t pgid)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( !RequireForeground(SIGTTOU) )
|
||||
return errno = EINTR, -1;
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
ScopedLock family_lock(&process_family_lock);
|
||||
if ( !RequireForegroundUnlocked(SIGTTOU) )
|
||||
return -1;
|
||||
if ( pgid <= 0 )
|
||||
return errno = ESRCH, -1;
|
||||
Process* process = CurrentProcess()->GetPTable()->Get(pgid);
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
kthread_mutex_lock(&process->groupparentlock);
|
||||
bool is_process_group = process->group == process;
|
||||
kthread_mutex_unlock(&process->groupparentlock);
|
||||
if ( !is_process_group )
|
||||
if ( !process->groupfirst )
|
||||
return errno = EINVAL, -1;
|
||||
foreground_pgid = pgid;
|
||||
return 0;
|
||||
|
@ -273,9 +303,26 @@ int TTY::tcsetpgrp(ioctx_t* /*ctx*/, pid_t pgid)
|
|||
pid_t TTY::tcgetpgrp(ioctx_t* /*ctx*/)
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
return foreground_pgid;
|
||||
}
|
||||
|
||||
void TTY::hup()
|
||||
{
|
||||
ScopedLock lock(&termlock);
|
||||
ScopedLock family_lock(&process_family_lock);
|
||||
hungup = true;
|
||||
if ( 0 < sid )
|
||||
{
|
||||
Process* process = CurrentProcess()->GetPTable()->Get(sid);
|
||||
if ( process )
|
||||
process->DeliverSessionSignal(SIGHUP);
|
||||
}
|
||||
kthread_cond_broadcast(&datacond);
|
||||
poll_channel.Signal(POLLHUP);
|
||||
}
|
||||
|
||||
void TTY::ProcessUnicode(uint32_t unicode)
|
||||
{
|
||||
mbstate_t ps;
|
||||
|
@ -311,6 +358,7 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
|
|||
{
|
||||
while ( linebuffer.CanBackspace() )
|
||||
linebuffer.Backspace();
|
||||
ScopedLock lock(&process_family_lock);
|
||||
if ( Process* process = CurrentProcess()->GetPTable()->Get(foreground_pgid) )
|
||||
process->DeliverGroupSignal(SIGQUIT);
|
||||
return;
|
||||
|
@ -320,6 +368,7 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
|
|||
{
|
||||
while ( linebuffer.CanBackspace() )
|
||||
linebuffer.Backspace();
|
||||
ScopedLock lock(&process_family_lock);
|
||||
if ( Process* process = CurrentProcess()->GetPTable()->Get(foreground_pgid) )
|
||||
process->DeliverGroupSignal(SIGINT);
|
||||
return;
|
||||
|
@ -340,6 +389,7 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
|
|||
{
|
||||
while ( linebuffer.CanBackspace() )
|
||||
linebuffer.Backspace();
|
||||
ScopedLock lock(&process_family_lock);
|
||||
if ( Process* process = CurrentProcess()->GetPTable()->Get(foreground_pgid) )
|
||||
process->DeliverGroupSignal(SIGQUIT);
|
||||
return;
|
||||
|
@ -359,9 +409,9 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
|
|||
{
|
||||
// TODO: Handle tab specially. (Is that even possible without
|
||||
// knowing cursor position?).
|
||||
Log::Print("\b \b");
|
||||
tty_output("\b \b");
|
||||
if ( !IsByteUnescaped(delchar) )
|
||||
Log::Print("\b \b");
|
||||
tty_output("\b \b");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -388,9 +438,9 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
|
|||
linebuffer.Backspace();
|
||||
if ( tio.c_lflag & ECHOE )
|
||||
{
|
||||
Log::Print("\b \b");
|
||||
tty_output("\b \b");
|
||||
if ( !IsByteUnescaped(delchar) )
|
||||
Log::Print("\b \b");
|
||||
tty_output("\b \b");
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -407,9 +457,9 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
|
|||
continue;
|
||||
if ( tio.c_lflag & ECHOE )
|
||||
{
|
||||
Log::Print("\b \b");
|
||||
tty_output("\b \b");
|
||||
if ( !IsByteUnescaped(delchar) )
|
||||
Log::Print("\b \b");
|
||||
tty_output("\b \b");
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -422,7 +472,7 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
|
|||
ProcessUnicode(KBKEY_ENCODE(KBKEY_ENTER));
|
||||
ProcessByte('\n');
|
||||
ProcessUnicode(KBKEY_ENCODE(-KBKEY_ENTER));
|
||||
Log::PrintF("\e[H\e[2J");
|
||||
tty_output("\e[H\e[2J");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -445,16 +495,19 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
|
|||
if ( byte == '\n' )
|
||||
{
|
||||
if ( tio.c_oflag & OPOST && tio.c_oflag & ONLCR )
|
||||
Log::PrintData("\r\n", 2);
|
||||
tty_output("\r\n");
|
||||
else if ( tio.c_oflag & OPOST && tio.c_oflag & OCRNL )
|
||||
Log::PrintData("\r", 1);
|
||||
tty_output("\r");
|
||||
else
|
||||
Log::PrintData("\n", 1);
|
||||
tty_output("\n");
|
||||
}
|
||||
else if ( IsByteUnescaped(byte) )
|
||||
Log::PrintData(&byte, 1);
|
||||
tty_output(&byte, 1);
|
||||
else
|
||||
Log::PrintF("^%c", CONTROL(byte));
|
||||
{
|
||||
unsigned char cs[2] = { '^', (unsigned char) CONTROL(byte) };
|
||||
tty_output(cs, sizeof(cs));
|
||||
}
|
||||
}
|
||||
|
||||
if ( !(tio.c_lflag & ICANON) || byte == '\n' )
|
||||
|
@ -476,8 +529,10 @@ ssize_t TTY::read(ioctx_t* ctx, uint8_t* userbuf, size_t count)
|
|||
ScopedLockSignal lock(&termlock);
|
||||
if ( !lock.IsAcquired() )
|
||||
return errno = EINTR, -1;
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( !RequireForeground(SIGTTIN) )
|
||||
return errno = EINTR, -1;
|
||||
return -1;
|
||||
size_t sofar = 0;
|
||||
size_t left = count;
|
||||
bool nonblocking = tio.c_lflag & ISORTIX_NONBLOCK ||
|
||||
|
@ -494,6 +549,8 @@ ssize_t TTY::read(ioctx_t* ctx, uint8_t* userbuf, size_t count)
|
|||
return errno = EWOULDBLOCK, -1;
|
||||
if ( !kthread_cond_wait_signal(&datacond, &termlock) )
|
||||
return sofar ? sofar : (errno = EINTR, -1);
|
||||
if ( hungup )
|
||||
return sofar ? sofar : (errno = EIO, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -511,6 +568,8 @@ ssize_t TTY::read(ioctx_t* ctx, uint8_t* userbuf, size_t count)
|
|||
}
|
||||
if ( !kthread_cond_wait_signal(&datacond, &termlock) )
|
||||
return sofar ? sofar : (errno = EINTR, -1);
|
||||
if ( hungup )
|
||||
return sofar ? sofar : (errno = EIO, -1);
|
||||
}
|
||||
else if ( tio.c_cc[VMIN] == 0 && 0 < tio.c_cc[VTIME] )
|
||||
{
|
||||
|
@ -522,6 +581,8 @@ ssize_t TTY::read(ioctx_t* ctx, uint8_t* userbuf, size_t count)
|
|||
// TODO: Only wait up until tio.c_cc[VTIME] * 0.1 seconds.
|
||||
if ( !kthread_cond_wait_signal(&datacond, &termlock) )
|
||||
return sofar ? sofar : (errno = EINTR, -1);
|
||||
if ( hungup )
|
||||
return sofar ? sofar : (errno = EIO, -1);
|
||||
}
|
||||
else
|
||||
return sofar;
|
||||
|
@ -586,8 +647,10 @@ ssize_t TTY::read(ioctx_t* ctx, uint8_t* userbuf, size_t count)
|
|||
ssize_t TTY::write(ioctx_t* ctx, const uint8_t* io_buffer, size_t count)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( tio.c_lflag & TOSTOP && !RequireForeground(SIGTTOU) )
|
||||
return errno = EINTR, -1;
|
||||
return -1;
|
||||
// TODO: Add support for ioctx to the kernel log.
|
||||
unsigned char buffer[256];
|
||||
size_t max_incoming = sizeof(buffer);
|
||||
|
@ -632,13 +695,15 @@ ssize_t TTY::write(ioctx_t* ctx, const uint8_t* io_buffer, size_t count)
|
|||
buffer[i] = '\n';
|
||||
}
|
||||
}
|
||||
Log::PrintData(buffer + offset, outgoing);
|
||||
tty_output(buffer + offset, outgoing);
|
||||
sofar += incoming;
|
||||
if ( ++rounds % 16 == 0 )
|
||||
{
|
||||
kthread_mutex_unlock(&termlock);
|
||||
kthread_yield();
|
||||
kthread_mutex_lock(&termlock);
|
||||
if ( hungup )
|
||||
return sofar;
|
||||
}
|
||||
if ( Signal::IsPending() )
|
||||
return sofar;
|
||||
|
@ -649,6 +714,8 @@ ssize_t TTY::write(ioctx_t* ctx, const uint8_t* io_buffer, size_t count)
|
|||
short TTY::PollEventStatus()
|
||||
{
|
||||
short status = 0;
|
||||
if ( hungup )
|
||||
status |= POLLHUP;
|
||||
if ( linebuffer.CanPop() || numeofs )
|
||||
status |= POLLIN | POLLRDNORM;
|
||||
if ( true /* can always write */ )
|
||||
|
@ -672,8 +739,10 @@ int TTY::poll(ioctx_t* /*ctx*/, PollNode* node)
|
|||
int TTY::tcdrain(ioctx_t* /*ctx*/)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( !RequireForeground(SIGTTOU) )
|
||||
return errno = EINTR, -1;
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -681,7 +750,7 @@ int TTY::tcflow(ioctx_t* /*ctx*/, int action)
|
|||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( !RequireForeground(SIGTTOU) )
|
||||
return errno = EINTR, -1;
|
||||
return -1;
|
||||
switch ( action )
|
||||
{
|
||||
case TCOOFF: break; // TODO: Suspend output.
|
||||
|
@ -698,8 +767,10 @@ int TTY::tcflush(ioctx_t* /*ctx*/, int queue_selector)
|
|||
if ( queue_selector & ~TCIOFLUSH )
|
||||
return errno = EINVAL, -1;
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( !RequireForeground(SIGTTOU) )
|
||||
return errno = EINTR, -1;
|
||||
return -1;
|
||||
if ( queue_selector & TCIFLUSH )
|
||||
linebuffer.Flush();
|
||||
return 0;
|
||||
|
@ -708,6 +779,8 @@ int TTY::tcflush(ioctx_t* /*ctx*/, int queue_selector)
|
|||
int TTY::tcgetattr(ioctx_t* ctx, struct termios* io_tio)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( !ctx->copy_to_dest(io_tio, &tio, sizeof(tio)) )
|
||||
return -1;
|
||||
return 0;
|
||||
|
@ -715,23 +788,29 @@ int TTY::tcgetattr(ioctx_t* ctx, struct termios* io_tio)
|
|||
|
||||
pid_t TTY::tcgetsid(ioctx_t* /*ctx*/)
|
||||
{
|
||||
// TODO: Implement sessions.
|
||||
return 1;
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
return sid;
|
||||
}
|
||||
|
||||
int TTY::tcsendbreak(ioctx_t* /*ctx*/, int /*duration*/)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( !RequireForeground(SIGTTOU) )
|
||||
return errno = EINTR, -1;
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TTY::tcsetattr(ioctx_t* ctx, int actions, const struct termios* io_tio)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( !RequireForeground(SIGTTOU) )
|
||||
return errno = EINTR, -1;
|
||||
return -1;
|
||||
switch ( actions )
|
||||
{
|
||||
case TCSANOW: break;
|
||||
|
@ -739,18 +818,88 @@ int TTY::tcsetattr(ioctx_t* ctx, int actions, const struct termios* io_tio)
|
|||
case TCSAFLUSH: linebuffer.Flush(); break;
|
||||
default: return errno = EINVAL, -1;
|
||||
}
|
||||
tcflag_t old_lflag = tio.c_lflag;
|
||||
if ( !ctx->copy_from_src(&tio, io_tio, sizeof(tio)) )
|
||||
return -1;
|
||||
// TODO: Potentially take action here if something changed.
|
||||
tcflag_t new_lflag = tio.c_lflag;
|
||||
bool oldnoutf8 = old_lflag & ISORTIX_32BIT;
|
||||
bool newnoutf8 = new_lflag & ISORTIX_32BIT;
|
||||
if ( oldnoutf8 != newnoutf8 )
|
||||
memset(&read_ps, 0, sizeof(read_ps));
|
||||
if ( !(tio.c_lflag & ICANON) )
|
||||
CommitLineBuffer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TTY::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
|
||||
{
|
||||
ScopedLockSignal lock(&termlock);
|
||||
if ( hungup )
|
||||
return errno = EIO, -1;
|
||||
if ( cmd == TIOCSCTTY )
|
||||
{
|
||||
ScopedLock family_lock(&process_family_lock);
|
||||
if ( 0 <= sid )
|
||||
return errno = EPERM, -1;
|
||||
Process* process = CurrentProcess();
|
||||
if ( !process->sessionfirst )
|
||||
return errno = EPERM, -1;
|
||||
if ( (ctx->dflags & (O_READ | O_WRITE)) != (O_READ | O_WRITE) )
|
||||
return errno = EPERM, -1;
|
||||
Ref<Vnode> vnode(new Vnode(Ref<Inode>(this), Ref<Vnode>(NULL), 0, 0));
|
||||
if ( !vnode )
|
||||
return -1;
|
||||
Ref<Descriptor> desc(new Descriptor(vnode, O_READ | O_WRITE));
|
||||
if ( !desc )
|
||||
return -1;
|
||||
sid = process->pid;
|
||||
foreground_pgid = process->pid;
|
||||
process->SetTTY(desc);
|
||||
return 0;
|
||||
}
|
||||
else if ( cmd == TIOCSPTLCK )
|
||||
{
|
||||
// TODO: Figure out what locked ptys are and implement it if sensible.
|
||||
const int* arg_ptr = (const int*) arg;
|
||||
int new_locked;
|
||||
if ( !ctx->copy_from_src(&new_locked, arg_ptr, sizeof(new_locked)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
else if ( cmd == TIOCGPTLCK )
|
||||
{
|
||||
// TODO: Figure out what locked ptys are and implement it if sensible.
|
||||
int* arg_ptr = (int*) arg;
|
||||
int locked = 0;
|
||||
if ( !ctx->copy_to_dest(arg_ptr, &locked, sizeof(locked)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
else if ( cmd == TIOCGNAME )
|
||||
{
|
||||
char* arg_ptr = (char*) arg;
|
||||
size_t ttynamesize = strlen(ttyname) + 1;
|
||||
if ( !ctx->copy_to_dest(arg_ptr, ttyname, ttynamesize) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
lock.Reset();
|
||||
return AbstractInode::ioctl(ctx, cmd, arg);
|
||||
}
|
||||
|
||||
bool TTY::RequireForeground(int sig)
|
||||
{
|
||||
ScopedLock family_lock(&process_family_lock);
|
||||
return RequireForegroundUnlocked(sig);
|
||||
}
|
||||
|
||||
bool TTY::RequireForegroundUnlocked(int sig) // process_family_lock held
|
||||
{
|
||||
Thread* thread = CurrentThread();
|
||||
Process* process = thread->process;
|
||||
ScopedLock group_lock(&process->groupparentlock);
|
||||
if ( process->group->pid == foreground_pgid )
|
||||
if ( !process->session || process->session->pid != sid || !process->group )
|
||||
return true;
|
||||
if ( foreground_pgid < 1 || process->group->pid == foreground_pgid )
|
||||
return true;
|
||||
if ( sigismember(&thread->signal_mask, sig) )
|
||||
return true;
|
||||
|
@ -758,8 +907,8 @@ bool TTY::RequireForeground(int sig)
|
|||
if ( process->signal_actions[sig].sa_handler == SIG_IGN )
|
||||
return true;
|
||||
signal_lock.Reset();
|
||||
group_lock.Reset();
|
||||
process->group->DeliverGroupSignal(sig);
|
||||
errno = EINTR;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
37
kernel/tty.h
37
kernel/tty.h
|
@ -20,8 +20,12 @@
|
|||
#ifndef SORTIX_TTY_H
|
||||
#define SORTIX_TTY_H
|
||||
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#if !defined(TTY_NAME_MAX)
|
||||
#include <sortix/limits.h>
|
||||
#endif
|
||||
#include <sortix/termios.h>
|
||||
|
||||
#include <sortix/kernel/kthread.h>
|
||||
|
@ -35,17 +39,29 @@
|
|||
|
||||
namespace Sortix {
|
||||
|
||||
class DevTTY : public AbstractInode
|
||||
{
|
||||
public:
|
||||
DevTTY(dev_t dev, mode_t mode, uid_t owner, gid_t group);
|
||||
virtual ~DevTTY();
|
||||
|
||||
public:
|
||||
virtual Ref<Inode> factory(ioctx_t* ctx, const char* filename, int flags,
|
||||
mode_t mode);
|
||||
|
||||
};
|
||||
|
||||
class TTY : public AbstractInode
|
||||
{
|
||||
public:
|
||||
TTY(dev_t dev, mode_t mode, uid_t owner, gid_t group);
|
||||
TTY(dev_t dev, ino_t ino, mode_t mode, uid_t owner, gid_t group,
|
||||
const char* name);
|
||||
virtual ~TTY();
|
||||
|
||||
public:
|
||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
|
||||
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
|
||||
virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
|
||||
virtual pid_t tcgetpgrp(ioctx_t* ctx);
|
||||
virtual int settermmode(ioctx_t* ctx, unsigned termmode);
|
||||
|
@ -58,6 +74,17 @@ public:
|
|||
virtual pid_t tcgetsid(ioctx_t* ctx);
|
||||
virtual int tcsendbreak(ioctx_t* ctx, int duration);
|
||||
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
|
||||
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
|
||||
|
||||
public:
|
||||
void hup();
|
||||
|
||||
protected:
|
||||
void tty_output(const char* str)
|
||||
{
|
||||
tty_output((const unsigned char*) str, strlen(str));
|
||||
}
|
||||
virtual void tty_output(const unsigned char* buffer, size_t length) = 0;
|
||||
|
||||
protected:
|
||||
void ProcessUnicode(uint32_t unicode);
|
||||
|
@ -66,17 +93,21 @@ protected:
|
|||
short PollEventStatus();
|
||||
bool CheckForeground();
|
||||
bool RequireForeground(int sig);
|
||||
bool RequireForegroundUnlocked(int sig);
|
||||
bool CheckHandledByte(tcflag_t lflags, unsigned char key, unsigned char byte);
|
||||
|
||||
protected:
|
||||
PollChannel poll_channel;
|
||||
mutable kthread_mutex_t termlock;
|
||||
kthread_mutex_t termlock;
|
||||
kthread_cond_t datacond;
|
||||
mbstate_t read_ps;
|
||||
size_t numeofs;
|
||||
LineBuffer linebuffer;
|
||||
struct termios tio;
|
||||
pid_t foreground_pgid;
|
||||
pid_t sid;
|
||||
bool hungup;
|
||||
char ttyname[TTY_NAME_MAX-5+1];
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -339,9 +339,9 @@ int Vnode::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
|
|||
return inode->tcgetwincurpos(ctx, wcp);
|
||||
}
|
||||
|
||||
int Vnode::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
|
||||
int Vnode::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
|
||||
{
|
||||
return inode->tcgetwinsize(ctx, ws);
|
||||
return inode->ioctl(ctx, cmd, arg);
|
||||
}
|
||||
|
||||
int Vnode::tcsetpgrp(ioctx_t* ctx, pid_t pgid)
|
||||
|
|
|
@ -688,6 +688,7 @@ unistd/getpagesize.o \
|
|||
unistd/getpgid.o \
|
||||
unistd/getpid.o \
|
||||
unistd/getppid.o \
|
||||
unistd/getsid.o \
|
||||
unistd/getuid.o \
|
||||
unistd/isatty.o \
|
||||
unistd/lchown.o \
|
||||
|
@ -710,6 +711,7 @@ unistd/seteuid.o \
|
|||
unistd/setgid.o \
|
||||
unistd/sethostname.o \
|
||||
unistd/setpgid.o \
|
||||
unistd/setsid.o \
|
||||
unistd/setuid.o \
|
||||
unistd/sfork.o \
|
||||
unistd/sleep.o \
|
||||
|
|
|
@ -440,7 +440,7 @@ ssize_t read(int, void*, size_t);
|
|||
int rmdir(const char*);
|
||||
int setgid(gid_t);
|
||||
int setpgid(pid_t, pid_t);
|
||||
/* TODO: pid_t setsid(void); */
|
||||
pid_t setsid(void);
|
||||
int setuid(uid_t);
|
||||
unsigned sleep(unsigned);
|
||||
long sysconf(int);
|
||||
|
@ -494,7 +494,7 @@ int symlink(const char*, const char*);
|
|||
#if __USE_SORTIX || 200809L <= __USE_POSIX || 420 <= __USE_XOPEN
|
||||
int fchdir(int);
|
||||
int fchown(int, uid_t, gid_t);
|
||||
/* TODO: pid_t getsid(void); */
|
||||
pid_t getsid(pid_t);
|
||||
int lchown(const char*, uid_t, gid_t);
|
||||
int truncate(const char*, off_t);
|
||||
#endif
|
||||
|
|
29
libc/unistd/getsid.c
Normal file
29
libc/unistd/getsid.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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/getsid.c
|
||||
* Get the current session.
|
||||
*/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL1(pid_t, sys_getsid, SYSCALL_GETSID, pid_t);
|
||||
|
||||
pid_t getsid(pid_t pid)
|
||||
{
|
||||
return sys_getsid(pid);
|
||||
}
|
29
libc/unistd/setsid.c
Normal file
29
libc/unistd/setsid.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2016 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/setsid.c
|
||||
* Enter a new session.
|
||||
*/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL0(pid_t, sys_setsid, SYSCALL_SETSID);
|
||||
|
||||
pid_t setsid(void)
|
||||
{
|
||||
return sys_setsid();
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2014 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2013, 2014, 2016 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
|
||||
|
@ -17,24 +17,24 @@
|
|||
* Returns the pathname of a terminal.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(TTY_NAME_MAX)
|
||||
#include <sortix/limits.h>
|
||||
#endif
|
||||
|
||||
char* ttyname(int fd)
|
||||
{
|
||||
static char* result = NULL;
|
||||
static size_t result_size = 0;
|
||||
while ( ttyname_r(fd, result, result_size) < 0 )
|
||||
{
|
||||
if ( errno != ERANGE )
|
||||
return NULL;
|
||||
size_t new_result_size = result_size ? 2 * result_size : 16;
|
||||
char* new_result = (char*) realloc(result, new_result_size);
|
||||
if ( !new_result )
|
||||
return NULL;
|
||||
result = new_result;
|
||||
result_size = new_result_size;
|
||||
}
|
||||
return result;
|
||||
static char name[TTY_NAME_MAX+1];
|
||||
name[0] = '/';
|
||||
name[1] = 'd';
|
||||
name[2] = 'e';
|
||||
name[3] = 'v';
|
||||
name[4] = '/';
|
||||
if ( ioctl(fd, TIOCGNAME, name + 5) < 0 )
|
||||
return NULL;
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2014 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2013, 2014, 2016 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
|
||||
|
@ -17,16 +17,28 @@
|
|||
* Returns the pathname of a terminal.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(TTY_NAME_MAX)
|
||||
#include <sortix/limits.h>
|
||||
#endif
|
||||
|
||||
int ttyname_r(int fd, char* path, size_t path_size)
|
||||
{
|
||||
if ( isatty(fd) < 1 )
|
||||
char name[TTY_NAME_MAX+1];
|
||||
name[0] = '/';
|
||||
name[1] = 'd';
|
||||
name[2] = 'e';
|
||||
name[3] = 'v';
|
||||
name[4] = '/';
|
||||
if ( ioctl(fd, TIOCGNAME, name + 5) < 0 )
|
||||
return -1;
|
||||
const char* result = "/dev/tty";
|
||||
if ( path_size <= strlcpy(path, result, path_size) )
|
||||
if ( path_size <= strlcpy(path, name, path_size) )
|
||||
return errno = ERANGE, -1;
|
||||
return 0;
|
||||
}
|
||||
|
|
41
utils/ps.c
41
utils/ps.c
|
@ -51,6 +51,27 @@ static char* get_program_path_of_pid(pid_t pid)
|
|||
}
|
||||
}
|
||||
|
||||
static char* get_ttyname_of_pid(pid_t pid)
|
||||
{
|
||||
struct psctl_ttyname ctl;
|
||||
memset(&ctl, 0, sizeof(ctl));
|
||||
ctl.buffer = NULL;
|
||||
ctl.size = 0;
|
||||
if ( psctl(pid, PSCTL_TTYNAME, &ctl) < 0 )
|
||||
return NULL;
|
||||
while ( true )
|
||||
{
|
||||
char* new_buffer = (char*) realloc(ctl.buffer, ctl.size);
|
||||
if ( !new_buffer )
|
||||
return free(ctl.buffer), (char*) NULL;
|
||||
ctl.buffer = new_buffer;
|
||||
if ( psctl(pid, PSCTL_TTYNAME, &ctl) == 0 )
|
||||
return ctl.buffer;
|
||||
if ( errno != ERANGE )
|
||||
return free(ctl.buffer), (char*) NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void compact_arguments(int* argc, char*** argv)
|
||||
{
|
||||
for ( int i = 0; i < *argc; i++ )
|
||||
|
@ -140,8 +161,12 @@ int main(int argc, char* argv[])
|
|||
if ( show_full || show_long )
|
||||
printf("PPID\t");
|
||||
if ( show_long )
|
||||
printf("NI ");
|
||||
printf("TTY ");
|
||||
printf("PGID\t");
|
||||
if ( show_long )
|
||||
printf("SID\t");
|
||||
if ( show_long )
|
||||
printf("NI\t");
|
||||
printf("TTY\t");
|
||||
printf("TIME\t ");
|
||||
printf("CMD\n");
|
||||
pid_t pid = 0;
|
||||
|
@ -175,8 +200,16 @@ int main(int argc, char* argv[])
|
|||
if ( show_full || show_long )
|
||||
printf("%" PRIiPID "\t", psst.ppid);
|
||||
if ( show_long )
|
||||
printf("%-4i", psst.nice);
|
||||
printf("tty ");
|
||||
printf("%" PRIiPID "\t", psst.pgid);
|
||||
if ( show_long )
|
||||
printf("%" PRIiPID "\t", psst.sid);
|
||||
if ( show_long )
|
||||
printf("%-4i\t", psst.nice);
|
||||
char* ttyname = get_ttyname_of_pid(pid);
|
||||
// TODO: Strip special characters from the ttyname lest an attacker
|
||||
// do things to the user's terminal.
|
||||
printf("%s\t", ttyname ? ttyname : "?");
|
||||
free(ttyname);
|
||||
time_t time = psst.tmns.tmns_utime.tv_sec;
|
||||
int hours = (time / (60 * 60)) % 24;
|
||||
int minutes = (time / 60) % 60;
|
||||
|
|
Loading…
Reference in a new issue