fix(terminal): use the shell's directory when the program in front hides its own

main
reionwong 1 week ago
parent 0c2f2d8c84
commit 16d5e11422

@ -325,6 +325,17 @@ void TerminalSession::setUserTitle(int what, const std::string& caption)
updateTitle();
}
// The cwd link, which only a process's own user can read.
static std::optional<std::string> workingDirectory(int pid)
{
char path[PATH_MAX + 1];
const ssize_t length = readlink(("/proc/" + std::to_string(pid) + "/cwd").c_str(), path, PATH_MAX);
if (length < 0)
return std::nullopt;
path[length] = '\0';
return strings::sanitizedUtf8(path);
}
void TerminalSession::updateForegroundProcessInfo()
{
const int foregroundPid = _shellProcess->foregroundProcessGroup();
@ -370,11 +381,8 @@ void TerminalSession::updateForegroundProcessInfo()
return;
_foregroundValid = true;
char path[PATH_MAX + 1];
const ssize_t length = readlink((base + "/cwd").c_str(), path, PATH_MAX);
if (length >= 0) {
path[length] = '\0';
_foregroundDir = strings::sanitizedUtf8(path);
if (std::optional<std::string> dir = workingDirectory(foregroundPid)) {
_foregroundDir = *dir;
_foregroundHasDir = true;
}
}
@ -388,7 +396,13 @@ std::string TerminalSession::foregroundProcessName()
std::string TerminalSession::currentDir()
{
updateForegroundProcessInfo();
return _foregroundValid && _foregroundHasDir ? _foregroundDir : std::string();
if (_foregroundValid && _foregroundHasDir)
return _foregroundDir;
// A program in front that runs as another user, such as su, hides its
// directory; the shell's stands in for it.
if (processId() > 0 && processId() != _foregroundPid)
return workingDirectory(processId()).value_or(std::string());
return std::string();
}
bool TerminalSession::hasActiveProcess() const

@ -12,6 +12,7 @@
#include "base/event_loop.h"
#include "base/file.h"
#include "base/paths.h"
#include "base/timer.h"
#include "TerminalSession.h"
@ -112,3 +113,29 @@ TEST(SessionTest, ChildSeesTheTerminalEnvironment)
ASSERT_TRUE(contents);
EXPECT_TRUE(contents->starts_with("xterm-256color|truecolor|15;0|/dev/pts/")) << *contents;
}
TEST(SessionTest, CurrentDirBehindAProgramOfAnotherUser)
{
set_kb_layout_dir(KB_LAYOUTS_DIR);
// Set-group-ID, so its working directory is not ours to read.
const std::string agent = cutefish::base::paths::findExecutable("ssh-agent");
if (agent.empty())
GTEST_SKIP() << "no ssh-agent";
cutefish::base::EventLoop loop;
cutefish::base::file::TemporaryDirectory directory("/tmp", "session-cwd");
ASSERT_TRUE(directory.isValid());
TerminalSession session;
session.setShellProgram("/bin/sh");
session.setInitialWorkingDirectory(directory.path());
session.startShellProgram();
ASSERT_TRUE(waitFor(loop, [&] { return session.currentDir() == directory.path(); }));
// Looked at only once the agent runs: its socket is there.
const std::string socket = directory.path() + "/agent";
session.sendText(agent + " -D -a " + socket + "\r");
ASSERT_TRUE(waitFor(loop, [&] { return std::filesystem::exists(socket); }));
ASSERT_EQ(session.foregroundProcessName(), "ssh-agent");
EXPECT_EQ(session.currentDir(), directory.path());
session.sendText("\x03");
}

Loading…
Cancel
Save