diff options
author | 2016-03-13 13:54:57 +1100 | |
---|---|---|
committer | 2016-03-14 18:55:00 +1100 | |
commit | 42fbb9c3967fcda37f2d9ae17d5796a79cf027b9 (patch) | |
tree | a43047ee00431e5e22bfc5f8f612ff775586e415 /src/osd/modules/file/posixptty.cpp | |
parent | 5fc27747031b6ed6f6c0582502098ebfb960be67 (diff) |
Make osd_file a polymorphic class that's held with smart pointers
Make avi_file a class that's held with smart pointers, encapsulate various AVI I/O structures
Make zip_file and _7z_file classes rather than having free functions everywhere
Hide zip/7z class implementation behind an interface, no longer need to call close() to send back to the cache
Don't dump as much crap in global namespace
Add solaris PTY implementation
Improve variable expansion for SDL OSD - supports ~/$FOO/${BAR} syntax
Rearrange stuff so the same things are in file module for all OSDs
Move file stuff into its own module
7z/zip open and destruct are still not thread-safe due to lack of interlocks around cache access
Directory functions still need to be moved to file module
SDL OSD may not initialise WinSock on Windows
Diffstat (limited to 'src/osd/modules/file/posixptty.cpp')
-rw-r--r-- | src/osd/modules/file/posixptty.cpp | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/osd/modules/file/posixptty.cpp b/src/osd/modules/file/posixptty.cpp new file mode 100644 index 00000000000..b84838c0578 --- /dev/null +++ b/src/osd/modules/file/posixptty.cpp @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb +//============================================================ +// +// sdlptty_unix.c - SDL pseudo tty access functions +// +// SDLMAME by Olivier Galibert and R. Belmont +// +//============================================================ + +#include "posixfile.h" + +#include <cassert> +#include <cerrno> +#include <cstring> + +#include <fcntl.h> +#include <limits.h> +#include <unistd.h> +#include <stdlib.h> + +#if defined(__FreeBSD__) || defined(__DragonFly__) +#include <termios.h> +#include <libutil.h> +#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) +#include <termios.h> +#include <util.h> +#elif defined(__linux__) || defined(EMSCRIPTEN) +#include <pty.h> +#elif defined(__HAIKU__) +#include <bsd/pty.h> +#endif + + +namespace { +#if defined(__APPLE__) +char const *const posix_ptty_identifier = "/dev/pty"; +#else +char const *const posix_ptty_identifier = "/dev/pts"; +#endif + + +class posix_osd_ptty : public osd_file +{ +public: + posix_osd_ptty(posix_osd_ptty const &) = delete; + posix_osd_ptty(posix_osd_ptty &&) = delete; + posix_osd_ptty& operator=(posix_osd_ptty const &) = delete; + posix_osd_ptty& operator=(posix_osd_ptty &&) = delete; + + posix_osd_ptty(int fd) : m_fd(fd) + { + assert(m_fd >= 0); + } + + virtual ~posix_osd_ptty() + { + ::close(m_fd); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + ssize_t const result = ::read(m_fd, buffer, count); + if (result < 0) + return errno_to_file_error(errno); + + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + ssize_t const result = ::write(m_fd, buffer, count); + if (result < 0) + return errno_to_file_error(errno); + + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + + virtual error truncate(std::uint64_t offset) override + { + // doesn't make sense on ptty + return error::INVALID_ACCESS; + } + + virtual error flush() override + { + // no userspace buffers on read/write + return error::NONE; + } + +private: + int m_fd; +}; + +} // anonymous namespace + + +bool posix_check_ptty_path(std::string const &path) +{ + return strncmp(path.c_str(), posix_ptty_identifier, strlen(posix_ptty_identifier)) == 0; +} + + +osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name) +{ +#if (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__)) + int access = O_NOCTTY; + if (openflags & OPEN_FLAG_WRITE) + access |= (openflags & OPEN_FLAG_READ) ? O_RDWR : O_WRONLY; + else if (openflags & OPEN_FLAG_READ) + access |= O_RDONLY; + else + return error::INVALID_ACCESS; + + int const masterfd = ::posix_openpt(access); + if (masterfd < 0) + return errno_to_file_error(errno); + + // grant access to slave device and check that it can be opened + char const *slavepath; + int slavefd; + if ((::grantpt(masterfd) < 0) || + (::unlockpt(masterfd) < 0) || + ((slavepath = ::ptsname(masterfd)) == nullptr) || + ((slavefd = ::open(slavepath, O_RDWR | O_NOCTTY)) < 0)) + { + int const err = errno; + ::close(masterfd); + return errno_to_file_error(err); + } + + // check that it's possible to stack BSD-compatibility STREAMS modules + if ((::ioctl(slavefd, I_PUSH, "ptem") < 0) || + (::ioctl(slavefd, I_PUSH, "ldterm") < 0) || + (::ioctl(slavefd, I_PUSH, "ttcompat") < 0)) + { + int const err = errno; + ::close(slavefd); + ::close(masterfd); + return errno_to_file_error(err); + } +#else + struct termios tios; + std::memset(&tios, 0, sizeof(tios)); + ::cfmakeraw(&tios); + + int masterfd = -1, slavefd = -1; + char slavepath[PATH_MAX]; + if (::openpty(&masterfd, &slavefd, slavepath, &tios, nullptr) < 0) + return errno_to_file_error(errno); +#endif + + ::close(slavefd); + + int const oldflags = ::fcntl(masterfd, F_GETFL, 0); + if (oldflags < 0) + { + int const err = errno; + ::close(masterfd); + return errno_to_file_error(err); + } + + if (::fcntl(masterfd, F_SETFL, oldflags | O_NONBLOCK) < 0) + { + int const err = errno; + ::close(masterfd); + return errno_to_file_error(err); + } + + try + { + name = slavepath; + file = std::make_unique<posix_osd_ptty>(masterfd); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(masterfd); + return osd_file::error::OUT_OF_MEMORY; + } +} |