#include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mlibc { static constexpr bool logIoctls = false; int ioctl_drm(int fd, unsigned long request, void *arg, int *result, HelHandle handle); int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { if(logIoctls) mlibc::infoLogger() << "mlibc: ioctl with" << " type: 0x" << frg::hex_fmt(_IOC_TYPE(request)) << ", number: 0x" << frg::hex_fmt(_IOC_NR(request)) << " (raw request: " << frg::hex_fmt(request) << ")" << " on fd " << fd << frg::endlog; SignalGuard sguard; auto handle = getHandleForFd(fd); if(!handle) return EBADF; if(_IOC_TYPE(request) == 'd') { return ioctl_drm(fd, request, arg, result, handle); } managarm::fs::IoctlRequest ioctl_req(getSysdepsAllocator()); switch(request) { case FIONBIO: { auto mode = reinterpret_cast(arg); int flags = fcntl(fd, F_GETFL, 0); if(*mode) { fcntl(fd, F_SETFL, flags | O_NONBLOCK); }else{ fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } return 0; } case FIONREAD: { auto argp = reinterpret_cast(arg); auto handle = getHandleForFd(fd); if (!handle) return EBADF; if(!argp) return EINVAL; managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(FIONREAD); auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if(resp.error() == managarm::fs::Errors::NOT_CONNECTED) { return ENOTCONN; } else { __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *argp = resp.fionread_count(); return 0; } } case FIOCLEX: { managarm::posix::IoctlFioclexRequest req(getSysdepsAllocator()); req.set_fd(fd); auto [offer, sendReq, recvResp] = exchangeMsgsSync( getPosixLane(), helix_ng::offer( helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(sendReq.error()); if(recvResp.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(recvResp.error()); managarm::posix::SvrResponse resp(getSysdepsAllocator()); resp.ParseFromArray(recvResp.data(), recvResp.length()); __ensure(resp.error() == managarm::posix::Errors::SUCCESS); return 0; } case TCGETS: { auto param = reinterpret_cast(arg); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); auto [offer, send_ioctl_req, send_req, recv_resp, recv_attrs] = exchangeMsgsSync(handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline(), helix_ng::recvBuffer(param, sizeof(struct termios)) ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); HEL_CHECK(recv_attrs.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); __ensure(resp.error() == managarm::fs::Errors::SUCCESS); __ensure(recv_attrs.actualLength() == sizeof(struct termios)); *result = resp.result(); return 0; } case TCSETS: { auto param = reinterpret_cast(arg); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); auto [offer, send_ioctl_req, send_req, send_attrs, recv_resp] = exchangeMsgsSync(handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::sendBuffer(param, sizeof(struct termios)), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(send_attrs.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); __ensure(resp.error() == managarm::fs::Errors::SUCCESS); if(result) *result = resp.result(); return 0; } case TIOCSCTTY: { managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::imbueCredentials(), helix_ng::recvInline()) ); HEL_CHECK(offer.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_ioctl_req.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { return EINVAL; }else if(resp.error() == managarm::fs::Errors::INSUFFICIENT_PERMISSIONS) { return EPERM; } __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = resp.result(); return 0; } case TIOCGWINSZ: { auto param = reinterpret_cast(arg); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync(handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) return EINVAL; __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = resp.result(); param->ws_col = resp.pts_width(); param->ws_row = resp.pts_height(); param->ws_xpixel = resp.pts_pixel_width(); param->ws_ypixel = resp.pts_pixel_height(); return 0; } case TIOCSWINSZ: { auto param = reinterpret_cast(arg); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); req.set_pts_width(param->ws_col); req.set_pts_height(param->ws_row); req.set_pts_pixel_width(param->ws_xpixel); req.set_pts_pixel_height(param->ws_ypixel); auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = resp.result(); return 0; } case TIOCGPTN: { auto param = reinterpret_cast(arg); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *param = resp.pts_index(); if(result) *result = resp.result(); return 0; } case TIOCGPGRP: { managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); frg::string ser(getSysdepsAllocator()); req.SerializeToString(&ser); auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBuffer(ser.data(), ser.size()), helix_ng::imbueCredentials(), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error()) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if(resp.error() == managarm::fs::Errors::NOT_A_TERMINAL) { return ENOTTY; } __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = resp.result(); *static_cast(arg) = resp.pid(); return 0; } case TIOCSPGRP: { auto param = reinterpret_cast(arg); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); req.set_pgid(*param); frg::string ser(getSysdepsAllocator()); req.SerializeToString(&ser); auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBuffer(ser.data(), ser.size()), helix_ng::imbueCredentials(), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if(resp.error() == managarm::fs::Errors::INSUFFICIENT_PERMISSIONS) { return EPERM; } else if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { return EINVAL; } __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = resp.result(); return 0; } case TIOCGSID: { managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); frg::string ser(getSysdepsAllocator()); req.SerializeToString(&ser); auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBuffer(ser.data(), ser.size()), helix_ng::imbueCredentials(), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); if(send_ioctl_req.error()) return EINVAL; HEL_CHECK(send_ioctl_req.error()); if(send_req.error()) return EINVAL; HEL_CHECK(send_req.error()); if(imbue_creds.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(imbue_creds.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if(resp.error() == managarm::fs::Errors::NOT_A_TERMINAL) { return ENOTTY; } __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = resp.result(); *static_cast(arg) = resp.pid(); return 0; } case CDROM_GET_CAPABILITY: { managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); frg::string ser(getSysdepsAllocator()); req.SerializeToString(&ser); auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBuffer(ser.data(), ser.size()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); if(send_ioctl_req.error()) return EINVAL; HEL_CHECK(send_ioctl_req.error()); if(send_req.error()) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); if(resp.error() == managarm::fs::Errors::NOT_A_TERMINAL) { return ENOTTY; } __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = resp.result(); return 0; } } // end of switch() if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGVERSION)) { *reinterpret_cast(arg) = 0x010001; // should be EV_VERSION *result = 0; return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGID)) { memset(arg, 0, sizeof(struct input_id)); *result = 0; return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGNAME(0))) { const char *s = "Managarm generic evdev"; auto chunk = frg::min(_IOC_SIZE(request), strlen(s) + 1); memcpy(arg, s, chunk); *result = chunk; return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGPHYS(0))) { // Returns the sysfs path of the device. const char *s = "input0"; auto chunk = frg::min(_IOC_SIZE(request), strlen(s) + 1); memcpy(arg, s, chunk); *result = chunk; return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGUNIQ(0))) { // Returns a unique ID for the device. const char *s = "0"; auto chunk = frg::min(_IOC_SIZE(request), strlen(s) + 1); memcpy(arg, s, chunk); *result = chunk; return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGPROP(0))) { // Returns a bitmask of properties of the device. auto size = _IOC_SIZE(request); memset(arg, 0, size); *result = size; return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGKEY(0))) { // Returns the current key state. auto size = _IOC_SIZE(request); memset(arg, 0, size); *result = size; return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGLED(0))) { // Returns the current LED state. auto size = _IOC_SIZE(request); memset(arg, 0, size); *result = size; return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCGSW(0))) { auto size = _IOC_SIZE(request); memset(arg, 0, size); *result = size; return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) >= _IOC_NR(EVIOCGBIT(0, 0)) && _IOC_NR(request) <= _IOC_NR(EVIOCGBIT(EV_MAX, 0))) { // Returns a bitmask of capabilities of the device. // If type is zero, return a mask of supported types. // As EV_SYN is zero, this implies that it is impossible // to get the mask of supported synthetic events. auto type = _IOC_NR(request) - _IOC_NR(EVIOCGBIT(0, 0)); if(!type) { // TODO: Check with the Linux ABI if we have to do this. memset(arg, 0, _IOC_SIZE(request)); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(EVIOCGBIT(0, 0)); req.set_size(_IOC_SIZE(request)); auto [offer, send_ioctl_req, send_req, recv_resp, recv_data] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline(), helix_ng::recvBuffer(arg, _IOC_SIZE(request))) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); HEL_CHECK(recv_data.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = recv_data.actualLength(); return 0; }else{ // TODO: Check with the Linux ABI if we have to do this. memset(arg, 0, _IOC_SIZE(request)); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(EVIOCGBIT(1, 0)); req.set_input_type(type); req.set_size(_IOC_SIZE(request)); auto [offer, send_ioctl_req, send_req, recv_resp, recv_data] = exchangeMsgsSync( handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline(), helix_ng::recvBuffer(arg, _IOC_SIZE(request))) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); HEL_CHECK(recv_data.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = recv_data.actualLength(); return 0; } }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) == _IOC_NR(EVIOCSCLOCKID)) { auto param = reinterpret_cast(arg); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(request); req.set_input_clock(*param); auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync(handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); __ensure(resp.error() == managarm::fs::Errors::SUCCESS); *result = resp.result(); return 0; }else if(_IOC_TYPE(request) == 'E' && _IOC_NR(request) >= _IOC_NR(EVIOCGABS(0)) && _IOC_NR(request) <= _IOC_NR(EVIOCGABS(ABS_MAX))) { auto param = reinterpret_cast(arg); auto type = _IOC_NR(request) - _IOC_NR(EVIOCGABS(0)); managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); req.set_command(EVIOCGABS(0)); req.set_input_type(type); auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync(handle, helix_ng::offer( helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline() ) ); HEL_CHECK(offer.error()); HEL_CHECK(send_ioctl_req.error()); if(send_req.error() == kHelErrDismissed) return EINVAL; HEL_CHECK(send_req.error()); HEL_CHECK(recv_resp.error()); managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); resp.ParseFromArray(recv_resp.data(), recv_resp.length()); __ensure(resp.error() == managarm::fs::Errors::SUCCESS); param->value = resp.input_value(); param->minimum = resp.input_min(); param->maximum = resp.input_max(); param->fuzz = resp.input_fuzz(); param->flat = resp.input_flat(); param->resolution = resp.input_resolution(); *result = resp.result(); return 0; }else if(request == KDSETMODE) { auto param = reinterpret_cast(arg); mlibc::infoLogger() << "\e[35mmlibc: KD_SETMODE(" << frg::hex_fmt(param) << ") is a no-op" << frg::endlog; *result = 0; return 0; }else if(request == KDGETMODE) { auto param = reinterpret_cast(arg); mlibc::infoLogger() << "\e[35mmlibc: KD_GETMODE is a no-op" << frg::endlog; *param = 0; *result = 0; return 0; }else if(request == KDSKBMODE) { auto param = reinterpret_cast(arg); mlibc::infoLogger() << "\e[35mmlibc: KD_SKBMODE(" << frg::hex_fmt(param) << ") is a no-op" << frg::endlog; *result = 0; return 0; }else if(request == VT_SETMODE) { // auto param = reinterpret_cast(arg); mlibc::infoLogger() << "\e[35mmlibc: VT_SETMODE is a no-op" << frg::endlog; *result = 0; return 0; }else if(request == VT_GETSTATE) { auto param = reinterpret_cast(arg); param->v_active = 0; param->v_signal = 0; param->v_state = 0; mlibc::infoLogger() << "\e[35mmlibc: VT_GETSTATE is a no-op" << frg::endlog; *result = 0; return 0; }else if(request == VT_ACTIVATE || request == VT_WAITACTIVE) { mlibc::infoLogger() << "\e[35mmlibc: VT_ACTIVATE/VT_WAITACTIVE are no-ops" << frg::endlog; *result = 0; return 0; }else if(request == TIOCSPTLCK) { mlibc::infoLogger() << "\e[35mmlibc: TIOCSPTLCK is a no-op" << frg::endlog; if(result) *result = 0; return 0; } mlibc::infoLogger() << "mlibc: Unexpected ioctl with" << " type: 0x" << frg::hex_fmt(_IOC_TYPE(request)) << ", number: 0x" << frg::hex_fmt(_IOC_NR(request)) << " (raw request: " << frg::hex_fmt(request) << ")" << frg::endlog; __ensure(!"Illegal ioctl request"); __builtin_unreachable(); } } //namespace mlibc