Refactor ioctl input/output buffer size handling

This commit is contained in:
Kim Woelders
2018-07-17 15:37:11 +02:00
parent 45e73de4b9
commit 2c3441dda5
+49 -93
View File
@@ -559,6 +559,11 @@ static const char *_ioctl_name(int cmd)
} }
} }
#define CHECK_BUF_IN(sz) \
if (in_bufsz < sz) do { in_bufsz = sz; goto retry_in; } while(0)
#define CHECK_BUF_OUT(sz) \
if (out_bufsz < sz) do { out_bufsz = sz; goto retry_out; } while(0)
static void static void
ttynvt_ioctl(fuse_req_t req, int cmd, void *arg, ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
struct fuse_file_info *info, unsigned int flags, struct fuse_file_info *info, unsigned int flags,
@@ -581,12 +586,7 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
case TCSETSF: case TCSETSF:
case TCSETSW: case TCSETSW:
case TCSETS: case TCSETS:
if (!in_bufsz) CHECK_BUF_IN(sizeof(struct termios));
{
struct iovec iov = { arg, sizeof(struct termios) };
fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
}
else
{ {
speed_t speed; speed_t speed;
int csize, par, sb; int csize, par, sb;
@@ -650,45 +650,20 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
} }
break; break;
case TCGETS: case TCGETS:
if (out_bufsz) CHECK_BUF_OUT(sizeof(struct termios));
{ fuse_reply_ioctl(req, 0, &tio, sizeof(struct termios));
fuse_reply_ioctl(req, 0, &tio, sizeof(struct termio));
}
else
{
struct iovec iov = { arg, sizeof(struct termio) };
fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
}
break; break;
case TIOCINQ: /* Get the number of bytes in the input case TIOCINQ: /* Get the number of bytes in the input
* buffer */ * buffer */
if (out_bufsz) CHECK_BUF_OUT(sizeof(int));
{ val = _read_avail(tty);
size_t rx_size = _read_avail(tty); fuse_reply_ioctl(req, 0, &val, sizeof(int));
fuse_reply_ioctl(req, 0, &rx_size, sizeof(size_t));
}
else
{
struct iovec iov = { arg, sizeof(size_t) };
fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
}
break; break;
case TIOCOUTQ: /* Get the number of bytes in the output case TIOCOUTQ: /* Get the number of bytes in the output
* buffer */ * buffer */
if (out_bufsz) CHECK_BUF_OUT(sizeof(int));
{ val = _write_avail(tty);
size_t tx_size = _write_avail(tty); fuse_reply_ioctl(req, 0, &val, sizeof(int));
fuse_reply_ioctl(req, 0, &tx_size, sizeof(size_t));
}
else
{
struct iovec iov = { arg, sizeof(size_t) };
fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
}
break; break;
case TCFLSH: case TCFLSH:
if (arg == TCIFLUSH) if (arg == TCIFLUSH)
@@ -711,7 +686,6 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
pthread_mutex_lock(&tty->tty_lock); pthread_mutex_lock(&tty->tty_lock);
tty->blen = 0; tty->blen = 0;
pthread_mutex_unlock(&tty->tty_lock); pthread_mutex_unlock(&tty->tty_lock);
fuse_reply_ioctl(req, 0, 0, 0); fuse_reply_ioctl(req, 0, 0, 0);
break; break;
case TCOFLUSH: case TCOFLUSH:
@@ -725,27 +699,13 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
fuse_reply_ioctl(req, 0, 0, 0); fuse_reply_ioctl(req, 0, 0, 0);
break; break;
case TIOCMGET: case TIOCMGET:
if (out_bufsz) CHECK_BUF_OUT(sizeof(int));
{ fuse_reply_ioctl(req, 0, &mcr, sizeof(int));
fuse_reply_ioctl(req, 0, &mcr, sizeof(unsigned int));
}
else
{
struct iovec iov = { arg, sizeof(unsigned int) };
fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
}
break; break;
case TIOCMBIS: case TIOCMBIS:
if (!in_bufsz) CHECK_BUF_IN(sizeof(int));
{ tiocm = *(unsigned int *)in_buf;
struct iovec iov = { arg, sizeof(unsigned int) }; fuse_reply_ioctl(req, 0, 0, 0);
fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
}
else
{
tiocm = *(unsigned int *)in_buf;
fuse_reply_ioctl(req, 0, 0, 0);
}
if (tiocm & TIOCM_RTS) if (tiocm & TIOCM_RTS)
{ {
mcr |= TIOCM_RTS; mcr |= TIOCM_RTS;
@@ -758,16 +718,9 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
} }
break; break;
case TIOCMBIC: case TIOCMBIC:
if (!in_bufsz) CHECK_BUF_IN(sizeof(int));
{ tiocm = *(unsigned int *)in_buf;
struct iovec iov = { arg, sizeof(unsigned int) }; fuse_reply_ioctl(req, 0, 0, 0);
fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
}
else
{
tiocm = *(unsigned int *)in_buf;
fuse_reply_ioctl(req, 0, 0, 0);
}
if (tiocm & TIOCM_RTS) if (tiocm & TIOCM_RTS)
{ {
mcr &= ~TIOCM_RTS; mcr &= ~TIOCM_RTS;
@@ -780,45 +733,48 @@ ttynvt_ioctl(fuse_req_t req, int cmd, void *arg,
} }
break; break;
case TIOCMSET: case TIOCMSET:
if (!in_bufsz) CHECK_BUF_IN(sizeof(int));
{ tiocm = *(unsigned int *)in_buf;
struct iovec iov = { arg, sizeof(unsigned int) }; fuse_reply_ioctl(req, 0, 0, 0);
fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
}
else
{
tiocm = *(unsigned int *)in_buf;
fuse_reply_ioctl(req, 0, 0, 0);
DBG("CFG ioctl: DTR=%c RTS=%c\n", DBG("CFG ioctl: DTR=%c RTS=%c\n",
tiocm & TIOCM_DTR ? '1' : '0', tiocm & TIOCM_RTS ? '1' : '0'); tiocm & TIOCM_DTR ? '1' : '0', tiocm & TIOCM_RTS ? '1' : '0');
mcr &= ~(TIOCM_RTS | TIOCM_DTR); mcr &= ~(TIOCM_RTS | TIOCM_DTR);
mcr |= tiocm & (TIOCM_RTS | TIOCM_DTR); mcr |= tiocm & (TIOCM_RTS | TIOCM_DTR);
telnet_rfc2217_ctl(tty->tn, (tiocm & TIOCM_DTR) ? telnet_rfc2217_ctl(tty->tn, (tiocm & TIOCM_DTR) ?
TNS_CTL_DTR_ON : TNS_CTL_DTR_OFF); TNS_CTL_DTR_ON : TNS_CTL_DTR_OFF);
telnet_rfc2217_ctl(tty->tn, (tiocm & TIOCM_RTS) ? telnet_rfc2217_ctl(tty->tn, (tiocm & TIOCM_RTS) ?
TNS_CTL_RTS_ON : TNS_CTL_RTS_OFF); TNS_CTL_RTS_ON : TNS_CTL_RTS_OFF);
}
break; break;
case TCSBRK: case TCSBRK:
fuse_reply_ioctl(req, 0, 0, 0); fuse_reply_ioctl(req, 0, 0, 0);
break; break;
case TIOCGWINSZ: case TIOCGWINSZ:
if (out_bufsz) CHECK_BUF_OUT(sizeof(struct winsize));
{ {
struct winsize ws = {.ws_row = 25,.ws_col = 80 }; struct winsize ws = {.ws_row = 25,.ws_col = 80 };
fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize)); fuse_reply_ioctl(req, 0, &ws, sizeof(struct winsize));
} }
else break;
default:
fuse_reply_err(req, ENOSYS);
break;
retry_in:
{ {
struct iovec iov = { arg, sizeof(struct winsize) }; struct iovec iov = { arg, in_bufsz };
fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
}
break;
retry_out:
{
struct iovec iov = { arg, out_bufsz };
fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1); fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
} }
break; break;
default:
fuse_reply_err(req, ENOSYS);
return;
} }
} }