diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt index ac6ff70b19..e54e10482a 100644 --- a/Meta/Lagom/CMakeLists.txt +++ b/Meta/Lagom/CMakeLists.txt @@ -48,6 +48,8 @@ file(GLOB LIBJS_SUBDIR_SOURCES "../../Libraries/LibJS/*/*.cpp") file(GLOB LIBCRYPTO_SOURCES "../../Libraries/LibCrypto/*.cpp") file(GLOB LIBCRYPTO_SUBDIR_SOURCES "../../Libraries/LibCrypto/*/*.cpp") file(GLOB LIBTLS_SOURCES "../../Libraries/LibTLS/*.cpp") +file(GLOB SHELL_SOURCES "../../Shell/*.cpp") +file(GLOB SHELL_TESTS "../../Shell/Tests/*.sh") set(LAGOM_CORE_SOURCES ${AK_SOURCES} ${LIBCORE_SOURCES}) set(LAGOM_MORE_SOURCES ${LIBIPC_SOURCES} ${LIBLINE_SOURCES} ${LIBJS_SOURCES} ${LIBJS_SUBDIR_SOURCES} ${LIBX86_SOURCES} ${LIBCRYPTO_SOURCES} ${LIBCRYPTO_SUBDIR_SOURCES} ${LIBTLS_SOURCES}) @@ -87,6 +89,20 @@ if (BUILD_LAGOM) set_target_properties(disasm_lagom PROPERTIES OUTPUT_NAME disasm) target_link_libraries(disasm_lagom Lagom) target_link_libraries(disasm_lagom stdc++) + + add_executable(shell_lagom ${SHELL_SOURCES}) + set_target_properties(shell_lagom PROPERTIES OUTPUT_NAME shell) + target_link_libraries(shell_lagom Lagom) + target_link_libraries(shell_lagom stdc++) + target_link_libraries(shell_lagom pthread) + foreach(TEST_PATH ${SHELL_TESTS}) + get_filename_component(TEST_NAME ${TEST_PATH} NAME_WE) + add_test( + NAME "Shell-${TEST_NAME}" + COMMAND shell_lagom "${TEST_PATH}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + endforeach() endif() if (ENABLE_FUZZER_SANITIZER) diff --git a/Shell/AST.cpp b/Shell/AST.cpp index 1f64d81c13..24c7ae3bef 100644 --- a/Shell/AST.cpp +++ b/Shell/AST.cpp @@ -49,7 +49,9 @@ static inline RefPtr create(std::initializer_list> arg) static inline void print_indented(const String& str, int indent) { - dbgprintf("%.*c%s\n", indent * 2, ' ', str.characters()); + for (auto i = 0; i < indent; ++i) + dbgprintf(" "); + dbgprintf("%s\n", str.characters()); } static inline Vector join_commands(Vector left, Vector right) diff --git a/Shell/Builtin.cpp b/Shell/Builtin.cpp index 5a3928fde9..a9526eb641 100644 --- a/Shell/Builtin.cpp +++ b/Shell/Builtin.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -94,7 +95,7 @@ int Shell::builtin_bg(int argc, const char** argv) job->set_running_in_background(true); dbg() << "Resuming " << job->pid() << " (" << job->cmd() << ")"; - fprintf(stderr, "Resuming job %llu - %s\n", job->job_id(), job->cmd().characters()); + fprintf(stderr, "Resuming job %" PRIu64 " - %s\n", job->job_id(), job->cmd().characters()); if (killpg(job->pgid(), SIGCONT) < 0) { perror("killpg"); @@ -340,7 +341,7 @@ int Shell::builtin_fg(int argc, const char** argv) job->set_running_in_background(false); dbg() << "Resuming " << job->pid() << " (" << job->cmd() << ")"; - fprintf(stderr, "Resuming job %llu - %s\n", job->job_id(), job->cmd().characters()); + fprintf(stderr, "Resuming job %" PRIu64 " - %s\n", job->job_id(), job->cmd().characters()); if (killpg(job->pgid(), SIGCONT) < 0) { perror("killpg"); @@ -406,7 +407,7 @@ int Shell::builtin_disown(int argc, const char** argv) job->deactivate(); if (!job->is_running_in_background()) - fprintf(stderr, "disown warning: job %llu is currently not running, 'kill -%d %d' to make it continue\n", job->job_id(), SIGCONT, job->pid()); + fprintf(stderr, "disown warning: job %" PRIu64 " is currently not running, 'kill -%d %d' to make it continue\n", job->job_id(), SIGCONT, job->pid()); jobs.remove(job_index); } @@ -473,13 +474,13 @@ int Shell::builtin_jobs(int argc, const char** argv) switch (mode) { case Basic: - printf("[%llu] %c %s %s\n", job.value->job_id(), background_indicator, status, job.value->cmd().characters()); + printf("[%" PRIu64 "] %c %s %s\n", job.value->job_id(), background_indicator, status, job.value->cmd().characters()); break; case OnlyPID: - printf("[%llu] %c %d %s %s\n", job.value->job_id(), background_indicator, pid, status, job.value->cmd().characters()); + printf("[%" PRIu64 "] %c %d %s %s\n", job.value->job_id(), background_indicator, pid, status, job.value->cmd().characters()); break; case ListAll: - printf("[%llu] %c %d %d %s %s\n", job.value->job_id(), background_indicator, pid, job.value->pgid(), status, job.value->cmd().characters()); + printf("[%" PRIu64 "] %c %d %d %s %s\n", job.value->job_id(), background_indicator, pid, job.value->pgid(), status, job.value->cmd().characters()); break; } } diff --git a/Shell/Shell.cpp b/Shell/Shell.cpp index 398d8fe631..715a8d3f64 100644 --- a/Shell/Shell.cpp +++ b/Shell/Shell.cpp @@ -423,7 +423,11 @@ RefPtr Shell::run_command(AST::Command& command) return nullptr; pid_t child = fork(); - if (!child) { + if (child < 0) { + perror("fork"); + return nullptr; + } + if (child == 0) { setpgid(0, 0); tcsetpgrp(0, getpid()); tcsetattr(0, TCSANOW, &default_termios); diff --git a/Shell/main.cpp b/Shell/main.cpp index 4ec41e2154..bf98f0e720 100644 --- a/Shell/main.cpp +++ b/Shell/main.cpp @@ -78,6 +78,12 @@ int main(int argc, char** argv) for (auto& job : jobs) { int wstatus = 0; auto child_pid = waitpid(job.value->pid(), &wstatus, WNOHANG); +#ifndef __serenity__ + if (child_pid == 0) { + // Linux: if child didn't "change state", but existed. + child_pid = job.value->pid(); + } +#endif if (child_pid == job.value->pid()) { if (WIFEXITED(wstatus)) { job.value->set_has_exit(WEXITSTATUS(wstatus)); @@ -95,10 +101,18 @@ int main(int argc, char** argv) // Ignore SIGTSTP as the shell should not be suspended with ^Z. signal(SIGTSTP, [](auto) {}); +#ifndef __serenity__ + sigset_t blocked; + sigemptyset(&blocked); + sigaddset(&blocked, SIGTTOU); + pthread_sigmask(SIG_BLOCK, &blocked, NULL); +#endif +#ifdef __serenity__ if (pledge("stdio rpath wpath cpath proc exec tty accept", nullptr) < 0) { perror("pledge"); return 1; } +#endif editor = Line::Editor::construct(Line::Configuration { Line::Configuration::UnescapedSpaces });