/*\r
- AcessOS Shell Version 2\r
-- Based on IOOS CLI Shell\r
-*/\r
+ * AcessOS Shell Version 3\r
+ */\r
+#define USE_READLINE 1\r
#include <acess/sys.h>\r
#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
#include "header.h"\r
+#include <readline.h>\r
+#include <errno.h>\r
\r
#define _stdin 0\r
#define _stdout 1\r
#define _stderr 2\r
\r
// ==== PROTOTYPES ====\r
-char *ReadCommandLine(int *Length);\r
-void Parse_Args(char *str, char **dest);\r
-void Command_Colour(int argc, char **argv);\r
+ int Parse_Args(const char *str, char **dest);\r
+void CallCommand(char **Args);\r
+void Command_Logout(int argc, char **argv);\r
void Command_Clear(int argc, char **argv);\r
+void Command_Help(int argc, char **argv);\r
void Command_Cd(int argc, char **argv);\r
void Command_Dir(int argc, char **argv);\r
\r
// ==== CONSTANT GLOBALS ====\r
-char *cCOLOUR_NAMES[8] = {"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"};\r
struct {\r
char *name;\r
void (*fcn)(int argc, char **argv);\r
} cBUILTINS[] = {\r
- {"colour", Command_Colour}, {"clear", Command_Clear},\r
+ {"exit", Command_Logout}, {"logout", Command_Logout},\r
+ {"help", Command_Help}, {"clear", Command_Clear},\r
{"cd", Command_Cd}, {"dir", Command_Dir}\r
};\r
+static char *cDEFAULT_PATH[] = {"/Acess/Bin","/Acess/SBin"};\r
#define BUILTIN_COUNT (sizeof(cBUILTINS)/sizeof(cBUILTINS[0]))\r
\r
// ==== LOCAL VARIABLES ====\r
+ int giNumPathDirs = 2;\r
+char **gasPathDirs = cDEFAULT_PATH;\r
+char **gasEnvironment;\r
char gsCommandBuffer[1024];\r
-char *gsCurrentDirectory = "/";\r
-char gsTmpBuffer[1024];\r
+char *gsCurrentDirectory = NULL;\r
char **gasCommandHistory;\r
int giLastCommand = 0;\r
int giCommandSpace = 0;\r
\r
// ==== CODE ====\r
-int main(int argc, char *argv[], char *envp[])\r
+int main(int argc, char *argv[], char **envp)\r
{\r
char *sCommandStr;\r
- char *saArgs[32];\r
- int length = 0;\r
- int pid = -1;\r
+ char *saArgs[32] = {0};\r
+ int i;\r
int iArgCount = 0;\r
- int bCached = 1;\r
- t_sysFInfo info;\r
+ tReadline *readline_state = Readline_Init(1);\r
+ \r
+ gasEnvironment = envp;\r
\r
- //Command_Clear(0, NULL);\r
+ Command_Clear(0, NULL);\r
+ \r
+ {\r
+ char *tmp = getenv("CWD");\r
+ if(tmp) {\r
+ gsCurrentDirectory = malloc(strlen(tmp)+1);\r
+ strcpy(gsCurrentDirectory, tmp);\r
+ } else {\r
+ gsCurrentDirectory = malloc(2);\r
+ strcpy(gsCurrentDirectory, "/");\r
+ }\r
+ } \r
\r
- write(_stdout, 1, "\n");\r
- write(_stdout, 36, "Acess Shell Version 3\n");\r
- write(_stdout, 30, " Based on CLI Shell for IOOS\n");\r
- write(_stdout, 2, "\n");\r
+ printf("Acess Shell Version 3\n\n");\r
for(;;)\r
{\r
// Free last command & arguments\r
- if(saArgs[0]) free(saArgs);\r
- if(!bCached) free(sCommandStr);\r
- bCached = 0;\r
- write(_stdout, strlen(gsCurrentDirectory), gsCurrentDirectory);\r
- write(_stdout, 3, "$ ");\r
+ if(saArgs[0]) free(saArgs[0]);\r
\r
- // Read Command line\r
- sCommandStr = ReadCommandLine( &length );\r
+ printf("%s$ ", gsCurrentDirectory);\r
+ fflush(stdout);\r
\r
- // Check if the command should be cached\r
- if(gasCommandHistory == NULL || strcmp(sCommandStr, gasCommandHistory[giLastCommand]) != 0)\r
- {\r
- if(giLastCommand >= giCommandSpace) {\r
- giCommandSpace += 12;\r
- gasCommandHistory = realloc(gasCommandHistory, giCommandSpace*sizeof(char*));\r
- }\r
- giLastCommand ++;\r
- gasCommandHistory[ giLastCommand ] = sCommandStr;\r
- bCached = 1;\r
+ // Read Command line\r
+ sCommandStr = Readline( readline_state );\r
+ printf("\n");\r
+ if( !sCommandStr ) {\r
+ perror("Readline");\r
+ return 1;\r
}\r
\r
// Parse Command Line into arguments\r
- Parse_Args(sCommandStr, saArgs);\r
- \r
- // Count Arguments\r
- iArgCount = 0;\r
- while(saArgs[iArgCount]) iArgCount++;\r
+ iArgCount = Parse_Args(sCommandStr, saArgs);\r
\r
// Silently Ignore all empty commands\r
if(saArgs[1][0] == '\0') continue;\r
\r
// Check Built-In Commands\r
- // [HACK] Mem Usage - Use Length in place of `i'\r
- for(length=0;length<BUILTIN_COUNT;length++)\r
+ for( i = 0; i < BUILTIN_COUNT; i++ )\r
{\r
- if(strcmp(saArgs[1], cBUILTINS[length].name) == 0)\r
+ if( strcmp(saArgs[1], cBUILTINS[i].name) == 0 )\r
{\r
- cBUILTINS[length].fcn(iArgCount-1, &saArgs[1]);\r
+ cBUILTINS[i].fcn(iArgCount-1, &saArgs[1]);\r
break;\r
}\r
}\r
+ if(i != BUILTIN_COUNT) continue;\r
\r
- if(length != BUILTIN_COUNT) continue;\r
-
- // - Calling a file\r
- GeneratePath(saArgs[1], gsCurrentDirectory, gsTmpBuffer);\r
- // Use length in place of fp\r
- length = open(gsTmpBuffer, 0);\r
- // Check file existence\r
- if(length == -1) {\r
- Print("Unknown Command: `");Print(saArgs[1]);Print("'\n"); // Error Message\r
- continue;\r
- }\r
- // Check if the file is a directory\r
- finfo( length, &info, 0 );
- close( length );\r
- if(info.flags & FILEFLAG_DIRECTORY) {\r
- Print("`");Print(saArgs[1]); // Error Message\r
- Print("' is a directory.\n");\r
- continue;\r
- }\r
- // Load new executable\r
- pid = clone(CLONE_VM, 0);\r
- if(pid == 0) execve(gsTmpBuffer, &saArgs[1], envp);\r
- if(pid <= 0) {\r
- Print("Unablt to create process: `");Print(gsTmpBuffer);Print("'\n"); // Error Message
- //SysDebug("pid = %i\n", pid);\r
- }\r
- else {\r
- int status;\r
- waittid(pid, &status);\r
- }\r
- }\r
-}\r
-\r
-/**\r
- * \fn char *ReadCommandLine(int *Length)\r
- * \brief Read from the command line\r
- */\r
-char *ReadCommandLine(int *Length)\r
-{\r
- char *ret;\r
- int len, pos, space = 1023;\r
- char ch;\r
- \r
- // Preset Variables\r
- ret = malloc( space+1 );\r
- len = 0;\r
- pos = 0;\r
+ // Shall we?\r
+ CallCommand( &saArgs[1] );\r
\r
- // Read In Command Line\r
- do {\r
- read(_stdin, 1, &ch); // Read Character from stdin (read is a blocking call)\r
- // Ignore control characters\r
- if(ch < 0) continue;\r
- // Backspace\r
- if(ch == '\b') {\r
- if(len <= 0) continue; // Protect against underflows\r
- if(pos == len) { // Simple case of end of string\r
- len --; pos--;\r
- } else {\r
- memmove(&ret[pos-1], &ret[pos], len-pos);\r
- pos --;\r
- len --;\r
- }\r
- write(_stdout, 1, &ch);\r
- continue;\r
- }\r
- // Expand Buffer\r
- if(len > space) {\r
- space += 256;\r
- ret = realloc(ret, space+1);\r
- if(!ret) return NULL;\r
- }\r
- \r
- write(_stdout, 1, &ch);\r
- ret[pos++] = ch;\r
- len ++;\r
- } while(ch != '\n');\r
- \r
- // Remove newline\r
- pos --;\r
- ret[pos] = '\0';\r
- \r
- // Return length\r
- if(Length) *Length = len;\r
- \r
- return ret;\r
+ free( sCommandStr );\r
+ }\r
}\r
\r
/**\r
- * \fn void Parse_Args(char *str, char **dest)\r
+ * \fn int Parse_Args(const char *str, char **dest)\r
* \brief Parse a string into an argument array\r
*/\r
-void Parse_Args(char *str, char **dest)\r
+int Parse_Args(const char *str, char **dest)\r
{\r
int i = 1;\r
char *buf = malloc( strlen(str) + 1 );\r
\r
+ if(buf == NULL) {\r
+ dest[0] = NULL;\r
+ printf("Parse_Args: Out of heap space!\n");\r
+ return 0;\r
+ }\r
+ \r
strcpy(buf, str);\r
dest[0] = buf;\r
\r
if(*buf == '\0') break;\r
}\r
dest[i] = NULL;\r
- if(i == 1) {\r
- free(buf);\r
- dest[0] = NULL;\r
- }\r
+ \r
+ return i;\r
}\r
\r
/**\r
- * \fn void Command_Colour(int argc, char **argv)\r
- * \brief \r
+ * \fn void CallCommand(char **Args)\r
*/\r
-void Command_Colour(int argc, char **argv)\r
+void CallCommand(char **Args)\r
{\r
- int fg, bg;\r
- char clrStr[6] = "\x1B[37m";\r
+ t_sysFInfo info;\r
+ int pid = -1;\r
+ int fd = 0;\r
+ char sTmpBuffer[1024];\r
+ char *exefile = Args[0];\r
\r
- // Verify Arg Count\r
- if(argc < 2)\r
+ if(exefile[0] == '/'\r
+ || (exefile[0] == '.' && exefile[1] == '/')\r
+ || (exefile[0] == '.' && exefile[1] == '.' && exefile[2] == '/')\r
+ )\r
{\r
- Print("Please specify a colour\n");\r
- goto usage;\r
- }\r
- \r
- // Check Colour\r
- for(fg=0;fg<8;fg++)\r
- if(strcmp(cCOLOUR_NAMES[fg], argv[1]) == 0)\r
- break;\r
-\r
- // Foreground a valid colour\r
- if(fg == 8) {\r
- Print("Unknown Colour '");Print(argv[1]);Print("'\n");\r
- goto usage;\r
+ GeneratePath(exefile, gsCurrentDirectory, sTmpBuffer);\r
+ // Check file existence\r
+ fd = _SysOpen(sTmpBuffer, OPENFLAG_EXEC);\r
+ if(fd == -1) {\r
+ printf("Unknown Command: `%s'\n", Args[0]); // Error Message\r
+ return ;\r
+ }\r
+ \r
+ // Get File info and close file\r
+ _SysFInfo( fd, &info, 0 );\r
+ _SysClose( fd );\r
+ \r
+ // Check if the file is a directory\r
+ if(info.flags & FILEFLAG_DIRECTORY) {\r
+ printf("`%s' is a directory.\n", sTmpBuffer);\r
+ return ;\r
+ }\r
}\r
- // Set Foreground\r
- clrStr[3] = '0' + fg;\r
- write(_stdout, 6, clrStr);\r
- \r
- // Need to Set Background?\r
- if(argc > 2)\r
+ else\r
{\r
- for(bg=0;bg<8;bg++)\r
- if(strcmp(cCOLOUR_NAMES[bg], argv[2]) == 0)\r
- break;\r
- \r
- // Valid colour\r
- if(bg == 8)\r
+ int i;\r
+ \r
+ // Check all components of $PATH\r
+ for( i = 0; i < giNumPathDirs; i++ )\r
{\r
- Print("Unknown Colour '");Print(argv[2]);Print("'\n");\r
- goto usage;\r
+ GeneratePath(exefile, gasPathDirs[i], sTmpBuffer);\r
+ fd = _SysOpen(sTmpBuffer, OPENFLAG_EXEC);\r
+ if(fd == -1) continue;\r
+ _SysFInfo( fd, &info, 0 );\r
+ _SysClose( fd );\r
+ if(info.flags & FILEFLAG_DIRECTORY) continue;\r
+ // Woohoo! We found a valid command\r
+ break;\r
+ }\r
+ \r
+ // Exhausted path directories\r
+ if( i == giNumPathDirs ) {\r
+ printf("Unknown Command: `%s'\n", exefile);\r
+ return ;\r
}\r
+ }\r
\r
- clrStr[2] = '4';\r
- clrStr[3] = '0' + bg;\r
- write(_stdout, 6, clrStr);\r
+ // Create new process\r
+ int fds[] = {0, 1, 2};\r
+ pid = _SysSpawn(sTmpBuffer, (const char **)Args, (const char **)gasEnvironment, 3, fds, NULL);\r
+ if(pid <= 0) {\r
+ printf("Unable to create process: `%s'\n", sTmpBuffer); // Error Message\r
}\r
- // Return\r
- return;\r
-\r
- // Function Usage (Requested via a Goto (I know it's ugly))\r
-usage:\r
- Print("Valid Colours are ");\r
- for(fg=0;fg<8;fg++)\r
- {\r
- Print(cCOLOUR_NAMES[fg]);\r
- write(_stdout, 3, ", ");\r
+ else {\r
+ int status;\r
+ _SysWaitTID(pid, &status);\r
}\r
- write(_stdout, 4, "\b\b\n");\r
+}\r
+\r
+/**\r
+ * \fn void Command_Logout(int argc, char **argv)\r
+ * \brief Exit the shell, logging the user out\r
+ */\r
+void Command_Logout(int argc, char **argv)\r
+{\r
+ exit(0);\r
+}\r
+\r
+/**\r
+ * \fn void Command_Colour(int argc, char **argv)\r
+ * \brief Displays the help screen\r
+ */\r
+void Command_Help(int argc, char **argv)\r
+{\r
+ printf( "Acess 2 Command Line Interface\n"\r
+ " By John Hodge (thePowersGang / [TPG])\n"\r
+ "\n"\r
+ "Builtin Commands:\n"\r
+ " logout: Return to the login prompt\n"\r
+ " exit: Same\n"\r
+ " help: Display this message\n"\r
+ " clear: Clear the screen\n"\r
+ " cd: Change the current directory\n"\r
+ " dir: Print the contents of the current directory\n");\r
return;\r
}\r
\r
+/**\r
+ * \fn void Command_Clear(int argc, char **argv)\r
+ * \brief Clear the screen\r
+ */\r
void Command_Clear(int argc, char **argv)\r
{\r
- write(_stdout, 4, "\x1B[2J"); //Clear Screen\r
+ _SysWrite(_stdout, "\x1B[2J", 4); //Clear Screen\r
}\r
\r
/**\r
\r
if(argc < 2)\r
{\r
- Print(gsCurrentDirectory);Print("\n");\r
+ printf("%s\n", gsCurrentDirectory);\r
return;\r
}\r
\r
GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
\r
- fp = open(tmpPath, 0);\r
+ fp = _SysOpen(tmpPath, 0);\r
if(fp == -1) {\r
- write(_stdout, 26, "Directory does not exist\n");\r
+ printf("Directory does not exist\n");\r
return;\r
}\r
- finfo(fp, &stats, 0);\r
- close(fp);\r
+ _SysFInfo(fp, &stats, 0);\r
+ _SysClose(fp);\r
\r
if( !(stats.flags & FILEFLAG_DIRECTORY) ) {\r
- write(_stdout, 17, "Not a Directory\n");\r
+ printf("Not a Directory\n");\r
return;\r
}\r
\r
+ free(gsCurrentDirectory);\r
+ gsCurrentDirectory = malloc(strlen(tmpPath)+1);\r
strcpy(gsCurrentDirectory, tmpPath);\r
+ \r
+ // Register change with kernel\r
+ _SysChdir( gsCurrentDirectory );\r
}\r
\r
/**\r
+ * \fn void Command_Dir(int argc, char **argv)\r
+ * \brief Print the contents of a directory\r
*/\r
void Command_Dir(int argc, char **argv)\r
{\r
- int dp, fp, dirLen;\r
- //char modeStr[11] = "RWXrwxRWX ";\r
- char tmpPath[1024];\r
- char *fileName;\r
+ int dp, fp;\r
+ char modeStr[11] = "RWXrwxRWX ";\r
+ char fileName[256];\r
t_sysFInfo info;\r
+ t_sysACL acl;\r
\r
+\r
+ // -- Generate and open directory --\r
// Generate Directory Path\r
+ char tmpPath[1024];\r
if(argc > 1)\r
- dirLen = GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
+ GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
else\r
- {\r
strcpy(tmpPath, gsCurrentDirectory);\r
- }\r
- dirLen = strlen(tmpPath);\r
- \r
// Open Directory\r
- dp = open(tmpPath, OPENFLAG_READ);\r
- // Check if file opened\r
- if(dp == -1)\r
- {\r
- //printf("Unable to open directory `%s', File cannot be found\n", tmpPath);\r
- write(_stdout, 27, "Unable to open directory `");\r
- write(_stdout, strlen(tmpPath)+1, tmpPath);\r
- write(_stdout, 25, "', File cannot be found\n");\r
+ dp = _SysOpen(tmpPath, OPENFLAG_READ);\r
+ if(dp == -1) {\r
+ printf("Unable to open directory `%s', File cannot be found\n", tmpPath);\r
return;\r
}\r
// Get File Stats\r
- if( finfo(dp, &info, 0) == -1 )\r
+ if( _SysFInfo(dp, &info, 0) == -1 )\r
{\r
- close(dp);\r
- write(_stdout, 34, "stat Failed, Bad File Descriptor\n");\r
+ _SysClose(dp);\r
+ printf("stat Failed, Bad File Descriptor\n");\r
return;\r
}\r
// Check if it's a directory\r
if(!(info.flags & FILEFLAG_DIRECTORY))\r
{\r
- close(dp);\r
- write(_stdout, 27, "Unable to open directory `");\r
- write(_stdout, strlen(tmpPath)+1, tmpPath);\r
- write(_stdout, 20, "', Not a directory\n");\r
+ _SysClose(dp);\r
+ printf("Unable to open directory `%s', Not a directory\n", tmpPath);\r
return;\r
}\r
\r
- // Append Shash for file paths\r
- if(tmpPath[dirLen-1] != '/')\r
- {\r
- tmpPath[dirLen++] = '/';\r
- tmpPath[dirLen] = '\0';\r
- }\r
- \r
- fileName = (char*)(tmpPath+dirLen);\r
- // Read Directory Content\r
- while( (fp = readdir(dp, fileName)) )\r
+ // -- Read Directory Contents --\r
+ while( (fp = _SysReadDir(dp, fileName)) )\r
{\r
if(fp < 0)\r
{\r
if(fp == -3)\r
- write(_stdout, 42, "Invalid Permissions to traverse directory\n");\r
+ printf("Invalid Permissions to traverse directory\n");\r
break;\r
}\r
// Open File\r
- fp = open(tmpPath, 0);\r
+ fp = _SysOpenChild(dp, fileName, 0);\r
if(fp == -1) continue;\r
// Get File Stats\r
- finfo(fp, &info, 0);\r
- close(fp);\r
+ _SysFInfo(fp, &info, 0);\r
\r
- // Colour Code\r
- if(info.flags & FILEFLAG_DIRECTORY) // Directory: Green\r
- write(_stdout, 6, "\x1B[32m");\r
+ if(info.flags & FILEFLAG_DIRECTORY)\r
+ printf("d");\r
else\r
- write(_stdout, 6, "\x1B[37m"); // Default: White\r
+ printf("-");\r
+ \r
+ // Print Mode\r
+ // - Owner\r
+ acl.object = info.uid;\r
+ _SysGetACL(fp, &acl);\r
+ if(acl.perms & 1) modeStr[0] = 'r'; else modeStr[0] = '-';\r
+ if(acl.perms & 2) modeStr[1] = 'w'; else modeStr[1] = '-';\r
+ if(acl.perms & 8) modeStr[2] = 'x'; else modeStr[2] = '-';\r
+ // - Group\r
+ acl.object = info.gid | 0x80000000;\r
+ _SysGetACL(fp, &acl);\r
+ if(acl.perms & 1) modeStr[3] = 'r'; else modeStr[3] = '-';\r
+ if(acl.perms & 2) modeStr[4] = 'w'; else modeStr[4] = '-';\r
+ if(acl.perms & 8) modeStr[5] = 'x'; else modeStr[5] = '-';\r
+ // - World\r
+ acl.object = 0xFFFFFFFF;\r
+ _SysGetACL(fp, &acl);\r
+ if(acl.perms & 1) modeStr[6] = 'r'; else modeStr[6] = '-';\r
+ if(acl.perms & 2) modeStr[7] = 'w'; else modeStr[7] = '-';\r
+ if(acl.perms & 8) modeStr[8] = 'x'; else modeStr[8] = '-';\r
+ printf(modeStr);\r
+ _SysClose(fp);\r
\r
- //Print Mode\r
- #if 0\r
- if(stats.st_mode & 0400) modeStr[0] = 'R'; else modeStr[0] = '-';\r
- if(stats.st_mode & 0200) modeStr[1] = 'W'; else modeStr[1] = '-';\r
- if(stats.st_mode & 0100) modeStr[2] = 'X'; else modeStr[2] = '-';\r
- if(stats.st_mode & 0040) modeStr[3] = 'R'; else modeStr[3] = '-';\r
- if(stats.st_mode & 0020) modeStr[4] = 'W'; else modeStr[4] = '-';\r
- if(stats.st_mode & 0010) modeStr[5] = 'X'; else modeStr[5] = '-';\r
- if(stats.st_mode & 0004) modeStr[6] = 'R'; else modeStr[6] = '-';\r
- if(stats.st_mode & 0002) modeStr[7] = 'W'; else modeStr[7] = '-';\r
- if(stats.st_mode & 0001) modeStr[8] = 'X'; else modeStr[8] = '-';\r
- write(_stdout, 10, modeStr);\r
- #endif\r
+ // Colour Code\r
+ if(info.flags & FILEFLAG_DIRECTORY) // Directory: Green\r
+ printf("\x1B[32m");\r
+ // Default: White\r
\r
// Print Name\r
- write(_stdout, strlen(fileName), fileName);\r
+ printf("%s", fileName);\r
+ \r
// Print slash if applicable\r
if(info.flags & FILEFLAG_DIRECTORY)\r
- write(_stdout, 1, "/");\r
+ printf("/");\r
+ \r
+ // Revert Colour\r
+ printf("\x1B[37m");\r
\r
- // Revert Colour and end line\r
- write(_stdout, 6, "\x1B[37m");\r
- write(_stdout, 1, "\n");\r
+ // Newline!\r
+ printf("\n");\r
}\r
// Close Directory\r
- close(dp);\r
+ _SysClose(dp);\r
}\r