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

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