Add termios(2).

This commit is contained in:
Jonas 'Sortie' Termansen 2016-01-23 20:56:07 +01:00
parent 8f233b4a10
commit bff1265d62
39 changed files with 1685 additions and 298 deletions

View File

@ -25,6 +25,7 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/termmode.h>
#include <sys/types.h>
#include <sys/wait.h>
@ -145,7 +146,17 @@ int child()
setenv("INIT_PID", init_pid_str, 1);
setpgid(0, 0);
tcsetpgrp(0, getpid());
sigset_t oldset, sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGTTOU);
sigprocmask(SIG_BLOCK, &sigs, &oldset);
tcsetpgrp(0, getpgid(0));
sigprocmask(SIG_SETMASK, &oldset, NULL);
unsigned int termmode = 0;
gettermmode(0, &termmode);
settermmode(0, termmode & ~TERMMODE_DISABLE);
const char* default_shell = "sh";
const char* default_home = "/root";

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015, 2016.
This file is part of Sortix.
@ -110,7 +110,7 @@ void PrintChar(char c)
{
if ( c == '\n' )
Newline();
else if ( c == '\b' )
else if ( c == '\b' || c == 127 )
{
if ( column )
column--;
@ -290,11 +290,11 @@ void ReadCommand(char* buffer, size_t buffer_length)
continue;
// Handle backspace.
if ( c == '\b' )
if ( c == '\b' || c == 127 )
{
if ( !written )
continue;
PrintChar(c);
PrintChar('\b');
written--;
continue;
}

View File

@ -828,4 +828,39 @@ Ref<Descriptor> Descriptor::fsm_mount(ioctx_t* ctx,
return result;
}
int Descriptor::tcdrain(ioctx_t* ctx)
{
return vnode->tcdrain(ctx);
}
int Descriptor::tcflow(ioctx_t* ctx, int action)
{
return vnode->tcflow(ctx, action);
}
int Descriptor::tcflush(ioctx_t* ctx, int queue_selector)
{
return vnode->tcflush(ctx, queue_selector);
}
int Descriptor::tcgetattr(ioctx_t* ctx, struct termios* tio)
{
return vnode->tcgetattr(ctx, tio);
}
pid_t Descriptor::tcgetsid(ioctx_t* ctx)
{
return vnode->tcgetsid(ctx);
}
int Descriptor::tcsendbreak(ioctx_t* ctx, int duration)
{
return vnode->tcsendbreak(ctx, duration);
}
int Descriptor::tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio)
{
return vnode->tcsetattr(ctx, actions, tio);
}
} // namespace Sortix

View File

@ -36,8 +36,8 @@
#include <sortix/dirent.h>
#include <sortix/fcntl.h>
#include <sortix/stat.h>
#include <sortix/termios.h>
#include <sortix/timespec.h>
#include <sortix/winsize.h>
#include <fsmarshall-msg.h>
@ -255,6 +255,13 @@ public:
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 unmounted(ioctx_t* ctx);
virtual int tcdrain(ioctx_t* ctx);
virtual int tcflow(ioctx_t* ctx, int action);
virtual int tcflush(ioctx_t* ctx, int queue_selector);
virtual int tcgetattr(ioctx_t* ctx, struct termios* tio);
virtual pid_t tcgetsid(ioctx_t* ctx);
virtual int tcsendbreak(ioctx_t* ctx, int duration);
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
private:
bool SendMessage(Channel* channel, size_t type, void* ptr, size_t size,
@ -1472,6 +1479,120 @@ int Unode::unmounted(ioctx_t* /*ctx*/)
return 0;
}
int Unode::tcdrain(ioctx_t* ctx)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcdrain msg;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCDRAIN, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::tcflow(ioctx_t* ctx, int action)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcflow msg;
msg.ino = ino;
msg.action = action;
if ( SendMessage(channel, FSM_REQ_TCFLOW, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::tcflush(ioctx_t* ctx, int queue_selector)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcflush msg;
msg.ino = ino;
msg.queue_selector = queue_selector;
if ( SendMessage(channel, FSM_REQ_TCFLUSH, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::tcgetattr(ioctx_t* ctx, struct termios* io_tio)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcgetattr msg;
struct fsm_resp_tcgetattr resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCGETATTR, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_TCGETATTR, &msg, sizeof(msg)) &&
ctx->copy_to_dest(io_tio, &resp.tio, sizeof(resp.tio)) )
ret = 0;
channel->KernelClose();
return ret;
}
pid_t Unode::tcgetsid(ioctx_t* ctx)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
pid_t ret = -1;
struct fsm_req_tcgetsid msg;
struct fsm_resp_tcgetsid resp;
msg.ino = ino;
if ( SendMessage(channel, FSM_REQ_TCGETSID, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_TCGETSID, &msg, sizeof(msg)) )
ret = resp.sid;
channel->KernelClose();
return ret;
}
int Unode::tcsendbreak(ioctx_t* ctx, int duration)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
struct fsm_req_tcsendbreak msg;
msg.ino = ino;
msg.duration = duration;
if ( SendMessage(channel, FSM_REQ_TCSENDBREAK, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
int Unode::tcsetattr(ioctx_t* ctx, int actions, const struct termios* user_tio)
{
struct fsm_req_tcsetattr msg;
if ( !ctx->copy_from_src(&msg.tio, user_tio, sizeof(msg.tio)) )
return -1;
Channel* channel = server->Connect(ctx);
if ( !channel )
return -1;
int ret = -1;
msg.ino = ino;
msg.actions = actions;
if ( SendMessage(channel, FSM_REQ_TCSETATTR, &msg, sizeof(msg)) &&
RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
ret = 0;
channel->KernelClose();
return ret;
}
bool Bootstrap(Ref<Inode>* out_root,
Ref<Inode>* out_server,
const struct stat* rootst)

View File

@ -0,0 +1,41 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2016.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
sortix/ioctl.h
Miscellaneous device control interface.
*******************************************************************************/
#ifndef INCLUDE_SORTIX_IOCTL_H
#define INCLUDE_SORTIX_IOCTL_H
#define __IOCTL_TYPE_EXP 3 /* 2^3 kinds of argument types supported.*/
#define __IOCTL_TYPE_MASK ((1 << __IOCTL_TYPE_EXP) - 1)
#define __IOCTL_TYPE_VOID 0
#define __IOCTL_TYPE_INT 1
#define __IOCTL_TYPE_LONG 2
#define __IOCTL_TYPE_PTR 3
/* 4-7 is unused in case of future expansion. */
#define __IOCTL(index, type) ((index) << __IOCTL_TYPE_EXP | (type))
#define __IOCTL_INDEX(value) ((value) >> __IOCTL_TYPE_EXP)
#define __IOCTL_TYPE(value) ((value) & __IOCTL_TYPE_MASK)
#define TIOCGWINSZ __IOCTL(1, __IOCTL_TYPE_PTR)
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014, 2015.
This file is part of Sortix.
@ -36,6 +36,7 @@
struct stat;
struct statvfs;
struct termios;
struct wincurpos;
struct winsize;
struct kernel_dirent;
@ -109,6 +110,13 @@ public:
int fsm_fsbind(ioctx_t* ctx, Ref<Descriptor> target, int flags);
Ref<Descriptor> fsm_mount(ioctx_t* ctx, const char* filename,
const struct stat* rootst, int flags);
int tcdrain(ioctx_t* ctx);
int tcflow(ioctx_t* ctx, int action);
int tcflush(ioctx_t* ctx, int queue_selector);
int tcgetattr(ioctx_t* ctx, struct termios* tio);
pid_t tcgetsid(ioctx_t* ctx);
int tcsendbreak(ioctx_t* ctx, int duration);
int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
private:
Ref<Descriptor> open_elem(ioctx_t* ctx, const char* filename, int flags,

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014, 2015.
This file is part of Sortix.
@ -36,6 +36,7 @@
struct stat;
struct statvfs;
struct termios;
struct wincurpos;
struct winsize;
struct kernel_dirent;
@ -113,6 +114,13 @@ public:
virtual ssize_t tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count) = 0;
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count) = 0;
virtual int unmounted(ioctx_t* ctx) = 0;
virtual int tcdrain(ioctx_t* ctx) = 0;
virtual int tcflow(ioctx_t* ctx, int action) = 0;
virtual int tcflush(ioctx_t* ctx, int queue_selector) = 0;
virtual int tcgetattr(ioctx_t* ctx, struct termios* tio) = 0;
virtual pid_t tcgetsid(ioctx_t* ctx) = 0;
virtual int tcsendbreak(ioctx_t* ctx, int duration) = 0;
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio) = 0;
};
@ -201,6 +209,13 @@ public:
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 unmounted(ioctx_t* ctx);
virtual int tcdrain(ioctx_t* ctx);
virtual int tcflow(ioctx_t* ctx, int action);
virtual int tcflush(ioctx_t* ctx, int queue_selector);
virtual int tcgetattr(ioctx_t* ctx, struct termios* tio);
virtual pid_t tcgetsid(ioctx_t* ctx);
virtual int tcsendbreak(ioctx_t* ctx, int duration);
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
};

View File

@ -47,6 +47,7 @@
#include <sortix/termios.h>
#include <sortix/timespec.h>
#include <sortix/tmns.h>
#include <sortix/winsize.h>
namespace Sortix {
@ -103,7 +104,7 @@ int sys_getsockopt(int, int, int, void*, size_t*);
int sys_gettermmode(int, unsigned*);
uid_t sys_getuid(void);
mode_t sys_getumask(void);
int sys_ioctl(int, int, void*);
int sys_ioctl(int, int, uintptr_t);
int sys_isatty(int);
ssize_t sys_kernelinfo(const char*, char*, size_t);
int sys_kill(pid_t, int);
@ -154,10 +155,17 @@ int sys_sigpending(sigset_t*);
int sys_sigprocmask(int, const sigset_t*, sigset_t*);
int sys_sigsuspend(const sigset_t*);
int sys_symlinkat(const char*, int, const char*);
int sys_tcdrain(int);
int sys_tcflow(int, int);
int sys_tcflush(int, int);
int sys_tcgetattr(int, struct termios*);
ssize_t sys_tcgetblob(int, const char*, void*, size_t);
int sys_tcgetpgrp(int);
pid_t sys_tcgetsid(int);
int sys_tcgetwincurpos(int, struct wincurpos*);
int sys_tcgetwinsize(int, struct winsize*);
int sys_tcsendbreak(int, int);
int sys_tcsetattr(int, int, const struct termios*);
ssize_t sys_tcsetblob(int, const char*, const void*, size_t);
int sys_tcsetpgrp(int, pid_t);
pid_t sys_tfork(int, struct tfork*);

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014, 2015.
This file is part of Sortix.
@ -35,6 +35,7 @@
struct stat;
struct statvfs;
struct termios;
struct wincurpos;
struct winsize;
struct kernel_dirent;
@ -105,6 +106,13 @@ public:
int unmount(ioctx_t* ctx, const char* filename, int flags);
int fsm_fsbind(ioctx_t* ctx, Ref<Vnode> target, int flags);
Ref<Vnode> fsm_mount(ioctx_t* ctx, const char* filename, const struct stat* rootst, int flags);
int tcdrain(ioctx_t* ctx);
int tcflow(ioctx_t* ctx, int action);
int tcflush(ioctx_t* ctx, int queue_selector);
int tcgetattr(ioctx_t* ctx, struct termios* tio);
pid_t tcgetsid(ioctx_t* ctx);
int tcsendbreak(ioctx_t* ctx, int duration);
int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
public /*TODO: private*/:
Ref<Inode> inode;

View File

@ -180,13 +180,13 @@
#define SYSCALL_CLOSEFROM 152
#define SYSCALL_RESERVED1 153
#define SYSCALL_PSCTL 154
#define SYSCALL_RESERVED2 155
#define SYSCALL_RESERVED3 156
#define SYSCALL_RESERVED4 157
#define SYSCALL_RESERVED5 158
#define SYSCALL_RESERVED6 159
#define SYSCALL_RESERVED7 160
#define SYSCALL_RESERVED8 161
#define SYSCALL_TCDRAIN 155
#define SYSCALL_TCFLOW 156
#define SYSCALL_TCFLUSH 157
#define SYSCALL_TCGETATTR 158
#define SYSCALL_TCGETSID 159
#define SYSCALL_TCSENDBREAK 160
#define SYSCALL_TCSETATTR 161
#define SYSCALL_SCRAM 162
#define SYSCALL_MAX_NUM 163 /* index of highest constant + 1 */

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
Copyright(C) Jonas 'Sortie' Termansen 2015, 2016.
This file is part of Sortix.
@ -18,7 +18,7 @@
Sortix. If not, see <http://www.gnu.org/licenses/>.
sortix/termios.h
Defines values for termios.
Termios types and constants.
*******************************************************************************/
@ -27,34 +27,108 @@
#include <sys/cdefs.h>
#include <sys/__/types.h>
#define VEOF 0
#define VEOL 1
#define VERASE 2
#define VINTR 3
#define VKILL 4
#define VMIN 5
#define VQUIT 6
#define VSTART 7
#define VSTOP 8
#define VSUSP 9
#define VTIME 10
#define VWERASE 11
#define NCCS 24
#ifdef __cplusplus
extern "C" {
#define BRKINT (1U << 0)
#define ICRNL (1U << 1)
#define IGNBRK (1U << 2)
#define IGNCR (1U << 3)
#define IGNPAR (1U << 4)
#define INLCR (1U << 5)
#define INPCK (1U << 6)
#define ISTRIP (1U << 7)
#define IXANY (1U << 8)
#define IXOFF (1U << 9)
#define IXON (1U << 10)
#define PARMRK (1U << 11)
#define OPOST (1U << 0)
#define B0 0
#define B50 50
#define B75 75
#define B110 110
#define B134 134
#define B150 150
#define B200 200
#define B300 300
#define B600 600
#define B1200 1200
#define B1800 1800
#define B2400 2400
#define B4800 4800
#define B9600 9600
#define B19200 19200
#define B38400 38400
#define CS5 (0U << 0)
#define CS6 (1U << 0)
#define CS7 (2U << 0)
#define CS8 (3U << 0)
#define CSIZE (CS5 | CS6 | CS7 | CS8)
#define CSTOPB (1U << 2)
#define CREAD (1U << 3)
#define PARENB (1U << 4)
#define PARODD (1U << 5)
#define HUPCL (1U << 6)
#define CLOCAL (1U << 7)
#define ECHO (1U << 0)
#define ECHOE (1U << 1)
#define ECHOK (1U << 2)
#define ECHONL (1U << 3)
#define ICANON (1U << 4)
#define IEXTEN (1U << 5)
#define ISIG (1U << 6)
#define NOFLSH (1U << 7)
#define TOSTOP (1U << 8)
/* Transitional compatibility as Sortix switches from termmode to termios. */
#if __USE_SORTIX
#define ISORTIX_TERMMODE (1U << 9)
#define ISORTIX_CHARS_DISABLE (1U << 10)
#define ISORTIX_KBKEY (1U << 11)
#define ISORTIX_32BIT (1U << 12)
#define ISORTIX_NONBLOCK (1U << 13)
#endif
#ifndef __size_t_defined
#define __size_t_defined
#define __need_size_t
#include <stddef.h>
#endif
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
struct wincurpos
#define TCIFLUSH (1 << 0)
#define TCOFLUSH (1 << 1)
#define TCIOFLUSH (TCIFLUSH | TCOFLUSH)
#define TCIOFF 0
#define TCION 1
#define TCOOFF 2
#define TCOON 3
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
struct termios
{
size_t wcp_row;
size_t wcp_col;
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
speed_t c_ispeed;
speed_t c_ospeed;
cc_t c_cc[NCCS];
};
struct winsize
{
size_t ws_row;
size_t ws_col;
size_t ws_xpixel;
size_t ws_ypixel;
};
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2015, 2016.
This file is part of Sortix.
@ -25,12 +25,16 @@
#ifndef SORTIX_TERMMODE_H
#define SORTIX_TERMMODE_H
#define TERMMODE_KBKEY (1U<<0U)
#define TERMMODE_UNICODE (1U<<1U)
#define TERMMODE_SIGNAL (1U<<2U)
#define TERMMODE_UTF8 (1U<<3U)
#define TERMMODE_LINEBUFFER (1U<<4U)
#define TERMMODE_ECHO (1U<<5U)
#define TERMMODE_NONBLOCK (1U<<6U)
#define TERMMODE_KBKEY (1U << 0) /* ISORTIX_ENABLE_KBKEY */
#define TERMMODE_UNICODE (1U << 1) /* !ISORTIX_DISABLE_CHARS */
#define TERMMODE_SIGNAL (1U << 2) /* ISIG */
#define TERMMODE_UTF8 (1U << 3) /* !ISORTIX_ENABLE_32BIT */
#define TERMMODE_LINEBUFFER (1U << 4) /* ICANON */
#define TERMMODE_ECHO (1U << 5) /* ECHO */
#define TERMMODE_NONBLOCK (1U << 6) /* ISORTIX_NONBLOCK */
#define TERMMODE_TERMIOS (1U << 7) /* !ISORTIX_TERMMODE */
#define TERMMODE_DISABLE (1U << 8) /* !CREAD */
#define TERMMODE_NORMAL (TERMMODE_UNICODE | TERMMODE_SIGNAL | TERMMODE_UTF8 | \
TERMMODE_LINEBUFFER | TERMMODE_ECHO | TERMMODE_TERMIOS)
#endif

View File

@ -0,0 +1,52 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2015.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
sortix/winsize.h
Defines values for termios.
*******************************************************************************/
#ifndef INCLUDE_SORTIX_WINSIZE_H
#define INCLUDE_SORTIX_WINSIZE_H
#include <sys/cdefs.h>
#include <sys/__/types.h>
#ifndef __size_t_defined
#define __size_t_defined
#define __need_size_t
#include <stddef.h>
#endif
struct wincurpos
{
size_t wcp_row;
size_t wcp_col;
};
struct winsize
{
size_t ws_row;
size_t ws_col;
size_t ws_xpixel;
size_t ws_ypixel;
};
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014, 2015.
This file is part of Sortix.
@ -412,4 +412,39 @@ int AbstractInode::unmounted(ioctx_t* /*ctx*/)
return 0;
}
int AbstractInode::tcdrain(ioctx_t* /*ctx*/)
{
return errno = ENOTTY, -1;
}
int AbstractInode::tcflow(ioctx_t* /*ctx*/, int /*action*/)
{
return errno = ENOTTY, -1;
}
int AbstractInode::tcflush(ioctx_t* /*ctx*/, int /*queue_selector*/)
{
return errno = ENOTTY, -1;
}
int AbstractInode::tcgetattr(ioctx_t* /*ctx*/, struct termios* /*tio*/)
{
return errno = ENOTTY, -1;
}
pid_t AbstractInode::tcgetsid(ioctx_t* /*ctx*/)
{
return errno = ENOTTY, -1;
}
int AbstractInode::tcsendbreak(ioctx_t* /*ctx*/, int /*duration*/)
{
return errno = ENOTTY, -1;
}
int AbstractInode::tcsetattr(ioctx_t* /*ctx*/, int /*actions*/, const struct termios* /*tio*/)
{
return errno = ENOTTY, -1;
}
} // namespace Sortix

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015, 2016.
This file is part of Sortix.
@ -33,6 +33,7 @@
#include <sortix/dirent.h>
#include <sortix/fcntl.h>
#include <sortix/ioctl.h>
#include <sortix/seek.h>
#include <sortix/socket.h>
#include <sortix/stat.h>
@ -370,19 +371,15 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg)
return errno = EINVAL, -1;
}
int sys_ioctl(int fd, int cmd, void* /*ptr*/)
int sys_ioctl(int fd, int cmd, uintptr_t arg)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
int ret = -1;
switch ( cmd )
{
case TIOCGWINSZ:
return sys_tcgetwinsize(fd, (struct winsize*) arg);
default:
errno = EINVAL;
break;
return errno = EINVAL, -1;
}
return ret;
}
ssize_t sys_readdirents(int fd, struct kernel_dirent* dirent, size_t size)
@ -1155,4 +1152,67 @@ int sys_fsm_mountat(int dirfd, const char* path, const struct stat* rootst, int
return ret;
}
int sys_tcdrain(int fd)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->tcdrain(&ctx);
}
int sys_tcflow(int fd, int action)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->tcflow(&ctx, action);
}
int sys_tcflush(int fd, int queue_selector)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->tcflush(&ctx, queue_selector);
}
int sys_tcgetattr(int fd, struct termios* tio)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->tcgetattr(&ctx, tio);
}
pid_t sys_tcgetsid(int fd)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->tcgetsid(&ctx);
}
int sys_tcsendbreak(int fd, int duration)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->tcsendbreak(&ctx, duration);
}
int sys_tcsetattr(int fd, int actions, const struct termios* tio)
{
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->tcsetattr(&ctx, actions, tio);
}
} // namespace Sortix

View File

@ -138,4 +138,12 @@ bool LineBuffer::CanBackspace() const
return bufferused - bufferfrozen;
}
void LineBuffer::Flush()
{
bufferoffset = 0;
buffercommitted = 0;
bufferfrozen = 0;
bufferused = 0;
}
} // namespace Sortix

View File

@ -46,6 +46,7 @@ public:
void Freeze();
bool CanPop() const;
bool CanBackspace() const;
void Flush();
private:
uint32_t* buffer;

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014, 2015, 2016.
This file is part of Sortix.
@ -25,9 +25,10 @@
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <sortix/fcntl.h>
@ -37,6 +38,7 @@
#include <sortix/stat.h>
#include <sortix/termios.h>
#include <sortix/termmode.h>
#include <sortix/winsize.h>
#include <sortix/kernel/inode.h>
#include <sortix/kernel/interlock.h>
@ -49,18 +51,86 @@
#include <sortix/kernel/ptable.h>
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/scheduler.h>
#include <sortix/kernel/thread.h>
#include "logterminal.h"
#define CONTROL(x) (((x) - 64) & 127)
#define M_CONTROL(x) (128 + CONTROL(x))
namespace Sortix {
const unsigned SUPPORTED_MODES = TERMMODE_KBKEY
| TERMMODE_UNICODE
| TERMMODE_SIGNAL
| TERMMODE_UTF8
| TERMMODE_LINEBUFFER
| TERMMODE_ECHO
| TERMMODE_NONBLOCK;
static const unsigned int SUPPORTED_TERMMODES = TERMMODE_KBKEY
| TERMMODE_UNICODE
| TERMMODE_SIGNAL
| TERMMODE_UTF8
| TERMMODE_LINEBUFFER
| TERMMODE_ECHO
| TERMMODE_NONBLOCK
| TERMMODE_TERMIOS
| TERMMODE_DISABLE;
static const int MODIFIER_ALT = 1 << 0;
static const int MODIFIER_LSHIFT = 1 << 1;
static const int MODIFIER_RSHIFT = 1 << 2;
static const int MODIFIER_LCONTROL = 1 << 3;
static const int MODIFIER_RCONTROL = 1 << 4;
static const int SEQUENCE_1IFMOD = 1 << 0;
static const int SEQUENCE_OSHORT = 1 << 1;
struct kbkey_sequence
{
const char* sequence;
int kbkey;
int flags;
};
static const struct kbkey_sequence kbkey_sequences[] =
{
{ "\e[A", KBKEY_UP, SEQUENCE_1IFMOD },
{ "\e[B", KBKEY_DOWN, SEQUENCE_1IFMOD},
{ "\e[C", KBKEY_RIGHT, SEQUENCE_1IFMOD },
{ "\e[D", KBKEY_LEFT, SEQUENCE_1IFMOD },
{ "\e[F", KBKEY_END, SEQUENCE_1IFMOD },
{ "\e[H", KBKEY_HOME, SEQUENCE_1IFMOD },
{ "\e[2~", KBKEY_INSERT, 0 },
{ "\e[3~", KBKEY_DELETE, 0 },
{ "\e[5~", KBKEY_PGUP, 0 },
{ "\e[6~", KBKEY_PGDOWN, 0 },
{ "\e[1P", KBKEY_F1, SEQUENCE_OSHORT },
{ "\e[1Q", KBKEY_F2, SEQUENCE_OSHORT },
{ "\e[1R", KBKEY_F3, SEQUENCE_OSHORT },
{ "\e[1S", KBKEY_F4, SEQUENCE_OSHORT },
{ "\e[15~", KBKEY_F5, 0 },
{ "\e[17~", KBKEY_F6, 0 },
{ "\e[18~", KBKEY_F7, 0 },
{ "\e[19~", KBKEY_F8, 0 },
{ "\e[20~", KBKEY_F9, 0 },
{ "\e[21~", KBKEY_F10, 0 },
{ "\e[23~", KBKEY_F11, 0 },
{ "\e[24~", KBKEY_F12, 0 },
};
static inline bool IsByteUnescaped(unsigned char byte)
{
return (32 <= byte && byte != 127) ||
byte == '\t' || byte == '\n' || byte == '\r';
}
static inline bool IsUTF8Continuation(unsigned char byte)
{
return (byte & 0b11000000) == 0b10000000;
}
static inline const struct kbkey_sequence* LookupKeystrokeSequence(int kbkey)
{
size_t count = sizeof(kbkey_sequences) / sizeof(kbkey_sequences[0]);
for ( size_t i = 0; i < count; i++ )
if ( kbkey_sequences[i].kbkey == kbkey )
return &kbkey_sequences[i];
return NULL;
}
LogTerminal::LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
Keyboard* keyboard, KeyboardLayoutExecutor* kblayout)
@ -74,16 +144,28 @@ LogTerminal::LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
this->stat_gid = group;
this->keyboard = keyboard;
this->kblayout = kblayout;
this->partiallywritten = 0;
this->control = false;
this->termmode = TERMMODE_UNICODE
| TERMMODE_SIGNAL
| TERMMODE_UTF8
| TERMMODE_LINEBUFFER
| TERMMODE_ECHO;
this->modifiers = 0;
memset(&tio, 0, sizeof(tio));
tio.c_iflag = BRKINT | ICRNL | IXANY | IXON;
tio.c_oflag = OPOST;
tio.c_cflag = CS8 /*| CREAD*/ | HUPCL; // CREAD unset for boot security.
tio.c_lflag = ECHO | ECHOE | ECHOK | ICANON | IEXTEN | ISIG;
tio.c_cc[VEOF] = CONTROL('D');
tio.c_cc[VEOL] = M_CONTROL('?');
tio.c_cc[VERASE] = CONTROL('?');
tio.c_cc[VINTR] = CONTROL('C');
tio.c_cc[VKILL] = CONTROL('U');
tio.c_cc[VMIN] = 1;
tio.c_cc[VQUIT] = CONTROL('\\');
tio.c_cc[VSTART] = CONTROL('Q');
tio.c_cc[VSTOP] = CONTROL('S');
tio.c_cc[VSUSP] = CONTROL('Z');
tio.c_cc[VTIME] = 0;
tio.c_cc[VWERASE] = CONTROL('W');
tio.c_ispeed = B38400;
tio.c_ospeed = B38400;
this->termlock = KTHREAD_MUTEX_INITIALIZER;
this->datacond = KTHREAD_COND_INITIALIZER;
this->numwaiting = 0;
this->numeofs = 0;
this->foreground_pgid = 0;
keyboard->SetOwner(this, NULL);
@ -95,25 +177,86 @@ LogTerminal::~LogTerminal()
delete kblayout;
}
int LogTerminal::settermmode(ioctx_t* /*ctx*/, unsigned newtermmode)
int LogTerminal::settermmode(ioctx_t* /*ctx*/, unsigned int termmode)
{
if ( newtermmode & ~SUPPORTED_MODES ) { errno = EINVAL; return -1; }
ScopedLock lock(&termlock);
unsigned oldtermmode = termmode;
bool oldutf8 = oldtermmode & TERMMODE_UTF8;
bool newutf8 = newtermmode & TERMMODE_UTF8;
if ( oldutf8 != newutf8 )
partiallywritten = 0;
termmode = newtermmode;
if ( !(newtermmode & TERMMODE_LINEBUFFER) )
if ( !RequireForeground(SIGTTOU) )
return errno = EINTR, -1;
if ( termmode & ~SUPPORTED_TERMMODES )
return errno = EINVAL, -1;
tcflag_t old_cflag = tio.c_cflag;
tcflag_t new_cflag = old_cflag;
tcflag_t old_lflag = tio.c_lflag;
tcflag_t new_lflag = old_lflag;
if ( termmode & TERMMODE_KBKEY )
new_lflag |= ISORTIX_KBKEY;
else
new_lflag &= ~ISORTIX_KBKEY;
if ( !(termmode & TERMMODE_UNICODE) )
new_lflag |= ISORTIX_CHARS_DISABLE;
else
new_lflag &= ~ISORTIX_CHARS_DISABLE;
if ( termmode & TERMMODE_SIGNAL )
new_lflag |= ISIG;
else
new_lflag &= ~ISIG;
if ( !(termmode & TERMMODE_UTF8) )
new_lflag |= ISORTIX_32BIT;
else
new_lflag &= ~ISORTIX_32BIT;
if ( termmode & TERMMODE_LINEBUFFER )
new_lflag |= ICANON;
else
new_lflag &= ~ICANON;
if ( termmode & TERMMODE_ECHO )
new_lflag |= ECHO | ECHOE;
else
new_lflag &= ~(ECHO | ECHOE);
if ( termmode & TERMMODE_NONBLOCK )
new_lflag |= ISORTIX_NONBLOCK;
else
new_lflag &= ~ISORTIX_NONBLOCK;
if ( !(termmode & TERMMODE_TERMIOS) )
new_lflag |= ISORTIX_TERMMODE;
else
new_lflag &= ~ISORTIX_TERMMODE;
if ( !(termmode & TERMMODE_DISABLE) )
new_cflag |= CREAD;
else
new_cflag &= ~CREAD;
bool oldnoutf8 = old_lflag & ISORTIX_32BIT;
bool newnoutf8 = new_lflag & ISORTIX_32BIT;
if ( oldnoutf8 != newnoutf8 )
memset(&read_ps, 0, sizeof(read_ps));
tio.c_cflag = new_cflag;
tio.c_lflag = new_lflag;
if ( !(tio.c_lflag & ICANON) )
CommitLineBuffer();
partiallywritten = 0;
return 0;
}
int LogTerminal::gettermmode(ioctx_t* ctx, unsigned* mode)
int LogTerminal::gettermmode(ioctx_t* ctx, unsigned int* mode)
{
ScopedLock lock(&termlock);
unsigned int termmode = 0;
if ( tio.c_lflag & ISORTIX_KBKEY )
termmode |= TERMMODE_KBKEY;
if ( !(tio.c_lflag & ISORTIX_CHARS_DISABLE) )
termmode |= TERMMODE_UNICODE;
if ( tio.c_lflag & ISIG )
termmode |= TERMMODE_SIGNAL;
if ( !(tio.c_lflag & ISORTIX_32BIT) )
termmode |= TERMMODE_UTF8;
if ( tio.c_lflag & ICANON )
termmode |= TERMMODE_LINEBUFFER;
if ( tio.c_lflag & (ECHO | ECHOE) )
termmode |= TERMMODE_ECHO;
if ( tio.c_lflag & ISORTIX_NONBLOCK )
termmode |= TERMMODE_NONBLOCK;
if ( !(tio.c_lflag & ISORTIX_TERMMODE) )
termmode |= TERMMODE_TERMIOS;
if ( !(tio.c_cflag & CREAD) )
termmode |= TERMMODE_DISABLE;
if ( !ctx->copy_to_dest(mode, &termmode, sizeof(termmode)) )
return -1;
return 0;
@ -121,6 +264,7 @@ int LogTerminal::gettermmode(ioctx_t* ctx, unsigned* mode)
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;
@ -134,6 +278,7 @@ int LogTerminal::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
int LogTerminal::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
{
ScopedLock lock(&termlock);
struct winsize retws;
memset(&retws, 0, sizeof(retws));
retws.ws_col = Log::Width();
@ -146,12 +291,16 @@ int LogTerminal::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
int LogTerminal::tcsetpgrp(ioctx_t* /*ctx*/, pid_t pgid)
{
ScopedLock lock(&termlock);
Process* process = CurrentProcess()->GetPTable()->Get(pgid);
if ( !pgid || !process )
if ( !RequireForeground(SIGTTOU) )
return errno = EINTR, -1;
if ( pgid <= 0 )
return errno = ESRCH, -1;
kthread_mutex_lock(&process->groupchildlock);
Process* process = CurrentProcess()->GetPTable()->Get(pgid);
if ( !process )
return errno = ESRCH, -1;
kthread_mutex_lock(&process->groupparentlock);
bool is_process_group = process->group == process;
kthread_mutex_unlock(&process->groupchildlock);
kthread_mutex_unlock(&process->groupparentlock);
if ( !is_process_group )
return errno = EINVAL, -1;
foreground_pgid = pgid;
@ -166,25 +315,160 @@ pid_t LogTerminal::tcgetpgrp(ioctx_t* /*ctx*/)
int LogTerminal::sync(ioctx_t* /*ctx*/)
{
ScopedLock lock(&termlock);
return Log::Sync() ? 0 : -1;
}
void LogTerminal::OnKeystroke(Keyboard* kb, void* /*user*/)
{
ScopedLock lock(&termlock);
while ( kb->HasPending() )
ProcessKeystroke(kb->Read());
{
int kbkey = kb->Read();
if ( kbkey == KBKEY_LALT )
modifiers |= MODIFIER_ALT;
else if ( kbkey == -KBKEY_LALT )
modifiers &= ~MODIFIER_ALT;
else if ( kbkey == KBKEY_LSHIFT )
modifiers |= MODIFIER_LSHIFT;
else if ( kbkey == -KBKEY_LSHIFT )
modifiers &= ~MODIFIER_LSHIFT;
else if ( kbkey == KBKEY_RSHIFT )
modifiers |= MODIFIER_RSHIFT;
else if ( kbkey == -KBKEY_RSHIFT )
modifiers &= ~MODIFIER_RSHIFT;
else if ( kbkey == KBKEY_LCTRL )
modifiers |= MODIFIER_LCONTROL;
else if ( kbkey == -KBKEY_LCTRL )
modifiers &= ~MODIFIER_LCONTROL;
else if ( kbkey == KBKEY_RCTRL )
modifiers |= MODIFIER_RCONTROL;
else if ( kbkey == -KBKEY_RCTRL )
modifiers &= ~MODIFIER_RCONTROL;
uint32_t unicode = kblayout->Translate(kbkey);
if ( !(tio.c_cflag & CREAD) )
continue;
ProcessKeystroke(kbkey);
if ( !unicode )
continue;
if ( unicode == '\n' )
unicode = '\r';
bool control = modifiers & (MODIFIER_LCONTROL | MODIFIER_RCONTROL);
if ( !(tio.c_cflag & ISORTIX_TERMMODE) && unicode == '\b' )
unicode = 127;
if ( control && unicode == L' ' )
ProcessByte(0, unicode);
else if ( control && (L'`' <= unicode && unicode <= L'}') )
ProcessByte(unicode - L'`', unicode);
else if ( control && (L'@' <= unicode && unicode <= L'_') )
ProcessByte(unicode - L'@', unicode);
else if ( control && unicode == L'?' )
ProcessByte(127, unicode);
else
ProcessUnicode(unicode);
}
}
void LogTerminal::ProcessKeystroke(int kbkey)
{
if ( !kbkey )
if ( tio.c_lflag & ISORTIX_32BIT )
{
if ( tio.c_lflag & ISORTIX_KBKEY )
{
uint32_t unikbkey = KBKEY_ENCODE(kbkey);
if ( !linebuffer.Push(unikbkey) )
return;
if ( !(tio.c_lflag & ICANON) )
CommitLineBuffer();
}
return;
}
if ( kbkey < 0 )
return;
ScopedLock lock(&termlock);
const struct kbkey_sequence* seq = LookupKeystrokeSequence(kbkey);
if ( !seq )
return;
if ( kbkey == KBKEY_LCTRL ) { control = true; }
if ( kbkey == -KBKEY_LCTRL ) { control = false; }
if ( termmode & TERMMODE_SIGNAL && control && kbkey == KBKEY_C )
const char* str = seq->sequence;
size_t len = strlen(str);
int mods = 0;
if ( modifiers & (MODIFIER_LSHIFT | MODIFIER_RSHIFT) )
mods |= 1;
if ( modifiers & MODIFIER_ALT )
mods |= 2;
if ( modifiers & (MODIFIER_LCONTROL | MODIFIER_RCONTROL) )
mods |= 4;
if ( (seq->flags & SEQUENCE_OSHORT) && mods == 0 )
{
ProcessByte('\e');
ProcessByte('O');
ProcessByte((unsigned char) str[len-1]);
return;
}
for ( size_t i = 0; i < len - 1; i++ )
ProcessByte((unsigned char) str[i]);
if ( seq->flags & SEQUENCE_1IFMOD && mods != 0 )
ProcessByte('1');
if ( mods )
{
ProcessByte(';');
ProcessByte('1' + mods);
}
ProcessByte(str[len-1]);
}
void LogTerminal::ProcessString(const char* string)
{
for ( size_t i = 0; string[i]; i++ )
ProcessByte((unsigned char) string[i]);
}
void LogTerminal::ProcessUnicode(uint32_t unicode)
{
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
char mb[MB_CUR_MAX];
size_t amount = wcrtomb(mb, unicode, &ps);
for ( size_t i = 0; amount != (size_t) -1 && i < amount; i++ )
ProcessByte((unsigned char) mb[i]);
}
bool LogTerminal::CheckHandledByte(tcflag_t lflags,
unsigned char key,
unsigned char byte)
{
return (tio.c_lflag & lflags) == lflags && key && key == byte;
}
void LogTerminal::ProcessByte(unsigned char byte, uint32_t control_unicode)
{
if ( byte == '\r' && tio.c_iflag & IGNCR )
return;
if ( byte == '\r' && tio.c_iflag & ICRNL )
byte = '\n';
else if ( byte == '\n' && tio.c_iflag & INLCR )
byte = '\r';
// TODO: tio.c_cc[VEOL]
// TODO: tio.c_cc[VSTART]
// TODO: tio.c_cc[VSTOP]
// TODO: tio.c_cc[VSUSP]
if ( CheckHandledByte(ISIG, tio.c_cc[VQUIT], byte) )
{
while ( linebuffer.CanBackspace() )
linebuffer.Backspace();
if ( Process* process = CurrentProcess()->GetPTable()->Get(foreground_pgid) )
process->DeliverGroupSignal(SIGQUIT);
return;
}
if ( CheckHandledByte(ISIG, tio.c_cc[VINTR], byte) )
{
while ( linebuffer.CanBackspace() )
linebuffer.Backspace();
@ -192,236 +476,250 @@ void LogTerminal::ProcessKeystroke(int kbkey)
process->DeliverGroupSignal(SIGINT);
return;
}
if ( termmode & TERMMODE_SIGNAL && control && kbkey == KBKEY_D )
if ( CheckHandledByte(ISIG | ICANON, tio.c_cc[VEOF], byte) )
{
if ( !linebuffer.CanPop() )
{
numeofs++;
if ( numwaiting )
kthread_cond_broadcast(&datacond);
kthread_cond_broadcast(&datacond);
poll_channel.Signal(POLLIN | POLLRDNORM);
}
return;
}
if ( termmode & TERMMODE_LINEBUFFER && control && kbkey == KBKEY_W )
if ( CheckHandledByte(ISIG, tio.c_cc[VQUIT], byte) )
{
bool had_non_whitespace = false;
c_w_delete_more:
if ( !linebuffer.CanBackspace() ) { return; }
uint32_t delchar = linebuffer.WouldBackspace();
bool waskbkey = KBKEY_DECODE(delchar);
bool wasuni = !waskbkey;
bool whitespace =
(wasuni && (delchar == ' ' ||
delchar == '\t' ||
delchar == '\n')) ||
(waskbkey && (abs(KBKEY_DECODE(delchar)) == -KBKEY_SPACE ||
abs(KBKEY_DECODE(delchar)) == -KBKEY_TAB ||
abs(KBKEY_DECODE(delchar)) == -KBKEY_ENTER));
if ( wasuni && whitespace && had_non_whitespace )
return;
if ( wasuni && !whitespace )
had_non_whitespace = true;
linebuffer.Backspace();
if ( (!waskbkey || termmode & TERMMODE_KBKEY) &&
(!wasuni || termmode & TERMMODE_UNICODE) &&
termmode & TERMMODE_ECHO &&
wasuni )
Log::Print("\b \b");
goto c_w_delete_more;
while ( linebuffer.CanBackspace() )
linebuffer.Backspace();
if ( Process* process = CurrentProcess()->GetPTable()->Get(foreground_pgid) )
process->DeliverGroupSignal(SIGQUIT);
return;
}
if ( termmode & TERMMODE_LINEBUFFER && control && kbkey == KBKEY_U )
if ( CheckHandledByte(ICANON, tio.c_cc[VERASE], byte) ||
CheckHandledByte(ICANON | ISORTIX_TERMMODE, '\b', byte) )
{
while ( linebuffer.CanBackspace() )
{
uint32_t delchar = linebuffer.Backspace();
bool waskbkey = KBKEY_DECODE(delchar);
bool wasuni = !waskbkey;
if ( (!waskbkey || termmode & TERMMODE_KBKEY) &&
(!wasuni || termmode & TERMMODE_UNICODE) &&
termmode & TERMMODE_ECHO &&
wasuni )
if ( 256 <= delchar )
continue;
if ( IsUTF8Continuation(delchar) )
continue;
if ( tio.c_lflag & ECHOE )
{
// TODO: Handle tab specially. (Is that even possible without
// knowing cursor position?).
Log::Print("\b \b");
if ( !IsByteUnescaped(delchar) )
Log::Print("\b \b");
}
break;
}
return;
}
if ( termmode & TERMMODE_LINEBUFFER && control && kbkey == KBKEY_L )
if ( CheckHandledByte(ICANON, tio.c_cc[VWERASE], byte) )
{
bool had_non_whitespace = false;
while ( linebuffer.CanBackspace() )
{
uint32_t delchar = linebuffer.WouldBackspace();
if ( 256 <= delchar )
continue;
if ( IsUTF8Continuation(delchar) )
continue;
if ( delchar == L' ' || delchar == L'\t' || delchar == L'\n' )
{
if ( had_non_whitespace )
break;
}
else
had_non_whitespace = true;
linebuffer.Backspace();
if ( tio.c_lflag & ECHOE )
{
Log::Print("\b \b");
if ( !IsByteUnescaped(delchar) )
Log::Print("\b \b");
}
}
return;
}
if ( CheckHandledByte(ICANON, tio.c_cc[VKILL], byte) )
{
while ( linebuffer.CanBackspace() )
{
uint32_t delchar = linebuffer.Backspace();
if ( 256 <= delchar )
continue;
if ( IsUTF8Continuation(delchar) )
continue;
if ( tio.c_lflag & ECHOE )
{
Log::Print("\b \b");
if ( !IsByteUnescaped(delchar) )
Log::Print("\b \b");
}
}
return;
}
if ( CheckHandledByte(ICANON | ISORTIX_TERMMODE, CONTROL('L'), byte) )
{
while ( linebuffer.CanBackspace() )
linebuffer.Backspace();
QueueUnicode(KBKEY_ENCODE(KBKEY_ENTER));
QueueUnicode('\n');
QueueUnicode(KBKEY_ENCODE(-KBKEY_ENTER));
ProcessUnicode(KBKEY_ENCODE(KBKEY_ENTER));
ProcessByte('\n');
ProcessUnicode(KBKEY_ENCODE(-KBKEY_ENTER));
Log::PrintF("\e[H\e[2J");
return;
}
uint32_t unikbkey = KBKEY_ENCODE(kbkey);
QueueUnicode(unikbkey);
uint32_t unicode = kblayout->Translate(kbkey);
if ( 0 < kbkey )
QueueUnicode(unicode);
}
void LogTerminal::QueueUnicode(uint32_t unicode)
{
if ( !unicode )
if ( tio.c_lflag & ISORTIX_CHARS_DISABLE )
return;
int kbkey = KBKEY_DECODE(unicode);
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
bool wasenter = kbkey == KBKEY_ENTER || unicode == '\n';
bool kbkeymode = termmode & TERMMODE_KBKEY;
bool unicodemode = termmode & TERMMODE_UNICODE;
bool linemode = termmode & TERMMODE_LINEBUFFER;
bool echomode = termmode & TERMMODE_ECHO;
if ( linemode && abskbkey == KBKEY_BKSPC ) { return; }
while ( linemode && unicode == '\b' )
if ( control_unicode &&
!(tio.c_lflag & (ICANON | ISIG)) &&
tio.c_lflag & ISORTIX_KBKEY )
{
if ( !linebuffer.CanBackspace() ) { return; }
uint32_t delchar = linebuffer.Backspace();
bool waskbkey = KBKEY_DECODE(delchar);
bool wasuni = !waskbkey;
if ( waskbkey && !kbkeymode ) { continue; }
if ( wasuni && !unicodemode ) { continue; }
if ( !echomode ) { return; }
if ( wasuni ) { Log::Print("\b \b"); }
ProcessUnicode(control_unicode);
return;
}
if ( !linebuffer.Push(unicode) )
{
Log::PrintF("Warning: LogTerminal driver dropping keystroke due "
"to insufficient buffer space\n");
if ( !linebuffer.Push(byte) )
return;
}
// TODO: Could it be the right thing to print the unicode character even
// if it is unprintable (it's an encoded keystroke)?
if ( !KBKEY_DECODE(unicode) && echomode )
if ( tio.c_lflag & ECHO )
{
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
char utf8buf[MB_CUR_MAX];
size_t num_bytes = wcrtomb(utf8buf, (wchar_t) unicode, &ps);
if ( num_bytes == 1 && utf8buf[0] == '\b' )
Log::PrintData("\b \b", 3);
if ( IsByteUnescaped(byte) )
Log::PrintData(&byte, 1);
else
Log::PrintData(utf8buf, num_bytes);
Log::PrintF("^%c", CONTROL(byte));
}
bool commit = !linemode || wasenter;
if ( commit )
if ( !(tio.c_lflag & ICANON) || byte == '\n' )
CommitLineBuffer();
}
void LogTerminal::CommitLineBuffer()
{
linebuffer.Commit();
if ( numwaiting )
if ( linebuffer.CanPop() || numeofs )
{
kthread_cond_broadcast(&datacond);
poll_channel.Signal(POLLIN | POLLRDNORM);
poll_channel.Signal(POLLIN | POLLRDNORM);
}
}
ssize_t LogTerminal::read(ioctx_t* ctx, uint8_t* userbuf, size_t count)
{
ScopedLockSignal lock(&termlock);
if ( !lock.IsAcquired() ) { errno = EINTR; return -1; }
if ( !lock.IsAcquired() )
return errno = EINTR, -1;
if ( !RequireForeground(SIGTTIN) )
return errno = EINTR, -1;
size_t sofar = 0;
size_t left = count;
bool blocking = !(termmode & TERMMODE_NONBLOCK);
while ( left && !linebuffer.CanPop() && blocking && !numeofs )
{
if ( ctx->dflags & O_NONBLOCK )
return errno = EWOULDBLOCK, -1;
numwaiting++;
bool abort = !kthread_cond_wait_signal(&datacond, &termlock);
numwaiting--;
if ( abort ) { errno = EINTR; return -1; }
}
if ( left && !linebuffer.CanPop() && !blocking && !numeofs )
{
errno = EWOULDBLOCK;
return -1;
}
if ( numeofs )
{
numeofs--;
return 0;
}
while ( left && linebuffer.CanPop() )
bool nonblocking = tio.c_lflag & ISORTIX_NONBLOCK ||
ctx->dflags & O_NONBLOCK;
while ( left )
{
while ( !(linebuffer.CanPop() || numeofs) )
{
if ( sofar )
return sofar;
if ( nonblocking )
return errno = EWOULDBLOCK, -1;
if ( !kthread_cond_wait_signal(&datacond, &termlock) )
return errno = EINTR, -1;
if ( !RequireForeground(SIGTTIN) )
return errno = EINTR, -1;
}
if ( numeofs )
{
if ( sofar )
return sofar;
return numeofs--, 0;
}
uint32_t codepoint = linebuffer.Peek();
int kbkey = KBKEY_DECODE(codepoint);
bool ignore = false;
if ( !(termmode & TERMMODE_KBKEY) && kbkey ) { ignore = true; }
if ( !(termmode & TERMMODE_UNICODE) && !kbkey ) { ignore = true; }
if ( ignore ) { linebuffer.Pop(); continue; }
uint8_t* buf;
size_t bufsize;
uint8_t codepointbuf[4];
char utf8buf[MB_CUR_MAX];
if ( termmode & TERMMODE_UTF8 )
if ( tio.c_lflag & ISORTIX_32BIT )
{
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
size_t num_bytes = wcrtomb(utf8buf, (wchar_t) codepoint, &ps);
if ( num_bytes == (size_t) -1)
if ( left < sizeof(codepoint) )
return sofar;
linebuffer.Pop();
if ( 256 <= codepoint && !(tio.c_lflag & ISORTIX_KBKEY) )
continue;
if ( codepoint < 256 && tio.c_lflag & ISORTIX_CHARS_DISABLE )
continue;
if ( codepoint < 256 )
{
Log::PrintF("Warning: logterminal driver dropping invalid "
"codepoint 0x%x\n", codepoint);
num_bytes = 0;
char c = codepoint;
wchar_t wc;
size_t amount = mbrtowc(&wc, &c, 1, &read_ps);
if ( amount == (size_t) -2 )
continue;
if ( amount == (size_t) -1 )
{
memset(&read_ps, 0, sizeof(read_ps));
wc = 0xFFFD; /* REPLACEMENT CHARACTER */
}
codepoint = wc;
}
buf = (uint8_t*) utf8buf;
bufsize = num_bytes;
if ( !ctx->copy_to_dest(userbuf + sofar, &codepoint,
sizeof(codepoint)) )
return sofar ? sofar : -1;
left -= sizeof(codepoint);
sofar += sizeof(codepoint);
continue;
}
else
if ( 256 <= codepoint )
{
codepointbuf[0] = (codepoint >> 24U) & 0xFFU;
codepointbuf[1] = (codepoint >> 16U) & 0xFFU;
codepointbuf[2] = (codepoint >> 8U) & 0xFFU;
codepointbuf[3] = (codepoint >> 0U) & 0xFFU;
buf = (uint8_t*) &codepointbuf;
bufsize = sizeof(codepointbuf);
// TODO: Whoops, the above is big-endian and the user programs
// expect the data to be in the host endian. That's bad. For now
// just send the data in host endian, but this will break when
// terminals are accessed over the network.
buf = (uint8_t*) &codepoint;
linebuffer.Pop();
continue;
}
if ( bufsize < partiallywritten ) { partiallywritten = bufsize; }
buf += partiallywritten;
bufsize -= partiallywritten;
if ( sofar && left < bufsize ) { return sofar; }
size_t amount = left < bufsize ? left : bufsize;
ctx->copy_to_dest(userbuf + sofar, buf, amount);
partiallywritten = (amount < bufsize) ? partiallywritten + amount : 0;
left -= amount;
sofar += amount;
if ( !partiallywritten ) { linebuffer.Pop(); }
unsigned char c = codepoint;
if ( !ctx->copy_to_dest(userbuf + sofar, &c, 1) )
return sofar ? sofar : -1;
linebuffer.Pop();
left -= 1;
sofar += 1;
if ( tio.c_lflag & ICANON && c == '\n' )
break;
}
return sofar;
}
ssize_t LogTerminal::write(ioctx_t* ctx, const uint8_t* io_buffer, size_t count)
{
ScopedLockSignal lock(&termlock);
if ( tio.c_lflag & TOSTOP && !RequireForeground(SIGTTOU) )
return errno = EINTR, -1;
// TODO: Add support for ioctx to the kernel log.
const size_t BUFFER_SIZE = 64UL;
if ( BUFFER_SIZE < count )
count = BUFFER_SIZE;
char buffer[BUFFER_SIZE];
if ( !ctx->copy_from_src(buffer, io_buffer, count) )
return -1;
Log::PrintData(buffer, count);
return count;
size_t sofar = 0;
while ( sofar < count )
{
size_t amount = count - sofar;
if ( BUFFER_SIZE < amount )
amount = BUFFER_SIZE;
if ( !ctx->copy_from_src(buffer, io_buffer + sofar, amount) )
return -1;
Log::PrintData(buffer, amount);
sofar += amount;
if ( sofar < count )
{
kthread_mutex_unlock(&termlock);
kthread_yield();
kthread_mutex_lock(&termlock);
if ( Signal::IsPending() )
return sofar;
}
}
return (ssize_t) sofar;
}
short LogTerminal::PollEventStatus()
@ -496,4 +794,99 @@ ssize_t LogTerminal::tcsetblob(ioctx_t* ctx, const char* name, const void* buffe
else
return errno = ENOENT, -1;
}
int LogTerminal::tcdrain(ioctx_t* /*ctx*/)
{
ScopedLockSignal lock(&termlock);
if ( !RequireForeground(SIGTTOU) )
return errno = EINTR, -1;
return 0;
}
int LogTerminal::tcflow(ioctx_t* /*ctx*/, int action)
{
ScopedLockSignal lock(&termlock);
if ( !RequireForeground(SIGTTOU) )
return errno = EINTR, -1;
switch ( action )
{
case TCOOFF: break; // TODO: Suspend output.
case TCOON: break; // TODO: Resume suspended output.
case TCIOFF: break; // TODO: Transmit STOP character.
case TCION: break; // TODO: Transmit START character.
default: return errno = EINVAL -1;
}
return 0;
}
int LogTerminal::tcflush(ioctx_t* /*ctx*/, int queue_selector)
{
if ( queue_selector & ~TCIOFLUSH )
return errno = EINVAL, -1;
ScopedLockSignal lock(&termlock);
if ( !RequireForeground(SIGTTOU) )
return errno = EINTR, -1;
if ( queue_selector & TCIFLUSH )
linebuffer.Flush();
return 0;
}
int LogTerminal::tcgetattr(ioctx_t* ctx, struct termios* io_tio)
{
ScopedLockSignal lock(&termlock);
if ( !ctx->copy_to_dest(io_tio, &tio, sizeof(tio)) )
return -1;
return 0;
}
pid_t LogTerminal::tcgetsid(ioctx_t* /*ctx*/)
{
// TODO: Implement sessions.
return 1;
}
int LogTerminal::tcsendbreak(ioctx_t* /*ctx*/, int /*duration*/)
{
ScopedLockSignal lock(&termlock);
if ( !RequireForeground(SIGTTOU) )
return errno = EINTR, -1;
return 0;
}
int LogTerminal::tcsetattr(ioctx_t* ctx, int actions, const struct termios* io_tio)
{
ScopedLockSignal lock(&termlock);
if ( !RequireForeground(SIGTTOU) )
return errno = EINTR, -1;
switch ( actions )
{
case TCSANOW: break;
case TCSADRAIN: break;
case TCSAFLUSH: linebuffer.Flush(); break;
default: return errno = EINVAL, -1;
}
if ( !ctx->copy_from_src(&tio, io_tio, sizeof(tio)) )
return -1;
// TODO: Potentially take action here if something changed.
return 0;
}
bool LogTerminal::RequireForeground(int sig)
{
Thread* thread = CurrentThread();
Process* process = thread->process;
ScopedLock group_lock(&process->groupparentlock);
if ( process->group->pid == foreground_pgid )
return true;
if ( sigismember(&thread->signal_mask, sig) )
return true;
ScopedLock signal_lock(&process->signal_lock);
if ( process->signal_actions[sig].sa_handler == SIG_IGN )
return true;
signal_lock.Reset();
group_lock.Reset();
process->group->DeliverGroupSignal(sig);
return false;
}
} // namespace Sortix

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014, 2015, 2016.
This file is part of Sortix.
@ -25,6 +25,10 @@
#ifndef SORTIX_LOGTERMINAL_H
#define SORTIX_LOGTERMINAL_H
#include <wchar.h>
#include <sortix/termios.h>
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/inode.h>
#include <sortix/kernel/keyboard.h>
@ -56,30 +60,40 @@ public:
virtual int poll(ioctx_t* ctx, PollNode* node);
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 tcdrain(ioctx_t* ctx);
virtual int tcflow(ioctx_t* ctx, int action);
virtual int tcflush(ioctx_t* ctx, int queue_selector);
virtual int tcgetattr(ioctx_t* ctx, struct termios* tio);
virtual pid_t tcgetsid(ioctx_t* ctx);
virtual int tcsendbreak(ioctx_t* ctx, int duration);
virtual int tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio);
public:
virtual void OnKeystroke(Keyboard* keyboard, void* user);
private:
void ProcessKeystroke(int kbkey);
void QueueUnicode(uint32_t unicode);
void ProcessString(const char* string);
void ProcessUnicode(uint32_t unicode);
void ProcessByte(unsigned char byte, uint32_t control_unicode = 0);
void CommitLineBuffer();
short PollEventStatus();
bool CheckForeground();
bool RequireForeground(int sig);
bool CheckHandledByte(tcflag_t lflags, unsigned char key, unsigned char byte);
private:
PollChannel poll_channel;
mutable kthread_mutex_t termlock;
kthread_cond_t datacond;
size_t numwaiting;
mbstate_t read_ps;
size_t numeofs;
Keyboard* keyboard;
KeyboardLayoutExecutor* kblayout;
LineBuffer linebuffer;
size_t partiallywritten;
unsigned termmode;
struct termios tio;
pid_t foreground_pgid;
bool control;
int modifiers;
};

View File

@ -190,13 +190,13 @@ void* syscall_list[SYSCALL_MAX_NUM + 1] =
[SYSCALL_CLOSEFROM] = (void*) sys_closefrom,
[SYSCALL_RESERVED1] = (void*) sys_bad_syscall,
[SYSCALL_PSCTL] = (void*) sys_psctl,
[SYSCALL_RESERVED2] = (void*) sys_bad_syscall,
[SYSCALL_RESERVED3] = (void*) sys_bad_syscall,
[SYSCALL_RESERVED4] = (void*) sys_bad_syscall,
[SYSCALL_RESERVED5] = (void*) sys_bad_syscall,
[SYSCALL_RESERVED6] = (void*) sys_bad_syscall,
[SYSCALL_RESERVED7] = (void*) sys_bad_syscall,
[SYSCALL_RESERVED8] = (void*) sys_bad_syscall,
[SYSCALL_TCDRAIN] = (void*) sys_tcdrain,
[SYSCALL_TCFLOW] = (void*) sys_tcflow,
[SYSCALL_TCFLUSH] = (void*) sys_tcflush,
[SYSCALL_TCGETATTR] = (void*) sys_tcgetattr,
[SYSCALL_TCGETSID] = (void*) sys_tcgetsid,
[SYSCALL_TCSENDBREAK] = (void*) sys_tcsendbreak,
[SYSCALL_TCSETATTR] = (void*) sys_tcsetattr,
[SYSCALL_SCRAM] = (void*) sys_scram,
[SYSCALL_MAX_NUM] = (void*) sys_bad_syscall,
};

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014, 2015.
This file is part of Sortix.
@ -424,4 +424,39 @@ ssize_t Vnode::tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, siz
return inode->tcsetblob(ctx, name, buffer, count);
}
int Vnode::tcdrain(ioctx_t* ctx)
{
return inode->tcdrain(ctx);
}
int Vnode::tcflow(ioctx_t* ctx, int action)
{
return inode->tcflow(ctx, action);
}
int Vnode::tcflush(ioctx_t* ctx, int queue_selector)
{
return inode->tcflush(ctx, queue_selector);
}
int Vnode::tcgetattr(ioctx_t* ctx, struct termios* tio)
{
return inode->tcgetattr(ctx, tio);
}
pid_t Vnode::tcgetsid(ioctx_t* ctx)
{
return inode->tcgetsid(ctx);
}
int Vnode::tcsendbreak(ioctx_t* ctx, int duration)
{
return inode->tcsendbreak(ctx, duration);
}
int Vnode::tcsetattr(ioctx_t* ctx, int actions, const struct termios* tio)
{
return inode->tcsetattr(ctx, actions, tio);
}
} // namespace Sortix

View File

@ -241,6 +241,10 @@ string/strverscmp.o \
string/strxfrm_l.o \
string/strxfrm.o \
string/timingsafe_memcmp.o \
termios/cfgetispeed.o \
termios/cfgetospeed.o \
termios/cfsetispeed.o \
termios/cfsetospeed.o \
time/asctime.o \
time/asctime_r.o \
time/gmtime.o \
@ -544,9 +548,16 @@ sys/uio/writev.o \
sys/utsname/uname.o \
sys/wait/wait.o \
sys/wait/waitpid.o \
termios/tcdrain.o \
termios/tcflow.o \
termios/tcflush.o \
termios/tcgetattr.o \
termios/tcgetblob.o \
termios/tcgetsid.o \
termios/tcgetwincurpos.o \
termios/tcgetwinsize.o \
termios/tcsendbreak.o \
termios/tcsetattr.o \
termios/tcsetblob.o \
time/clock_getres.o \
time/clock_gettime.o \

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014, 2015.
This file is part of the Sortix C Library.
@ -33,6 +33,7 @@
#include <sortix/statvfs.h>
#include <sortix/termios.h>
#include <sortix/timespec.h>
#include <sortix/winsize.h>
#ifdef __cplusplus
extern "C" {
@ -434,8 +435,66 @@ struct fsm_resp_tcgetwincurpos
struct wincurpos pos;
};
#define FSM_REQ_TCDRAIN 54
struct fsm_req_tcdrain
{
ino_t ino;
};
#define FSM_MSG_NUM 53
#define FSM_REQ_TCFLOW 55
struct fsm_req_tcflow
{
ino_t ino;
int action;
};
#define FSM_REQ_TCFLUSH 56
struct fsm_req_tcflush
{
ino_t ino;
int queue_selector;
};
#define FSM_REQ_TCGETATTR 57
struct fsm_req_tcgetattr
{
ino_t ino;
};
#define FSM_RESP_TCGETATTR 58
struct fsm_resp_tcgetattr
{
struct termios tio;
};
#define FSM_REQ_TCGETSID 59
struct fsm_req_tcgetsid
{
ino_t ino;
};
#define FSM_RESP_TCGETSID 60
struct fsm_resp_tcgetsid
{
pid_t sid;
};
#define FSM_REQ_TCSENDBREAK 61
struct fsm_req_tcsendbreak
{
ino_t ino;
int duration;
};
#define FSM_REQ_TCSETATTR 62
struct fsm_req_tcsetattr
{
ino_t ino;
int actions;
struct termios tio;
};
#define FSM_MSG_NUM 63
#ifdef __cplusplus
} /* extern "C" */

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2016.
This file is part of the Sortix C Library.
@ -27,6 +27,9 @@
#include <sys/cdefs.h>
#include <sortix/ioctl.h>
#include <sortix/winsize.h>
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -31,12 +31,14 @@
#include <sys/__/types.h>
#if __USE_SORTIX
#include <sortix/termios.h>
#if __USE_SORTIX
#include <sortix/winsize.h>
#endif
#ifdef __cplusplus
extern "C" {
#ifndef __pid_t_defined
#define __pid_t_defined
typedef __pid_t pid_t;
#endif
#if __USE_SORTIX
@ -45,13 +47,31 @@ extern "C" {
#define __need_size_t
#include <stddef.h>
#endif
#endif
#if __USE_SORTIX
#ifndef __ssize_t_defined
#define __ssize_t_defined
typedef __ssize_t ssize_t;
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
speed_t cfgetispeed(const struct termios*);
speed_t cfgetospeed(const struct termios*);
int cfsetispeed(struct termios*, speed_t);
int cfsetospeed(struct termios*, speed_t);
int tcdrain(int);
int tcflow(int, int);
int tcflush(int, int);
int tcgetattr(int, struct termios*);
pid_t tcgetsid(int);
int tcsendbreak(int, int);
int tcsetattr(int, int, const struct termios*);
/* Functions that are Sortix extensions. */
#if __USE_SORTIX
ssize_t tcgetblob(int, const char*, void*, size_t);

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
Copyright(C) Jonas 'Sortie' Termansen 2013, 2016.
This file is part of the Sortix C Library.
@ -25,15 +25,25 @@
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
DEFN_SYSCALL3(int, sys_ioctl, SYSCALL_IOCTL, int, int, void*);
DEFN_SYSCALL3(int, sys_ioctl, SYSCALL_IOCTL, int, int, uintptr_t);
extern "C" int ioctl(int fd, int request, ...)
{
uintptr_t arg;
va_list ap;
va_start(ap, request);
void* ptr = va_arg(ap, void*);
switch ( __IOCTL_TYPE(request) )
{
case __IOCTL_TYPE_VOID: arg = 0; break;
case __IOCTL_TYPE_INT: arg = (uintptr_t) va_arg(ap, int); break;
case __IOCTL_TYPE_LONG: arg = (uintptr_t) va_arg(ap, long); break;
case __IOCTL_TYPE_PTR: arg = (uintptr_t) va_arg(ap, void*); break;
default: return errno = EINVAL, -1;
}
va_end(ap);
return sys_ioctl(fd, request, ptr);
return sys_ioctl(fd, request, arg);
}

View File

@ -0,0 +1,30 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/cfgetispeed.cpp
Get termios input speed.
*******************************************************************************/
#include <termios.h>
extern "C" speed_t cfgetispeed(const struct termios* tio)
{
return tio->c_ispeed;
}

View File

@ -0,0 +1,30 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/cfgetospeed.cpp
Get termios output speed.
*******************************************************************************/
#include <termios.h>
extern "C" speed_t cfgetospeed(const struct termios* tio)
{
return tio->c_ospeed;
}

View File

@ -0,0 +1,31 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/cfsetispeed.cpp
Set termios input speed.
*******************************************************************************/
#include <termios.h>
extern "C" int cfsetispeed(struct termios* tio, speed_t speed)
{
tio->c_ispeed = speed;
return 0;
}

View File

@ -0,0 +1,31 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/cfsetospeed.cpp
Set termios output speed.
*******************************************************************************/
#include <termios.h>
extern "C" int cfsetospeed(struct termios* tio, speed_t speed)
{
tio->c_ospeed = speed;
return 0;
}

34
libc/termios/tcdrain.cpp Normal file
View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/tcdrain.cpp
Wait for transmission of output.
*******************************************************************************/
#include <sys/syscall.h>
#include <termios.h>
DEFN_SYSCALL1(int, sys_tcdrain, SYSCALL_TCDRAIN, int);
extern "C" int tcdrain(int fd)
{
return sys_tcdrain(fd);
}

34
libc/termios/tcflow.cpp Normal file
View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/tcflow.cpp
Suspend or restart the transmission or reception of data.
*******************************************************************************/
#include <sys/syscall.h>
#include <termios.h>
DEFN_SYSCALL2(int, sys_tcflow, SYSCALL_TCFLOW, int, int);
extern "C" int tcflow(int fd, int action)
{
return sys_tcflow(fd, action);
}

34
libc/termios/tcflush.cpp Normal file
View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/tcflush.cpp
Flush non-transmitted output data, non-read input data, or both.
*******************************************************************************/
#include <sys/syscall.h>
#include <termios.h>
DEFN_SYSCALL2(int, sys_tcflush, SYSCALL_TCFLUSH, int, int);
extern "C" int tcflush(int fd, int queue_selector)
{
return sys_tcflush(fd, queue_selector);
}

View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/tcgetattr.cpp
Get the parameters associated with the terminal.
*******************************************************************************/
#include <sys/syscall.h>
#include <termios.h>
DEFN_SYSCALL2(int, sys_tcgetattr, SYSCALL_TCGETATTR, int, struct termios*);
extern "C" int tcgetattr(int fd, struct termios* tio)
{
return sys_tcgetattr(fd, tio);
}

34
libc/termios/tcgetsid.cpp Normal file
View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/tcgetsid.cpp
Get terminal session id.
*******************************************************************************/
#include <sys/syscall.h>
#include <termios.h>
DEFN_SYSCALL1(int, sys_tcgetsid, SYSCALL_TCGETSID, int);
extern "C" pid_t tcgetsid(int fd)
{
return sys_tcgetsid(fd);
}

View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/tcsendbreak.cpp
Send a break for a specific duration.
*******************************************************************************/
#include <sys/syscall.h>
#include <termios.h>
DEFN_SYSCALL2(int, sys_tcsendbreak, SYSCALL_TCSENDBREAK, int, int);
extern "C" int tcsendbreak(int fd, int duration)
{
return sys_tcsendbreak(fd, duration);
}

View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2015.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
termios/tcsetattr.cpp
Set the parameters associated with the terminal.
*******************************************************************************/
#include <sys/syscall.h>
#include <termios.h>
DEFN_SYSCALL3(int, sys_tcsetattr, SYSCALL_TCSETATTR, int, int, const struct termios*);
extern "C" int tcsetattr(int fd, int actions, const struct termios* tio)
{
return sys_tcsetattr(fd, actions, tio);
}

View File

@ -35,13 +35,6 @@
#include "editline.h"
#include "showline.h"
static const unsigned int NORMAL_TERMMODE =
TERMMODE_UNICODE |
TERMMODE_SIGNAL |
TERMMODE_UTF8 |
TERMMODE_LINEBUFFER |
TERMMODE_ECHO;
void edit_line_show(struct edit_line* edit_state)
{
size_t line_length = 0;
@ -564,7 +557,7 @@ void edit_line_codepoint(struct edit_line* edit_state, wchar_t wc)
return;
}
if ( wc == L'\b' )
if ( wc == L'\b' || wc == 127 )
return;
if ( wc == L'\t' )
return;
@ -617,5 +610,5 @@ void edit_line(struct edit_line* edit_state)
show_line_finish(&edit_state->show_state);
}
settermmode(edit_state->in_fd, NORMAL_TERMMODE);
settermmode(edit_state->in_fd, TERMMODE_NORMAL);
}

View File

@ -40,6 +40,7 @@
#include <math.h>
#include <poll.h>
#include <pwd.h>
#include <signal.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@ -155,7 +156,12 @@ static bool ForkAndWait()
{
int status;
waitpid(child_pid, &status, 0);
sigset_t oldset, sigttou;
sigemptyset(&sigttou);
sigaddset(&sigttou, SIGTTOU);
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
tcsetpgrp(0, getpgid(0));
sigprocmask(SIG_SETMASK, &oldset, NULL);
settermmode(0, old_termmode);
return false;
}
@ -166,13 +172,18 @@ static bool ForkAndWait()
open("/dev/tty", O_WRONLY);
open("/dev/tty", O_WRONLY);
setpgid(0, 0);
sigset_t oldset, sigttou;
sigemptyset(&sigttou);
sigaddset(&sigttou, SIGTTOU);
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
tcsetpgrp(0, getpgid(0));
sigprocmask(SIG_SETMASK, &oldset, NULL);
#if 1 /* Magic to somehow fix a weird keyboard-related bug nortti has. */
settermmode(0, TERMMODE_UNICODE | TERMMODE_SIGNAL | TERMMODE_UTF8 | TERMMODE_LINEBUFFER | TERMMODE_ECHO | TERMMODE_NONBLOCK);
settermmode(0, TERMMODE_NORMAL | TERMMODE_NONBLOCK);
char c;
while ( 0 <= read(0, &c, sizeof(c)) );
#endif
settermmode(0, TERMMODE_UNICODE | TERMMODE_SIGNAL | TERMMODE_UTF8 | TERMMODE_LINEBUFFER | TERMMODE_ECHO);
settermmode(0, TERMMODE_NORMAL);
printf("\e[m\e[2J\e[H");
fflush(stdout);
fsync(0);
@ -1719,7 +1730,7 @@ void HandleCodepoint(uint32_t codepoint, struct Desktop* desktop)
size_t column = 0;
while ( desktop->command[column] )
column++;
if ( c == '\b' )
if ( c == '\b' || c == 127 )
{
if ( column )
desktop->command[column-1] = '\0';
@ -1918,9 +1929,6 @@ static int CreateKeyboardConnection()
int main(int argc, char* argv[])
{
setpgid(0, 0);
tcsetpgrp(0, getpgid(0));
struct stat st;
if ( stat("/etc/rune-enable", &st) == 0 )
use_runes = true, configured_use_runes = true;