1
0
Fork 0
mirror of https://gitlab.com/sortix/sortix.git synced 2023-02-13 20:55:38 -05:00

Add mkpty(2).

This commit is contained in:
Jonas 'Sortie' Termansen 2015-05-09 22:38:04 +02:00
parent d5236cd8ac
commit 1a3b3f6deb
21 changed files with 471 additions and 77 deletions

View file

@ -134,6 +134,7 @@ poll.o \
process.o \
psctl.o \
ptable.o \
pty.o \
random.o \
refcount.o \
registers.o \

View file

@ -694,9 +694,9 @@ int Descriptor::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
return vnode->tcgetwincurpos(ctx, wcp);
}
int Descriptor::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
int Descriptor::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
{
return vnode->tcgetwinsize(ctx, ws);
return vnode->ioctl(ctx, cmd, arg);
}
int Descriptor::tcsetpgrp(ioctx_t* ctx, pid_t pgid)

View file

@ -30,6 +30,7 @@
#include <sortix/dirent.h>
#include <sortix/fcntl.h>
#include <sortix/ioctl.h>
#include <sortix/stat.h>
#include <sortix/timespec.h>
#include <sortix/winsize.h>
@ -225,7 +226,7 @@ public:
const char* filename);
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
virtual pid_t tcgetpgrp(ioctx_t* ctx);
virtual int settermmode(ioctx_t* ctx, unsigned mode);
@ -1219,23 +1220,27 @@ int Unode::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
return ret;
}
int Unode::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
int Unode::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcgetwinsize msg;
struct fsm_resp_tcgetwinsize resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCGETWINSIZE, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_TCGETWINSIZE, &resp, sizeof(resp)) &&
ctx->copy_to_dest(ws, &resp.size, sizeof(*ws)) )
ret = 0;
channel->KernelClose();
return ret;
if ( cmd == TIOCGWINSZ )
{
struct winsize* ws = (struct winsize*) arg;
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcgetwinsize msg;
struct fsm_resp_tcgetwinsize resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCGETWINSIZE, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_TCGETWINSIZE, &resp, sizeof(resp)) &&
ctx->copy_to_dest(ws, &resp.size, sizeof(*ws)) )
ret = 0;
channel->KernelClose();
return ret;
}
return errno = ENOTTY, -1;
}
int Unode::tcsetpgrp(ioctx_t* ctx, pid_t pgid)
{
Channel* channel = server->Connect(ctx);

View file

@ -32,5 +32,6 @@
#define __IOCTL_TYPE(value) ((value) & __IOCTL_TYPE_MASK)
#define TIOCGWINSZ __IOCTL(1, __IOCTL_TYPE_PTR)
#define TIOCSWINSZ __IOCTL(2, __IOCTL_TYPE_PTR)
#endif

View file

@ -78,7 +78,7 @@ public:
int symlink(ioctx_t* ctx, const char* oldname, const char* filename);
ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
pid_t tcgetpgrp(ioctx_t* ctx);
int settermmode(ioctx_t* ctx, unsigned mode);

View file

@ -84,7 +84,7 @@ public:
const char* filename) = 0;
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz) = 0;
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp) = 0;
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws) = 0;
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg) = 0;
virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid) = 0;
virtual pid_t tcgetpgrp(ioctx_t* ctx) = 0;
virtual int settermmode(ioctx_t* ctx, unsigned mode) = 0;
@ -177,7 +177,7 @@ public:
const char* filename);
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
virtual pid_t tcgetpgrp(ioctx_t* ctx);
virtual int settermmode(ioctx_t* ctx, unsigned mode);

View file

@ -115,6 +115,7 @@ off_t sys_lseek(int, off_t, int);
int sys_memstat(size_t*, size_t*);
int sys_mkdirat(int, const char*, mode_t);
int sys_mkpartition(int, off_t, off_t, int);
int sys_mkptyline(int*, int*, int);
void* sys_mmap_wrapper(struct mmap_request*);
int sys_mprotect(const void*, size_t, int);
int sys_munmap(void*, size_t);

View file

@ -77,7 +77,7 @@ public:
ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
int fsbind(ioctx_t* ctx, Vnode* node, int flags);
int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
pid_t tcgetpgrp(ioctx_t* ctx);
int settermmode(ioctx_t* ctx, unsigned mode);

View file

@ -173,7 +173,7 @@
#define SYSCALL_UNMOUNTAT 150
#define SYSCALL_FSM_MOUNTAT 151
#define SYSCALL_CLOSEFROM 152
#define SYSCALL_RESERVED1 153
#define SYSCALL_MKPTYLINE 153
#define SYSCALL_PSCTL 154
#define SYSCALL_TCDRAIN 155
#define SYSCALL_TCFLOW 156

View file

@ -290,10 +290,8 @@ int AbstractInode::tcgetwincurpos(ioctx_t* /*ctx*/, struct wincurpos* /*wcp*/)
return errno = ENOTTY, -1;
}
int AbstractInode::tcgetwinsize(ioctx_t* /*ctx*/, struct winsize* /*ws*/)
int AbstractInode::ioctl(ioctx_t* /*ctx*/, int /*cmd*/, uintptr_t /*arg*/)
{
if ( inode_type == INODE_TYPE_TTY )
return errno = EBADF, -1;
return errno = ENOTTY, -1;
}

View file

@ -368,13 +368,11 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg)
int sys_ioctl(int fd, int cmd, uintptr_t arg)
{
switch ( cmd )
{
case TIOCGWINSZ:
return sys_tcgetwinsize(fd, (struct winsize*) arg);
default:
return errno = EINVAL, -1;
}
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->ioctl(&ctx, cmd, arg);
}
ssize_t sys_readdirents(int fd, struct dirent* dirent, size_t size)
@ -645,14 +643,9 @@ int sys_tcgetwincurpos(int fd, struct wincurpos* wcp)
return desc->tcgetwincurpos(&ctx, wcp);
}
int sys_tcgetwinsize(int fd, struct winsize* ws)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->tcgetwinsize(&ctx, ws);
return sys_ioctl(fd, TIOCGWINSZ, (uintptr_t) ws);
}
int sys_tcsetpgrp(int fd, pid_t pgid)

View file

@ -27,6 +27,7 @@
#include <wchar.h>
#include <sortix/fcntl.h>
#include <sortix/ioctl.h>
#include <sortix/keycodes.h>
#include <sortix/poll.h>
#include <sortix/signal.h>
@ -122,6 +123,11 @@ LogTerminal::~LogTerminal()
delete kblayout;
}
void LogTerminal::tty_output(const unsigned char* buffer, size_t length)
{
Log::PrintData(buffer, length);
}
int LogTerminal::sync(ioctx_t* /*ctx*/)
{
ScopedLock lock(&termlock);
@ -281,4 +287,35 @@ ssize_t LogTerminal::tcsetblob(ioctx_t* ctx, const char* name, const void* buffe
return errno = ENOENT, -1;
}
int LogTerminal::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
{
ScopedLock lock(&termlock);
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)
{
if ( cmd == TIOCGWINSZ )
{
struct winsize* ws = (struct winsize*) arg;
ScopedLock lock(&termlock);
struct winsize retws;
memset(&retws, 0, sizeof(retws));
retws.ws_col = Log::Width();
retws.ws_row = Log::Height();
if ( !ctx->copy_to_dest(ws, &retws, sizeof(retws)) )
return -1;
return 0;
}
return TTY::ioctl(ctx, cmd, arg);
}
} // namespace Sortix

View file

@ -35,10 +35,15 @@ public:
virtual int sync(ioctx_t* ctx);
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
public:
virtual void OnKeystroke(Keyboard* keyboard, void* user);
protected:
virtual void tty_output(const unsigned char* buffer, size_t length);
private:
void ProcessKeystroke(int kbkey);

333
kernel/pty.cpp Normal file
View file

@ -0,0 +1,333 @@
/*
* Copyright (c) 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* 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.
*
* pty.cpp
* Pseudoterminals.
*/
#include <sys/types.h>
#include <errno.h>
#include <sortix/fcntl.h>
#include <sortix/ioctl.h>
#include <sortix/poll.h>
#include <sortix/stat.h>
#include <sortix/termmode.h>
#include <sortix/winsize.h>
#include <sortix/kernel/copy.h>
#include <sortix/kernel/descriptor.h>
#include <sortix/kernel/dtable.h>
#include <sortix/kernel/inode.h>
#include <sortix/kernel/ioctx.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/poll.h>
#include <sortix/kernel/process.h>
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/signal.h>
#include <sortix/kernel/syscall.h>
#include <sortix/kernel/vnode.h>
#include "tty.h"
namespace Sortix {
class PTY : public TTY
{
public:
PTY(mode_t mode, uid_t owner, gid_t group);
virtual ~PTY();
public:
virtual int sync(ioctx_t* ctx);
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
public:
ssize_t master_read(ioctx_t* ctx, uint8_t* buf, size_t count);
ssize_t master_write(ioctx_t* ctx, const uint8_t* buf, size_t count);
int master_poll(ioctx_t* ctx, PollNode* node);
int master_ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
protected:
virtual void tty_output(const unsigned char* buffer, size_t length);
private:
struct winsize ws;
kthread_mutex_t input_lock;
kthread_mutex_t output_lock;
kthread_cond_t output_ready_cond;
kthread_cond_t output_possible_cond;
size_t output_offset;
size_t output_used;
static const size_t output_size = 4096;
uint8_t output[output_size];
};
PTY::PTY(mode_t mode, uid_t owner, gid_t group)
: TTY(0, mode, owner, group)
{
tio.c_cflag |= CREAD;
input_lock = KTHREAD_MUTEX_INITIALIZER;
output_lock = KTHREAD_MUTEX_INITIALIZER;
output_ready_cond = KTHREAD_COND_INITIALIZER;
output_possible_cond = KTHREAD_COND_INITIALIZER;
output_offset = 0;
output_used = 0;
memset(&ws, 0, sizeof(ws));
}
PTY::~PTY()
{
}
ssize_t PTY::master_read(ioctx_t* ctx, uint8_t* buf, size_t count)
{
ScopedLockSignal lock(&output_lock);
if ( !lock.IsAcquired() )
return errno = EINTR, -1;
while ( !output_used )
{
if ( ctx->dflags & O_NONBLOCK )
return errno = EWOULDBLOCK, -1;
if ( !kthread_cond_wait_signal(&output_ready_cond, &output_lock) )
return errno = EINTR, -1;
}
size_t sofar = 0;
while ( output_used && sofar < count )
{
size_t limit = output_size - output_offset;
size_t possible = limit < output_used ? limit : output_used;
size_t amount = count < possible ? count : possible;
if ( !ctx->copy_to_dest(buf + sofar, output + output_offset, amount) )
return sofar ? (ssize_t) sofar : -1;
output_used -= amount;
output_offset += amount;
if ( output_offset == output_size )
output_offset = 0;
sofar += amount;
kthread_cond_signal(&output_possible_cond);
}
return (ssize_t) sofar;
}
ssize_t PTY::master_write(ioctx_t* ctx, const uint8_t* buf, size_t count)
{
ScopedLockSignal lock(&input_lock);
if ( !lock.IsAcquired() )
return errno = EINTR, -1;
size_t sofar = 0;
while ( sofar < count )
{
uint8_t input[1024];
size_t amount = count < sizeof(input) ? count : sizeof(input);
if ( !ctx->copy_from_src(input, buf + sofar, amount) )
return sofar ? (ssize_t) sofar : -1;
for ( size_t i = 0; i < amount; i++ )
{
if ( Signal::IsPending() )
return sofar ? (ssize_t) sofar : (errno = EINTR, -1);
ProcessByte(input[i]);
}
sofar += amount;
}
return (ssize_t) sofar;
}
// TODO: This function can deadlock if data is written using master_write, with
// tty ECHO on, then it echos the input through this function, but the
// output buffer is full, so it blocks. But there only was a single thread
// using the pty, which did a write, and now is waiting for itself to
// read. Either this is a broken usage of pty's and you must have a
// dedicated read thread, or need a dedicated kernel thread for each pty
// that buffers up a large amount of input, then processes it at its own
// pace.
void PTY::tty_output(const unsigned char* buffer, size_t length)
{
ScopedLock lock(&output_lock);
while ( length )
{
while ( output_used == output_size )
if ( !kthread_cond_wait_signal(&output_possible_cond, &output_lock) )
return; // TODO: Data loss?
size_t offset = output_offset + output_used;
if ( output_size <= offset )
offset -= output_size;
size_t left = output_size - output_used;
size_t end = offset + left;
if ( output_size < end )
end = output_size;
size_t possible = end - offset;
size_t amount = length < possible ? length : possible;
memcpy(output + offset, buffer, amount);
buffer += amount;
length -= amount;
output_used += amount;
kthread_cond_signal(&output_ready_cond);
}
}
int PTY::master_poll(ioctx_t* ctx, PollNode* node)
{
(void) ctx;
(void) node;
return errno = ENOTSUP, -1; // TODO: Implement this.
}
int PTY::sync(ioctx_t* /*ctx*/)
{
return 0;
}
int PTY::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
{
if ( cmd == TIOCGWINSZ )
{
ScopedLock lock(&termlock);
struct winsize* user_ws = (struct winsize*) arg;
if ( !ctx->copy_to_dest(user_ws, &ws, sizeof(ws)) )
return -1;
return 0;
}
return TTY::ioctl(ctx, cmd, arg);
}
int PTY::master_ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
{
if ( cmd == TIOCSWINSZ )
{
ScopedLock lock(&termlock);
const struct winsize* user_ws = (const struct winsize*) arg;
if ( !ctx->copy_from_src(&ws, user_ws, sizeof(ws)) )
return -1;
return 0;
}
return ioctl(ctx, cmd, arg);
}
class MasterNode : public AbstractInode
{
public:
MasterNode(uid_t owner, gid_t group, mode_t mode, Ref<PTY> pty);
virtual ~MasterNode();
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
virtual int poll(ioctx_t* ctx, PollNode* node);
virtual int ioctl(ioctx_t* ctx, int cmd, uintptr_t arg);
public:
Ref<PTY> pty;
};
MasterNode::MasterNode(uid_t owner, gid_t group, mode_t mode, Ref<PTY> pty)
: pty(pty)
{
inode_type = INODE_TYPE_TTY;
this->dev = (dev_t) this;
this->ino = (ino_t) this;
this->stat_uid = owner;
this->stat_gid = group;
this->type = S_IFCHR;
this->stat_mode = (mode & S_SETABLE) | this->type;
}
MasterNode::~MasterNode()
{
// TODO: Destrution of master should probably SIGHUP everything that has the
// pty as its controlling terminal.
}
ssize_t MasterNode::read(ioctx_t* ctx, uint8_t* buf, size_t count)
{
return pty->master_read(ctx, buf, count);
}
ssize_t MasterNode::write(ioctx_t* ctx, const uint8_t* buf, size_t count)
{
return pty->master_write(ctx, buf, count);
}
int MasterNode::poll(ioctx_t* ctx, PollNode* node)
{
return pty->master_poll(ctx, node);
}
int MasterNode::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
{
return pty->master_ioctl(ctx, cmd, arg);
}
int sys_mkptyline(int* master_fd_user, int* slave_fd_user, int flags)
{
int fdflags = 0;
if ( flags & O_CLOEXEC ) fdflags |= FD_CLOEXEC;
if ( flags & O_CLOFORK ) fdflags |= FD_CLOFORK;
flags &= ~(O_CLOEXEC | O_CLOFORK);
if ( flags & ~(O_NONBLOCK) )
return errno = EINVAL, -1;
Process* process = CurrentProcess();
uid_t uid = process->uid;
uid_t gid = process->gid;
mode_t mode = 0600;
Ref<PTY> slave_inode(new PTY(uid, gid, mode));
if ( !slave_inode )
return -1;
Ref<MasterNode> master_inode(new MasterNode(uid, gid, mode, slave_inode));
if ( !master_inode )
return -1;
Ref<Vnode> master_vnode(new Vnode(master_inode, Ref<Vnode>(NULL), 0, 0));
Ref<Vnode> slave_vnode(new Vnode(slave_inode, Ref<Vnode>(NULL), 0, 0));
master_inode.Reset();
slave_inode.Reset();
if ( !master_vnode || !slave_vnode )
return -1;
Ref<Descriptor> master_desc(new Descriptor(master_vnode, O_READ | O_WRITE | flags));
Ref<Descriptor> slave_desc(new Descriptor(slave_vnode, O_READ | O_WRITE | flags));
master_vnode.Reset();
slave_vnode.Reset();
if ( !master_desc || !slave_desc )
return -1;
Ref<DescriptorTable> dtable = process->GetDTable();
int master_fd = dtable->Allocate(master_desc, fdflags);
int slave_fd = dtable->Allocate(slave_desc, fdflags);
master_desc.Reset();
slave_desc.Reset();
if ( master_fd < 0 || slave_fd < 0 )
{
if ( 0 < master_fd )
dtable->Free(master_fd);
if ( 0 < master_fd )
dtable->Free(slave_fd);
return -1;
}
dtable.Reset();
if ( !CopyToUser(master_fd_user, &master_fd, sizeof(int)) ||
!CopyToUser(slave_fd_user, &slave_fd, sizeof(int)) )
return -1;
return 0;
}
} // namespace Sortix

View file

@ -187,7 +187,7 @@ void* syscall_list[SYSCALL_MAX_NUM + 1] =
[SYSCALL_UNMOUNTAT] = (void*) sys_unmountat,
[SYSCALL_FSM_MOUNTAT] = (void*) sys_fsm_mountat,
[SYSCALL_CLOSEFROM] = (void*) sys_closefrom,
[SYSCALL_RESERVED1] = (void*) sys_bad_syscall,
[SYSCALL_MKPTYLINE] = (void*) sys_mkptyline,
[SYSCALL_PSCTL] = (void*) sys_psctl,
[SYSCALL_TCDRAIN] = (void*) sys_tcdrain,
[SYSCALL_TCFLOW] = (void*) sys_tcflow,

View file

@ -201,30 +201,9 @@ int TTY::gettermmode(ioctx_t* ctx, unsigned int* mode)
return 0;
}
int TTY::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
int TTY::tcgetwincurpos(ioctx_t* /*ctx*/, struct wincurpos* /*wcp*/)
{
ScopedLock lock(&termlock);
struct wincurpos retwcp;
memset(&retwcp, 0, sizeof(retwcp));
size_t cursor_column, cursor_row;
Log::GetCursor(&cursor_column, &cursor_row);
retwcp.wcp_col = cursor_column;
retwcp.wcp_row = cursor_row;
if ( !ctx->copy_to_dest(wcp, &retwcp, sizeof(retwcp)) )
return -1;
return 0;
}
int TTY::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
{
ScopedLock lock(&termlock);
struct winsize retws;
memset(&retws, 0, sizeof(retws));
retws.ws_col = Log::Width();
retws.ws_row = Log::Height();
if ( !ctx->copy_to_dest(ws, &retws, sizeof(retws)) )
return -1;
return 0;
return errno = ENOTSUP, -1;
}
int TTY::tcsetpgrp(ioctx_t* /*ctx*/, pid_t pgid)
@ -335,9 +314,9 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
{
// TODO: Handle tab specially. (Is that even possible without
// knowing cursor position?).
Log::Print("\b \b");
tty_output("\b \b");
if ( !IsByteUnescaped(delchar) )
Log::Print("\b \b");
tty_output("\b \b");
}
break;
}
@ -364,9 +343,9 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
linebuffer.Backspace();
if ( tio.c_lflag & ECHOE )
{
Log::Print("\b \b");
tty_output("\b \b");
if ( !IsByteUnescaped(delchar) )
Log::Print("\b \b");
tty_output("\b \b");
}
}
return;
@ -383,9 +362,9 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
continue;
if ( tio.c_lflag & ECHOE )
{
Log::Print("\b \b");
tty_output("\b \b");
if ( !IsByteUnescaped(delchar) )
Log::Print("\b \b");
tty_output("\b \b");
}
}
return;
@ -398,7 +377,7 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
ProcessUnicode(KBKEY_ENCODE(KBKEY_ENTER));
ProcessByte('\n');
ProcessUnicode(KBKEY_ENCODE(-KBKEY_ENTER));
Log::PrintF("\e[H\e[2J");
tty_output("\e[H\e[2J");
return;
}
@ -419,9 +398,12 @@ void TTY::ProcessByte(unsigned char byte, uint32_t control_unicode)
if ( tio.c_lflag & ECHO )
{
if ( IsByteUnescaped(byte) )
Log::PrintData(&byte, 1);
tty_output(&byte, 1);
else
Log::PrintF("^%c", CONTROL(byte));
{
unsigned char cs[2] = { '^', (unsigned char) CONTROL(byte) };
tty_output(cs, sizeof(cs));
}
}
if ( !(tio.c_lflag & ICANON) || byte == '\n' )
@ -523,7 +505,7 @@ ssize_t TTY::write(ioctx_t* ctx, const uint8_t* io_buffer, size_t count)
return errno = EINTR, -1;
// TODO: Add support for ioctx to the kernel log.
const size_t BUFFER_SIZE = 64UL;
char buffer[BUFFER_SIZE];
unsigned char buffer[BUFFER_SIZE];
size_t sofar = 0;
while ( sofar < count )
{
@ -532,7 +514,7 @@ ssize_t TTY::write(ioctx_t* ctx, const uint8_t* io_buffer, size_t count)
amount = BUFFER_SIZE;
if ( !ctx->copy_from_src(buffer, io_buffer + sofar, amount) )
return -1;
Log::PrintData(buffer, amount);
tty_output(buffer, amount);
sofar += amount;
if ( sofar < count )
{

View file

@ -20,6 +20,7 @@
#ifndef SORTIX_TTY_H
#define SORTIX_TTY_H
#include <string.h>
#include <wchar.h>
#include <sortix/termios.h>
@ -45,7 +46,6 @@ public:
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
virtual int tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp);
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
virtual pid_t tcgetpgrp(ioctx_t* ctx);
virtual int settermmode(ioctx_t* ctx, unsigned termmode);
@ -59,6 +59,13 @@ public:
virtual int tcsendbreak(ioctx_t* ctx, int duration);
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
protected:
void tty_output(const char* str)
{
tty_output((const unsigned char*) str, strlen(str));
}
virtual void tty_output(const unsigned char* buffer, size_t length) = 0;
protected:
void ProcessUnicode(uint32_t unicode);
void ProcessByte(unsigned char byte, uint32_t control_unicode = 0);

View file

@ -332,9 +332,9 @@ int Vnode::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
return inode->tcgetwincurpos(ctx, wcp);
}
int Vnode::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
int Vnode::ioctl(ioctx_t* ctx, int cmd, uintptr_t arg)
{
return inode->tcgetwinsize(ctx, ws);
return inode->ioctl(ctx, cmd, arg);
}
int Vnode::tcsetpgrp(ioctx_t* ctx, pid_t pgid)

View file

@ -602,6 +602,7 @@ sys/uio/writev.o \
sys/utsname/uname.o \
sys/wait/wait.o \
sys/wait/waitpid.o \
termios/mkptyline.o \
termios/tcdrain.o \
termios/tcflow.o \
termios/tcflush.o \

View file

@ -69,6 +69,7 @@ int tcsetattr(int, int, const struct termios*);
/* Functions that are Sortix extensions. */
#if __USE_SORTIX
int mkptyline(int*, int*, int);
ssize_t tcgetblob(int, const char*, void*, size_t);
ssize_t tcsetblob(int, const char*, const void*, size_t);
int tcgetwincurpos(int, struct wincurpos*);

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2015 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.
*
* termios/mkptyline.cpp
* Creates an unnamed pseudoterminal.
*/
#include <sys/syscall.h>
#include <termios.h>
DEFN_SYSCALL3(int, sys_mkptyline, SYSCALL_MKPTYLINE, int*, int*, int);
extern "C" int mkptyline(int* master_fd, int* slave_fd, int flags)
{
return sys_mkptyline(master_fd, slave_fd, flags);
}