support for line disciplines (TTY, PPP)

ttynvt now uses pseudoterminal (pty) to be able to get use of
the tty line disciplines.
Currently only the line discipline: TTY and PPP are supported.
This commit is contained in:
Frank Rolsted Jensen
2018-07-24 13:57:05 +02:00
parent 3cae838cf0
commit 7f4d2f3a51
2 changed files with 294 additions and 198 deletions
+267 -193
View File
@@ -19,6 +19,7 @@
#include <unistd.h>
#include <asm/termbits.h>
#include <linux/sockios.h>
#include <linux/ppp-ioctl.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
@@ -27,7 +28,12 @@
#include "telnet.h"
#define RX_BUF_SIZE 1024
#define NET_BUF_SIZE 1024
#define TMP_BUF_SIZE 1024
#define FD_NET 0
#define FD_SLAVE 1
#define FD_MASTER 2
#define _PRF_N_(no) __attribute__((__format__(__printf__, (no), (no) + 1)))
#define _PRF2_ _PRF_N_(2)
@@ -47,28 +53,24 @@ static struct ttynvt_param {
} ttynvt_param;
typedef struct {
int nonblock;
pthread_mutex_t tty_lock;
pthread_mutex_t poll_lock;
pthread_t thread_id;
pthread_cond_t cond;
struct fuse_pollhandle *ph;
struct pollfd fds[1];
struct pollfd fds[3];
struct termios tio;
unsigned char mcr;
char excl;
char buf[RX_BUF_SIZE];
size_t blen;
size_t rxcnt;
char net_buf[NET_BUF_SIZE];
size_t net_cnt;
char tmp_buf[TMP_BUF_SIZE];
int txbuf_size;
int epipe;
volatile sig_atomic_t error;
volatile sig_atomic_t pollin;
tn_ctx_t *tn;
} ttynvt_t;
@@ -97,6 +99,28 @@ _PRF2_ static void _log(int prio, const char *fmt, ...)
if (ttynvt_param.debug > 1) _log(LOG_DEBUG, __VA_ARGS__)
static void sig_handler(int sig)
{
}
static void set_signal_handler(void)
{
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = sig_handler;
sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
sigaction(SIGUSR2, &sa, NULL);
}
static void ttynvt_interrupted(fuse_req_t req, void *data)
{
pthread_t thread = (pthread_t) data;
pthread_kill(thread, SIGUSR2);
}
static int _check_dev(void)
{
int rc;
@@ -119,13 +143,14 @@ static void ttynvt_release(fuse_req_t req, struct fuse_file_info *info)
_log(LOG_INFO, "connection closed\n");
close(tty->fds[0].fd);
close(tty->fds[FD_NET].fd);
close(tty->fds[FD_MASTER].fd);
close(tty->fds[FD_SLAVE].fd);
(void)pthread_cancel(tty->thread_id);
(void)pthread_join(tty->thread_id, NULL);
(void)pthread_mutex_destroy(&tty->tty_lock);
(void)pthread_mutex_destroy(&tty->poll_lock);
(void)pthread_cond_destroy(&tty->cond);
if (tty->ph)
fuse_pollhandle_destroy(tty->ph);
@@ -145,7 +170,6 @@ static void _notify(ttynvt_t * tty)
tty->ph = NULL;
}
pthread_mutex_unlock(&tty->poll_lock);
pthread_cond_signal(&tty->cond);
}
static void _update_notify(ttynvt_t * tty, struct fuse_pollhandle *ph)
@@ -159,44 +183,16 @@ static void _update_notify(ttynvt_t * tty, struct fuse_pollhandle *ph)
fuse_pollhandle_destroy(tmp_ph);
}
static unsigned int _write_avail(ttynvt_t * tty)
{
size_t write_avail;
int used;
pthread_mutex_lock(&tty->tty_lock);
if (ioctl(tty->fds[0].fd, SIOCOUTQ, &used) < 0)
return 0;
write_avail = tty->txbuf_size - used;
pthread_mutex_unlock(&tty->tty_lock);
return write_avail;
}
static int _read_avail(ttynvt_t * tty)
{
int read_avail;
pthread_mutex_lock(&tty->tty_lock);
read_avail = tty->rxcnt;
pthread_mutex_unlock(&tty->tty_lock);
return read_avail;
}
static void *_read_net(void *arg)
{
ttynvt_t *tty = (ttynvt_t *) arg;
ssize_t res;
int tn_res = -1;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
while (1)
{
res = poll(tty->fds, 1, -1);
res = poll(tty->fds, 3, -1);
if (res < 0)
{
if (errno == EINTR)
@@ -204,48 +200,56 @@ static void *_read_net(void *arg)
else
break;
}
else if (tty->fds[0].revents & (POLLERR | POLLHUP | POLLNVAL))
else if (tty->fds[FD_NET].revents & (POLLERR | POLLHUP | POLLNVAL))
{
_log(LOG_ERR, "net io error\n");
break;
}
else if (tty->fds[0].revents & POLLIN)
else if (tty->fds[FD_NET].revents & POLLIN)
{
pthread_mutex_lock(&tty->tty_lock);
int read_avail = RX_BUF_SIZE - tty->blen;
if (read_avail == 0)
res = read(tty->fds[FD_NET].fd, tty->net_buf + tty->net_cnt,
NET_BUF_SIZE - tty->net_cnt);
if (res < 0)
{
/*buffer overflow */
tty->blen = 0;
read_avail = RX_BUF_SIZE;
_log(LOG_WARNING, "Rx buffer overflow\n");
}
res = read(tty->fds[0].fd, tty->buf + tty->blen, read_avail);
if (res <= 0)
{
pthread_mutex_unlock(&tty->tty_lock);
_log(LOG_ERR, "net read error: %s\n", strerror(errno));
break;
}
else
else if (res == 0)
{
tty->blen += res;
tn_res = telnet_rx(tty->tn, tty->buf, &tty->blen);
if (tn_res == 0)
_log(LOG_INFO, "Connection closed by remote host\n");
break;
}
tty->net_cnt += res;
res = telnet_rx(tty->tn, tty->net_buf, &tty->net_cnt);
if (tty->net_cnt > 0 && res == 0)
{
res =
write(tty->fds[FD_MASTER].fd, tty->net_buf, tty->net_cnt);
if (res < 0)
{
tty->rxcnt = tty->blen;
_notify(tty);
_log(LOG_ERR, "master write error:%s\n", strerror(errno));
break;
}
pthread_mutex_unlock(&tty->tty_lock);
tty->net_cnt = 0;
}
}
if (tty->fds[FD_MASTER].revents & POLLIN)
{
res = read(tty->fds[FD_MASTER].fd, tty->tmp_buf, TMP_BUF_SIZE);
if (res < 0)
{
_log(LOG_ERR, "master read error:%s\n", strerror(errno));
break;
}
telnet_tx(tty->tn, tty->tmp_buf, res);
}
if (tty->fds[FD_SLAVE].revents & POLLIN)
{
tty->pollin = 1;
_notify(tty);
}
}
if (res == 0)
_log(LOG_INFO, "Connection closed by remote host\n");
else
_log(LOG_ERR, "Rx read error:%s\n", strerror(errno));
tty->error = 1;
_notify(tty);
@@ -296,7 +300,7 @@ static int _srv_write(void *cctx, const void *buf, int len)
ttynvt_t *tty = cctx;
int res;
res = write(tty->fds[0].fd, buf, len);
res = write(tty->fds[FD_NET].fd, buf, len);
return res;
}
@@ -308,23 +312,20 @@ static int _srv_read(void *cctx, int timeout)
while (1)
{
res = poll(tty->fds, 1, timeout);
res = poll(&tty->fds[FD_NET], 1, timeout);
if (res <= 0)
return res;
if (tty->fds[0].revents & POLLIN)
if (tty->fds[FD_NET].revents & POLLIN)
{
res = read(tty->fds[0].fd, tty->buf + tty->blen,
RX_BUF_SIZE - tty->blen);
res = read(tty->fds[FD_NET].fd, tty->net_buf + tty->net_cnt,
NET_BUF_SIZE - tty->net_cnt);
if (res <= 0)
return res;
tty->blen += (size_t) res;
res = telnet_rx(tty->tn, tty->buf, &tty->blen);
tty->net_cnt += (size_t) res;
res = telnet_rx(tty->tn, tty->net_buf, &tty->net_cnt);
if (res == 0)
{
tty->rxcnt = tty->blen;
break;
}
}
}
return 1;
@@ -334,9 +335,14 @@ static void _modem_status_cb(void *cctx, int status)
{
ttynvt_t *tty = cctx;
tty->mcr &= ~(TIOCM_CD | TIOCM_RI | TIOCM_CTS | TIOCM_DSR);
DBG("MCR: DSR=%c CTS=%c RI=%c CD=%c\n",
status & TNS_STATE_DSR ? '1' : '0',
status & TNS_STATE_CTS ? '1' : '0',
status & TNS_STATE_RI ? '1' : '0', status & TNS_STATE_CD ? '1' : '0');
_log(LOG_INFO, "Modem status: 0x%02x\n", status);
pthread_mutex_lock(&tty->tty_lock);
tty->mcr &= ~(TIOCM_CD | TIOCM_RI | TIOCM_CTS | TIOCM_DSR);
if (status & TNS_STATE_CD)
tty->mcr |= TIOCM_CD;
@@ -346,14 +352,26 @@ static void _modem_status_cb(void *cctx, int status)
tty->mcr |= TIOCM_CTS;
if (status & TNS_STATE_DSR)
tty->mcr |= TIOCM_DSR;
pthread_mutex_unlock(&tty->tty_lock);
}
static void ttynvt_init(void *userdata, struct fuse_conn_info *conn)
{
set_signal_handler();
}
static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
{
ttynvt_t *tty;
socklen_t len;
char *slave_name;
struct termios ios;
int sockfd;
int fd;
int res;
int n;
DBG2("open: thread:%lu\n", pthread_self());
tty = calloc(1, sizeof(*tty));
if (!tty)
@@ -361,6 +379,8 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
fuse_reply_err(req, ENOMEM);
return;
}
for (n = 0; n < 3; n++)
tty->fds[n].fd = -1;
tty->tn = telnet_ctx_init(tty, _srv_write, _srv_read, _modem_status_cb);
if (!tty->tn)
@@ -375,52 +395,77 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
{
free(tty->tn);
free(tty);
fuse_reply_err(req, EFAULT);
fuse_reply_err(req, EHOSTUNREACH);
return;
}
tty->fds[0].fd = sockfd;
tty->fds[0].events = POLLIN;
tty->blen = 0;
tty->rxcnt = 0;
tty->fds[FD_NET].fd = sockfd;
tty->fds[FD_NET].events = POLLIN;
tty->net_cnt = 0;
if ((fd = open("/dev/ptmx", O_RDWR)) < 0) /* open master */
goto open_err;
tty->fds[FD_MASTER].fd = fd;
tty->fds[FD_MASTER].events = POLLIN;
ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
ios.c_oflag &= ~OPOST;
ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
ios.c_cflag &= ~(CSIZE | PARENB);
ios.c_cflag |= CS8;
if (ioctl(fd, TCSETS, &ios) < 0)
goto open_err;
grantpt(fd); /* change permission of slave */
unlockpt(fd); /* unlock slave */
slave_name = ptsname(fd); /* get name of slave */
if ((fd = open(slave_name, O_RDWR | O_NOCTTY)) < 0) /* open slave */
goto open_err;
tty->fds[FD_SLAVE].fd = fd;
tty->fds[FD_SLAVE].events = POLLIN;
res = telnet_open(tty->tn);
if (res < 0)
{
free(tty->tn);
free(tty);
fuse_reply_err(req, EBADE);
return;
errno = EPROTO;
goto open_err;
}
len = sizeof(tty->txbuf_size);
if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &tty->txbuf_size, &len) < 0)
if ((res = pthread_mutex_init(&tty->tty_lock, NULL) < 0) ||
(res = pthread_mutex_init(&tty->poll_lock, NULL) < 0) ||
(res = pthread_create(&tty->thread_id, NULL, &_read_net, tty)))
{
free(tty->tn);
free(tty);
fuse_reply_err(req, EIO);
return;
}
if (pthread_mutex_init(&tty->tty_lock, NULL) < 0 ||
pthread_mutex_init(&tty->poll_lock, NULL) < 0 ||
pthread_cond_init(&tty->cond, NULL) < 0 ||
pthread_create(&tty->thread_id, NULL, &_read_net, tty))
{
free(tty->tn);
free(tty);
fuse_reply_err(req, ENOMEM);
return;
errno = res;
goto open_err;
}
info->fh = (uintptr_t) tty;
info->nonseekable = 1;
info->direct_io = 1;
_log(LOG_INFO, "Open connection to server: %s:%d\n",
_log(LOG_INFO, "Connected to server: %s:%d\n",
ttynvt_param.host, ttynvt_param.port);
fuse_reply_open(req, info);
return;
open_err:
_log(LOG_INFO, "Connection to server: %s:%d failed:%s\n",
ttynvt_param.host, ttynvt_param.port, strerror(errno));
for (n = 0; n < 3; n++)
if (tty->fds[n].fd >= 0)
close(tty->fds[n].fd);
free(tty->tn);
free(tty);
fuse_reply_err(req, errno);
}
static void
@@ -428,14 +473,16 @@ ttynvt_read(fuse_req_t req, size_t size, off_t off,
struct fuse_file_info *info)
{
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
ssize_t res;
if (tty->error)
{
DBG2("read (slave) in error state, thread:%lu\n", pthread_self());
if (tty->epipe == 0)
{
_log(LOG_WARNING, "Rx EPIPE\n");
tty->epipe = 1;
fuse_reply_buf(req, tty->buf, 0);
fuse_reply_buf(req, tty->tmp_buf, 0);
}
else
fuse_reply_err(req, EBADFD);
@@ -443,34 +490,31 @@ ttynvt_read(fuse_req_t req, size_t size, off_t off,
return;
}
pthread_mutex_lock(&tty->tty_lock);
if (tty->rxcnt == 0 && !(info->flags & O_NONBLOCK))
if (size > TMP_BUF_SIZE)
size = TMP_BUF_SIZE;
fuse_req_interrupt_func(req, ttynvt_interrupted, (void *)pthread_self());
res = read(tty->fds[FD_SLAVE].fd, tty->tmp_buf, size);
fuse_req_interrupt_func(req, NULL, NULL);
if (res < 0)
{
pthread_cond_wait(&tty->cond, &tty->tty_lock);
DBG2("read (slave) error: %s\n", strerror(errno));
fuse_reply_err(req, errno);
return;
}
if (size > tty->rxcnt)
size = tty->rxcnt;
if (size > 0)
{
fuse_reply_buf(req, tty->buf, size);
memmove(tty->buf, tty->buf + size, tty->blen - size);
tty->blen -= size;
tty->rxcnt -= size;
}
else
{
fuse_reply_err(req, EINTR);
}
pthread_mutex_unlock(&tty->tty_lock);
DBG2("read (slave): size:%ld, thread:%lu\n", res, pthread_self());
fuse_reply_buf(req, tty->tmp_buf, res);
}
static void
ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
struct fuse_file_info *info)
{
int res;
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
ssize_t res;
if (size == 0)
{
@@ -484,30 +528,18 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
return;
}
if (tty->nonblock || (info->flags & O_NONBLOCK))
{
size_t write_avail = _write_avail(tty);
if (size > write_avail)
size = write_avail;
}
res = telnet_tx(tty->tn, data, size);
res = write(tty->fds[FD_SLAVE].fd, data, size);
if (res < 0)
{
DBG2("write (slave) error: %s\n", strerror(errno));
tty->error = 1;
fuse_reply_err(req, EPIPE);
fuse_reply_err(req, errno);
return;
}
#if 0
else if (res == 0)
{
fuse_reply_err(req, EAGAIN);
return;
}
#endif
fuse_reply_write(req, size);
DBG2("write (slave): size:%ld, thread:%lu\n", size, pthread_self());
fuse_reply_write(req, res);
}
static int baudrate(speed_t speed)
@@ -557,6 +589,7 @@ static const char *_ioctl_name(int cmd)
CASE(TIOCMSET);
CASE(TCSBRK);
CASE(TIOCGWINSZ);
CASE(TIOCSWINSZ);
/* Exclusive mode */
CASE(TIOCEXCL);
CASE(TIOCGEXCL);
@@ -564,6 +597,8 @@ static const char *_ioctl_name(int cmd)
/* Line discipline */
CASE(TIOCGETD);
CASE(TIOCSETD);
/*PPP support */
CASE(PPPIOCGCHAN);
}
}
@@ -578,12 +613,13 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
const void *in_buf, size_t in_bufsz, size_t out_bufsz)
{
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
struct winsize ws;
unsigned int tiocm = 0;
static unsigned int mcr = 0;
static struct termios tio = {
.c_cflag = B115200 | CS8 | PARODD | CREAD | CLOCAL,
};
int val;
int res;
DBG("%s: cmd=%s arg=%p ibuf=%p:%u obuf=:%u\n", __func__,
_ioctl_name(cmd), arg, in_buf,
@@ -641,19 +677,24 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
if (tio.c_cflag & CRTSCTS)
telnet_rfc2217_ctl(tty->tn, TNS_CTL_CTSRTS);
if (!(mcr & TIOCM_DTR) && speed != B0)
#if 1
pthread_mutex_lock(&tty->tty_lock);
if (!(tty->mcr & TIOCM_DTR) && speed != B0)
{
mcr |= TIOCM_DTR;
tty->mcr |= TIOCM_DTR;
telnet_rfc2217_ctl(tty->tn, TNS_CTL_DTR_ON);
}
DBG("CFG ioctl: %u%c%u%u %cCTSRTS %cCREAD %cHUPCL %cCLOCAL\n",
pthread_mutex_unlock(&tty->tty_lock);
#endif
DBG("termios: %u%c%u%u %cCTSRTS %cCREAD %cHUPCL %cCLOCAL\n",
baudrate(speed), pstr[par], csize, sb,
tio.c_cflag & CRTSCTS ? '+' : '-',
tio.c_cflag & CREAD ? '+' : '-',
tio.c_cflag & HUPCL ? '+' : '-',
tio.c_cflag & CLOCAL ? '+' : '-');
ioctl(tty->fds[FD_SLAVE].fd, cmd, &tio);
fuse_reply_ioctl(req, 0, 0, 0);
}
break;
@@ -664,13 +705,13 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
case TIOCINQ: /* Get the number of bytes in the input
* buffer */
CHECK_BUF_OUT(sizeof(int));
val = _read_avail(tty);
ioctl(tty->fds[FD_SLAVE].fd, TIOCINQ, &val);
fuse_reply_ioctl(req, 0, &val, sizeof(int));
break;
case TIOCOUTQ: /* Get the number of bytes in the output
* buffer */
CHECK_BUF_OUT(sizeof(int));
val = _write_avail(tty);
ioctl(tty->fds[FD_SLAVE].fd, TIOCOUTQ, &val);
fuse_reply_ioctl(req, 0, &val, sizeof(int));
break;
case TCFLSH:
@@ -691,9 +732,6 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
case TCIFLUSH:
val = 1;
telnet_rfc2217_cfg(tty->tn, TNS_SET_PURGE, &val, 1);
pthread_mutex_lock(&tty->tty_lock);
tty->blen = 0;
pthread_mutex_unlock(&tty->tty_lock);
fuse_reply_ioctl(req, 0, 0, 0);
break;
case TCOFLUSH:
@@ -708,88 +746,128 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
break;
case TIOCMGET:
CHECK_BUF_OUT(sizeof(int));
fuse_reply_ioctl(req, 0, &mcr, sizeof(int));
pthread_mutex_lock(&tty->tty_lock);
fuse_reply_ioctl(req, 0, &tty->mcr, sizeof(int));
pthread_mutex_unlock(&tty->tty_lock);
break;
case TIOCMBIS:
CHECK_BUF_IN(sizeof(int));
tiocm = *(unsigned int *)in_buf;
fuse_reply_ioctl(req, 0, 0, 0);
DBG("%s: cmd=%s tiocm=%#x\n", __func__, _ioctl_name(cmd), tiocm);
pthread_mutex_lock(&tty->tty_lock);
if (tiocm & TIOCM_RTS)
{
mcr |= TIOCM_RTS;
tty->mcr |= TIOCM_RTS;
telnet_rfc2217_ctl(tty->tn, TNS_CTL_RTS_ON);
}
if (tiocm & TIOCM_DTR)
{
mcr |= TIOCM_DTR;
tty->mcr |= TIOCM_DTR;
telnet_rfc2217_ctl(tty->tn, TNS_CTL_DTR_ON);
}
pthread_mutex_unlock(&tty->tty_lock);
goto show_mctl;
case TIOCMBIC:
CHECK_BUF_IN(sizeof(int));
tiocm = *(unsigned int *)in_buf;
fuse_reply_ioctl(req, 0, 0, 0);
DBG("%s: cmd=%s tiocm=%#x\n", __func__, _ioctl_name(cmd), tiocm);
pthread_mutex_lock(&tty->tty_lock);
if (tiocm & TIOCM_RTS)
{
mcr &= ~TIOCM_RTS;
tty->mcr &= ~TIOCM_RTS;
telnet_rfc2217_ctl(tty->tn, TNS_CTL_RTS_OFF);
}
if (tiocm & TIOCM_DTR)
{
mcr &= ~TIOCM_DTR;
tty->mcr &= ~TIOCM_DTR;
telnet_rfc2217_ctl(tty->tn, TNS_CTL_DTR_OFF);
}
pthread_mutex_unlock(&tty->tty_lock);
goto show_mctl;
case TIOCMSET:
CHECK_BUF_IN(sizeof(int));
tiocm = *(unsigned int *)in_buf;
fuse_reply_ioctl(req, 0, 0, 0);
DBG("%s: cmd=%s tiocm=%#x\n", __func__, _ioctl_name(cmd), tiocm);
mcr &= ~(TIOCM_RTS | TIOCM_DTR);
mcr |= tiocm & (TIOCM_RTS | TIOCM_DTR);
pthread_mutex_lock(&tty->tty_lock);
tty->mcr &= ~(TIOCM_RTS | TIOCM_DTR);
tty->mcr |= tiocm & (TIOCM_RTS | TIOCM_DTR);
telnet_rfc2217_ctl(tty->tn, (tiocm & TIOCM_DTR) ?
TNS_CTL_DTR_ON : TNS_CTL_DTR_OFF);
telnet_rfc2217_ctl(tty->tn, (tiocm & TIOCM_RTS) ?
TNS_CTL_RTS_ON : TNS_CTL_RTS_OFF);
pthread_mutex_unlock(&tty->tty_lock);
goto show_mctl;
show_mctl:
DBG("CFG ioctl: DTR=%c RTS=%c\n",
mcr & TIOCM_DTR ? '1' : '0', mcr & TIOCM_RTS ? '1' : '0');
DBG("MCR: DTR=%c RTS=%c\n",
tty->mcr & TIOCM_DTR ? '1' : '0',
tty->mcr & TIOCM_RTS ? '1' : '0');
break;
case TCSBRK:
fuse_reply_ioctl(req, 0, 0, 0);
break;
case TIOCGWINSZ:
CHECK_BUF_OUT(sizeof(struct winsize));
res = ioctl(tty->fds[FD_SLAVE].fd, TIOCGWINSZ, &ws);
if (res < 0)
{
struct winsize ws = {.ws_row = 25,.ws_col = 80 };
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
fuse_reply_err(req, errno);
return;
}
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
break;
case TIOCSWINSZ:
CHECK_BUF_IN(sizeof(struct winsize));
ws = *(struct winsize *)in_buf;
res = ioctl(tty->fds[FD_SLAVE].fd, TIOCSWINSZ, &ws);
if (res < 0)
{
fuse_reply_err(req, errno);
return;
}
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
break;
case TIOCEXCL:
if (tty->excl)
{
fuse_reply_err(req, EBUSY);
}
else
{
tty->excl = 1;
fuse_reply_ioctl(req, 0, 0, 0);
}
ioctl(tty->fds[FD_SLAVE].fd, TIOCEXCL, NULL);
fuse_reply_ioctl(req, 0, 0, 0);
break;
case TIOCGEXCL:
CHECK_BUF_OUT(sizeof(int));
val = tty->excl;
ioctl(tty->fds[FD_SLAVE].fd, TIOCGEXCL, &val);
fuse_reply_ioctl(req, 0, &val, sizeof(int));
break;
case TIOCNXCL:
tty->excl = 0;
ioctl(tty->fds[FD_SLAVE].fd, TIOCNXCL, NULL);
fuse_reply_ioctl(req, 0, 0, 0);
break;
case TIOCSETD:
CHECK_BUF_IN(sizeof(int));
val = *(int *)in_buf;
res = ioctl(tty->fds[FD_SLAVE].fd, TIOCSETD, &val);
if (res < 0)
fuse_reply_err(req, errno);
else
fuse_reply_ioctl(req, 0, 0, 0);
break;
case TIOCGETD:
CHECK_BUF_OUT(sizeof(int));
res = ioctl(tty->fds[FD_SLAVE].fd, TIOCGETD, &val);
if (res < 0)
fuse_reply_err(req, errno);
else
fuse_reply_ioctl(req, 0, &val, sizeof(int));
break;
case PPPIOCGCHAN:
CHECK_BUF_OUT(sizeof(int));
res = ioctl(tty->fds[FD_SLAVE].fd, PPPIOCGCHAN, &val);
if (res < 0)
fuse_reply_err(req, errno);
else
fuse_reply_ioctl(req, 0, &val, sizeof(int));
break;
default:
fuse_reply_err(req, ENOSYS);
break;
@@ -819,12 +897,11 @@ ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
_update_notify(tty, ph);
if (_write_avail(tty) > 0)
revents |= POLLOUT;
if (_read_avail(tty) > 0)
if (tty->pollin)
{
tty->pollin = 0;
revents |= POLLIN;
}
if (tty->error)
{
if (tty->epipe == 0)
@@ -837,12 +914,9 @@ ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
}
static const struct cuse_lowlevel_ops ttynvt_op = {
.open = ttynvt_open,
.read = ttynvt_read,
.write = ttynvt_write,
.ioctl = ttynvt_ioctl,
.poll = ttynvt_poll,
.release = ttynvt_release,
.init = ttynvt_init,
.open = ttynvt_open,.read = ttynvt_read,.write = ttynvt_write,.ioctl =
ttynvt_ioctl,.poll = ttynvt_poll,.release = ttynvt_release,
};
#define TTYNET_OPT(t, p, v) { t, offsetof(struct ttynvt_param, p), v }