1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 14:57:35 +00:00

LibC: Implement openpty(), forkpty() and login_tty()

These are used by OpenSSH.
This commit is contained in:
Gunnar Beutner 2021-04-30 03:40:38 +02:00 committed by Andreas Kling
parent 6783f65d5a
commit f48f26f52d
4 changed files with 161 additions and 93 deletions

View file

@ -34,6 +34,7 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <pty.h>
#include <pwd.h> #include <pwd.h>
#include <serenity.h> #include <serenity.h>
#include <signal.h> #include <signal.h>
@ -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(); String shell = "/bin/Shell";
if (pid < 0) { auto* pw = getpwuid(getuid());
perror("fork"); if (pw && pw->pw_shell) {
dbgln("run_command: could not fork to run '{}'", command); shell = pw->pw_shell;
return pid;
} }
endpwent();
if (pid == 0) { const char* args[4] = { shell.characters(), nullptr, nullptr, nullptr };
const char* tty_name = ptsname(ptm_fd); if (!command.is_empty()) {
if (!tty_name) { args[1] = "-c";
perror("ptsname"); args[2] = command.characters();
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<char**>(args), const_cast<char**>(envs));
if (rc < 0) {
perror("execve");
exit(1);
}
VERIFY_NOT_REACHED();
} }
const char* envs[] = { "TERM=xterm", "PAGER=more", "PATH=/bin:/usr/bin:/usr/local/bin", nullptr };
return pid; int rc = execve(shell.characters(), const_cast<char**>(args), const_cast<char**>(envs));
if (rc < 0) {
perror("execve");
exit(1);
}
VERIFY_NOT_REACHED();
} }
static RefPtr<GUI::Window> create_settings_window(VT::TerminalWidget& terminal) static RefPtr<GUI::Window> create_settings_window(VT::TerminalWidget& terminal)
@ -314,29 +258,25 @@ int main(int argc, char** argv)
args_parser.parse(argc, 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<Core::ConfigFile> config = Core::ConfigFile::get_for_app("Terminal"); RefPtr<Core::ConfigFile> config = Core::ConfigFile::get_for_app("Terminal");
Core::File::ensure_parent_directories(config->filename()); 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) close(pts_fd);
shell_pid = run_command(ptm_fd, command_to_execute);
else
shell_pid = run_command(ptm_fd, config->read_entry("Startup", "Command", ""));
auto* pts_name = ptsname(ptm_fd); auto* pts_name = ptsname(ptm_fd);
utmp_update(pts_name, shell_pid, true); utmp_update(pts_name, shell_pid, true);

View file

@ -23,6 +23,7 @@ set(LIBC_SOURCES
pthread_forward.cpp pthread_forward.cpp
pthread_integration.cpp pthread_integration.cpp
pthread_tls.cpp pthread_tls.cpp
pty.cpp
pwd.cpp pwd.cpp
qsort.cpp qsort.cpp
scanf.cpp scanf.cpp

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Format.h>
#include <fcntl.h>
#include <pty.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
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;
}

View file

@ -0,0 +1,18 @@
/*
* Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <sys/cdefs.h>
#include <termios.h>
__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