/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #include #include #include #include #include #include "../Modules/PersonalSystem2/keyboard.hpp" #include "../kernel.h" #include "../Fex.hpp" #include "../DAPI.hpp" #include "cmds.hpp" using namespace PS2Keyboard; NewLock(ShellLock); const char sc_ascii_low[] = {'?', '?', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '?', '?', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '?', '?', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', '?', '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '?', '?', '?', ' '}; const char sc_ascii_high[] = {'?', '?', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '?', '?', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\"', '~', '?', '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '?', '?', '?', ' '}; static int LowerCase = true; char GetLetterFromScanCode(uint8_t ScanCode) { if (ScanCode & 0x80) { switch (ScanCode) { case KEY_U_LSHIFT: LowerCase = true; return 0; case KEY_U_RSHIFT: LowerCase = true; return 0; default: return 0; } } else { switch (ScanCode) { case KEY_D_RETURN: return '\n'; case KEY_D_LSHIFT: LowerCase = false; return 0; case KEY_D_RSHIFT: LowerCase = false; return 0; case KEY_D_BACKSPACE: return ScanCode; default: { if (ScanCode > 0x39) break; if (LowerCase) return sc_ascii_low[ScanCode]; else return sc_ascii_high[ScanCode]; } } } return 0; } int GetChar() { return 0; } struct Command { const char *Name; void (*Function)(const char *); }; static Command commands[] = { {"lsof", cmd_lsof}, {"ls", cmd_ls}, {"cd", cmd_cd}, {"cat", cmd_cat}, {"echo", cmd_echo}, {"mkdir", nullptr}, {"touch", nullptr}, {"rm", nullptr}, {"rmdir", nullptr}, {"mv", nullptr}, {"cp", nullptr}, {"clear", nullptr}, {"help", nullptr}, {"exit", cmd_exit}, {"reboot", cmd_reboot}, {"shutdown", cmd_shutdown}, {"ps", cmd_ps}, {"kill", cmd_kill}, {"killall", cmd_killall}, {"top", cmd_top}, {"mem", cmd_mem}, {"mount", nullptr}, {"umount", nullptr}, {"uname", cmd_uname}, {"whoami", cmd_whoami}, {"passwd", nullptr}, {"su", nullptr}, {"login", nullptr}, {"logout", nullptr}, {"uptime", cmd_uptime}, {"chown", nullptr}, {"chgrp", nullptr}, {"chmod", nullptr}, {"chroot", nullptr}, {"lspci", cmd_lspci}}; void StartKernelShell() { SmartLock(ShellLock); debug("Starting kernel shell..."); printf("Starting kernel shell...\n"); thisThread->SetPriority(Tasking::TaskPriority::High); Display->SetBuffer(0); Driver::DriverFile KeyboardModule; if (likely(DriverManager->GetDrivers().size() > 0)) { foreach (auto Driver in DriverManager->GetDrivers()) { if (((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Input && ((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.TypeFlags & FexDriverInputTypes::FexDriverInputTypes_Keyboard) { KeyboardModule = Driver; printf("Using driver \eCA21F6%s\eCCCCCC for keyboard input.\n", ((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Name); break; } } } Display->SetBuffer(0); std::string Buffer; std::vector History; size_t HistoryIndex = 0; bool CtrlDown = false; bool TabDoublePress = false; while (true) { size_t BackspaceCount = 0; Buffer.clear(); VirtualFileSystem::Node *cwd = thisProcess->CurrentWorkingDirectory; if (!cwd) cwd = vfs->GetNodeFromPath("/"); printf("\e34C6EB%s@%s:%s$ \eCCCCCC", "kernel", "fennix", cwd->FileSystem->GetPathFromNode(cwd).c_str()); Display->SetBuffer(0); while (true) { KernelCallback callback{}; callback.Reason = PollWaitReason; DriverManager->IOCB(KeyboardModule.DriverUID, &callback); char c = GetLetterFromScanCode(callback.InputCallback.Keyboard.Key); switch (callback.InputCallback.Keyboard.Key) { case KEY_D_LCTRL: { CtrlDown = true; continue; } case KEY_U_LCTRL: { CtrlDown = false; continue; } case KEY_D_BACKSPACE: { if (BackspaceCount == 0) continue; Display->Print('\b', 0); Buffer.pop_back(); BackspaceCount--; Display->SetBuffer(0); continue; } case KEY_D_UP: { if (History.size() == 0 || HistoryIndex == 0) continue; HistoryIndex--; for (size_t i = 0; i < Buffer.size(); i++) Display->Print('\b', 0); Display->SetBuffer(0); Buffer = History[HistoryIndex]->c_str(); for (size_t i = 0; i < strlen(Buffer.c_str()); i++) Display->Print(Buffer[i], 0); BackspaceCount = Buffer.size(); Display->SetBuffer(0); continue; } case KEY_D_DOWN: { if (History.size() == 0 || HistoryIndex == History.size()) continue; if (HistoryIndex == History.size() - 1) { HistoryIndex++; for (size_t i = 0; i < Buffer.size(); i++) Display->Print('\b', 0); BackspaceCount = Buffer.size(); Display->SetBuffer(0); continue; } for (size_t i = 0; i < Buffer.size(); i++) Display->Print('\b', 0); Display->SetBuffer(0); HistoryIndex++; Buffer = History[HistoryIndex]->c_str(); for (size_t i = 0; i < strlen(Buffer.c_str()); i++) Display->Print(Buffer[i], 0); BackspaceCount = Buffer.size(); Display->SetBuffer(0); continue; } case KEY_D_TAB: { if (!TabDoublePress) { TabDoublePress = true; continue; } TabDoublePress = false; if (Buffer.size() == 0) { for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { printf("%s ", commands[i].Name); Display->SetBuffer(0); } Display->Print('\n', 0); Display->SetBuffer(0); goto SecLoopEnd; } for (size_t i = 0; i < Buffer.size(); i++) Display->Print('\b', 0); Display->SetBuffer(0); for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { if (strncmp(Buffer.c_str(), commands[i].Name, Buffer.size()) == 0) { Buffer = commands[i].Name; for (size_t i = 0; i < strlen(Buffer.c_str()); i++) Display->Print(Buffer[i], 0); BackspaceCount = Buffer.size(); Display->SetBuffer(0); break; } } continue; } default: break; } if (c == 0) continue; if (CtrlDown) { switch (std::toupper((char)c)) { case 'C': { Display->Print('^', 0); Display->Print('C', 0); Display->Print('\n', 0); fixme("No SIGINT handler yet."); Display->SetBuffer(0); goto SecLoopEnd; } case 'D': { Display->Print('^', 0); Display->Print('D', 0); Display->Print('\n', 0); fixme("No SIGKILL handler yet."); Display->SetBuffer(0); goto SecLoopEnd; } default: continue; } } Display->Print(c, 0); if (c == '\n') { if (Buffer.length() > 0) { std::string *hBuff = new std::string(Buffer.c_str()); History.push_back(hBuff); HistoryIndex = History.size(); } break; } Buffer += c; BackspaceCount++; Display->SetBuffer(0); } SecLoopEnd: if (Buffer.length() == 0) continue; bool Found = false; for (size_t i = 0; i < sizeof(commands) / sizeof(Command); i++) { std::string cmd_extracted; for (size_t i = 0; i < Buffer.length(); i++) { if (Buffer[i] == ' ') break; cmd_extracted += Buffer[i]; } debug("cmd: %s, array[%d]: %s", cmd_extracted.c_str(), i, commands[i].Name); if (strncmp(commands[i].Name, cmd_extracted.c_str(), cmd_extracted.size()) == 0) { if (strlen(commands[i].Name) != cmd_extracted.size()) continue; Found = true; std::string arg_only; const char *cmd_name = commands[i].Name; for (size_t i = strlen(cmd_name) + 1; i < Buffer.length(); i++) arg_only += Buffer[i]; if (commands[i].Function) commands[i].Function(arg_only.c_str()); else { std::string cmd_only; for (size_t i = 0; i < Buffer.length(); i++) { if (Buffer[i] == ' ') break; cmd_only += Buffer[i]; } printf("%s: command not implemented\n", cmd_only.c_str()); } break; } } if (!Found) { std::string cmd_only; for (size_t i = 0; i < Buffer.length(); i++) { if (Buffer[i] == ' ') break; cmd_only += Buffer[i]; } printf("%s: command not found\n", cmd_only.c_str()); } } } void KShellThread() { StartKernelShell(); inf_loop; }