blob: b5d7650239f2ca23e5fb01a49edc77942aa2f432 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <algorithm>
#include <filesystem>
#include <iterator>
#include <sstream>
#include <string>
#include <zxtest/zxtest.h>
#include "lib/fdio/fd.h"
#include "lib/fdio/fdio.h"
#include "lib/fdio/io.h"
#include "lib/fdio/spawn.h"
#include "lib/zx/channel.h"
#include "lib/zx/object.h"
#include "lib/zx/process.h"
#include "lib/zx/socket.h"
#include "zircon/limits.h"
#include "zircon/processargs.h"
#include "zircon/syscalls/object.h"
#include "zircon/syscalls/policy.h"
#include "zircon/types.h"
static constexpr char kDash[] = "/pkg/bin/sh";
static constexpr const char* kDashArgv[] = {kDash, nullptr};
static void join(const zx::process& process) {
ASSERT_OK(process.wait_one(ZX_TASK_TERMINATED, zx::time::infinite(), nullptr));
zx_info_process_v2_t proc_info{};
ASSERT_OK(process.get_info(ZX_INFO_PROCESS_V2, &proc_info, sizeof(proc_info), nullptr, nullptr));
ASSERT_EQ(0, proc_info.return_code);
}
TEST(DashTests, dash_ls_test) {
zx_status_t status;
zx::process process;
zx::socket sstdout, sstdin;
int stdout, stdin;
status = fdio_pipe_half(&stdout, sstdout.reset_and_get_address());
ASSERT_GE(status, ZX_OK);
status = fdio_pipe_half(&stdin, sstdin.reset_and_get_address());
ASSERT_GE(status, ZX_OK);
fdio_spawn_action_t actions[3];
actions[0].action = FDIO_SPAWN_ACTION_CLONE_FD;
actions[0].fd.local_fd = 2;
actions[0].fd.target_fd = 2;
actions[1].action = FDIO_SPAWN_ACTION_TRANSFER_FD;
actions[1].fd.local_fd = stdout;
actions[1].fd.target_fd = 1;
actions[2].action = FDIO_SPAWN_ACTION_TRANSFER_FD;
actions[2].fd.local_fd = stdin;
actions[2].fd.target_fd = 0;
status = fdio_spawn_etc(
ZX_HANDLE_INVALID,
FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_NAMESPACE | FDIO_SPAWN_DEFAULT_LDSVC, kDash,
kDashArgv, nullptr, 3, actions, process.reset_and_get_address(), nullptr);
ASSERT_EQ(ZX_OK, status);
// Note: the PATH=; here forces the call to reach the builtin.
std::string ls("PATH=; ls /\n");
ASSERT_EQ(ZX_OK, sstdin.write(0, ls.data(), ls.length(), nullptr));
sstdin.reset();
join(process);
std::string buf(4096, 0);
size_t actual;
sstdout.read(0, buf.data(), buf.length(), &actual);
buf.resize(actual);
// We don't really care to be hard-coupled to ls output format yet, but we
// want one line per non-dot dirent.
std::istringstream output(std::string(buf.begin(), buf.end()));
int lines = 0;
for (std::string line; std::getline(output, line);) {
auto pos = line.rfind(" ");
if (pos == std::string::npos) {
continue;
}
line = line.substr(pos + 1);
if (line == "." || line.size() == 0) {
continue;
}
lines++;
}
// Check we have something vaguely meaningful
EXPECT_GT(lines, 1);
int expected = 0;
for (__attribute__((unused)) auto& _ : std::filesystem::directory_iterator{"/"}) {
expected++;
}
ASSERT_EQ(lines, expected);
}