463b4e0f06ce3ebf7716df59fa2b0dd525813bdd
[tpg/acess2.git] / Kernel / system.c
1 /*
2  * Acess 2
3  * Architecture Independent System Init
4  * system.c
5  */
6 #define DEBUG   0
7 #include <acess.h>
8
9 // === TYPES ===
10 typedef struct
11 {
12          int    TrueLine;
13          int    nParts;
14         char    **Parts;
15 }       tConfigLine;
16 typedef struct
17 {
18          int    nLines;
19         tConfigLine     Lines[];
20 }       tConfigFile;
21
22 // === IMPORTS ===
23 extern int      Modules_LoadBuiltins();
24 //extern int    PCI_Install();
25 extern void     DMA_Install();
26 extern void     Debug_SetKTerminal(char *File);
27 extern void     StartupPrint(char *Str);
28
29 // === PROTOTYPES ===
30 void    System_Init(char *ArgString);
31 void    System_ParseCommandLine(char *ArgString);
32 void    System_ParseVFS(char *Arg);
33 void    System_ParseSetting(char *Arg);
34 void    System_ExecuteScript();
35 tConfigFile     *System_Int_ParseFile(char *File);
36
37 // === GLOBALS ===
38 char    *gsConfigScript = "/Acess/Conf/BootConf.cfg";
39
40 // === CODE ===
41 void System_Init(char *ArgString)
42 {       
43         // Set the debug to be echoed to the terminal
44         StartupPrint("Kernel now echoes to VT7 (Ctrl-Alt-F8)");
45         Debug_SetKTerminal("/Devices/VTerm/7");
46         
47         // - Parse Kernel's Command Line
48         System_ParseCommandLine(ArgString);
49         
50         // - Execute the Config Script
51         Log("Executing config script...");
52         System_ExecuteScript();
53 }
54
55 /**
56  * \fn void System_ParseCommandLine(char *ArgString)
57  * \brief Parses the kernel's command line and sets the environment
58  */
59 void System_ParseCommandLine(char *ArgString)
60 {
61         char    *argv[32];
62          int    argc;
63          int    i;
64         char    *str;
65         
66         Log("Kernel Command Line: \"%s\"", ArgString);
67         
68         // --- Get Arguments ---
69         str = ArgString;
70         for( argc = 0; argc < 32; argc++ )
71         {
72                 // Eat Whitespace
73                 while(*str == ' ')      str++;
74                 // Check for the end of the string
75                 if(*str == '\0') {      argc--; break;} 
76                 argv[argc] = str;
77                 while(*str && *str != ' ')
78                 {
79                         /*if(*str == '"') {
80                                 while(*str && !(*str == '"' && str[-1] != '\\'))
81                                         str ++;
82                         }*/
83                         str++;
84                 }
85                 if(*str == '\0')        break;  // Check for EOS
86                 *str = '\0';    // Cap off argument string
87                 str ++; // and increment the string pointer
88         }
89         if(argc < 32)
90                 argc ++;        // Count last argument
91         
92         // --- Parse Arguments ---
93         for( i = 1; i < argc; i++ )
94         {
95                 if( argv[i][0] == '/' )
96                         System_ParseVFS( argv[i] );
97                 else
98                         System_ParseSetting( argv[i] );
99         }
100 }
101
102 /**
103  * \fn void System_ParseVFS(char *Arg)
104  */
105 void System_ParseVFS(char *Arg)
106 {
107         char    *value;
108          int    fd;
109         
110         value = Arg;
111         // Search for the '=' token
112         while( *value && *value != '=' )
113                 value++;
114         
115         // Check if the equals was found
116         if( *value == '\0' ) {
117                 Warning("Expected '=' in the string '%s'", Arg);
118                 return ;
119         }
120         
121         // Edit string
122         *value = '\0';  value ++;
123         
124         // Check assignment type
125         // - Symbolic Link <link>=<destination>
126         if(value[0] == '/')
127         {
128                 Log("Symbolic link '%s' pointing to '%s'", Arg, value);
129                 VFS_Symlink(Arg, value);
130         }
131         // - Mount <mountpoint>=<fs>:<device>
132         else
133         {
134                 char    *dev = value;
135                 // Find colon
136                 while(*dev && *dev != ':')      dev++;
137                 if(*dev) {
138                         *dev = '\0';
139                         dev++;  // Eat ':'
140                 }
141                 // Create Mountpoint
142                 if( (fd = VFS_Open(Arg, 0)) == -1 ) {
143                         Log("Creating directory '%s'", Arg, value);
144                         VFS_MkDir( Arg );
145                 } else {
146                         VFS_Close(fd);
147                 }
148                 // Mount
149                 Log("Mounting '%s' to '%s' ('%s')", dev, Arg, value);
150                 VFS_Mount(dev, Arg, value, "");
151         }
152 }
153
154 /**
155  * \fn void System_ParseSetting(char *Arg)
156  */
157 void System_ParseSetting(char *Arg)
158 {
159         char    *value;
160         value = Arg;
161
162         // Search for the '=' token
163         while( *value && *value != '=' )
164                 value++;
165         
166         // Check for boolean/flag (no '=')
167         if(*value == '\0')
168         {
169                 //if(strcmp(Arg, "") == 0) {
170                 //} else {
171                         Warning("Kernel flag '%s' is not recognised", Arg);
172                 //}
173         }
174         else
175         {
176                 *value = '\0';  // Remove '='
177                 value ++;       // and eat it's position
178                 
179                 if(strcmp(Arg, "SCRIPT") == 0) {
180                         Log("Config Script: '%s'", value);
181                         gsConfigScript = value;
182                 } else {
183                         Warning("Kernel config setting '%s' is not recognised", Arg);
184                 }
185                 
186         }
187 }
188
189 /**
190  * \fn void System_ExecuteScript()
191  */
192 void System_ExecuteScript()
193 {
194          int    fp;
195          int    fLen = 0;
196          int    i;
197         char    *fData;
198         tConfigFile     *file;
199         tConfigLine     *line;
200         
201         // Open Script
202         fp = VFS_Open(gsConfigScript, VFS_OPENFLAG_READ);
203         if(fp == -1) {
204                 Warning("[CFG] Passed script '%s' does not exist", gsConfigScript);
205                 return;
206         }
207         
208         // Read into memory buffer
209         VFS_Seek(fp, 0, SEEK_END);
210         fLen = VFS_Tell(fp);
211         VFS_Seek(fp, 0, SEEK_SET);
212         fData = malloc(fLen+1);
213         VFS_Read(fp, fLen, fData);
214         fData[fLen] = '\0';
215         VFS_Close(fp);
216         
217         
218         
219         // Parse File
220         file = System_Int_ParseFile(fData);
221         
222         // Parse each line
223         for( i = 0; i < file->nLines; i++ )
224         {
225                 line = &file->Lines[i];
226                 if( line->nParts == 0 ) continue;       // Skip blank
227                 
228                 // Mount Device
229                 if( strcmp(line->Parts[0], "mount") == 0 )
230                 {
231                         if( line->nParts != 4 ) {
232                                 Warning("Configuration command 'mount' requires 3 arguments, %i given",
233                                         line->nParts-1);
234                                 continue;
235                         }
236                         //Log("[CFG ] Mount '%s' to '%s' (%s)",
237                         //      line->Parts[1], line->Parts[2], line->Parts[3]);
238                         //! \todo Use an optional 4th argument for the options string
239                         VFS_Mount(line->Parts[1], line->Parts[2], line->Parts[3], "");
240                 }
241                 // Load a Module
242                 else if(strcmp(line->Parts[0], "module") == 0)
243                 {
244                         if( line->nParts < 2 || line->nParts > 3 ) {
245                                 Warning("Configuration command 'module' requires 1 or 2 arguments, %i given",
246                                         line->nParts-1);
247                                 continue;
248                         }
249                         if( line->nParts == 3 )
250                                 Module_LoadFile(line->Parts[1], line->Parts[2]);
251                         else
252                                 Module_LoadFile(line->Parts[1], "");
253                 }
254                 // Load a UDI Module
255                 else if(strcmp(line->Parts[0], "udimod") == 0)
256                 {
257                         if( line->nParts != 2 ) {
258                                 Warning("Configuration command 'udimod' requires 1 argument, %i given",
259                                         line->nParts-1);
260                                 continue;
261                         }
262                         Log("[CFG  ] Load UDI Module '%s'", line->Parts[1]);
263                         Module_LoadFile(line->Parts[1], "");
264                 }
265                 // Load a EDI Module
266                 else if(strcmp(line->Parts[0], "edimod") == 0)
267                 {
268                         if( line->nParts != 2 ) {
269                                 Warning("Configuration command 'edimod' requires 1 argument, %i given",
270                                         line->nParts-1);
271                                 continue;
272                         }
273                         Log("[CFG  ] Load EDI Module '%s'", line->Parts[1]);
274                         Module_LoadFile(line->Parts[1], "");
275                 }
276                 // Create a Symbolic Link
277                 else if(strcmp(line->Parts[0], "symlink") == 0)
278                 {
279                         if( line->nParts != 3 ) {
280                                 Warning("Configuration command 'symlink' requires 2 arguments, %i given",
281                                         line->nParts-1);
282                                 continue;
283                         }
284                         Log("[CFG  ] Symlink '%s' pointing to '%s'",
285                                 line->Parts[1], line->Parts[2]);
286                         VFS_Symlink(line->Parts[1], line->Parts[2]);
287                 }
288                 // Create a Directory
289                 else if(strcmp(line->Parts[0], "mkdir") == 0)
290                 {
291                         if( line->nParts != 2 ) {
292                                 Warning("Configuration command 'mkdir' requires 1 argument, %i given",
293                                         line->nParts-1);
294                                 continue;
295                         }
296                         Log("[CFG  ] New Directory '%s'", line->Parts[1]);
297                         VFS_MkDir(line->Parts[1]);
298                 }
299                 // Spawn a process
300                 else if(strcmp(line->Parts[0], "spawn") == 0)
301                 {
302                         if( line->nParts != 2 ) {
303                                 Warning("Configuration command 'spawn' requires 1 argument, %i given",
304                                         line->nParts-1);
305                                 continue;
306                         }
307                         Log("[CFG  ] Starting '%s' as a new task", line->Parts[1]);
308                         Proc_Spawn(line->Parts[1]);
309                 }
310                 else {
311                         Warning("Unknown configuration command '%s' on line %i",
312                                 line->Parts[0],
313                                 line->TrueLine
314                                 );
315                 }
316         }
317         
318         // Clean up after ourselves
319         for( i = 0; i < file->nLines; i++ ) {
320                 if( file->Lines[i].nParts == 0 )        continue;       // Skip blank
321                 free( file->Lines[i].Parts );
322         }
323         free( file );
324         free( fData );
325 }
326
327 /**
328  * \brief Parses a config file
329  * \param FileData      Read/Write buffer containing the config file data
330  *                  (will be modified)
331  * \return ::tConfigFile structure that represents the original contents
332  *         of \a FileData
333  */
334 tConfigFile     *System_Int_ParseFile(char *FileData)
335 {
336         char    *ptr;
337         char    *start;
338          int    nLines = 1;
339          int    i, j;
340         tConfigFile     *ret;
341         
342         ENTER("pFileData", FileData);
343         
344         // Prescan and count the number of lines
345         for(ptr = FileData; *ptr; ptr++)
346         {               
347                 if(*ptr != '\n')        continue;
348                 
349                 if(ptr == FileData) {
350                         nLines ++;
351                         continue;
352                 }
353                 
354                 // Escaped EOL
355                 if(ptr[-1] == '\\')     continue;
356                 
357                 nLines ++;
358         }
359         
360         LOG("nLines = %i", nLines);
361         
362         // Ok so we have `nLines` lines, now to allocate our return
363         ret = malloc( sizeof(tConfigFile) + sizeof(tConfigLine)*nLines );
364         ret->nLines = nLines;
365         
366         // Read the file for real
367         for(
368                 ptr = FileData, i = 0;
369                 *ptr;
370                 i++
371                 )
372         {
373                 start = ptr;
374                 
375                 ret->Lines[i].nParts = 0;
376                 
377                 // Count parts
378                 for(;;)
379                 {
380                         // Read leading whitespace
381                         while( *ptr == '\t' || *ptr == ' ' )    ptr++;
382                         
383                         // End of line/file
384                         if( *ptr == '\0' || *ptr == '\n' ) {
385                                 if(*ptr == '\n')        ptr ++;
386                                 break;
387                         }
388                         // Comment
389                         if( *ptr == '#' || *ptr == ';' ) {
390                                 while( *ptr && *ptr != '\n' )   ptr ++;
391                                 if(*ptr == '\n')        ptr ++;
392                                 break;
393                         }
394                         
395                         ret->Lines[i].nParts ++;
396                         // Quoted
397                         if( *ptr == '"' ) {
398                                 ptr ++;
399                                 while( *ptr && !(*ptr == '"' && ptr[-1] == '\\') && *ptr != '\n' )
400                                         ptr++;
401                                 continue;
402                         }
403                         // Unquoted
404                         while( *ptr && !(*ptr == '\t' || *ptr == ' ') && *ptr != '\n' )
405                                 ptr++;
406                 }
407                 
408                 LOG("ret->Lines[%i].nParts = %i", i, ret->Lines[i].nParts);
409                 
410                 if( ret->Lines[i].nParts == 0 ) {
411                         ret->Lines[i].Parts = NULL;
412                         continue;
413                 }
414                 
415                 // Allocate part list
416                 ret->Lines[i].Parts = malloc( sizeof(char*) * ret->Lines[i].nParts );
417                 
418                 // Fill list
419                 for( ptr = start, j = 0; ; j++ )
420                 {
421                         // Read leading whitespace
422                         while( *ptr == '\t' || *ptr == ' ' )    ptr++;
423                         
424                         // End of line/file
425                         if( *ptr == '\0' || *ptr == '\n' ) {
426                                 if(*ptr == '\n')        ptr ++;
427                                 break;
428                         }
429                         // Comment
430                         if( *ptr == '#' || *ptr == ';' ) {
431                                 while( *ptr && *ptr != '\n' )   ptr ++;
432                                 if(*ptr == '\n')        ptr ++;
433                                 break;
434                         }
435                         
436                         ret->Lines[i].Parts[j] = ptr;
437                         
438                         // Quoted
439                         if( *ptr == '"' ) {
440                                 ptr ++;
441                                 while( *ptr && !(*ptr == '"' && ptr[-1] == '\\') && *ptr != '\n' )
442                                         ptr++;
443                         }
444                         // Unquoted
445                         else {
446                                 while( *ptr != '\t' && *ptr != ' ' && *ptr != '\n' )
447                                         ptr++;
448                         }
449                         
450                         // Break if we have reached NULL
451                         if( *ptr == '\0' ) {
452                                 LOG("ret->Lines[%i].Parts[%i] = '%s'", i, j, ret->Lines[i].Parts[j]);
453                                 break;
454                         }
455                         if( *ptr == '\n' ) {
456                                 *ptr = '\0';
457                                 LOG("ret->Lines[%i].Parts[%i] = '%s'", i, j, ret->Lines[i].Parts[j]);
458                                 ptr ++;
459                                 break;
460                         }
461                         *ptr = '\0';    // Cap off string
462                         LOG("ret->Lines[%i].Parts[%i] = '%s'", i, j, ret->Lines[i].Parts[j]);
463                         ptr ++; // And increment for the next round
464                 }
465         }
466         
467         LEAVE('p', ret);
468         return ret;
469 }

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