diff --git a/init/init.c++ b/init/init.c++ index 40c392ea..d9c2c8a4 100644 --- a/init/init.c++ +++ b/init/init.c++ @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -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"; diff --git a/kernel/debugger.cpp b/kernel/debugger.cpp index ae8ecab1..f718f0b4 100644 --- a/kernel/debugger.cpp +++ b/kernel/debugger.cpp @@ -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; } diff --git a/kernel/descriptor.cpp b/kernel/descriptor.cpp index 6584c5f3..5d951f8e 100644 --- a/kernel/descriptor.cpp +++ b/kernel/descriptor.cpp @@ -828,4 +828,39 @@ Ref 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 diff --git a/kernel/fs/user.cpp b/kernel/fs/user.cpp index 6b6dc08f..373c3eca 100644 --- a/kernel/fs/user.cpp +++ b/kernel/fs/user.cpp @@ -36,8 +36,8 @@ #include #include #include -#include #include +#include #include @@ -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* out_root, Ref* out_server, const struct stat* rootst) diff --git a/kernel/include/sortix/ioctl.h b/kernel/include/sortix/ioctl.h new file mode 100644 index 00000000..b3d6ef89 --- /dev/null +++ b/kernel/include/sortix/ioctl.h @@ -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 . + + 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 diff --git a/kernel/include/sortix/kernel/descriptor.h b/kernel/include/sortix/kernel/descriptor.h index 0ae96ada..fd42d3a2 100644 --- a/kernel/include/sortix/kernel/descriptor.h +++ b/kernel/include/sortix/kernel/descriptor.h @@ -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 target, int flags); Ref 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 open_elem(ioctx_t* ctx, const char* filename, int flags, diff --git a/kernel/include/sortix/kernel/inode.h b/kernel/include/sortix/kernel/inode.h index da447051..6c35af06 100644 --- a/kernel/include/sortix/kernel/inode.h +++ b/kernel/include/sortix/kernel/inode.h @@ -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); }; diff --git a/kernel/include/sortix/kernel/syscall.h b/kernel/include/sortix/kernel/syscall.h index f1ef4586..2314b86d 100644 --- a/kernel/include/sortix/kernel/syscall.h +++ b/kernel/include/sortix/kernel/syscall.h @@ -47,6 +47,7 @@ #include #include #include +#include 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*); diff --git a/kernel/include/sortix/kernel/vnode.h b/kernel/include/sortix/kernel/vnode.h index 10165168..80b14571 100644 --- a/kernel/include/sortix/kernel/vnode.h +++ b/kernel/include/sortix/kernel/vnode.h @@ -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 target, int flags); Ref 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; diff --git a/kernel/include/sortix/syscall.h b/kernel/include/sortix/syscall.h index ed77701b..ff56789c 100644 --- a/kernel/include/sortix/syscall.h +++ b/kernel/include/sortix/syscall.h @@ -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 */ diff --git a/kernel/include/sortix/termios.h b/kernel/include/sortix/termios.h index 0096baa2..a2f571fc 100644 --- a/kernel/include/sortix/termios.h +++ b/kernel/include/sortix/termios.h @@ -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 . sortix/termios.h - Defines values for termios. + Termios types and constants. *******************************************************************************/ @@ -27,34 +27,108 @@ #include -#include +#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 -#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 diff --git a/kernel/include/sortix/termmode.h b/kernel/include/sortix/termmode.h index 9c7fd9d4..6f1d71c9 100644 --- a/kernel/include/sortix/termmode.h +++ b/kernel/include/sortix/termmode.h @@ -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 diff --git a/kernel/include/sortix/winsize.h b/kernel/include/sortix/winsize.h new file mode 100644 index 00000000..adf25b7d --- /dev/null +++ b/kernel/include/sortix/winsize.h @@ -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 . + + sortix/winsize.h + Defines values for termios. + +*******************************************************************************/ + +#ifndef INCLUDE_SORTIX_WINSIZE_H +#define INCLUDE_SORTIX_WINSIZE_H + +#include + +#include + +#ifndef __size_t_defined +#define __size_t_defined +#define __need_size_t +#include +#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 diff --git a/kernel/inode.cpp b/kernel/inode.cpp index dac70c15..b1f2d24d 100644 --- a/kernel/inode.cpp +++ b/kernel/inode.cpp @@ -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 diff --git a/kernel/io.cpp b/kernel/io.cpp index 3c57bd86..43cc8689 100644 --- a/kernel/io.cpp +++ b/kernel/io.cpp @@ -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 #include +#include #include #include #include @@ -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 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 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 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 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 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 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 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 desc = CurrentProcess()->GetDescriptor(fd); + if ( !desc ) + return -1; + ioctx_t ctx; SetupUserIOCtx(&ctx); + return desc->tcsetattr(&ctx, actions, tio); +} + } // namespace Sortix diff --git a/kernel/linebuffer.cpp b/kernel/linebuffer.cpp index 2003a314..13e9e056 100644 --- a/kernel/linebuffer.cpp +++ b/kernel/linebuffer.cpp @@ -138,4 +138,12 @@ bool LineBuffer::CanBackspace() const return bufferused - bufferfrozen; } +void LineBuffer::Flush() +{ + bufferoffset = 0; + buffercommitted = 0; + bufferfrozen = 0; + bufferused = 0; +} + } // namespace Sortix diff --git a/kernel/linebuffer.h b/kernel/linebuffer.h index 95ff1223..aa0e4550 100644 --- a/kernel/linebuffer.h +++ b/kernel/linebuffer.h @@ -46,6 +46,7 @@ public: void Freeze(); bool CanPop() const; bool CanBackspace() const; + void Flush(); private: uint32_t* buffer; diff --git a/kernel/logterminal.cpp b/kernel/logterminal.cpp index d15d0b12..b8e538e7 100644 --- a/kernel/logterminal.cpp +++ b/kernel/logterminal.cpp @@ -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 #include -#include -#include +#include #include +#include +#include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include #include @@ -49,18 +51,86 @@ #include #include #include +#include #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 diff --git a/kernel/logterminal.h b/kernel/logterminal.h index 2b128e2d..d7a4086f 100644 --- a/kernel/logterminal.h +++ b/kernel/logterminal.h @@ -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 + +#include + #include #include #include @@ -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; }; diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index b2dd8b88..796be46d 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -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, }; diff --git a/kernel/vnode.cpp b/kernel/vnode.cpp index 053482ca..733b657b 100644 --- a/kernel/vnode.cpp +++ b/kernel/vnode.cpp @@ -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 diff --git a/libc/Makefile b/libc/Makefile index 885a6eb6..5f9129da 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -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 \ diff --git a/libc/include/fsmarshall-msg.h b/libc/include/fsmarshall-msg.h index 0bd6344f..c54dfc35 100644 --- a/libc/include/fsmarshall-msg.h +++ b/libc/include/fsmarshall-msg.h @@ -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 #include #include +#include #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" */ diff --git a/libc/include/sys/ioctl.h b/libc/include/sys/ioctl.h index 135d4e83..afc4325b 100644 --- a/libc/include/sys/ioctl.h +++ b/libc/include/sys/ioctl.h @@ -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 +#include +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/libc/include/termios.h b/libc/include/termios.h index 3de39d0b..391a7273 100644 --- a/libc/include/termios.h +++ b/libc/include/termios.h @@ -31,12 +31,14 @@ #include -#if __USE_SORTIX #include +#if __USE_SORTIX +#include #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 #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); diff --git a/libc/sys/ioctl/ioctl.cpp b/libc/sys/ioctl/ioctl.cpp index c8e889cd..36bae922 100644 --- a/libc/sys/ioctl/ioctl.cpp +++ b/libc/sys/ioctl/ioctl.cpp @@ -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 #include +#include #include +#include -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); } diff --git a/libc/termios/cfgetispeed.cpp b/libc/termios/cfgetispeed.cpp new file mode 100644 index 00000000..bc897380 --- /dev/null +++ b/libc/termios/cfgetispeed.cpp @@ -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 . + + termios/cfgetispeed.cpp + Get termios input speed. + +*******************************************************************************/ + +#include + +extern "C" speed_t cfgetispeed(const struct termios* tio) +{ + return tio->c_ispeed; +} diff --git a/libc/termios/cfgetospeed.cpp b/libc/termios/cfgetospeed.cpp new file mode 100644 index 00000000..f2f7e305 --- /dev/null +++ b/libc/termios/cfgetospeed.cpp @@ -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 . + + termios/cfgetospeed.cpp + Get termios output speed. + +*******************************************************************************/ + +#include + +extern "C" speed_t cfgetospeed(const struct termios* tio) +{ + return tio->c_ospeed; +} diff --git a/libc/termios/cfsetispeed.cpp b/libc/termios/cfsetispeed.cpp new file mode 100644 index 00000000..4130e0a2 --- /dev/null +++ b/libc/termios/cfsetispeed.cpp @@ -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 . + + termios/cfsetispeed.cpp + Set termios input speed. + +*******************************************************************************/ + +#include + +extern "C" int cfsetispeed(struct termios* tio, speed_t speed) +{ + tio->c_ispeed = speed; + return 0; +} diff --git a/libc/termios/cfsetospeed.cpp b/libc/termios/cfsetospeed.cpp new file mode 100644 index 00000000..8ed87588 --- /dev/null +++ b/libc/termios/cfsetospeed.cpp @@ -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 . + + termios/cfsetospeed.cpp + Set termios output speed. + +*******************************************************************************/ + +#include + +extern "C" int cfsetospeed(struct termios* tio, speed_t speed) +{ + tio->c_ospeed = speed; + return 0; +} diff --git a/libc/termios/tcdrain.cpp b/libc/termios/tcdrain.cpp new file mode 100644 index 00000000..886dfff0 --- /dev/null +++ b/libc/termios/tcdrain.cpp @@ -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 . + + termios/tcdrain.cpp + Wait for transmission of output. + +*******************************************************************************/ + +#include + +#include + +DEFN_SYSCALL1(int, sys_tcdrain, SYSCALL_TCDRAIN, int); + +extern "C" int tcdrain(int fd) +{ + return sys_tcdrain(fd); +} diff --git a/libc/termios/tcflow.cpp b/libc/termios/tcflow.cpp new file mode 100644 index 00000000..c72f9ee4 --- /dev/null +++ b/libc/termios/tcflow.cpp @@ -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 . + + termios/tcflow.cpp + Suspend or restart the transmission or reception of data. + +*******************************************************************************/ + +#include + +#include + +DEFN_SYSCALL2(int, sys_tcflow, SYSCALL_TCFLOW, int, int); + +extern "C" int tcflow(int fd, int action) +{ + return sys_tcflow(fd, action); +} diff --git a/libc/termios/tcflush.cpp b/libc/termios/tcflush.cpp new file mode 100644 index 00000000..6a1c0fa6 --- /dev/null +++ b/libc/termios/tcflush.cpp @@ -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 . + + termios/tcflush.cpp + Flush non-transmitted output data, non-read input data, or both. + +*******************************************************************************/ + +#include + +#include + +DEFN_SYSCALL2(int, sys_tcflush, SYSCALL_TCFLUSH, int, int); + +extern "C" int tcflush(int fd, int queue_selector) +{ + return sys_tcflush(fd, queue_selector); +} diff --git a/libc/termios/tcgetattr.cpp b/libc/termios/tcgetattr.cpp new file mode 100644 index 00000000..b250cc3e --- /dev/null +++ b/libc/termios/tcgetattr.cpp @@ -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 . + + termios/tcgetattr.cpp + Get the parameters associated with the terminal. + +*******************************************************************************/ + +#include + +#include + +DEFN_SYSCALL2(int, sys_tcgetattr, SYSCALL_TCGETATTR, int, struct termios*); + +extern "C" int tcgetattr(int fd, struct termios* tio) +{ + return sys_tcgetattr(fd, tio); +} diff --git a/libc/termios/tcgetsid.cpp b/libc/termios/tcgetsid.cpp new file mode 100644 index 00000000..686ca8a6 --- /dev/null +++ b/libc/termios/tcgetsid.cpp @@ -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 . + + termios/tcgetsid.cpp + Get terminal session id. + +*******************************************************************************/ + +#include + +#include + +DEFN_SYSCALL1(int, sys_tcgetsid, SYSCALL_TCGETSID, int); + +extern "C" pid_t tcgetsid(int fd) +{ + return sys_tcgetsid(fd); +} diff --git a/libc/termios/tcsendbreak.cpp b/libc/termios/tcsendbreak.cpp new file mode 100644 index 00000000..f00b6620 --- /dev/null +++ b/libc/termios/tcsendbreak.cpp @@ -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 . + + termios/tcsendbreak.cpp + Send a break for a specific duration. + +*******************************************************************************/ + +#include + +#include + +DEFN_SYSCALL2(int, sys_tcsendbreak, SYSCALL_TCSENDBREAK, int, int); + +extern "C" int tcsendbreak(int fd, int duration) +{ + return sys_tcsendbreak(fd, duration); +} diff --git a/libc/termios/tcsetattr.cpp b/libc/termios/tcsetattr.cpp new file mode 100644 index 00000000..c2be4c31 --- /dev/null +++ b/libc/termios/tcsetattr.cpp @@ -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 . + + termios/tcsetattr.cpp + Set the parameters associated with the terminal. + +*******************************************************************************/ + +#include + +#include + +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); +} diff --git a/sh/editline.cpp b/sh/editline.cpp index 59cf522c..2b2058ff 100644 --- a/sh/editline.cpp +++ b/sh/editline.cpp @@ -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); } diff --git a/trianglix/trianglix.cpp b/trianglix/trianglix.cpp index fc52e4f8..14bbdcbd 100644 --- a/trianglix/trianglix.cpp +++ b/trianglix/trianglix.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -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;