21 Commits

Author SHA1 Message Date
Kim Woelders 85394b243e ttynvt version 0.12 2018-10-17 14:53:59 +02:00
Kim Woelders 673ddd9739 Fix RFC2217 server death
We now properly kick the connected clients hanging in reads (cu) instead
of locking up.
2018-10-17 13:51:55 +02:00
Kim Woelders 1e05632ec0 Eliminate ttynvt_t::tmp_buf
ttynvt_read() and _read_net() both used this buffer which could cause
things to mess up entirely.
2018-10-17 11:15:00 +02:00
Kim Woelders 86aebe372e Add TIOCSCTTY/TIOCNOTTY name decoding 2018-10-17 08:11:46 +02:00
Kim Woelders 71de4b1ab4 Set RTS if CRTSCTS is set 2018-10-17 08:11:46 +02:00
Kim Woelders a05b17f142 Properly exit on SIGTERM
Previously we could get hung when killed, e.g. when using cu.
When using minicom or screen this problem did not seem to occur.
2018-10-17 08:11:46 +02:00
Kim Woelders ef3d01556e Properly initialize termios struct before use in ttynvt_open() 2018-10-17 08:11:46 +02:00
Kim Woelders 2fe0428d92 Use struct termios in ttynvt_t and drop static one.
Also set termios on pty slave on init.
2018-10-17 08:11:03 +02:00
Kim Woelders af3c3d4162 Always set POLLOUT on slave poll 2018-10-17 08:11:03 +02:00
Kim Woelders 540ddd5659 Fix polling of pty slave 2018-10-17 08:11:03 +02:00
Kim Woelders 6dc40e44e2 Enable debug logging data too 2018-10-17 08:11:03 +02:00
Kim Woelders 08e7fb1d7e More debug 2018-10-17 08:11:03 +02:00
Kim Woelders d85251400f Optionally print debug to stdout 2018-10-17 08:11:03 +02:00
Kim Woelders e8913f62af Logging cleanups
- Consistently use %m instead of strerror(errno)
- Add some missing \n's
2018-10-17 08:11:03 +02:00
Kim Woelders 44ddf67386 Avoid (s)size_t for portability 2018-10-17 08:11:03 +02:00
Kim Woelders 2d993212c5 Cosmetics 2018-10-17 08:11:03 +02:00
Kim Woelders 00430e5f64 ttynvt version 0.11 2018-10-04 09:38:24 +02:00
Kim Woelders 1ded3b11d2 ICS-664: Fix "cu problem"
In ttynvt_read(), the "interrupted" signal may be delivered after
installing the handler (fuse_req_interrupt_func()) but before calling
read().
If this happens the signal intended to be delivered while in the read()
function call (SIGUSR2) is handled before the read(), and we may hang
indefinitely.
2018-10-04 09:32:02 +02:00
Kim Woelders bf21ada8c7 Indent 2018-10-03 15:06:52 +02:00
Frank Rolsted Jensen e68e140ef0 ttynvt version 0.10 2018-09-12 14:04:23 +02:00
Frank Rolsted Jensen 02a2149c1f Add LICENSE 2018-06-07 11:37:24 +00:00
4 changed files with 184 additions and 78 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
m4_define([pkg_version], [0.10])
m4_define([pkg_version], [0.12])
#m4_define([pkg_revision], [005])
m4_define([pkg_version], m4_ifdef([pkg_revision], [pkg_version.pkg_revision], [pkg_version]))
+1 -1
View File
@@ -31,7 +31,7 @@ extern tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f * ftx, srv_rx_f * frx,
extern int telnet_open(tn_ctx_t * tcc);
extern int telnet_rx(tn_ctx_t * tcc, char *buf, size_t * plen);
extern int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen);
extern int telnet_tx(tn_ctx_t * tcc, const char *buf, int len);
extern void telnet_set_opt(tn_ctx_t * tcc, int opt, int prm,
+3 -3
View File
@@ -121,18 +121,18 @@ static void _telnet_handle_opt(tn_ctx_t * tcc, int opt,
}
}
int telnet_rx(tn_ctx_t * tcc, char *buf, size_t * plen)
int telnet_rx(tn_ctx_t * tcc, char *buf, int *plen)
{
char *s, *p;
unsigned char *pu;
size_t len, rem;
int len, rem;
int np, nd;
int b1, b2;
len = *plen;
tcc->bytes_rx += len;
if (len < (size_t) tcc->off_rx)
if (len < (int)tcc->off_rx)
tcc->off_rx = 0;
for (s = buf + tcc->off_rx, rem = len - tcc->off_rx; rem > 0; s = p)
+177 -71
View File
@@ -32,8 +32,8 @@
#define TMP_BUF_SIZE 1024
#define FD_NET 0
#define FD_SLAVE 1
#define FD_MASTER 2
#define FD_MASTER 1
#define FD_SLAVE 2
#define _PRF_N_(no) __attribute__((__format__(__printf__, (no), (no) + 1)))
#define _PRF2_ _PRF_N_(2)
@@ -45,6 +45,7 @@ static struct ttynvt_param {
const char *dev_name;
char *server;
unsigned int debug;
int logstd;
/* Derived */
char host[64];
unsigned int port;
@@ -55,23 +56,25 @@ static struct ttynvt_param {
typedef struct {
pthread_mutex_t tty_lock;
pthread_mutex_t poll_lock;
pthread_t thread_id;
pthread_t ptid_poll;
pthread_t ptid_read;
struct fuse_pollhandle *ph;
volatile char n_fds;
struct pollfd fds[3];
char net_buf[NET_BUF_SIZE];
size_t net_cnt;
char tmp_buf[TMP_BUF_SIZE];
int net_cnt;
struct termios tio;
int cmcr;
int epipe;
int cmcr;
volatile int smcr;
volatile int error;
volatile int pollin;
volatile int error;
int epipe;
tn_ctx_t *tn;
} ttynvt_t;
@@ -85,23 +88,57 @@ _PRF2_ static void _log(int prio, const char *fmt, ...)
char buf[256];
va_start(arg, fmt);
#if 0
vsyslog(prio, fmt, arg);
#else
vsnprintf(buf, sizeof(buf), fmt, arg);
if (ttynvt_param.logstd)
printf("[%d] %d: %s", gettid(), prio, buf);
else
syslog(prio, "[%d] %s", gettid(), buf);
#endif
va_end(arg);
}
#define BPL 16 /* Bytes per line */
void _log_buf(int prio, const char *txt, const void *ptr_, unsigned int len)
{
unsigned int ix, i, imax;
int l, n;
char buf[128];
const unsigned char *ptr = ptr_;
for (ix = 0; ix < len || (len == 0 && ix == 0); ix += BPL)
{
n = snprintf(buf, sizeof(buf), "%s: %04x:", txt, ix);
if (n <= 0)
return; /* Just playing it safe */
imax = (len - ix < BPL) ? len - ix : BPL;
for (i = 0; i < imax; i++)
{
l = snprintf(buf + n, sizeof(buf) - n, " %02x", *ptr++);
if (l <= 0)
return; /* Just playing it safe */
n += l;
}
_log(prio, "%s\n", buf);
}
}
#define DBG(...) \
if (ttynvt_param.debug > 0) _log(LOG_DEBUG, __VA_ARGS__)
#define DBG2(...) \
if (ttynvt_param.debug > 1) _log(LOG_DEBUG, __VA_ARGS__)
#define DBG2_BUF(txt, ptr, len) \
if (ttynvt_param.debug > 1) _log_buf(LOG_DEBUG, txt, ptr, len)
static volatile char _is_interrupted = 0;
static void sig_handler(int sig)
{
DBG("Interruped, signal = %d\n", sig);
_is_interrupted = 1;
if (sig != SIGUSR2)
exit(0);
}
static void set_signal_handler(void)
@@ -113,6 +150,7 @@ static void set_signal_handler(void)
sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
sigaction(SIGUSR2, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
}
static void ttynvt_interrupted(fuse_req_t req, void *data)
@@ -144,12 +182,13 @@ static void ttynvt_release(fuse_req_t req, struct fuse_file_info *info)
_log(LOG_INFO, "connection closed\n");
tty->n_fds = 0;
close(tty->fds[FD_NET].fd);
close(tty->fds[FD_MASTER].fd);
close(tty->fds[FD_SLAVE].fd);
pthread_cancel(tty->thread_id);
pthread_join(tty->thread_id, NULL);
pthread_cancel(tty->ptid_poll);
pthread_join(tty->ptid_poll, NULL);
pthread_mutex_destroy(&tty->tty_lock);
pthread_mutex_destroy(&tty->poll_lock);
@@ -187,65 +226,86 @@ static void _update_notify(ttynvt_t * tty, struct fuse_pollhandle *ph)
static void *_read_net(void *arg)
{
ttynvt_t *tty = (ttynvt_t *) arg;
ssize_t res;
char buf[TMP_BUF_SIZE];
int res;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
DBG2("%s: net_cnt=%d\n", __func__, tty->net_cnt);
while (1)
while (tty->n_fds > 0)
{
res = poll(tty->fds, 3, -1);
tty->fds[FD_NET].revents = tty->fds[FD_MASTER].revents =
tty->fds[FD_SLAVE].revents = 0;
res = poll(tty->fds, tty->n_fds, -1);
DBG2("%s: res=%d N=%d events-N/M/S=%#x/%#x/%#x\n", __func__,
res, tty->n_fds,
tty->fds[FD_NET].revents, tty->fds[FD_MASTER].revents,
tty->fds[FD_SLAVE].revents);
if (res < 0)
{
if (errno == EINTR)
continue;
else
break;
}
if (tty->n_fds == 0)
break;
if (tty->fds[FD_NET].revents & POLLIN)
{
res = read(tty->fds[FD_NET].fd, tty->net_buf + tty->net_cnt,
NET_BUF_SIZE - tty->net_cnt);
if (res < 0)
{
_log(LOG_ERR, "net read error: %s\n", strerror(errno));
_log(LOG_ERR, "net read error: %m\n");
break;
}
else if (res == 0)
if (res == 0)
{
_log(LOG_INFO, "Connection closed by remote host\n");
break;
}
tty->net_cnt += res;
DBG2_BUF("Serv in A", tty->net_buf, tty->net_cnt);
res = telnet_rx(tty->tn, tty->net_buf, &tty->net_cnt);
DBG2_BUF("Serv in B", tty->net_buf, tty->net_cnt);
if (tty->net_cnt > 0 && res == 0)
{
DBG2_BUF("TtyM out ", tty->net_buf, tty->net_cnt);
res =
write(tty->fds[FD_MASTER].fd, tty->net_buf, tty->net_cnt);
if (res < 0)
{
_log(LOG_ERR, "master write error:%s\n", strerror(errno));
_log(LOG_ERR, "master write error: %m\n");
break;
}
tty->net_cnt = 0;
}
}
if (tty->fds[FD_MASTER].revents & POLLIN)
{
res = read(tty->fds[FD_MASTER].fd, tty->tmp_buf, TMP_BUF_SIZE);
res = read(tty->fds[FD_MASTER].fd, buf, TMP_BUF_SIZE);
if (res < 0)
{
_log(LOG_ERR, "master read error:%s\n", strerror(errno));
_log(LOG_ERR, "master read error: %m\n");
break;
}
telnet_tx(tty->tn, tty->tmp_buf, res);
DBG2_BUF("TtyM in ", buf, res);
telnet_tx(tty->tn, buf, res);
}
if (tty->fds[FD_SLAVE].revents & POLLIN)
{
tty->pollin = 1;
tty->n_fds = 2; /* Disable polling of Slave */
_notify(tty);
}
}
DBG2("%s: done\n", __func__);
if (tty->ptid_read)
pthread_kill(tty->ptid_read, SIGUSR2);
tty->error = 1;
_notify(tty);
@@ -261,14 +321,14 @@ static int _srv_connect(const char *host, unsigned int port)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
_log(LOG_ERR, "Socket open failed: %s\n", strerror(errno));
_log(LOG_ERR, "Socket open failed: %m\n");
return sockfd;
}
server = gethostbyname(host);
if (server == NULL)
{
_log(LOG_ERR, "Cannot resolve host name: %s\n", strerror(errno));
_log(LOG_ERR, "Cannot resolve host name: %m\n");
close(sockfd);
return -1;
}
@@ -282,8 +342,7 @@ static int _srv_connect(const char *host, unsigned int port)
err = connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if (err < 0)
{
_log(LOG_ERR, "Failed to connect to: %s:%u:%s\n",
host, port, strerror(errno));
_log(LOG_ERR, "Failed to connect to: %s:%u: %m\n", host, port);
close(sockfd);
return -1;
}
@@ -296,8 +355,13 @@ static int _srv_write(void *cctx, const void *buf, int len)
ttynvt_t *tty = cctx;
int res;
DBG2_BUF("Serv out ", buf, len);
res = write(tty->fds[FD_NET].fd, buf, len);
DBG2("%s: fd=%d: len=%u: res=%d\n", __func__,
tty->fds[FD_NET].fd, len, res);
return res;
}
@@ -306,9 +370,12 @@ static int _srv_read(void *cctx, int timeout)
ttynvt_t *tty = cctx;
int res;
DBG2("%s: net_cnt=%d\n", __func__, tty->net_cnt);
while (1)
{
res = poll(&tty->fds[FD_NET], 1, timeout);
DBG("%s: res=%d events-N=%#x\n",
__func__, res, tty->fds[FD_NET].revents);
if (res <= 0)
return res;
@@ -316,10 +383,15 @@ static int _srv_read(void *cctx, int timeout)
{
res = read(tty->fds[FD_NET].fd, tty->net_buf + tty->net_cnt,
NET_BUF_SIZE - tty->net_cnt);
DBG2("%s: fd=%d: res=%d net_cnt=%d\n", __func__,
tty->fds[FD_NET].fd, res, tty->net_cnt);
if (res <= 0)
return res;
tty->net_cnt += (size_t) res;
tty->net_cnt += res;
DBG2_BUF("Serv in a", tty->net_buf, tty->net_cnt);
res = telnet_rx(tty->tn, tty->net_buf, &tty->net_cnt);
DBG2_BUF("Serv in b", tty->net_buf, tty->net_cnt);
DBG2("%s: res=%d net_cnt=%d\n", __func__, res, tty->net_cnt);
if (res == 0)
break;
}
@@ -366,7 +438,7 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
int res;
int n;
DBG2("open: thread:%lu\n", pthread_self());
DBG("%s\n", __func__);
tty = calloc(1, sizeof(*tty));
if (!tty)
@@ -404,6 +476,8 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
tty->fds[FD_MASTER].fd = fd;
tty->fds[FD_MASTER].events = POLLIN;
memset(&ios, 0, sizeof(ios));
ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
ios.c_oflag &= ~OPOST;
@@ -421,6 +495,11 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
if ((fd = open(slave_name, O_RDWR | O_NOCTTY)) < 0) /* open slave */
goto open_err;
ioctl(fd, TCGETS, &tty->tio);
tty->tio.c_cflag &= ~(CSIZE | PARENB);
tty->tio.c_cflag |= B115200 | CS8 | CREAD | CLOCAL;
ioctl(fd, TCSETS, &tty->tio);
tty->fds[FD_SLAVE].fd = fd;
tty->fds[FD_SLAVE].events = POLLIN;
@@ -432,12 +511,14 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
}
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)))
(res = pthread_create(&tty->ptid_poll, NULL, &_read_net, tty)))
{
errno = res;
goto open_err;
}
tty->n_fds = 3; /* Initially poll Net, Master, and Slave */
info->fh = (uintptr_t) tty;
info->nonseekable = 1;
info->direct_io = 1;
@@ -451,8 +532,8 @@ static void ttynvt_open(fuse_req_t req, struct fuse_file_info *info)
open_err:
_log(LOG_INFO, "Connection to server: %s:%d failed:%s\n",
ttynvt_param.host, ttynvt_param.port, strerror(errno));
_log(LOG_INFO, "Connection to server: %s:%d failed: %m\n",
ttynvt_param.host, ttynvt_param.port);
for (n = 0; n < 3; n++)
if (tty->fds[n].fd >= 0)
@@ -468,16 +549,19 @@ 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;
char buf[TMP_BUF_SIZE];
int res;
DBG2("%s\n", __func__);
if (tty->error)
{
DBG2("read (slave) in error state, thread:%lu\n", pthread_self());
DBG2("%s: tty->error=%d\n", __func__, tty->error);
if (tty->epipe == 0)
{
_log(LOG_WARNING, "Rx EPIPE\n");
tty->epipe = 1;
fuse_reply_buf(req, tty->tmp_buf, 0);
fuse_reply_buf(req, NULL, 0);
}
else
fuse_reply_err(req, EBADFD);
@@ -488,19 +572,24 @@ ttynvt_read(fuse_req_t req, size_t size, off_t off,
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);
tty->ptid_read = pthread_self();
fuse_req_interrupt_func(req, ttynvt_interrupted, (void *)tty->ptid_read);
res = _is_interrupted ? -2 : read(tty->fds[FD_SLAVE].fd, buf, size);
_is_interrupted = 0;
tty->ptid_read = 0;
tty->n_fds = 3; /* Enable polling of Slave */
fuse_req_interrupt_func(req, NULL, NULL);
if (res < 0)
{
DBG2("read (slave) error: %s\n", strerror(errno));
DBG2("%s: error: %m\n", __func__);
fuse_reply_err(req, errno);
return;
}
DBG2("read (slave): size:%d, thread:%lu\n", res, pthread_self());
DBG2("%s: fd=%d: sz=%u/%u: '%.*s'\n", __func__,
tty->fds[FD_SLAVE].fd, res, (int)size, res, buf);
fuse_reply_buf(req, tty->tmp_buf, res);
fuse_reply_buf(req, buf, res);
}
static void
@@ -508,8 +597,10 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
struct fuse_file_info *info)
{
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
ssize_t res;
int res;
DBG2("%s: fd=%d: sz=%u: '%.*s'\n", __func__,
tty->fds[FD_SLAVE].fd, (int)size, (int)size, data);
if (size == 0)
{
@@ -519,6 +610,7 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
if (tty->error)
{
DBG2("%s: tty->error=%d\n", __func__, tty->error);
fuse_reply_err(req, EPIPE);
return;
}
@@ -526,14 +618,12 @@ ttynvt_write(fuse_req_t req, const char *data, size_t size, off_t off,
res = write(tty->fds[FD_SLAVE].fd, data, size);
if (res < 0)
{
DBG2("write (slave) error: %s\n", strerror(errno));
DBG2("%s: error: %m\n", __func__);
tty->error = 1;
fuse_reply_err(req, errno);
return;
}
DBG2("write (slave): size:%d, thread:%lu\n", (int)size, pthread_self());
fuse_reply_write(req, res);
}
@@ -585,6 +675,9 @@ static const char *_ioctl_name(int cmd)
CASE(TCSBRK);
CASE(TIOCGWINSZ);
CASE(TIOCSWINSZ);
/* Controlling terminal */
CASE(TIOCSCTTY);
CASE(TIOCNOTTY);
/* Exclusive mode */
CASE(TIOCEXCL);
CASE(TIOCGEXCL);
@@ -608,12 +701,10 @@ 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 termios *tio = &tty->tio;
struct winsize ws;
unsigned int tiocm = 0;
int mcr;
static struct termios tio = {
.c_cflag = B115200 | CS8 | PARODD | CREAD | CLOCAL,
};
int val;
int res;
@@ -631,47 +722,50 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
speed_t speed;
int csize, par, sb;
memcpy(&tio, in_buf, in_bufsz);
memcpy(tio, in_buf, in_bufsz);
speed = tio.c_cflag & (CBAUD | CBAUDEX);
speed = tio->c_cflag & (CBAUD | CBAUDEX);
val = htonl(baudrate(speed));
telnet_rfc2217_cfg(tty->tn, TNS_SET_BAUDRATE, &val, 4);
if ((tio.c_cflag & CSIZE) == CS5)
if ((tio->c_cflag & CSIZE) == CS5)
csize = 5;
else if ((tio.c_cflag & CSIZE) == CS6)
else if ((tio->c_cflag & CSIZE) == CS6)
csize = 6;
else if ((tio.c_cflag & CSIZE) == CS7)
else if ((tio->c_cflag & CSIZE) == CS7)
csize = 7;
else
csize = 8;
telnet_rfc2217_cfg(tty->tn, TNS_SET_DATASIZE, &csize, 1);
if (tio.c_cflag & PARENB && tio.c_iflag & IGNPAR)
if (tio->c_cflag & PARENB && tio->c_iflag & IGNPAR)
par = 1;
#ifdef CMSPAR
else if (tio.c_cflag & PARENB && tio.c_iflag & CMSPAR)
else if (tio->c_cflag & PARENB && tio->c_iflag & CMSPAR)
{
if (tio.c_cflag & PARODD)
if (tio->c_cflag & PARODD)
par = 4;
else
par = 5;
}
#endif
else if (tio.c_cflag & PARENB)
else if (tio->c_cflag & PARENB)
par = 3;
else
par = 1;
telnet_rfc2217_cfg(tty->tn, TNS_SET_PARITY, &par, 1);
if (tio.c_cflag & CSTOPB)
if (tio->c_cflag & CSTOPB)
sb = 2;
else
sb = 1;
telnet_rfc2217_cfg(tty->tn, TNS_SET_STOPSIZE, &sb, 1);
if (tio.c_cflag & CRTSCTS)
if (tio->c_cflag & CRTSCTS)
{
tty->cmcr |= TIOCM_RTS;
telnet_rfc2217_ctl(tty->tn, TNS_CTL_CTSRTS);
}
if (!(tty->cmcr & TIOCM_DTR) && speed != B0)
{
@@ -681,19 +775,19 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
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 ? '+' : '-');
tio->c_cflag & CRTSCTS ? '+' : '-',
tio->c_cflag & CREAD ? '+' : '-',
tio->c_cflag & HUPCL ? '+' : '-',
tio->c_cflag & CLOCAL ? '+' : '-');
ioctl(tty->fds[FD_SLAVE].fd, cmd, &tio);
ioctl(tty->fds[FD_SLAVE].fd, cmd, tio);
fuse_reply_ioctl(req, 0, 0, 0);
}
break;
case TCGETS:
CHECK_BUF_OUT(sizeof(struct termios));
fuse_reply_ioctl(req, 0, &tio, sizeof(struct termios));
fuse_reply_ioctl(req, 0, tio, sizeof(struct termios));
break;
case TIOCINQ: /* Get the number of bytes in the input
* buffer */
@@ -833,7 +927,6 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
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);
@@ -881,10 +974,15 @@ ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
struct fuse_pollhandle *ph)
{
ttynvt_t *tty = (ttynvt_t *) (uintptr_t) info->fh;
int revents = 0;
int revents;
DBG2("%s: tty->pollin=%d tty->error/epipe=%d/%d\n",
__func__, tty->pollin, tty->error, tty->epipe);
_update_notify(tty, ph);
revents = POLLOUT;
if (tty->pollin)
{
tty->pollin = 0;
@@ -893,24 +991,31 @@ ttynvt_poll(fuse_req_t req, struct fuse_file_info *info,
if (tty->error)
{
if (tty->epipe == 0)
revents = POLLHUP | POLLIN;
revents |= POLLHUP | POLLIN;
else
revents = 0;
}
DBG2("%s: revents=%#x\n", __func__, revents);
fuse_reply_poll(req, revents);
}
static const struct cuse_lowlevel_ops ttynvt_op = {
.init = ttynvt_init,
.open = ttynvt_open,.read = ttynvt_read,.write = ttynvt_write,.ioctl =
ttynvt_ioctl,.poll = ttynvt_poll,.release = ttynvt_release,
.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 }
static const struct fuse_opt ttynvt_opts[] = {
TTYNET_OPT("-D %d", debug, 1),
TTYNET_OPT("-E", logstd, 1),
TTYNET_OPT("-M %u", major, 1),
TTYNET_OPT("--maj=%u", major, 1),
TTYNET_OPT("-m %u", minor, 1),
@@ -928,6 +1033,7 @@ static void print_help(void)
{
fprintf(stderr, "ttynvt Usage:\n"
"\t-D level\tEnable debug\n"
"\t-E\t\tPrint debug to stdout (default is syslog)\n"
"\t-M major, --maj=major\n"
"\t-m minor, --min=minor\n"
"\t-n name, --name=name (default: ttyNVT0)\n"
@@ -1009,14 +1115,14 @@ int main(int argc, char *argv[])
switch (cpid)
{
case -1:
_log(LOG_ERR, "fork(): %m");
_log(LOG_ERR, "fork(): %m\n");
return -1;
case 0: /* Child */
DBG("Child proceeding...\n");
rc = cuse_lowlevel_main(args.argc, args.argv, &ci, &ttynvt_op, NULL);
if (rc != 0)
_log(LOG_ERR, "ttynvt failed rc=%d", rc);
_log(LOG_ERR, "ttynvt failed rc=%d\n", rc);
else
DBG("Child exited\n");
return rc;