/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
/* Copyright (C) 2014 Stony Brook University
This file is part of Graphene Library OS.
Graphene Library OS 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.
Graphene Library OS 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 this program. If not, see . */
/*
* shim_ioctl.c
*
* Implementation of system call "ioctl".
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define TERM_DEFAULT_IFLAG (ICRNL|IUTF8)
#define TERM_DEFAULT_OFLAG (OPOST|ONLCR)
#define TERM_DEFAULT_CFLAG (B38400|CS8|CREAD)
#define TERM_DEFAULT_LFLAG (ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN)
static int ioctl_termios (struct shim_handle * hdl, unsigned int cmd,
unsigned long arg)
{
if (hdl->type != TYPE_FILE ||
hdl->info.file.type != FILE_TTY)
return -ENOTTY;
if (!arg)
return -EINVAL;
switch(cmd) {
/* */
case TIOCGPGRP:
*(int *) arg = get_cur_thread()->pgid;
return 0;
case TIOCSPGRP:
return -EINVAL;
case TCGETS: {
#if 0
struct termios * termios = (struct termios *) arg;
termios->c_iflag = TERM_DEFAULT_IFLAG;
termios->c_oflag = TERM_DEFAULT_OFLAG;
termios->c_cflag = TERM_DEFAULT_CFLAG;
termios->c_lflag = TERM_DEFAULT_LFLAG;
return 0;
#endif
return -EINVAL;
}
case TCSETS:
case TCSETSW:
case TCSETSF:
return -EINVAL;
/* 0x00005405 TCGETA struct termio * */
case TCGETA:
/* 0x00005406 TCSETA const struct termio * */
case TCSETA:
/* 0x00005407 TCSETAW const struct termio * */
case TCSETAW:
/* 0x00005408 TCSETAF const struct termio * */
case TCSETAF:
/* 0x00005409 TCSBRK int */
case TCSBRK:
/* 0x0000540A TCXONC int */
case TCXONC:
/* 0x0000540B TCFLSH int */
case TCFLSH:
/* 0x0000540C TIOCEXCL void */
case TIOCEXCL:
/* 0x0000540D TIOCNXCL void */
case TIOCNXCL:
/* 0x0000540E TIOCSCTTY int */
case TIOCSCTTY:
/* 0x0000540F TIOCGPGRP pid_t * */
case TIOCOUTQ:
/* 0x00005412 TIOCSTI const char * */
case TIOCSTI:
/* 0x00005413 TIOCGWINSZ struct winsize * */
case TIOCGWINSZ:
/* 0x00005415 TIOCMGET int * */
case TIOCMGET:
/* 0x00005416 TIOCMBIS const int * */
case TIOCMBIS:
/* 0x00005417 TIOCMBIC const int * */
case TIOCMBIC:
/* 0x00005418 TIOCMSET const int * */
case TIOCMSET:
/* 0x00005419 TIOCGSOFTCAR int * */
case TIOCGSOFTCAR:
/* 0x0000541A TIOCSSOFTCAR const int * */
case TIOCSSOFTCAR:
/* 0x0000541B FIONREAD int / TIOCINQ int * */
case TIOCINQ:
/* 0x0000541C TIOCLINUX const char * */
case TIOCLINUX:
/* 0x0000541D TIOCCONS void */
case TIOCCONS:
/* 0x0000541E TIOCGSERIAL struct serial_struct * */
case TIOCGSERIAL:
/* 0x0000541F TIOCSSERIAL const struct serial_struct * */
case TIOCSSERIAL:
/* 0x00005420 TIOCPKT const int * */
case TIOCPKT:
/* 0x00005422 TIOCNOTTY void */
case TIOCNOTTY:
/* 0x00005423 TIOCSETD const int * */
case TIOCSETD:
/* 0x00005424 TIOCGETD int * */
case TIOCGETD:
/* 0x00005425 TCSBRKP int */
case TCSBRKP:
/* 0x00005453 TIOCSERCONFIG void */
case TIOCSERCONFIG:
/* 0x00005454 TIOCSERGWILD int * */
case TIOCSERGWILD:
/* 0x00005455 TIOCSERSWILD const int * */
case TIOCSERSWILD:
/* 0x00005456 TIOCGLCKTRMIOS struct termios * */
case TIOCGLCKTRMIOS:
/* 0x00005457 TIOCSLCKTRMIOS const struct termios * */
case TIOCSLCKTRMIOS:
/* 0x00005458 TIOCSERGSTRUCT struct async_struct * */
case TIOCSERGSTRUCT:
/* 0x00005459 TIOCSERGETLSR int * */
case TIOCSERGETLSR:
/* 0x0000545A TIOCSERGETMULTI struct serial_multiport_struct * */
case TIOCSERGETMULTI:
/* 0x0000545B TIOCSERSETMULTI const struct serial_multiport_struct * */
case TIOCSERSETMULTI:
default:
goto passthrough;
}
passthrough:
return -EAGAIN;
}
static int ioctl_fd (struct shim_handle * hdl, unsigned int cmd,
unsigned long arg)
{
switch(cmd) {
/* */
/* 0x00000000 FDCLRPRM void */
case FDCLRPRM:
/* 0x00000001 FDSETPRM const struct floppy_struct * */
case FDSETPRM:
/* 0x00000002 FDDEFPRM const struct floppy_struct * */
case FDDEFPRM:
/* 0x00000003 FDGETPRM struct floppy_struct * */
case FDGETPRM:
/* 0x00000004 FDMSGON void */
case FDMSGON:
/* 0x00000005 FDMSGOFF void */
case FDMSGOFF:
/* 0x00000006 FDFMTBEG void */
case FDFMTBEG:
/* 0x00000007 FDFMTTRK const struct format_descr * */
case FDFMTTRK:
/* 0x00000008 FDFMTEND void */
case FDFMTEND:
/* 0x0000000A FDSETEMSGTRESH int */
case FDSETEMSGTRESH:
/* 0x0000000B FDFLUSH void */
case FDFLUSH:
/* 0x0000000C FDSETMAXERRS const struct floppy_max_errors * */
case FDSETMAXERRS:
/* 0x0000000E FDGETMAXERRS struct floppy_max_errors * */
case FDGETMAXERRS:
/* 0x00000010 FDGETDRVTYP struct { char [16]; } * */
case FDGETDRVTYP:
/* 0x00000014 FDSETDRVPRM const struct floppy_drive_params * */
case FDSETDRVPRM:
/* 0x00000015 FDGETDRVPRM struct floppy_drive_params * */
case FDGETDRVPRM:
/* 0x00000016 FDGETDRVSTAT struct floppy_drive_struct * */
case FDGETDRVSTAT:
/* 0x00000017 FDPOLLDRVSTAT struct floppy_drive_struct * */
case FDPOLLDRVSTAT:
/* 0x00000018 FDRESET int */
case FDRESET:
/* 0x00000019 FDGETFDCSTAT struct floppy_fdc_state * */
case FDGETFDCSTAT:
/* 0x0000001B FDWERRORCLR void */
case FDWERRORCLR:
/* 0x0000001C FDWERRORGET struct floppy_write_errors * */
case FDWERRORGET:
/* 0x0000001E FDRAWCMD struct floppy_raw_cmd *floppy_raw_cmd */
case FDRAWCMD:
/* 0x00000028 FDTWADDLE void */
case FDTWADDLE:
default:
goto passthrough;
}
passthrough:
return -EAGAIN;
}
static int ioctl_netdevice (struct shim_handle * hdl, unsigned int cmd,
unsigned long arg)
{
if (hdl->type != TYPE_SOCK)
return -ENOTSOCK;
struct shim_sock_handle * sock = &hdl->info.sock;
if (sock->sock_state == SOCK_CREATED) {
if (sock->sock_type == SOCK_STREAM)
return -ENOTCONN;
}
switch(cmd) {
/* Socket configuration controls. */
case SIOCGIFNAME: /* 0x8910 get iface name */
case SIOCSIFLINK: /* 0x8911 set iface channel */
case SIOCGIFCONF: /* 0x8912 get iface list */
case SIOCGIFFLAGS: /* 0x8913 get flags */
case SIOCSIFFLAGS: /* 0x8914 set flags */
case SIOCGIFADDR: /* 0x8915 get PA address */
case SIOCSIFADDR: /* 0x8916 set PA address */
case SIOCGIFDSTADDR: /* 0x8917 get remote PA address */
case SIOCSIFDSTADDR: /* 0x8918 set remote PA address */
case SIOCGIFBRDADDR: /* 0x8919 get broadcast PA address */
case SIOCSIFBRDADDR: /* 0x891a set broadcast PA address */
case SIOCGIFNETMASK: /* 0x891b get network PA mask */
case SIOCSIFNETMASK: /* 0x891c set network PA mask */
case SIOCGIFMETRIC: /* 0x891d get metric */
case SIOCSIFMETRIC: /* 0x891e set metric */
case SIOCGIFMEM: /* 0x891f get memory address (BSD) */
case SIOCSIFMEM: /* 0x8920 set memory address (BSD) */
case SIOCGIFMTU: /* 0x8921 get MTU size */
case SIOCSIFMTU: /* 0x8922 set MTU size */
case SIOCSIFNAME: /* 0x8923 set interface name */
case SIOCSIFHWADDR: /* 0x8924 set hardware address */
case SIOCGIFENCAP: /* 0x8925 get/set encapsulations */
case SIOCSIFENCAP: /* 0x8926 */
case SIOCGIFHWADDR: /* 0x8927 Get hardware address */
case SIOCGIFSLAVE: /* 0x8929 Driver slaving support */
case SIOCSIFSLAVE: /* 0x8930 */
case SIOCADDMULTI: /* 0x8931 Multicast address lists */
case SIOCDELMULTI: /* 0x8932 */
case SIOCGIFINDEX: /* 0x8933 name -> if_index mapping */
/* SIOGIFINDEX = SIOCGIFINDEX misprint compatibility :-) */
case SIOCSIFPFLAGS: /* 0x8934 set/get extended flags set */
case SIOCGIFPFLAGS: /* 0x8935 */
case SIOCDIFADDR: /* 0x8936 delete PA address */
case SIOCSIFHWBROADCAST: /* 0x8937 set hardware broadcast addr */
case SIOCGIFCOUNT: /* 0x8938 get number of devices */
case SIOCGIFBR: /* 0x8940 Bridging support */
case SIOCSIFBR: /* 0x8941 Set bridging options */
case SIOCGIFTXQLEN: /* 0x8942 Get the tx queue length */
case SIOCSIFTXQLEN: /* 0x8943 Set the tx queue length */
default:
goto passthrough;
}
passthrough:
return -EAGAIN;
}
void signal_io (IDTYPE target, void * arg)
{
debug("detecting input, signaling thread %u\n", target);
struct shim_thread * thread = lookup_thread(target);
if (!thread)
return;
append_signal(thread, SIGIO, NULL, true);
}
int shim_do_ioctl (int fd, int cmd, unsigned long arg)
{
struct shim_handle * hdl = get_fd_handle(fd, NULL, NULL);
if (!hdl)
return -EBADF;
int ret = -EAGAIN;
switch(cmd) {
/* */
case TCGETS:
case TCSETS:
case TCSETSW:
case TCSETSF:
case TCGETA:
case TCSETA:
case TCSETAW:
case TCSETAF:
case TCSBRK:
case TCXONC:
case TCFLSH:
case TIOCEXCL:
case TIOCNXCL:
case TIOCSCTTY:
case TIOCGPGRP:
case TIOCSPGRP:
case TIOCOUTQ:
case TIOCSTI:
case TIOCGWINSZ:
case TIOCMGET:
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
case TIOCGSOFTCAR:
case TIOCSSOFTCAR:
/* case TIOCINQ = FIONREAD */
case TIOCLINUX:
case TIOCCONS:
case TIOCGSERIAL:
case TIOCSSERIAL:
case TIOCPKT:
case TIOCNOTTY:
case TIOCSETD:
case TIOCGETD:
case TCSBRKP:
ret = ioctl_termios(hdl, cmd, arg);
break;
case FIONBIO:
if (hdl->fs && hdl->fs->fs_ops &&
hdl->fs->fs_ops->setflags)
hdl->fs->fs_ops->setflags(hdl, hdl->flags | O_NONBLOCK);
hdl->flags |= O_NONBLOCK;
ret = 0;
break;
case FIONCLEX:
hdl->flags &= ~FD_CLOEXEC;
ret = 0;
break;
case FIOCLEX:
hdl->flags |= FD_CLOEXEC;
ret = 0;
break;
case FIOASYNC:
ret = install_async_event(hdl->pal_handle, 0, &signal_io, NULL);
break;
case TIOCSERCONFIG:
case TIOCSERGWILD:
case TIOCSERSWILD:
case TIOCGLCKTRMIOS:
case TIOCSLCKTRMIOS:
case TIOCSERGSTRUCT:
case TIOCSERGETLSR:
case TIOCSERGETMULTI:
case TIOCSERSETMULTI:
ret = ioctl_termios(hdl, cmd, arg);
break;
case FDCLRPRM:
case FDSETPRM:
case FDDEFPRM:
case FDGETPRM:
case FDMSGON:
case FDMSGOFF:
case FDFMTBEG:
case FDFMTTRK:
case FDFMTEND:
case FDSETEMSGTRESH:
case FDFLUSH:
case FDSETMAXERRS:
case FDGETMAXERRS:
case FDGETDRVTYP:
case FDSETDRVPRM:
case FDGETDRVPRM:
case FDGETDRVSTAT:
case FDPOLLDRVSTAT:
case FDRESET:
case FDGETFDCSTAT:
case FDWERRORCLR:
case FDWERRORGET:
case FDRAWCMD:
case FDTWADDLE:
ret = ioctl_fd(hdl, cmd, arg);
break;
case FIONREAD: {
struct shim_mount * fs = hdl->fs;
int size = 0;
int offset = 0;
if (!fs || !fs->fs_ops) {
ret = -EACCES;
break;
}
if (fs->fs_ops->hstat) {
struct stat stat;
ret = fs->fs_ops->hstat(hdl, &stat);
if (ret < 0)
break;
size = stat.st_size;
goto done_fioread;
}
if (hdl->pal_handle) {
PAL_STREAM_ATTR attr;
if (!DkStreamAttributesQuerybyHandle(hdl->pal_handle, &attr)) {
ret = -PAL_ERRNO;
break;
}
size = attr.pending_size;
goto done_fioread;
}
done_fioread:
if (fs->fs_ops->seek) {
ret = fs->fs_ops->seek(hdl, 0, SEEK_CUR);
if (ret < 0)
break;
offset = ret;
}
*(int *) arg = size - offset;
ret = 0;
break;
}
/* Socket configuration controls. */
case SIOCGIFNAME: /* 0x8910 get iface name */
case SIOCSIFLINK: /* 0x8911 set iface channel */
case SIOCGIFCONF: /* 0x8912 get iface list */
case SIOCGIFFLAGS: /* 0x8913 get flags */
case SIOCSIFFLAGS: /* 0x8914 set flags */
case SIOCGIFADDR: /* 0x8915 get PA address */
case SIOCSIFADDR: /* 0x8916 set PA address */
case SIOCGIFDSTADDR: /* 0x8917 get remote PA address */
case SIOCSIFDSTADDR: /* 0x8918 set remote PA address */
case SIOCGIFBRDADDR: /* 0x8919 get broadcast PA address */
case SIOCSIFBRDADDR: /* 0x891a set broadcast PA address */
case SIOCGIFNETMASK: /* 0x891b get network PA mask */
case SIOCSIFNETMASK: /* 0x891c set network PA mask */
case SIOCGIFMETRIC: /* 0x891d get metric */
case SIOCSIFMETRIC: /* 0x891e set metric */
case SIOCGIFMEM: /* 0x891f get memory address (BSD) */
case SIOCSIFMEM: /* 0x8920 set memory address (BSD) */
case SIOCGIFMTU: /* 0x8921 get MTU size */
case SIOCSIFMTU: /* 0x8922 set MTU size */
case SIOCSIFNAME: /* 0x8923 set interface name */
case SIOCSIFHWADDR: /* 0x8924 set hardware address */
case SIOCGIFENCAP: /* 0x8925 get/set encapsulations */
case SIOCSIFENCAP: /* 0x8926 */
case SIOCGIFHWADDR: /* 0x8927 Get hardware address */
case SIOCGIFSLAVE: /* 0x8929 Driver slaving support */
case SIOCSIFSLAVE: /* 0x8930 */
case SIOCADDMULTI: /* 0x8931 Multicast address lists */
case SIOCDELMULTI: /* 0x8932 */
case SIOCGIFINDEX: /* 0x8933 name -> if_index mapping */
/* SIOGIFINDEX = SIOCGIFINDEX misprint compatibility :-) */
case SIOCSIFPFLAGS: /* 0x8934 set/get extended flags set */
case SIOCGIFPFLAGS: /* 0x8935 */
case SIOCDIFADDR: /* 0x8936 delete PA address */
case SIOCSIFHWBROADCAST: /* 0x8937 set hardware broadcast addr */
case SIOCGIFCOUNT: /* 0x8938 get number of devices */
case SIOCGIFBR: /* 0x8940 Bridging support */
case SIOCSIFBR: /* 0x8941 Set bridging options */
case SIOCGIFTXQLEN: /* 0x8942 Get the tx queue length */
case SIOCSIFTXQLEN: /* 0x8943 Set the tx queue length */
ret = ioctl_netdevice(hdl, cmd, arg);
break;
default:
ret = -ENOSYS;
break;
}
put_handle(hdl);
return ret;
}