diff --git a/Userland/Libraries/LibC/stdlib.cpp b/Userland/Libraries/LibC/stdlib.cpp index d56dfc03d1..d9e7d73ead 100644 --- a/Userland/Libraries/LibC/stdlib.cpp +++ b/Userland/Libraries/LibC/stdlib.cpp @@ -24,8 +24,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -724,8 +727,39 @@ char* ptsname(int fd) int ptsname_r(int fd, char* buffer, size_t size) { - int rc = syscall(SC_ptsname, fd, buffer, size); - __RETURN_WITH_ERRNO(rc, rc, -1); + struct stat stat; + if (fstat(fd, &stat) < 0) + return -1; + + StringBuilder devpts_path_builder; + devpts_path_builder.append("/dev/pts/"sv); + + int master_pty_index = 0; + // Note: When the user opens a PTY from /dev/ptmx with posix_openpt(), the open file descriptor + // points to /dev/ptmx, (major number is 5 and minor number is 2), but internally + // in the kernel, it points to a new MasterPTY device. When we do ioctl with TIOCGPTN option + // on the open file descriptor, it actually asks the MasterPTY what is the assigned index + // of it when the PTYMultiplexer created it. + if (ioctl(fd, TIOCGPTN, &master_pty_index) < 0) + return -1; + + if (master_pty_index < 0) { + errno = EINVAL; + return -1; + } + + devpts_path_builder.appendff("{:d}", master_pty_index); + if (devpts_path_builder.length() > size) { + errno = ERANGE; + return -1; + } + memset(buffer, 0, devpts_path_builder.length() + 1); + auto full_devpts_path_string = devpts_path_builder.build(); + if (!full_devpts_path_string.copy_characters_to_buffer(buffer, size)) { + errno = ERANGE; + return -1; + } + return 0; } static unsigned long s_next_rand = 1; diff --git a/Userland/Libraries/LibC/unistd.cpp b/Userland/Libraries/LibC/unistd.cpp index b05f7e62e8..c7caea4678 100644 --- a/Userland/Libraries/LibC/unistd.cpp +++ b/Userland/Libraries/LibC/unistd.cpp @@ -4,12 +4,14 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include #include #include #include +#include #include #include #include @@ -22,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -398,11 +402,72 @@ ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) return nwritten; } +// Note: Be sure to send to directory_name parameter a directory name ended with trailing slash. +static int ttyname_r_for_directory(const char* directory_name, dev_t device_mode, ino_t inode_number, char* buffer, size_t size) +{ + DIR* dirstream = opendir(directory_name); + if (!dirstream) { + return -1; + } + + auto close_dir_stream_on_exit = ScopeGuard([dirstream] { + closedir(dirstream); + }); + + struct dirent* entry = nullptr; + char* name_path = nullptr; + + // FIXME: Use LibCore DirIterator here instead + while ((entry = readdir(dirstream)) != nullptr) { + if (((ino_t)entry->d_ino == inode_number) + && strcmp(entry->d_name, "stdin") + && strcmp(entry->d_name, "stdout") + && strcmp(entry->d_name, "stderr")) { + + size_t name_length = strlen(directory_name) + strlen(entry->d_name) + 1; + + if (name_length > size) { + errno = ERANGE; + return -1; + } + + name_path = (char*)malloc(name_length); + memset(name_path, 0, name_length); + memcpy(name_path, directory_name, strlen(directory_name)); + memcpy(&name_path[strlen(directory_name)], entry->d_name, strlen(entry->d_name)); + struct stat st; + if (lstat(name_path, &st) < 0) { + free(name_path); + continue; + } + + if (device_mode == st.st_rdev) { + memset(buffer, 0, name_length); + memcpy(buffer, name_path, name_length); + free(name_path); + return 0; + } + } + } + free(name_path); + return -1; +} + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/ttyname_r.html int ttyname_r(int fd, char* buffer, size_t size) { - int rc = syscall(SC_ttyname, fd, buffer, size); - __RETURN_WITH_ERRNO(rc, rc, -1); + struct stat stat; + if (fstat(fd, &stat) < 0) + return -1; + dev_t major_minor_numbers = stat.st_rdev; + ino_t inode_number = stat.st_ino; + if (ttyname_r_for_directory("/dev/", major_minor_numbers, inode_number, buffer, size) < 0) { + if (ttyname_r_for_directory("/dev/pts/", major_minor_numbers, inode_number, buffer, size) < 0) { + errno = ENOTTY; + return -1; + } + } + return 0; } static char ttyname_buf[32];