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