toaruos/kernel/fs/tty.c

234 lines
5.8 KiB
C
Raw Normal View History

2013-03-18 03:34:23 +04:00
#include <system.h>
#include <fs.h>
#include <pipe.h>
#include <logging.h>
#include <ioctl.h>
2013-03-18 11:52:12 +04:00
#include <termios.h>
2013-04-03 10:02:43 +04:00
#include <ringbuffer.h>
2013-03-18 11:52:12 +04:00
2013-03-18 03:34:23 +04:00
#define TTY_BUFFER_SIZE 512
2013-03-18 11:52:12 +04:00
#define M_ICANON 0x01
#define M_RAW 0x02
#define M_RRAW 0x04
2013-03-18 03:34:23 +04:00
typedef struct pty {
2013-03-18 11:52:12 +04:00
/* the PTY number */
2013-03-18 03:34:23 +04:00
int name;
2013-03-18 11:52:12 +04:00
/* Master and slave endpoints */
2013-03-18 03:34:23 +04:00
fs_node_t * master;
fs_node_t * slave;
2013-03-18 11:52:12 +04:00
/* term io "window size" struct (width/height) */
2013-03-18 03:34:23 +04:00
struct winsize size;
2013-03-18 11:52:12 +04:00
/* termios data structure */
struct termios tios;
/* directional pipes */
2013-04-03 10:02:43 +04:00
ring_buffer_t * in;
ring_buffer_t * out;
2013-03-18 11:52:12 +04:00
/* line discipline modes */
unsigned char mode;
pid_t ct_proc; /* Controlling process (shell) */
pid_t fg_proc; /* Foreground process (might also be shell) */
2013-03-18 03:34:23 +04:00
} pty_t;
list_t * pty_list = NULL;
2013-03-19 10:57:40 +04:00
int pty_ioctl(pty_t * pty, int request, void * argp) {
debug_print(WARNING, "Incoming IOCTL request %d", request);
switch (request) {
case IOCTLDTYPE:
/*
* This is a special toaru-specific call to get a simple
* integer that describes the kind of device this is.
* It's more specific than just "character device" or "file",
* but for here we just need to say we're a TTY.
*/
return IOCTL_DTYPE_TTY;
2013-03-19 10:57:40 +04:00
case TIOCSWINSZ:
2013-04-03 05:06:06 +04:00
if (!argp) return -1;
validate(argp);
2013-03-19 10:57:40 +04:00
memcpy(&pty->size, argp, sizeof(struct winsize));
/* TODO send sigwinch to fg_prog */
return 0;
case TIOCGWINSZ:
2013-04-03 05:06:06 +04:00
if (!argp) return -1;
validate(argp);
2013-03-19 10:57:40 +04:00
memcpy(argp, &pty->size, sizeof(struct winsize));
return 0;
default:
return -1; /* TODO EINV... something or other */
}
return -1;
}
2013-03-18 03:34:23 +04:00
uint32_t read_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
2013-03-26 08:48:16 +04:00
pty_t * pty = (pty_t *)node->device;
2013-03-18 03:34:23 +04:00
/* Standard pipe read */
2013-04-03 10:02:43 +04:00
return ring_buffer_read(pty->out, size, buffer);
2013-03-18 03:34:23 +04:00
}
uint32_t write_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
2013-03-26 08:48:16 +04:00
pty_t * pty = (pty_t *)node->device;
2013-03-18 03:34:23 +04:00
2013-04-03 10:02:43 +04:00
/* XXX process special sequences and implement line discipline */
return ring_buffer_write(pty->in, size, buffer);
2013-03-18 03:34:23 +04:00
}
void open_pty_master(fs_node_t * node, unsigned int flags) {
2013-03-18 03:34:23 +04:00
return;
}
void close_pty_master(fs_node_t * node) {
return;
}
uint32_t read_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
2013-03-26 08:48:16 +04:00
pty_t * pty = (pty_t *)node->device;
2013-03-18 03:34:23 +04:00
2013-04-03 10:02:43 +04:00
return ring_buffer_read(pty->in, size, buffer);
2013-03-18 03:34:23 +04:00
}
uint32_t write_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) {
2013-03-26 08:48:16 +04:00
pty_t * pty = (pty_t *)node->device;
2013-03-18 03:34:23 +04:00
2013-04-03 10:02:43 +04:00
return ring_buffer_write(pty->out, size, buffer);
2013-03-18 03:34:23 +04:00
}
void open_pty_slave(fs_node_t * node, unsigned int flags) {
2013-03-18 03:34:23 +04:00
return;
}
void close_pty_slave(fs_node_t * node) {
return;
}
2013-03-19 10:57:40 +04:00
/*
* These are separate functions just in case I ever feel the need to do
* things differently in the slave or master.
*/
int ioctl_pty_master(fs_node_t * node, int request, void * argp) {
2013-03-26 08:48:16 +04:00
pty_t * pty = (pty_t *)node->device;
2013-03-19 10:57:40 +04:00
return pty_ioctl(pty, request, argp);
}
int ioctl_pty_slave(fs_node_t * node, int request, void * argp) {
2013-03-26 08:48:16 +04:00
pty_t * pty = (pty_t *)node->device;
2013-03-19 10:57:40 +04:00
return pty_ioctl(pty, request, argp);
}
2013-03-22 22:58:22 +04:00
int pty_available_input(fs_node_t * node) {
2013-03-26 08:48:16 +04:00
pty_t * pty = (pty_t *)node->device;
2013-04-03 10:02:43 +04:00
return ring_buffer_unread(pty->in);
2013-03-22 22:58:22 +04:00
}
int pty_available_output(fs_node_t * node) {
2013-03-26 08:48:16 +04:00
pty_t * pty = (pty_t *)node->device;
2013-04-03 10:02:43 +04:00
return ring_buffer_unread(pty->out);
2013-03-22 22:58:22 +04:00
}
2013-03-18 03:34:23 +04:00
fs_node_t * pty_master_create(pty_t * pty) {
fs_node_t * fnode = malloc(sizeof(fs_node_t));
memset(fnode, 0x00, sizeof(fs_node_t));
fnode->name[0] = '\0';
sprintf(fnode->name, "pty master");
fnode->uid = 0;
fnode->gid = 0;
fnode->flags = FS_PIPE;
fnode->read = read_pty_master;
fnode->write = write_pty_master;
fnode->open = open_pty_master;
fnode->close = close_pty_master;
fnode->readdir = NULL;
fnode->finddir = NULL;
2013-03-19 10:57:40 +04:00
fnode->ioctl = ioctl_pty_master;
2013-03-22 22:58:22 +04:00
fnode->get_size = pty_available_output;
2013-03-18 03:34:23 +04:00
2013-03-26 08:48:16 +04:00
fnode->device = pty;
2013-03-18 03:34:23 +04:00
return fnode;
}
fs_node_t * pty_slave_create(pty_t * pty) {
fs_node_t * fnode = malloc(sizeof(fs_node_t));
memset(fnode, 0x00, sizeof(fs_node_t));
fnode->name[0] = '\0';
sprintf(fnode->name, "pty slave");
fnode->uid = 0;
fnode->gid = 0;
fnode->flags = FS_PIPE;
fnode->read = read_pty_slave;
fnode->write = write_pty_slave;
fnode->open = open_pty_slave;
fnode->close = close_pty_slave;
fnode->readdir = NULL;
fnode->finddir = NULL;
2013-03-19 10:57:40 +04:00
fnode->ioctl = ioctl_pty_slave;
2013-03-22 22:58:22 +04:00
fnode->get_size = pty_available_input;
2013-03-18 03:34:23 +04:00
2013-03-26 08:48:16 +04:00
fnode->device = pty;
2013-03-18 03:34:23 +04:00
return fnode;
}
void pty_install(void) {
pty_list = list_create();
}
pty_t * pty_new(struct winsize * size) {
pty_t * pty = malloc(sizeof(pty_t));
2013-03-18 11:52:12 +04:00
/* stdin linkage; characters from terminal → PTY slave */
2013-04-03 10:02:43 +04:00
pty->in = ring_buffer_create(TTY_BUFFER_SIZE);
pty->out = ring_buffer_create(TTY_BUFFER_SIZE);
2013-03-18 03:34:23 +04:00
2013-03-18 11:52:12 +04:00
/* Master endpoint - writes go to stdin, reads come from stdout */
2013-03-18 03:34:23 +04:00
pty->master = pty_master_create(pty);
2013-03-18 11:52:12 +04:00
/* Slave endpoint, reads come from stdin, writes go to stdout */
2013-03-18 03:34:23 +04:00
pty->slave = pty_slave_create(pty);
2013-03-18 11:52:12 +04:00
/* TODO PTY name */
pty->name = 0;
2013-03-18 03:34:23 +04:00
if (size) {
memcpy(&pty->size, size, sizeof(struct winsize));
} else {
/* Sane defaults */
2013-03-18 11:52:12 +04:00
pty->size.ws_row = 25;
pty->size.ws_col = 80;
2013-03-18 03:34:23 +04:00
}
2013-03-18 11:52:12 +04:00
/* tty mode (cooked, raw, etc.) */
pty->mode = M_ICANON;
/* Controlling and foreground processes are set to 0 by default */
pty->ct_proc = 0;
pty->fg_proc = 0;
2013-03-18 03:34:23 +04:00
return pty;
}
int openpty(int * master, int * slave, char * name, void * _ign0, void * size) {
2013-03-18 11:52:12 +04:00
/* We require a place to put these when we are done. */
2013-03-18 03:34:23 +04:00
if (!master || !slave) return -1;
2013-03-18 11:52:12 +04:00
if (validate_safe(master) || validate_safe(slave)) return -1;
if (validate_safe(size)) return -1;
2013-03-18 03:34:23 +04:00
2013-03-18 11:52:12 +04:00
/* Create a new pseudo terminal */
2013-03-18 03:34:23 +04:00
pty_t * pty = pty_new(size);
2013-03-18 11:52:12 +04:00
/* Append the master and slave to the calling process */
2013-03-18 03:34:23 +04:00
*master = process_append_fd((process_t *)current_process, pty->master);
*slave = process_append_fd((process_t *)current_process, pty->slave);
2013-03-18 11:52:12 +04:00
/* Return success */
2013-03-18 03:34:23 +04:00
return 0;
}