Implemented SYS_CHDIR at user level. Added process dump key combo to KB driver
[tpg/acess2.git] / Usermode / Applications / CLIShell_src / main.c
1 /*\r
2  * AcessOS Shell Version 3\r
3  */\r
4 #include <acess/sys.h>\r
5 #include <stdlib.h>\r
6 #include <stdio.h>\r
7 #include "header.h"\r
8 \r
9 #define _stdin  0\r
10 #define _stdout 1\r
11 #define _stderr 2\r
12 \r
13 // ==== PROTOTYPES ====\r
14 char    *ReadCommandLine(int *Length);\r
15 void    Parse_Args(char *str, char **dest);\r
16 void    Command_Colour(int argc, char **argv);\r
17 void    Command_Clear(int argc, char **argv);\r
18 void    Command_Cd(int argc, char **argv);\r
19 void    Command_Dir(int argc, char **argv);\r
20 \r
21 // ==== CONSTANT GLOBALS ====\r
22 char    *cCOLOUR_NAMES[8] = {"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"};\r
23 struct  {\r
24         char    *name;\r
25         void    (*fcn)(int argc, char **argv);\r
26 }       cBUILTINS[] = {\r
27         {"colour", Command_Colour}, {"clear", Command_Clear},\r
28         {"cd", Command_Cd}, {"dir", Command_Dir}\r
29 };\r
30 #define BUILTIN_COUNT   (sizeof(cBUILTINS)/sizeof(cBUILTINS[0]))\r
31 \r
32 // ==== LOCAL VARIABLES ====\r
33 char    gsCommandBuffer[1024];\r
34 char    *gsCurrentDirectory = NULL;\r
35 char    gsTmpBuffer[1024];\r
36 char    **gasCommandHistory;\r
37  int    giLastCommand = 0;\r
38  int    giCommandSpace = 0;\r
39 \r
40 // ==== CODE ====\r
41 int main(int argc, char *argv[], char *envp[])\r
42 {\r
43         char    *sCommandStr;\r
44         char    *saArgs[32];\r
45          int    length = 0;\r
46          int    pid = -1;\r
47          int    iArgCount = 0;\r
48          int    bCached = 1;\r
49         t_sysFInfo      info;\r
50         \r
51         Command_Clear(0, NULL);\r
52         \r
53         {\r
54                 char    *tmp = getenv("CWD");\r
55                 if(tmp) {\r
56                         gsCurrentDirectory = malloc(strlen(tmp)+1);\r
57                         strcpy(gsCurrentDirectory, tmp);\r
58                 } else {\r
59                         gsCurrentDirectory = malloc(2);\r
60                         strcpy(gsCurrentDirectory, "/");\r
61                 }\r
62         }       \r
63         \r
64         write(_stdout, 1, "\n");\r
65         write(_stdout, 22, "Acess Shell Version 3\n");\r
66         write(_stdout,  2, "\n");\r
67         for(;;)\r
68         {\r
69                 // Free last command & arguments\r
70                 if(saArgs[0])   free(saArgs);\r
71                 if(!bCached)    free(sCommandStr);\r
72                 bCached = 0;\r
73                 write(_stdout, strlen(gsCurrentDirectory), gsCurrentDirectory);\r
74                 write(_stdout, 3, "$ ");\r
75                 \r
76                 // Read Command line\r
77                 sCommandStr = ReadCommandLine( &length );\r
78                 \r
79                 // Check if the command should be cached\r
80                 if(gasCommandHistory == NULL || strcmp(sCommandStr, gasCommandHistory[giLastCommand]) != 0)\r
81                 {\r
82                         if(giLastCommand >= giCommandSpace) {\r
83                                 giCommandSpace += 12;\r
84                                 gasCommandHistory = realloc(gasCommandHistory, giCommandSpace*sizeof(char*));\r
85                         }\r
86                         giLastCommand ++;\r
87                         gasCommandHistory[ giLastCommand ] = sCommandStr;\r
88                         bCached = 1;\r
89                 }\r
90                 \r
91                 // Parse Command Line into arguments\r
92                 Parse_Args(sCommandStr, saArgs);\r
93                 \r
94                 // Count Arguments\r
95                 iArgCount = 0;\r
96                 while(saArgs[iArgCount])        iArgCount++;\r
97                 \r
98                 // Silently Ignore all empty commands\r
99                 if(saArgs[1][0] == '\0')        continue;\r
100                 \r
101                 // Check Built-In Commands\r
102                 //  [HACK] Mem Usage - Use Length in place of `i'\r
103                 for(length=0;length<BUILTIN_COUNT;length++)\r
104                 {\r
105                         if(strcmp(saArgs[1], cBUILTINS[length].name) == 0)\r
106                         {\r
107                                 cBUILTINS[length].fcn(iArgCount-1, &saArgs[1]);\r
108                                 break;\r
109                         }\r
110                 }\r
111                 \r
112                 if(length != BUILTIN_COUNT)     continue;\r
113                 
114                 // - Calling a file\r
115                 GeneratePath(saArgs[1], gsCurrentDirectory, gsTmpBuffer);\r
116                 // Use length in place of fp\r
117                 length = open(gsTmpBuffer, 0);\r
118                 // Check file existence\r
119                 if(length == -1) {\r
120                         Print("Unknown Command: `");Print(saArgs[1]);Print("'\n");      // Error Message\r
121                         continue;\r
122                 }\r
123                 // Check if the file is a directory\r
124                 finfo( length, &info, 0 );
125                 close( length );\r
126                 if(info.flags & FILEFLAG_DIRECTORY) {\r
127                         Print("`");Print(saArgs[1]);    // Error Message\r
128                         Print("' is a directory.\n");\r
129                         continue;\r
130                 }\r
131                 // Load new executable\r
132                 pid = clone(CLONE_VM, 0);\r
133                 printf("pid = %i\n", pid);\r
134                 if(pid == 0)    execve(gsTmpBuffer, &saArgs[1], envp);\r
135                 if(pid <= 0) {\r
136                         Print("Unablt to create process: `");Print(gsTmpBuffer);Print("'\n");   // Error Message
137                         //SysDebug("pid = %i\n", pid);\r
138                 }\r
139                 else {\r
140                          int    status;\r
141                         waittid(pid, &status);\r
142                 }\r
143         }\r
144 }\r
145 \r
146 /**\r
147  * \fn char *ReadCommandLine(int *Length)\r
148  * \brief Read from the command line\r
149  */\r
150 char *ReadCommandLine(int *Length)\r
151 {\r
152         char    *ret;\r
153          int    len, pos, space = 1023;\r
154         char    ch;\r
155          \r
156         // Preset Variables\r
157         ret = malloc( space+1 );\r
158         if(!ret)        return NULL;\r
159         len = 0;\r
160         pos = 0;\r
161                 \r
162         // Read In Command Line\r
163         do {\r
164                 read(_stdin, 1, &ch);   // Read Character from stdin (read is a blocking call)\r
165                 // Ignore control characters\r
166                 if(ch == '\x1B') {\r
167                         read(_stdin, 1, &ch);   // Read control character\r
168                         switch(ch)\r
169                         {\r
170                         case 'D':       if(pos) pos--;  break;\r
171                         case 'C':       if(pos<len)     pos++;  break;\r
172                         case '[':\r
173                                 read(_stdin, 1, &ch);   // Read control character\r
174                                 switch(ch)\r
175                                 {\r
176                                 case 'D':       if(pos) pos--;  break;\r
177                                 case 'C':       if(pos<len)     pos++;  break;\r
178                                 }\r
179                         }\r
180                         continue;\r
181                 }\r
182                 // Backspace\r
183                 if(ch == '\b') {\r
184                         if(len <= 0)            continue;       // Protect against underflows\r
185                         if(pos == len) {        // Simple case of end of string\r
186                                 len --; pos--;\r
187                         } else {\r
188                                 memmove(&ret[pos-1], &ret[pos], len-pos);\r
189                                 pos --;\r
190                                 len --;\r
191                         }\r
192                         write(_stdout, 1, &ch);\r
193                         continue;\r
194                 }\r
195                 // Expand Buffer\r
196                 if(len > space) {\r
197                         space += 256;\r
198                         ret = realloc(ret, space+1);\r
199                         if(!ret)        return NULL;\r
200                 }\r
201                 \r
202                 write(_stdout, 1, &ch);\r
203                 ret[pos++] = ch;\r
204                 len ++;\r
205         } while(ch != '\n');\r
206         \r
207         // Remove newline\r
208         pos --;\r
209         ret[pos] = '\0';\r
210         \r
211         // Return length\r
212         if(Length)      *Length = len;\r
213         \r
214         return ret;\r
215 }\r
216 \r
217 /**\r
218  * \fn void Parse_Args(char *str, char **dest)\r
219  * \brief Parse a string into an argument array\r
220  */\r
221 void Parse_Args(char *str, char **dest)\r
222 {\r
223          int    i = 1;\r
224         char    *buf = malloc( strlen(str) + 1 );\r
225         \r
226         strcpy(buf, str);\r
227         dest[0] = buf;\r
228         \r
229         // Trim leading whitespace\r
230         while(*buf == ' ' && *buf)      buf++;\r
231         \r
232         for(;;)\r
233         {\r
234                 dest[i] = buf;  // Save start of string\r
235                 i++;\r
236                 while(*buf && *buf != ' ')\r
237                 {\r
238                         if(*buf++ == '"')\r
239                         {\r
240                                 while(*buf && !(*buf == '"' && buf[-1] != '\\'))\r
241                                         buf++;\r
242                         }\r
243                 }\r
244                 if(*buf == '\0')        break;\r
245                 *buf = '\0';\r
246                 while(*++buf == ' ' && *buf);\r
247                 if(*buf == '\0')        break;\r
248         }\r
249         dest[i] = NULL;\r
250         if(i == 1) {\r
251                 free(buf);\r
252                 dest[0] = NULL;\r
253         }\r
254 }\r
255 \r
256 /**\r
257  * \fn void Command_Colour(int argc, char **argv)\r
258  * \brief \r
259  */\r
260 void Command_Colour(int argc, char **argv)\r
261 {\r
262         int fg, bg;\r
263         char    clrStr[6] = "\x1B[37m";\r
264         \r
265         // Verify Arg Count\r
266         if(argc < 2)\r
267         {\r
268                 Print("Please specify a colour\n");\r
269                 goto usage;\r
270         }\r
271         \r
272         // Check Colour\r
273         for(fg=0;fg<8;fg++)\r
274                 if(strcmp(cCOLOUR_NAMES[fg], argv[1]) == 0)\r
275                         break;\r
276 \r
277         // Foreground a valid colour\r
278         if(fg == 8) {\r
279                 Print("Unknown Colour '");Print(argv[1]);Print("'\n");\r
280                 goto usage;\r
281         }\r
282         // Set Foreground\r
283         clrStr[3] = '0' + fg;\r
284         write(_stdout, 6, clrStr);\r
285         \r
286         // Need to Set Background?\r
287         if(argc > 2)\r
288         {\r
289                 for(bg=0;bg<8;bg++)\r
290                         if(strcmp(cCOLOUR_NAMES[bg], argv[2]) == 0)\r
291                                 break;\r
292         \r
293                 // Valid colour\r
294                 if(bg == 8)\r
295                 {\r
296                         Print("Unknown Colour '");Print(argv[2]);Print("'\n");\r
297                         goto usage;\r
298                 }\r
299         \r
300                 clrStr[2] = '4';\r
301                 clrStr[3] = '0' + bg;\r
302                 write(_stdout, 6, clrStr);\r
303         }\r
304         // Return\r
305         return;\r
306 \r
307         // Function Usage (Requested via a Goto (I know it's ugly))\r
308 usage:\r
309         Print("Valid Colours are ");\r
310         for(fg=0;fg<8;fg++)\r
311         {\r
312                 Print(cCOLOUR_NAMES[fg]);\r
313                 write(_stdout, 3, ", ");\r
314         }\r
315         write(_stdout, 4, "\b\b\n");\r
316         return;\r
317 }\r
318 \r
319 void Command_Clear(int argc, char **argv)\r
320 {\r
321         write(_stdout, 4, "\x1B[2J");   //Clear Screen\r
322 }\r
323 \r
324 /**\r
325  * \fn void Command_Cd(int argc, char **argv)\r
326  * \brief Change directory\r
327  */\r
328 void Command_Cd(int argc, char **argv)\r
329 {\r
330         char    tmpPath[1024];\r
331         int             fp;\r
332         t_sysFInfo      stats;\r
333         \r
334         if(argc < 2)\r
335         {\r
336                 Print(gsCurrentDirectory);Print("\n");\r
337                 return;\r
338         }\r
339         \r
340         GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
341         \r
342         fp = open(tmpPath, 0);\r
343         if(fp == -1) {\r
344                 write(_stdout, 26, "Directory does not exist\n");\r
345                 return;\r
346         }\r
347         finfo(fp, &stats, 0);\r
348         close(fp);\r
349         \r
350         if( !(stats.flags & FILEFLAG_DIRECTORY) ) {\r
351                 write(_stdout, 17, "Not a Directory\n");\r
352                 return;\r
353         }\r
354         \r
355         free(gsCurrentDirectory);\r
356         gsCurrentDirectory = malloc(strlen(tmpPath)+1);\r
357         strcpy(gsCurrentDirectory, tmpPath);\r
358         \r
359         // Register change with kernel\r
360         chdir( gsCurrentDirectory );\r
361 }\r
362 \r
363 /**\r
364  */\r
365 void Command_Dir(int argc, char **argv)\r
366 {\r
367          int    dp, fp, dirLen;\r
368         char    modeStr[11] = "RWXrwxRWX ";\r
369         char    tmpPath[1024];\r
370         char    *fileName;\r
371         t_sysFInfo      info;\r
372         t_sysACL        acl;\r
373         \r
374         // Generate Directory Path\r
375         if(argc > 1)\r
376                 dirLen = GeneratePath(argv[1], gsCurrentDirectory, tmpPath);\r
377         else\r
378         {\r
379                 strcpy(tmpPath, gsCurrentDirectory);\r
380         }\r
381         dirLen = strlen(tmpPath);\r
382         \r
383         // Open Directory\r
384         dp = open(tmpPath, OPENFLAG_READ);\r
385         // Check if file opened\r
386         if(dp == -1)\r
387         {\r
388                 //printf("Unable to open directory `%s', File cannot be found\n", tmpPath);\r
389                 write(_stdout, 27, "Unable to open directory `");\r
390                 write(_stdout, strlen(tmpPath)+1, tmpPath);\r
391                 write(_stdout, 25, "', File cannot be found\n");\r
392                 return;\r
393         }\r
394         // Get File Stats\r
395         if( finfo(dp, &info, 0) == -1 )\r
396         {\r
397                 close(dp);\r
398                 write(_stdout, 34, "stat Failed, Bad File Descriptor\n");\r
399                 return;\r
400         }\r
401         // Check if it's a directory\r
402         if(!(info.flags & FILEFLAG_DIRECTORY))\r
403         {\r
404                 close(dp);\r
405                 write(_stdout, 27, "Unable to open directory `");\r
406                 write(_stdout, strlen(tmpPath)+1, tmpPath);\r
407                 write(_stdout, 20, "', Not a directory\n");\r
408                 return;\r
409         }\r
410         \r
411         // Append Shash for file paths\r
412         if(tmpPath[dirLen-1] != '/')\r
413         {\r
414                 tmpPath[dirLen++] = '/';\r
415                 tmpPath[dirLen] = '\0';\r
416         }\r
417         \r
418         fileName = (char*)(tmpPath+dirLen);\r
419         // Read Directory Content\r
420         while( (fp = readdir(dp, fileName)) )\r
421         {\r
422                 if(fp < 0)\r
423                 {\r
424                         if(fp == -3)\r
425                                 write(_stdout, 42, "Invalid Permissions to traverse directory\n");\r
426                         break;\r
427                 }\r
428                 // Open File\r
429                 fp = open(tmpPath, 0);\r
430                 if(fp == -1)    continue;\r
431                 // Get File Stats\r
432                 finfo(fp, &info, 0);\r
433                 \r
434                 if(info.flags & FILEFLAG_DIRECTORY)\r
435                         write(_stdout, 1, "d");\r
436                 else\r
437                         write(_stdout, 1, "-");\r
438                 \r
439                 // Print Mode\r
440                 acl.group = 0;  acl.id = info.uid;\r
441                 _SysGetACL(fp, &acl);\r
442                 if(acl.perms & 1)       modeStr[0] = 'r';       else    modeStr[0] = '-';\r
443                 if(acl.perms & 2)       modeStr[1] = 'w';       else    modeStr[1] = '-';\r
444                 if(acl.perms & 8)       modeStr[2] = 'x';       else    modeStr[2] = '-';\r
445                 acl.group = 1;  acl.id = info.gid;\r
446                 _SysGetACL(fp, &acl);\r
447                 if(acl.perms & 1)       modeStr[3] = 'r';       else    modeStr[3] = '-';\r
448                 if(acl.perms & 1)       modeStr[4] = 'w';       else    modeStr[4] = '-';\r
449                 if(acl.perms & 1)       modeStr[5] = 'x';       else    modeStr[5] = '-';\r
450                 acl.group = 1;  acl.id = -1;\r
451                 _SysGetACL(fp, &acl);\r
452                 if(acl.perms & 1)       modeStr[6] = 'r';       else    modeStr[6] = '-';\r
453                 if(acl.perms & 1)       modeStr[7] = 'w';       else    modeStr[7] = '-';\r
454                 if(acl.perms & 1)       modeStr[8] = 'x';       else    modeStr[8] = '-';\r
455                 write(_stdout, 10, modeStr);\r
456                 close(fp);\r
457                 \r
458                 // Colour Code\r
459                 if(info.flags & FILEFLAG_DIRECTORY)     // Directory: Green\r
460                         write(_stdout, 6, "\x1B[32m");\r
461                 // Default: White\r
462                 \r
463                 // Print Name\r
464                 write(_stdout, strlen(fileName), fileName);\r
465                 \r
466                 // Print slash if applicable\r
467                 if(info.flags & FILEFLAG_DIRECTORY)\r
468                         write(_stdout, 1, "/");\r
469                 \r
470                 // Revert Colour\r
471                 write(_stdout, 6, "\x1B[37m");\r
472                 \r
473                 // Newline!\r
474                 write(_stdout, 1, "\n");\r
475         }\r
476         // Close Directory\r
477         close(dp);\r
478 }\r

UCC git Repository :: git.ucc.asn.au