Updating drivers to use the Log_ functions instead of Log() and Warning()
[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_Log("CFG", "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_Log("CFG", "Kernel Invocation \"%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                 Log_Warning("CFG", "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_Log("CFG", "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_Log("CFG", "Creating directory '%s'", Arg, value);
144                         VFS_MkDir( Arg );
145                 } else {
146                         VFS_Close(fd);
147                 }
148                 // Mount
149                 Log_Log("CFG", "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                         Log_Warning("CFG", "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_Log("CFG", "Config Script: '%s'", value);
181                         gsConfigScript = value;
182                 } else {
183                         Log_Warning("CFG", "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                 Log_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                                 Log_Warning("CFG", "Configuration command 'mount' requires 3 arguments, %i given",
233                                         line->nParts-1);
234                                 continue;
235                         }
236                         //Log_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                                 Log_Warning("CFG",
246                                         "Configuration command 'module' requires 1 or 2 arguments, %i given",
247                                         line->nParts-1);
248                                 continue;
249                         }
250                         if( line->nParts == 3 )
251                                 Module_LoadFile(line->Parts[1], line->Parts[2]);
252                         else
253                                 Module_LoadFile(line->Parts[1], "");
254                 }
255                 // Load a UDI Module
256                 else if(strcmp(line->Parts[0], "udimod") == 0)
257                 {
258                         if( line->nParts != 2 ) {
259                                 Log_Warning("CFG", "Configuration command 'udimod' requires 1 argument, %i given",
260                                         line->nParts-1);
261                                 continue;
262                         }
263                         Log_Log("CFG", "Load UDI Module '%s'", line->Parts[1]);
264                         Module_LoadFile(line->Parts[1], "");
265                 }
266                 // Load a EDI Module
267                 else if(strcmp(line->Parts[0], "edimod") == 0)
268                 {
269                         if( line->nParts != 2 ) {
270                                 Log_Warning("CFG", "Configuration command 'edimod' requires 1 argument, %i given",
271                                         line->nParts-1);
272                                 continue;
273                         }
274                         Log_Log("CFG", "Load EDI Module '%s'", line->Parts[1]);
275                         Module_LoadFile(line->Parts[1], "");
276                 }
277                 // Create a Symbolic Link
278                 else if(strcmp(line->Parts[0], "symlink") == 0)
279                 {
280                         if( line->nParts != 3 ) {
281                                 Log_Warning("CFG", "Configuration command 'symlink' requires 2 arguments, %i given",
282                                         line->nParts-1);
283                                 continue;
284                         }
285                         Log_Log("CFG", "Symlink '%s' pointing to '%s'",
286                                 line->Parts[1], line->Parts[2]);
287                         VFS_Symlink(line->Parts[1], line->Parts[2]);
288                 }
289                 // Create a Directory
290                 else if(strcmp(line->Parts[0], "mkdir") == 0)
291                 {
292                         if( line->nParts != 2 ) {
293                                 Log_Warning("CFG", "Configuration command 'mkdir' requires 1 argument, %i given",
294                                         line->nParts-1);
295                                 continue;
296                         }
297                         Log_Log("CFG", "New Directory '%s'", line->Parts[1]);
298                         VFS_MkDir(line->Parts[1]);
299                 }
300                 // Spawn a process
301                 else if(strcmp(line->Parts[0], "spawn") == 0)
302                 {
303                         if( line->nParts != 2 ) {
304                                 Log_Warning("CFG", "Configuration command 'spawn' requires 1 argument, %i given",
305                                         line->nParts-1);
306                                 continue;
307                         }
308                         Log_Log("CFG", "Starting '%s' as a new task", line->Parts[1]);
309                         Proc_Spawn(line->Parts[1]);
310                 }
311                 else {
312                         Log_Warning("CFG", "Unknown configuration command '%s' on line %i",
313                                 line->Parts[0],
314                                 line->TrueLine
315                                 );
316                 }
317         }
318         
319         // Clean up after ourselves
320         for( i = 0; i < file->nLines; i++ ) {
321                 if( file->Lines[i].nParts == 0 )        continue;       // Skip blank
322                 free( file->Lines[i].Parts );
323         }
324         free( file );
325         free( fData );
326 }
327
328 /**
329  * \brief Parses a config file
330  * \param FileData      Read/Write buffer containing the config file data
331  *                  (will be modified)
332  * \return ::tConfigFile structure that represents the original contents
333  *         of \a FileData
334  */
335 tConfigFile     *System_Int_ParseFile(char *FileData)
336 {
337         char    *ptr;
338         char    *start;
339          int    nLines = 1;
340          int    i, j;
341         tConfigFile     *ret;
342         
343         ENTER("pFileData", FileData);
344         
345         // Prescan and count the number of lines
346         for(ptr = FileData; *ptr; ptr++)
347         {               
348                 if(*ptr != '\n')        continue;
349                 
350                 if(ptr == FileData) {
351                         nLines ++;
352                         continue;
353                 }
354                 
355                 // Escaped EOL
356                 if(ptr[-1] == '\\')     continue;
357                 
358                 nLines ++;
359         }
360         
361         LOG("nLines = %i", nLines);
362         
363         // Ok so we have `nLines` lines, now to allocate our return
364         ret = malloc( sizeof(tConfigFile) + sizeof(tConfigLine)*nLines );
365         ret->nLines = nLines;
366         
367         // Read the file for real
368         for(
369                 ptr = FileData, i = 0;
370                 *ptr;
371                 i++
372                 )
373         {
374                 start = ptr;
375                 
376                 ret->Lines[i].nParts = 0;
377                 
378                 // Count parts
379                 for(;;)
380                 {
381                         // Read leading whitespace
382                         while( *ptr == '\t' || *ptr == ' ' )    ptr++;
383                         
384                         // End of line/file
385                         if( *ptr == '\0' || *ptr == '\n' ) {
386                                 if(*ptr == '\n')        ptr ++;
387                                 break;
388                         }
389                         // Comment
390                         if( *ptr == '#' || *ptr == ';' ) {
391                                 while( *ptr && *ptr != '\n' )   ptr ++;
392                                 if(*ptr == '\n')        ptr ++;
393                                 break;
394                         }
395                         
396                         ret->Lines[i].nParts ++;
397                         // Quoted
398                         if( *ptr == '"' ) {
399                                 ptr ++;
400                                 while( *ptr && !(*ptr == '"' && ptr[-1] == '\\') && *ptr != '\n' )
401                                         ptr++;
402                                 continue;
403                         }
404                         // Unquoted
405                         while( *ptr && !(*ptr == '\t' || *ptr == ' ') && *ptr != '\n' )
406                                 ptr++;
407                 }
408                 
409                 LOG("ret->Lines[%i].nParts = %i", i, ret->Lines[i].nParts);
410                 
411                 if( ret->Lines[i].nParts == 0 ) {
412                         ret->Lines[i].Parts = NULL;
413                         continue;
414                 }
415                 
416                 // Allocate part list
417                 ret->Lines[i].Parts = malloc( sizeof(char*) * ret->Lines[i].nParts );
418                 
419                 // Fill list
420                 for( ptr = start, j = 0; ; j++ )
421                 {
422                         // Read leading whitespace
423                         while( *ptr == '\t' || *ptr == ' ' )    ptr++;
424                         
425                         // End of line/file
426                         if( *ptr == '\0' || *ptr == '\n' ) {
427                                 if(*ptr == '\n')        ptr ++;
428                                 break;
429                         }
430                         // Comment
431                         if( *ptr == '#' || *ptr == ';' ) {
432                                 while( *ptr && *ptr != '\n' )   ptr ++;
433                                 if(*ptr == '\n')        ptr ++;
434                                 break;
435                         }
436                         
437                         ret->Lines[i].Parts[j] = ptr;
438                         
439                         // Quoted
440                         if( *ptr == '"' ) {
441                                 ptr ++;
442                                 while( *ptr && !(*ptr == '"' && ptr[-1] == '\\') && *ptr != '\n' )
443                                         ptr++;
444                         }
445                         // Unquoted
446                         else {
447                                 while( *ptr != '\t' && *ptr != ' ' && *ptr != '\n' )
448                                         ptr++;
449                         }
450                         
451                         // Break if we have reached NULL
452                         if( *ptr == '\0' ) {
453                                 LOG("ret->Lines[%i].Parts[%i] = '%s'", i, j, ret->Lines[i].Parts[j]);
454                                 break;
455                         }
456                         if( *ptr == '\n' ) {
457                                 *ptr = '\0';
458                                 LOG("ret->Lines[%i].Parts[%i] = '%s'", i, j, ret->Lines[i].Parts[j]);
459                                 ptr ++;
460                                 break;
461                         }
462                         *ptr = '\0';    // Cap off string
463                         LOG("ret->Lines[%i].Parts[%i] = '%s'", i, j, ret->Lines[i].Parts[j]);
464                         ptr ++; // And increment for the next round
465                 }
466         }
467         
468         LEAVE('p', ret);
469         return ret;
470 }

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