root/src/bin/debug/strace/ioctl.cpp
/*
 * Copyright 2007-2010, Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Hugo Santos <hugosantos@gmail.com>
 */


#include <sys/ioctl.h>
#include <sys/sockio.h>
#include <termios.h>

#include <Drivers.h>
#include <tty.h>
#include <scsi.h>

#include "strace.h"
#include "Syscall.h"
#include "TypeHandler.h"


struct ioctl_info {
        unsigned int index;
        const char *name;
        TypeHandler *handler;
};

#define IOCTL_INFO_ENTRY(name) \
        { name, #name, NULL }

#define IOCTL_INFO_ENTRY_TYPE(name, type) \
        { name, #name, TypeHandlerFactory<type>::Create() }

static const ioctl_info kIOCtls[] = {
        // <Drivers.h>
        IOCTL_INFO_ENTRY_TYPE(B_GET_DEVICE_SIZE, size_t *),
        IOCTL_INFO_ENTRY_TYPE(B_SET_DEVICE_SIZE, size_t *),
        IOCTL_INFO_ENTRY(B_SET_NONBLOCKING_IO),
        IOCTL_INFO_ENTRY(B_SET_BLOCKING_IO),
        IOCTL_INFO_ENTRY(B_GET_READ_STATUS),
        IOCTL_INFO_ENTRY(B_GET_WRITE_STATUS),
        IOCTL_INFO_ENTRY(B_GET_GEOMETRY),
        IOCTL_INFO_ENTRY(B_GET_DRIVER_FOR_DEVICE),
        IOCTL_INFO_ENTRY(B_GET_PARTITION_INFO),
        IOCTL_INFO_ENTRY(B_SET_PARTITION),
        IOCTL_INFO_ENTRY(B_FORMAT_DEVICE),
        IOCTL_INFO_ENTRY(B_EJECT_DEVICE),
        IOCTL_INFO_ENTRY(B_GET_ICON),
        IOCTL_INFO_ENTRY(B_GET_BIOS_GEOMETRY),
        IOCTL_INFO_ENTRY(B_GET_MEDIA_STATUS),
        IOCTL_INFO_ENTRY(B_LOAD_MEDIA),
        IOCTL_INFO_ENTRY(B_GET_BIOS_DRIVE_ID),
        IOCTL_INFO_ENTRY(B_SET_UNINTERRUPTABLE_IO),
        IOCTL_INFO_ENTRY(B_SET_INTERRUPTABLE_IO),
        IOCTL_INFO_ENTRY(B_FLUSH_DRIVE_CACHE),
        IOCTL_INFO_ENTRY(B_GET_PATH_FOR_DEVICE),
        IOCTL_INFO_ENTRY(B_GET_NEXT_OPEN_DEVICE),
        IOCTL_INFO_ENTRY(B_ADD_FIXED_DRIVER),
        IOCTL_INFO_ENTRY(B_REMOVE_FIXED_DRIVER),

        /*
        IOCTL_INFO_ENTRY(B_AUDIO_DRIVER_BASE), // conflicts
        IOCTL_INFO_ENTRY(B_MIDI_DRIVER_BASE),
        IOCTL_INFO_ENTRY(B_JOYSTICK_DRIVER_BASE),
        IOCTL_INFO_ENTRY(B_GRAPHIC_DRIVER_BASE),
        IOCTL_INFO_ENTRY(B_DEVICE_OP_CODES_END),
        */

        // <sys/sockio.h>
        IOCTL_INFO_ENTRY(SIOCADDRT),
        IOCTL_INFO_ENTRY(SIOCDELRT),
        IOCTL_INFO_ENTRY_TYPE(SIOCSIFADDR, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFADDR, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCSIFDSTADDR, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFDSTADDR, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCSIFFLAGS, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFFLAGS, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFBRDADDR, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCSIFBRDADDR, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFCOUNT, struct ifconf *),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFCONF, struct ifconf *),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFINDEX, struct ifreq *),
        IOCTL_INFO_ENTRY(SIOCGIFNAME),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFNETMASK, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCSIFNETMASK, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFMETRIC, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCSIFMETRIC, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCDIFADDR, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCAIFADDR, struct ifaliasreq *),
        IOCTL_INFO_ENTRY(SIOCADDMULTI),
        IOCTL_INFO_ENTRY(SIOCDELMULTI),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFMTU, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCSIFMTU, struct ifreq *),
        IOCTL_INFO_ENTRY(SIOCSIFMEDIA),
        IOCTL_INFO_ENTRY(SIOCGIFMEDIA),
        IOCTL_INFO_ENTRY(SIOCGRTSIZE),
        IOCTL_INFO_ENTRY(SIOCGRTTABLE),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFSTATS, struct ifreq *),
        IOCTL_INFO_ENTRY_TYPE(SIOCGIFTYPE, struct ifreq *),
        IOCTL_INFO_ENTRY(SIOCSPACKETCAP),
        IOCTL_INFO_ENTRY(SIOCCPACKETCAP),
        IOCTL_INFO_ENTRY(SIOCSHIWAT),
        IOCTL_INFO_ENTRY(SIOCGHIWAT),
        IOCTL_INFO_ENTRY(SIOCSLOWAT),
        IOCTL_INFO_ENTRY(SIOCGLOWAT),
        IOCTL_INFO_ENTRY(SIOCATMARK),
        IOCTL_INFO_ENTRY(SIOCSPGRP),

        IOCTL_INFO_ENTRY_TYPE(B_SOCKET_SET_ALIAS, struct ifaliasreq *),
        IOCTL_INFO_ENTRY_TYPE(B_SOCKET_GET_ALIAS, struct ifaliasreq *),
        IOCTL_INFO_ENTRY_TYPE(B_SOCKET_COUNT_ALIASES, struct ifreq *),

        // termios ioctls
#define TCWAITEVENT                             (TCGETA + 4)
#define TCQUERYCONNECTED                (TCGETA + 8)
#define TCVTIME                                 (TCGETA + 14)
        IOCTL_INFO_ENTRY(TCGETA),
        IOCTL_INFO_ENTRY(TCSETA),
        IOCTL_INFO_ENTRY(TCSETAF),
        IOCTL_INFO_ENTRY(TCSETAW),
        IOCTL_INFO_ENTRY(TCWAITEVENT),
        IOCTL_INFO_ENTRY(TCSBRK),
        IOCTL_INFO_ENTRY(TCFLSH),
        IOCTL_INFO_ENTRY(TCXONC),
        IOCTL_INFO_ENTRY(TCQUERYCONNECTED),
        IOCTL_INFO_ENTRY(TCGETBITS),
        IOCTL_INFO_ENTRY(TCSETDTR),
        IOCTL_INFO_ENTRY(TCSETRTS),
        IOCTL_INFO_ENTRY(TIOCGWINSZ),
        IOCTL_INFO_ENTRY(TIOCSWINSZ),
        IOCTL_INFO_ENTRY(TCVTIME),
        IOCTL_INFO_ENTRY(TIOCGPGRP),
        IOCTL_INFO_ENTRY(TIOCSPGRP),
        IOCTL_INFO_ENTRY(TIOCSCTTY),
        IOCTL_INFO_ENTRY(TIOCMGET),
        IOCTL_INFO_ENTRY(TIOCMSET),
        IOCTL_INFO_ENTRY(TIOCSBRK),
        IOCTL_INFO_ENTRY(TIOCCBRK),
        IOCTL_INFO_ENTRY(TIOCMBIS),
        IOCTL_INFO_ENTRY(TIOCMBIC),
        IOCTL_INFO_ENTRY(TIOCOUTQ),
        IOCTL_INFO_ENTRY(TIOCEXCL),
        IOCTL_INFO_ENTRY(TIOCNXCL),

        // private termios
        IOCTL_INFO_ENTRY(B_IOCTL_GET_TTY_INDEX),
        IOCTL_INFO_ENTRY(B_IOCTL_GRANT_TTY),

        // scsi ioctls
        IOCTL_INFO_ENTRY(B_SCSI_SCAN_FOR_DEVICES),
        IOCTL_INFO_ENTRY(B_SCSI_ENABLE_PROFILING),
        IOCTL_INFO_ENTRY(B_SCSI_INQUIRY),
        IOCTL_INFO_ENTRY(B_SCSI_EJECT),
        IOCTL_INFO_ENTRY(B_SCSI_PREVENT_ALLOW),
        IOCTL_INFO_ENTRY(B_RAW_DEVICE_COMMAND),
        IOCTL_INFO_ENTRY(B_SCSI_GET_TOC),
        IOCTL_INFO_ENTRY(B_SCSI_PLAY_TRACK),
        IOCTL_INFO_ENTRY(B_SCSI_PLAY_POSITION),
        IOCTL_INFO_ENTRY(B_SCSI_STOP_AUDIO),
        IOCTL_INFO_ENTRY(B_SCSI_PAUSE_AUDIO),
        IOCTL_INFO_ENTRY(B_SCSI_RESUME_AUDIO),
        IOCTL_INFO_ENTRY(B_SCSI_GET_POSITION),
        IOCTL_INFO_ENTRY(B_SCSI_SET_VOLUME),
        IOCTL_INFO_ENTRY(B_SCSI_GET_VOLUME),
        IOCTL_INFO_ENTRY(B_SCSI_READ_CD),
        IOCTL_INFO_ENTRY(B_SCSI_SCAN),
        IOCTL_INFO_ENTRY(B_SCSI_DATA_MODE),

        // socket ioctls
        IOCTL_INFO_ENTRY_TYPE(FIONBIO, int*),
        IOCTL_INFO_ENTRY_TYPE(FIONREAD, int*),
        IOCTL_INFO_ENTRY_TYPE(FIOSEEKDATA, off_t*),
        IOCTL_INFO_ENTRY_TYPE(FIOSEEKHOLE, off_t*),

        { 0, NULL, NULL }
};

static EnumTypeHandler::EnumMap kIoctlNames;
static TypeHandlerSelector::SelectMap kIoctlTypeHandlers;

void
patch_ioctl()
{
        for (int i = 0; kIOCtls[i].name != NULL; i++) {
                kIoctlNames[kIOCtls[i].index] = kIOCtls[i].name;
                if (kIOCtls[i].handler != NULL)
                        kIoctlTypeHandlers[kIOCtls[i].index] = kIOCtls[i].handler;
        }

        Syscall *ioctl = get_syscall("_kern_ioctl");

        ioctl->GetParameter("cmd")->SetHandler(
                        new EnumTypeHandler(kIoctlNames));
        ioctl->GetParameter("data")->SetHandler(
                        new TypeHandlerSelector(kIoctlTypeHandlers,
                                        1, TypeHandlerFactory<void *>::Create()));
}