diff --git a/Userland/Applications/Terminal/main.cpp b/Userland/Applications/Terminal/main.cpp index 71b0cc81da..90074061dc 100644 --- a/Userland/Applications/Terminal/main.cpp +++ b/Userland/Applications/Terminal/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -79,84 +80,27 @@ static void utmp_update(const char* tty, pid_t pid, bool create) } } -static pid_t run_command(int ptm_fd, String command) +static void run_command(String command) { - pid_t pid = fork(); - if (pid < 0) { - perror("fork"); - dbgln("run_command: could not fork to run '{}'", command); - return pid; + String shell = "/bin/Shell"; + auto* pw = getpwuid(getuid()); + if (pw && pw->pw_shell) { + shell = pw->pw_shell; } + endpwent(); - if (pid == 0) { - const char* tty_name = ptsname(ptm_fd); - if (!tty_name) { - perror("ptsname"); - exit(1); - } - close(ptm_fd); - int pts_fd = open(tty_name, O_RDWR); - if (pts_fd < 0) { - perror("open"); - exit(1); - } - - if (setsid() < 0) { - perror("setsid"); - } - - close(0); - close(1); - close(2); - - int rc = dup2(pts_fd, 0); - if (rc < 0) { - perror("dup2"); - exit(1); - } - rc = dup2(pts_fd, 1); - if (rc < 0) { - perror("dup2"); - exit(1); - } - rc = dup2(pts_fd, 2); - if (rc < 0) { - perror("dup2"); - exit(1); - } - rc = close(pts_fd); - if (rc < 0) { - perror("close"); - exit(1); - } - rc = ioctl(0, TIOCSCTTY); - if (rc < 0) { - perror("ioctl(TIOCSCTTY)"); - exit(1); - } - - String shell = "/bin/Shell"; - auto* pw = getpwuid(getuid()); - if (pw && pw->pw_shell) { - shell = pw->pw_shell; - } - endpwent(); - - const char* args[4] = { shell.characters(), nullptr, nullptr, nullptr }; - if (!command.is_empty()) { - args[1] = "-c"; - args[2] = command.characters(); - } - const char* envs[] = { "TERM=xterm", "PAGER=more", "PATH=/bin:/usr/bin:/usr/local/bin", nullptr }; - rc = execve(shell.characters(), const_cast(args), const_cast(envs)); - if (rc < 0) { - perror("execve"); - exit(1); - } - VERIFY_NOT_REACHED(); + const char* args[4] = { shell.characters(), nullptr, nullptr, nullptr }; + if (!command.is_empty()) { + args[1] = "-c"; + args[2] = command.characters(); } - - return pid; + const char* envs[] = { "TERM=xterm", "PAGER=more", "PATH=/bin:/usr/bin:/usr/local/bin", nullptr }; + int rc = execve(shell.characters(), const_cast(args), const_cast(envs)); + if (rc < 0) { + perror("execve"); + exit(1); + } + VERIFY_NOT_REACHED(); } static RefPtr create_settings_window(VT::TerminalWidget& terminal) @@ -314,29 +258,25 @@ int main(int argc, char** argv) args_parser.parse(argc, argv); - int ptm_fd = posix_openpt(O_RDWR | O_CLOEXEC); - if (ptm_fd < 0) { - perror("posix_openpt"); - return 1; - } - if (grantpt(ptm_fd) < 0) { - perror("grantpt"); - return 1; - } - if (unlockpt(ptm_fd) < 0) { - perror("unlockpt"); - return 1; - } - RefPtr config = Core::ConfigFile::get_for_app("Terminal"); Core::File::ensure_parent_directories(config->filename()); - pid_t shell_pid = 0; + int ptm_fd, pts_fd; + pid_t shell_pid = forkpty(&ptm_fd, &pts_fd, nullptr, nullptr, nullptr); + if (shell_pid < 0) { + perror("forkpty"); + return 1; + } + if (shell_pid == 0) { + close(ptm_fd); + if (command_to_execute) + run_command(command_to_execute); + else + run_command(config->read_entry("Startup", "Command", "")); + VERIFY_NOT_REACHED(); + } - if (command_to_execute) - shell_pid = run_command(ptm_fd, command_to_execute); - else - shell_pid = run_command(ptm_fd, config->read_entry("Startup", "Command", "")); + close(pts_fd); auto* pts_name = ptsname(ptm_fd); utmp_update(pts_name, shell_pid, true); diff --git a/Userland/Libraries/LibC/CMakeLists.txt b/Userland/Libraries/LibC/CMakeLists.txt index f2d90963db..b84282ee33 100644 --- a/Userland/Libraries/LibC/CMakeLists.txt +++ b/Userland/Libraries/LibC/CMakeLists.txt @@ -23,6 +23,7 @@ set(LIBC_SOURCES pthread_forward.cpp pthread_integration.cpp pthread_tls.cpp + pty.cpp pwd.cpp qsort.cpp scanf.cpp diff --git a/Userland/Libraries/LibC/pty.cpp b/Userland/Libraries/LibC/pty.cpp new file mode 100644 index 0000000000..0b13b2c8b1 --- /dev/null +++ b/Userland/Libraries/LibC/pty.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Gunnar Beutner + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +int openpty(int* amaster, int* aslave, char* name, const struct termios* termp, const struct winsize* winp) +{ + *amaster = posix_openpt(O_RDWR); + if (*amaster < 0) { + return -1; + } + if (grantpt(*amaster) < 0) { + int error = errno; + close(*amaster); + errno = error; + return -1; + } + if (unlockpt(*amaster) < 0) { + int error = errno; + close(*amaster); + errno = error; + return -1; + } + + const char* tty_name = ptsname(*amaster); + if (!tty_name) { + int error = errno; + close(*amaster); + errno = error; + return -1; + } + + if (name) { + /* The spec doesn't say how large name has to be. Good luck. */ + [[maybe_unused]] auto rc = strlcpy(name, tty_name, 128); + } + + *aslave = open(tty_name, O_RDWR | O_NOCTTY); + if (*aslave < 0) { + int error = errno; + close(*amaster); + errno = error; + return -1; + } + if (termp) { + // FIXME: error handling + tcsetattr(*aslave, TCSAFLUSH, termp); + } + if (winp) { + // FIXME: error handling + ioctl(*aslave, TIOCGWINSZ, winp); + } + + dbgln("openpty, master={}, slave={}, tty_name={}", *amaster, *aslave, tty_name); + + return 0; +} + +pid_t forkpty(int* amaster, int* aslave, char* name, const struct termios* termp, const struct winsize* winp) +{ + int rc = openpty(amaster, aslave, name, termp, winp); + if (rc < 0) + return rc; + rc = fork(); + if (rc < 0) { + close(*amaster); + close(*aslave); + return -1; + } + if (rc == 0) + rc = login_tty(*aslave); + return rc; +} + +int login_tty(int fd) +{ + setsid(); + + close(0); + close(1); + close(2); + + int rc = dup2(fd, 0); + if (rc < 0) + return rc; + rc = dup2(fd, 1); + if (rc < 0) + return -1; + rc = dup2(fd, 2); + if (rc < 0) + return rc; + rc = close(fd); + if (rc < 0) + return rc; + rc = ioctl(0, TIOCSCTTY); + if (rc < 0) + return rc; + return 0; +} diff --git a/Userland/Libraries/LibC/pty.h b/Userland/Libraries/LibC/pty.h new file mode 100644 index 0000000000..45681620bf --- /dev/null +++ b/Userland/Libraries/LibC/pty.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021, Gunnar Beutner + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +__BEGIN_DECLS + +int openpty(int* amaster, int* aslave, char* name, const struct termios* termp, const struct winsize* winp); +pid_t forkpty(int* amaster, int* aslave, char* name, const struct termios* termp, const struct winsize* winp); +int login_tty(int fd); + +__END_DECLS