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/mount.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/termmode.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -145,7 +146,17 @@ int child()
setenv("INIT_PID", init_pid_str, 1); setenv("INIT_PID", init_pid_str, 1);
setpgid(0, 0); 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_shell = "sh";
const char* default_home = "/root"; 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. This file is part of Sortix.
@ -110,7 +110,7 @@ void PrintChar(char c)
{ {
if ( c == '\n' ) if ( c == '\n' )
Newline(); Newline();
else if ( c == '\b' ) else if ( c == '\b' || c == 127 )
{ {
if ( column ) if ( column )
column--; column--;
@ -290,11 +290,11 @@ void ReadCommand(char* buffer, size_t buffer_length)
continue; continue;
// Handle backspace. // Handle backspace.
if ( c == '\b' ) if ( c == '\b' || c == 127 )
{ {
if ( !written ) if ( !written )
continue; continue;
PrintChar(c); PrintChar('\b');
written--; written--;
continue; continue;
} }

View File

@ -828,4 +828,39 @@ Ref<Descriptor> Descriptor::fsm_mount(ioctx_t* ctx,
return result; 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 } // namespace Sortix

View File

@ -36,8 +36,8 @@
#include <sortix/dirent.h> #include <sortix/dirent.h>
#include <sortix/fcntl.h> #include <sortix/fcntl.h>
#include <sortix/stat.h> #include <sortix/stat.h>
#include <sortix/termios.h>
#include <sortix/timespec.h> #include <sortix/timespec.h>
#include <sortix/winsize.h>
#include <fsmarshall-msg.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 tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count); virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
virtual int unmounted(ioctx_t* ctx); 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: private:
bool SendMessage(Channel* channel, size_t type, void* ptr, size_t size, bool SendMessage(Channel* channel, size_t type, void* ptr, size_t size,
@ -1472,6 +1479,120 @@ int Unode::unmounted(ioctx_t* /*ctx*/)
return 0; 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, bool Bootstrap(Ref<Inode>* out_root,
Ref<Inode>* out_server, Ref<Inode>* out_server,
const struct stat* rootst) 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. This file is part of Sortix.
@ -36,6 +36,7 @@
struct stat; struct stat;
struct statvfs; struct statvfs;
struct termios;
struct wincurpos; struct wincurpos;
struct winsize; struct winsize;
struct kernel_dirent; struct kernel_dirent;
@ -109,6 +110,13 @@ public:
int fsm_fsbind(ioctx_t* ctx, Ref<Descriptor> target, int flags); int fsm_fsbind(ioctx_t* ctx, Ref<Descriptor> target, int flags);
Ref<Descriptor> fsm_mount(ioctx_t* ctx, const char* filename, Ref<Descriptor> fsm_mount(ioctx_t* ctx, const char* filename,
const struct stat* rootst, int flags); 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: private:
Ref<Descriptor> open_elem(ioctx_t* ctx, const char* filename, int flags, 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. This file is part of Sortix.
@ -36,6 +36,7 @@
struct stat; struct stat;
struct statvfs; struct statvfs;
struct termios;
struct wincurpos; struct wincurpos;
struct winsize; struct winsize;
struct kernel_dirent; 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 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 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 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 tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count); virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
virtual int unmounted(ioctx_t* ctx); 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/termios.h>
#include <sortix/timespec.h> #include <sortix/timespec.h>
#include <sortix/tmns.h> #include <sortix/tmns.h>
#include <sortix/winsize.h>
namespace Sortix { namespace Sortix {
@ -103,7 +104,7 @@ int sys_getsockopt(int, int, int, void*, size_t*);
int sys_gettermmode(int, unsigned*); int sys_gettermmode(int, unsigned*);
uid_t sys_getuid(void); uid_t sys_getuid(void);
mode_t sys_getumask(void); mode_t sys_getumask(void);
int sys_ioctl(int, int, void*); int sys_ioctl(int, int, uintptr_t);
int sys_isatty(int); int sys_isatty(int);
ssize_t sys_kernelinfo(const char*, char*, size_t); ssize_t sys_kernelinfo(const char*, char*, size_t);
int sys_kill(pid_t, int); 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_sigprocmask(int, const sigset_t*, sigset_t*);
int sys_sigsuspend(const sigset_t*); int sys_sigsuspend(const sigset_t*);
int sys_symlinkat(const char*, int, const char*); 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); ssize_t sys_tcgetblob(int, const char*, void*, size_t);
int sys_tcgetpgrp(int); int sys_tcgetpgrp(int);
pid_t sys_tcgetsid(int);
int sys_tcgetwincurpos(int, struct wincurpos*); int sys_tcgetwincurpos(int, struct wincurpos*);
int sys_tcgetwinsize(int, struct winsize*); 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); ssize_t sys_tcsetblob(int, const char*, const void*, size_t);
int sys_tcsetpgrp(int, pid_t); int sys_tcsetpgrp(int, pid_t);
pid_t sys_tfork(int, struct tfork*); 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. This file is part of Sortix.
@ -35,6 +35,7 @@
struct stat; struct stat;
struct statvfs; struct statvfs;
struct termios;
struct wincurpos; struct wincurpos;
struct winsize; struct winsize;
struct kernel_dirent; struct kernel_dirent;
@ -105,6 +106,13 @@ public:
int unmount(ioctx_t* ctx, const char* filename, int flags); int unmount(ioctx_t* ctx, const char* filename, int flags);
int fsm_fsbind(ioctx_t* ctx, Ref<Vnode> target, 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); 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*/: public /*TODO: private*/:
Ref<Inode> inode; Ref<Inode> inode;

View File

@ -180,13 +180,13 @@
#define SYSCALL_CLOSEFROM 152 #define SYSCALL_CLOSEFROM 152
#define SYSCALL_RESERVED1 153 #define SYSCALL_RESERVED1 153
#define SYSCALL_PSCTL 154 #define SYSCALL_PSCTL 154
#define SYSCALL_RESERVED2 155 #define SYSCALL_TCDRAIN 155
#define SYSCALL_RESERVED3 156 #define SYSCALL_TCFLOW 156
#define SYSCALL_RESERVED4 157 #define SYSCALL_TCFLUSH 157
#define SYSCALL_RESERVED5 158 #define SYSCALL_TCGETATTR 158
#define SYSCALL_RESERVED6 159 #define SYSCALL_TCGETSID 159
#define SYSCALL_RESERVED7 160 #define SYSCALL_TCSENDBREAK 160
#define SYSCALL_RESERVED8 161 #define SYSCALL_TCSETATTR 161
#define SYSCALL_SCRAM 162 #define SYSCALL_SCRAM 162
#define SYSCALL_MAX_NUM 163 /* index of highest constant + 1 */ #define SYSCALL_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. This file is part of Sortix.
@ -18,7 +18,7 @@
Sortix. If not, see <http://www.gnu.org/licenses/>. Sortix. If not, see <http://www.gnu.org/licenses/>.
sortix/termios.h sortix/termios.h
Defines values for termios. Termios types and constants.
*******************************************************************************/ *******************************************************************************/
@ -27,34 +27,108 @@
#include <sys/cdefs.h> #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 #define BRKINT (1U << 0)
extern "C" { #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 #endif
#ifndef __size_t_defined #define TCSANOW 0
#define __size_t_defined #define TCSADRAIN 1
#define __need_size_t #define TCSAFLUSH 2
#include <stddef.h>
#endif
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; tcflag_t c_iflag;
size_t wcp_col; 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 #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. This file is part of Sortix.
@ -25,12 +25,16 @@
#ifndef SORTIX_TERMMODE_H #ifndef SORTIX_TERMMODE_H
#define SORTIX_TERMMODE_H #define SORTIX_TERMMODE_H
#define TERMMODE_KBKEY (1U<<0U) #define TERMMODE_KBKEY (1U << 0) /* ISORTIX_ENABLE_KBKEY */
#define TERMMODE_UNICODE (1U<<1U) #define TERMMODE_UNICODE (1U << 1) /* !ISORTIX_DISABLE_CHARS */
#define TERMMODE_SIGNAL (1U<<2U) #define TERMMODE_SIGNAL (1U << 2) /* ISIG */
#define TERMMODE_UTF8 (1U<<3U) #define TERMMODE_UTF8 (1U << 3) /* !ISORTIX_ENABLE_32BIT */
#define TERMMODE_LINEBUFFER (1U<<4U) #define TERMMODE_LINEBUFFER (1U << 4) /* ICANON */
#define TERMMODE_ECHO (1U<<5U) #define TERMMODE_ECHO (1U << 5) /* ECHO */
#define TERMMODE_NONBLOCK (1U<<6U) #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 #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. This file is part of Sortix.
@ -412,4 +412,39 @@ int AbstractInode::unmounted(ioctx_t* /*ctx*/)
return 0; 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 } // 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. This file is part of Sortix.
@ -33,6 +33,7 @@
#include <sortix/dirent.h> #include <sortix/dirent.h>
#include <sortix/fcntl.h> #include <sortix/fcntl.h>
#include <sortix/ioctl.h>
#include <sortix/seek.h> #include <sortix/seek.h>
#include <sortix/socket.h> #include <sortix/socket.h>
#include <sortix/stat.h> #include <sortix/stat.h>
@ -370,19 +371,15 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg)
return errno = EINVAL, -1; 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 ) switch ( cmd )
{ {
case TIOCGWINSZ:
return sys_tcgetwinsize(fd, (struct winsize*) arg);
default: default:
errno = EINVAL; return errno = EINVAL, -1;
break;
} }
return ret;
} }
ssize_t sys_readdirents(int fd, struct kernel_dirent* dirent, size_t size) 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; 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 } // namespace Sortix

View File

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

View File

@ -46,6 +46,7 @@ public:
void Freeze(); void Freeze();
bool CanPop() const; bool CanPop() const;
bool CanBackspace() const; bool CanBackspace() const;
void Flush();
private: private:
uint32_t* buffer; 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. This file is part of Sortix.
@ -25,9 +25,10 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <signal.h>
#include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h> #include <wchar.h>
#include <sortix/fcntl.h> #include <sortix/fcntl.h>
@ -37,6 +38,7 @@
#include <sortix/stat.h> #include <sortix/stat.h>
#include <sortix/termios.h> #include <sortix/termios.h>
#include <sortix/termmode.h> #include <sortix/termmode.h>
#include <sortix/winsize.h>
#include <sortix/kernel/inode.h> #include <sortix/kernel/inode.h>
#include <sortix/kernel/interlock.h> #include <sortix/kernel/interlock.h>
@ -49,18 +51,86 @@
#include <sortix/kernel/ptable.h> #include <sortix/kernel/ptable.h>
#include <sortix/kernel/refcount.h> #include <sortix/kernel/refcount.h>
#include <sortix/kernel/scheduler.h> #include <sortix/kernel/scheduler.h>
#include <sortix/kernel/thread.h>
#include "logterminal.h" #include "logterminal.h"
#define CONTROL(x) (((x) - 64) & 127)
#define M_CONTROL(x) (128 + CONTROL(x))
namespace Sortix { namespace Sortix {
const unsigned SUPPORTED_MODES = TERMMODE_KBKEY static const unsigned int SUPPORTED_TERMMODES = TERMMODE_KBKEY
| TERMMODE_UNICODE | TERMMODE_UNICODE
| TERMMODE_SIGNAL | TERMMODE_SIGNAL
| TERMMODE_UTF8 | TERMMODE_UTF8
| TERMMODE_LINEBUFFER | TERMMODE_LINEBUFFER
| TERMMODE_ECHO | TERMMODE_ECHO
| TERMMODE_NONBLOCK; | 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, LogTerminal::LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
Keyboard* keyboard, KeyboardLayoutExecutor* kblayout) 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->stat_gid = group;
this->keyboard = keyboard; this->keyboard = keyboard;
this->kblayout = kblayout; this->kblayout = kblayout;
this->partiallywritten = 0; this->modifiers = 0;
this->control = false; memset(&tio, 0, sizeof(tio));
this->termmode = TERMMODE_UNICODE tio.c_iflag = BRKINT | ICRNL | IXANY | IXON;
| TERMMODE_SIGNAL tio.c_oflag = OPOST;
| TERMMODE_UTF8 tio.c_cflag = CS8 /*| CREAD*/ | HUPCL; // CREAD unset for boot security.
| TERMMODE_LINEBUFFER tio.c_lflag = ECHO | ECHOE | ECHOK | ICANON | IEXTEN | ISIG;
| TERMMODE_ECHO; 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->termlock = KTHREAD_MUTEX_INITIALIZER;
this->datacond = KTHREAD_COND_INITIALIZER; this->datacond = KTHREAD_COND_INITIALIZER;
this->numwaiting = 0;
this->numeofs = 0; this->numeofs = 0;
this->foreground_pgid = 0; this->foreground_pgid = 0;
keyboard->SetOwner(this, NULL); keyboard->SetOwner(this, NULL);
@ -95,25 +177,86 @@ LogTerminal::~LogTerminal()
delete kblayout; 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); ScopedLock lock(&termlock);
unsigned oldtermmode = termmode; if ( !RequireForeground(SIGTTOU) )
bool oldutf8 = oldtermmode & TERMMODE_UTF8; return errno = EINTR, -1;
bool newutf8 = newtermmode & TERMMODE_UTF8; if ( termmode & ~SUPPORTED_TERMMODES )
if ( oldutf8 != newutf8 ) return errno = EINVAL, -1;
partiallywritten = 0; tcflag_t old_cflag = tio.c_cflag;
termmode = newtermmode; tcflag_t new_cflag = old_cflag;
if ( !(newtermmode & TERMMODE_LINEBUFFER) ) 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(); CommitLineBuffer();
partiallywritten = 0;
return 0; return 0;
} }
int LogTerminal::gettermmode(ioctx_t* ctx, unsigned* mode) int LogTerminal::gettermmode(ioctx_t* ctx, unsigned int* mode)
{ {
ScopedLock lock(&termlock); 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)) ) if ( !ctx->copy_to_dest(mode, &termmode, sizeof(termmode)) )
return -1; return -1;
return 0; return 0;
@ -121,6 +264,7 @@ int LogTerminal::gettermmode(ioctx_t* ctx, unsigned* mode)
int LogTerminal::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp) int LogTerminal::tcgetwincurpos(ioctx_t* ctx, struct wincurpos* wcp)
{ {
ScopedLock lock(&termlock);
struct wincurpos retwcp; struct wincurpos retwcp;
memset(&retwcp, 0, sizeof(retwcp)); memset(&retwcp, 0, sizeof(retwcp));
size_t cursor_column, cursor_row; 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) int LogTerminal::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
{ {
ScopedLock lock(&termlock);
struct winsize retws; struct winsize retws;
memset(&retws, 0, sizeof(retws)); memset(&retws, 0, sizeof(retws));
retws.ws_col = Log::Width(); 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) int LogTerminal::tcsetpgrp(ioctx_t* /*ctx*/, pid_t pgid)
{ {
ScopedLock lock(&termlock); ScopedLock lock(&termlock);
Process* process = CurrentProcess()->GetPTable()->Get(pgid); if ( !RequireForeground(SIGTTOU) )
if ( !pgid || !process ) return errno = EINTR, -1;
if ( pgid <= 0 )
return errno = ESRCH, -1; 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; bool is_process_group = process->group == process;
kthread_mutex_unlock(&process->groupchildlock); kthread_mutex_unlock(&process->groupparentlock);
if ( !is_process_group ) if ( !is_process_group )
return errno = EINVAL, -1; return errno = EINVAL, -1;
foreground_pgid = pgid; foreground_pgid = pgid;
@ -166,25 +315,160 @@ pid_t LogTerminal::tcgetpgrp(ioctx_t* /*ctx*/)
int LogTerminal::sync(ioctx_t* /*ctx*/) int LogTerminal::sync(ioctx_t* /*ctx*/)
{ {
ScopedLock lock(&termlock);
return Log::Sync() ? 0 : -1; return Log::Sync() ? 0 : -1;
} }
void LogTerminal::OnKeystroke(Keyboard* kb, void* /*user*/) void LogTerminal::OnKeystroke(Keyboard* kb, void* /*user*/)
{ {
ScopedLock lock(&termlock);
while ( kb->HasPending() ) 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) 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; return;
ScopedLock lock(&termlock); const struct kbkey_sequence* seq = LookupKeystrokeSequence(kbkey);
if ( !seq )
return;
if ( kbkey == KBKEY_LCTRL ) { control = true; } const char* str = seq->sequence;
if ( kbkey == -KBKEY_LCTRL ) { control = false; } size_t len = strlen(str);
if ( termmode & TERMMODE_SIGNAL && control && kbkey == KBKEY_C )
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() ) while ( linebuffer.CanBackspace() )
linebuffer.Backspace(); linebuffer.Backspace();
@ -192,236 +476,250 @@ void LogTerminal::ProcessKeystroke(int kbkey)
process->DeliverGroupSignal(SIGINT); process->DeliverGroupSignal(SIGINT);
return; return;
} }
if ( termmode & TERMMODE_SIGNAL && control && kbkey == KBKEY_D )
if ( CheckHandledByte(ISIG | ICANON, tio.c_cc[VEOF], byte) )
{ {
if ( !linebuffer.CanPop() ) if ( !linebuffer.CanPop() )
{ {
numeofs++; numeofs++;
if ( numwaiting ) kthread_cond_broadcast(&datacond);
kthread_cond_broadcast(&datacond);
poll_channel.Signal(POLLIN | POLLRDNORM); poll_channel.Signal(POLLIN | POLLRDNORM);
} }
return; return;
} }
if ( termmode & TERMMODE_LINEBUFFER && control && kbkey == KBKEY_W ) if ( CheckHandledByte(ISIG, tio.c_cc[VQUIT], byte) )
{ {
bool had_non_whitespace = false; while ( linebuffer.CanBackspace() )
c_w_delete_more: linebuffer.Backspace();
if ( !linebuffer.CanBackspace() ) { return; } if ( Process* process = CurrentProcess()->GetPTable()->Get(foreground_pgid) )
uint32_t delchar = linebuffer.WouldBackspace(); process->DeliverGroupSignal(SIGQUIT);
bool waskbkey = KBKEY_DECODE(delchar); return;
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;
} }
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() ) while ( linebuffer.CanBackspace() )
{ {
uint32_t delchar = linebuffer.Backspace(); uint32_t delchar = linebuffer.Backspace();
bool waskbkey = KBKEY_DECODE(delchar); if ( 256 <= delchar )
bool wasuni = !waskbkey; continue;
if ( (!waskbkey || termmode & TERMMODE_KBKEY) && if ( IsUTF8Continuation(delchar) )
(!wasuni || termmode & TERMMODE_UNICODE) && continue;
termmode & TERMMODE_ECHO && if ( tio.c_lflag & ECHOE )
wasuni ) {
// TODO: Handle tab specially. (Is that even possible without
// knowing cursor position?).
Log::Print("\b \b"); Log::Print("\b \b");
if ( !IsByteUnescaped(delchar) )
Log::Print("\b \b");
}
break;
} }
return; 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() ) while ( linebuffer.CanBackspace() )
linebuffer.Backspace(); linebuffer.Backspace();
QueueUnicode(KBKEY_ENCODE(KBKEY_ENTER)); ProcessUnicode(KBKEY_ENCODE(KBKEY_ENTER));
QueueUnicode('\n'); ProcessByte('\n');
QueueUnicode(KBKEY_ENCODE(-KBKEY_ENTER)); ProcessUnicode(KBKEY_ENCODE(-KBKEY_ENTER));
Log::PrintF("\e[H\e[2J"); Log::PrintF("\e[H\e[2J");
return; return;
} }
uint32_t unikbkey = KBKEY_ENCODE(kbkey); if ( tio.c_lflag & ISORTIX_CHARS_DISABLE )
QueueUnicode(unikbkey);
uint32_t unicode = kblayout->Translate(kbkey);
if ( 0 < kbkey )
QueueUnicode(unicode);
}
void LogTerminal::QueueUnicode(uint32_t unicode)
{
if ( !unicode )
return; return;
int kbkey = KBKEY_DECODE(unicode); if ( control_unicode &&
int abskbkey = (kbkey < 0) ? -kbkey : kbkey; !(tio.c_lflag & (ICANON | ISIG)) &&
bool wasenter = kbkey == KBKEY_ENTER || unicode == '\n'; tio.c_lflag & ISORTIX_KBKEY )
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 ( !linebuffer.CanBackspace() ) { return; } ProcessUnicode(control_unicode);
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"); }
return; return;
} }
if ( !linebuffer.Push(unicode) ) if ( !linebuffer.Push(byte) )
{
Log::PrintF("Warning: LogTerminal driver dropping keystroke due "
"to insufficient buffer space\n");
return; return;
}
// TODO: Could it be the right thing to print the unicode character even if ( tio.c_lflag & ECHO )
// if it is unprintable (it's an encoded keystroke)?
if ( !KBKEY_DECODE(unicode) && echomode )
{ {
mbstate_t ps; if ( IsByteUnescaped(byte) )
memset(&ps, 0, sizeof(ps)); Log::PrintData(&byte, 1);
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);
else else
Log::PrintData(utf8buf, num_bytes); Log::PrintF("^%c", CONTROL(byte));
} }
bool commit = !linemode || wasenter; if ( !(tio.c_lflag & ICANON) || byte == '\n' )
if ( commit )
CommitLineBuffer(); CommitLineBuffer();
} }
void LogTerminal::CommitLineBuffer() void LogTerminal::CommitLineBuffer()
{ {
linebuffer.Commit(); linebuffer.Commit();
if ( numwaiting ) if ( linebuffer.CanPop() || numeofs )
{
kthread_cond_broadcast(&datacond); 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) ssize_t LogTerminal::read(ioctx_t* ctx, uint8_t* userbuf, size_t count)
{ {
ScopedLockSignal lock(&termlock); 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 sofar = 0;
size_t left = count; size_t left = count;
bool blocking = !(termmode & TERMMODE_NONBLOCK); bool nonblocking = tio.c_lflag & ISORTIX_NONBLOCK ||
while ( left && !linebuffer.CanPop() && blocking && !numeofs ) ctx->dflags & O_NONBLOCK;
{ while ( left )
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() )
{ {
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(); uint32_t codepoint = linebuffer.Peek();
int kbkey = KBKEY_DECODE(codepoint); if ( tio.c_lflag & ISORTIX_32BIT )
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 )
{ {
mbstate_t ps; if ( left < sizeof(codepoint) )
memset(&ps, 0, sizeof(ps)); return sofar;
size_t num_bytes = wcrtomb(utf8buf, (wchar_t) codepoint, &ps); linebuffer.Pop();
if ( num_bytes == (size_t) -1) 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 " char c = codepoint;
"codepoint 0x%x\n", codepoint); wchar_t wc;
num_bytes = 0; 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; if ( !ctx->copy_to_dest(userbuf + sofar, &codepoint,
bufsize = num_bytes; sizeof(codepoint)) )
return sofar ? sofar : -1;
left -= sizeof(codepoint);
sofar += sizeof(codepoint);
continue;
} }
else if ( 256 <= codepoint )
{ {
codepointbuf[0] = (codepoint >> 24U) & 0xFFU; linebuffer.Pop();
codepointbuf[1] = (codepoint >> 16U) & 0xFFU; continue;
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;
} }
if ( bufsize < partiallywritten ) { partiallywritten = bufsize; } unsigned char c = codepoint;
buf += partiallywritten; if ( !ctx->copy_to_dest(userbuf + sofar, &c, 1) )
bufsize -= partiallywritten; return sofar ? sofar : -1;
if ( sofar && left < bufsize ) { return sofar; } linebuffer.Pop();
size_t amount = left < bufsize ? left : bufsize; left -= 1;
ctx->copy_to_dest(userbuf + sofar, buf, amount); sofar += 1;
partiallywritten = (amount < bufsize) ? partiallywritten + amount : 0; if ( tio.c_lflag & ICANON && c == '\n' )
left -= amount; break;
sofar += amount;
if ( !partiallywritten ) { linebuffer.Pop(); }
} }
return sofar; return sofar;
} }
ssize_t LogTerminal::write(ioctx_t* ctx, const uint8_t* io_buffer, size_t count) 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. // TODO: Add support for ioctx to the kernel log.
const size_t BUFFER_SIZE = 64UL; const size_t BUFFER_SIZE = 64UL;
if ( BUFFER_SIZE < count )
count = BUFFER_SIZE;
char buffer[BUFFER_SIZE]; char buffer[BUFFER_SIZE];
if ( !ctx->copy_from_src(buffer, io_buffer, count) ) size_t sofar = 0;
return -1; while ( sofar < count )
Log::PrintData(buffer, count); {
return 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() short LogTerminal::PollEventStatus()
@ -496,4 +794,99 @@ ssize_t LogTerminal::tcsetblob(ioctx_t* ctx, const char* name, const void* buffe
else else
return errno = ENOENT, -1; 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 } // 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. This file is part of Sortix.
@ -25,6 +25,10 @@
#ifndef SORTIX_LOGTERMINAL_H #ifndef SORTIX_LOGTERMINAL_H
#define SORTIX_LOGTERMINAL_H #define SORTIX_LOGTERMINAL_H
#include <wchar.h>
#include <sortix/termios.h>
#include <sortix/kernel/kthread.h> #include <sortix/kernel/kthread.h>
#include <sortix/kernel/inode.h> #include <sortix/kernel/inode.h>
#include <sortix/kernel/keyboard.h> #include <sortix/kernel/keyboard.h>
@ -56,30 +60,40 @@ public:
virtual int poll(ioctx_t* ctx, PollNode* node); 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 tcgetblob(ioctx_t* ctx, const char* name, void* buffer, size_t count);
virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count); virtual ssize_t tcsetblob(ioctx_t* ctx, const char* name, const void* buffer, size_t count);
virtual int 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: public:
virtual void OnKeystroke(Keyboard* keyboard, void* user); virtual void OnKeystroke(Keyboard* keyboard, void* user);
private: private:
void ProcessKeystroke(int kbkey); 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(); void CommitLineBuffer();
short PollEventStatus(); short PollEventStatus();
bool CheckForeground();
bool RequireForeground(int sig);
bool CheckHandledByte(tcflag_t lflags, unsigned char key, unsigned char byte);
private: private:
PollChannel poll_channel; PollChannel poll_channel;
mutable kthread_mutex_t termlock; mutable kthread_mutex_t termlock;
kthread_cond_t datacond; kthread_cond_t datacond;
size_t numwaiting; mbstate_t read_ps;
size_t numeofs; size_t numeofs;
Keyboard* keyboard; Keyboard* keyboard;
KeyboardLayoutExecutor* kblayout; KeyboardLayoutExecutor* kblayout;
LineBuffer linebuffer; LineBuffer linebuffer;
size_t partiallywritten; struct termios tio;
unsigned termmode;
pid_t foreground_pgid; 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_CLOSEFROM] = (void*) sys_closefrom,
[SYSCALL_RESERVED1] = (void*) sys_bad_syscall, [SYSCALL_RESERVED1] = (void*) sys_bad_syscall,
[SYSCALL_PSCTL] = (void*) sys_psctl, [SYSCALL_PSCTL] = (void*) sys_psctl,
[SYSCALL_RESERVED2] = (void*) sys_bad_syscall, [SYSCALL_TCDRAIN] = (void*) sys_tcdrain,
[SYSCALL_RESERVED3] = (void*) sys_bad_syscall, [SYSCALL_TCFLOW] = (void*) sys_tcflow,
[SYSCALL_RESERVED4] = (void*) sys_bad_syscall, [SYSCALL_TCFLUSH] = (void*) sys_tcflush,
[SYSCALL_RESERVED5] = (void*) sys_bad_syscall, [SYSCALL_TCGETATTR] = (void*) sys_tcgetattr,
[SYSCALL_RESERVED6] = (void*) sys_bad_syscall, [SYSCALL_TCGETSID] = (void*) sys_tcgetsid,
[SYSCALL_RESERVED7] = (void*) sys_bad_syscall, [SYSCALL_TCSENDBREAK] = (void*) sys_tcsendbreak,
[SYSCALL_RESERVED8] = (void*) sys_bad_syscall, [SYSCALL_TCSETATTR] = (void*) sys_tcsetattr,
[SYSCALL_SCRAM] = (void*) sys_scram, [SYSCALL_SCRAM] = (void*) sys_scram,
[SYSCALL_MAX_NUM] = (void*) sys_bad_syscall, [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. 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); 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 } // namespace Sortix

View File

@ -241,6 +241,10 @@ string/strverscmp.o \
string/strxfrm_l.o \ string/strxfrm_l.o \
string/strxfrm.o \ string/strxfrm.o \
string/timingsafe_memcmp.o \ string/timingsafe_memcmp.o \
termios/cfgetispeed.o \
termios/cfgetospeed.o \
termios/cfsetispeed.o \
termios/cfsetospeed.o \
time/asctime.o \ time/asctime.o \
time/asctime_r.o \ time/asctime_r.o \
time/gmtime.o \ time/gmtime.o \
@ -544,9 +548,16 @@ sys/uio/writev.o \
sys/utsname/uname.o \ sys/utsname/uname.o \
sys/wait/wait.o \ sys/wait/wait.o \
sys/wait/waitpid.o \ sys/wait/waitpid.o \
termios/tcdrain.o \
termios/tcflow.o \
termios/tcflush.o \
termios/tcgetattr.o \
termios/tcgetblob.o \ termios/tcgetblob.o \
termios/tcgetsid.o \
termios/tcgetwincurpos.o \ termios/tcgetwincurpos.o \
termios/tcgetwinsize.o \ termios/tcgetwinsize.o \
termios/tcsendbreak.o \
termios/tcsetattr.o \
termios/tcsetblob.o \ termios/tcsetblob.o \
time/clock_getres.o \ time/clock_getres.o \
time/clock_gettime.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. This file is part of the Sortix C Library.
@ -33,6 +33,7 @@
#include <sortix/statvfs.h> #include <sortix/statvfs.h>
#include <sortix/termios.h> #include <sortix/termios.h>
#include <sortix/timespec.h> #include <sortix/timespec.h>
#include <sortix/winsize.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -434,8 +435,66 @@ struct fsm_resp_tcgetwincurpos
struct wincurpos pos; 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 #ifdef __cplusplus
} /* extern "C" */ } /* 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. This file is part of the Sortix C Library.
@ -27,6 +27,9 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include <sortix/ioctl.h>
#include <sortix/winsize.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -31,12 +31,14 @@
#include <sys/__/types.h> #include <sys/__/types.h>
#if __USE_SORTIX
#include <sortix/termios.h> #include <sortix/termios.h>
#if __USE_SORTIX
#include <sortix/winsize.h>
#endif #endif
#ifdef __cplusplus #ifndef __pid_t_defined
extern "C" { #define __pid_t_defined
typedef __pid_t pid_t;
#endif #endif
#if __USE_SORTIX #if __USE_SORTIX
@ -45,13 +47,31 @@ extern "C" {
#define __need_size_t #define __need_size_t
#include <stddef.h> #include <stddef.h>
#endif #endif
#endif
#if __USE_SORTIX
#ifndef __ssize_t_defined #ifndef __ssize_t_defined
#define __ssize_t_defined #define __ssize_t_defined
typedef __ssize_t ssize_t; typedef __ssize_t ssize_t;
#endif #endif
#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. */ /* Functions that are Sortix extensions. */
#if __USE_SORTIX #if __USE_SORTIX
ssize_t tcgetblob(int, const char*, void*, size_t); 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. This file is part of the Sortix C Library.
@ -25,15 +25,25 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <errno.h>
#include <stdarg.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, ...) extern "C" int ioctl(int fd, int request, ...)
{ {
uintptr_t arg;
va_list ap; va_list ap;
va_start(ap, request); 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); 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 "editline.h"
#include "showline.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) void edit_line_show(struct edit_line* edit_state)
{ {
size_t line_length = 0; size_t line_length = 0;
@ -564,7 +557,7 @@ void edit_line_codepoint(struct edit_line* edit_state, wchar_t wc)
return; return;
} }
if ( wc == L'\b' ) if ( wc == L'\b' || wc == 127 )
return; return;
if ( wc == L'\t' ) if ( wc == L'\t' )
return; return;
@ -617,5 +610,5 @@ void edit_line(struct edit_line* edit_state)
show_line_finish(&edit_state->show_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 <math.h>
#include <poll.h> #include <poll.h>
#include <pwd.h> #include <pwd.h>
#include <signal.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -155,7 +156,12 @@ static bool ForkAndWait()
{ {
int status; int status;
waitpid(child_pid, &status, 0); waitpid(child_pid, &status, 0);
sigset_t oldset, sigttou;
sigemptyset(&sigttou);
sigaddset(&sigttou, SIGTTOU);
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
tcsetpgrp(0, getpgid(0)); tcsetpgrp(0, getpgid(0));
sigprocmask(SIG_SETMASK, &oldset, NULL);
settermmode(0, old_termmode); settermmode(0, old_termmode);
return false; return false;
} }
@ -166,13 +172,18 @@ static bool ForkAndWait()
open("/dev/tty", O_WRONLY); open("/dev/tty", O_WRONLY);
open("/dev/tty", O_WRONLY); open("/dev/tty", O_WRONLY);
setpgid(0, 0); setpgid(0, 0);
sigset_t oldset, sigttou;
sigemptyset(&sigttou);
sigaddset(&sigttou, SIGTTOU);
sigprocmask(SIG_BLOCK, &sigttou, &oldset);
tcsetpgrp(0, getpgid(0)); tcsetpgrp(0, getpgid(0));
sigprocmask(SIG_SETMASK, &oldset, NULL);
#if 1 /* Magic to somehow fix a weird keyboard-related bug nortti has. */ #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; char c;
while ( 0 <= read(0, &c, sizeof(c)) ); while ( 0 <= read(0, &c, sizeof(c)) );
#endif #endif
settermmode(0, TERMMODE_UNICODE | TERMMODE_SIGNAL | TERMMODE_UTF8 | TERMMODE_LINEBUFFER | TERMMODE_ECHO); settermmode(0, TERMMODE_NORMAL);
printf("\e[m\e[2J\e[H"); printf("\e[m\e[2J\e[H");
fflush(stdout); fflush(stdout);
fsync(0); fsync(0);
@ -1719,7 +1730,7 @@ void HandleCodepoint(uint32_t codepoint, struct Desktop* desktop)
size_t column = 0; size_t column = 0;
while ( desktop->command[column] ) while ( desktop->command[column] )
column++; column++;
if ( c == '\b' ) if ( c == '\b' || c == 127 )
{ {
if ( column ) if ( column )
desktop->command[column-1] = '\0'; desktop->command[column-1] = '\0';
@ -1918,9 +1929,6 @@ static int CreateKeyboardConnection()
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
setpgid(0, 0);
tcsetpgrp(0, getpgid(0));
struct stat st; struct stat st;
if ( stat("/etc/rune-enable", &st) == 0 ) if ( stat("/etc/rune-enable", &st) == 0 )
use_runes = true, configured_use_runes = true; use_runes = true, configured_use_runes = true;