2 * Acess2 System Init Task
13 #define DEFAULT_SHELL "/Acess/SBin/login"
14 #define INITTAB_FILE "/Acess/Conf/inittab"
16 #define ARRAY_SIZE(x) ((sizeof(x))/(sizeof((x)[0])))
19 int ProcessInittab(const char *Path);
20 char *ReadQuotedString(FILE *FP);
21 char **ReadCommand(FILE *FP);
22 void FreeCommand(char **Command);
24 tInitProgram *AllocateProgram(char **Command, enum eProgType Type, size_t ExtraSpace);
25 void RespawnProgam(tInitProgram *Program);
27 int AddKTerminal(int TerminalSpec, char **Command);
28 int AddSerialTerminal(const char *DevPathSegment, const char *ModeStr, char **Command);
29 int AddDaemon(char *StdoutPath, char *StderrPath, char **Command);
31 int SpawnCommand(int c_stdin, int c_stdout, int c_stderr, char **ArgV, const char **EnvP);
32 int SpawnKTerm(tInitProgram *Program);
33 int SpawnSTerm(tInitProgram *Program);
34 int SpawnDaemon(tInitProgram *Program);
37 const char *gsInittabPath = INITTAB_FILE;
38 tInitProgram *gpInitPrograms;
42 * \fn int main(int argc, char *argv[])
45 int main(int argc, char *argv[])
47 // Parse commandline args
50 // TODO: Behave differently if not invoked as first process?
53 if( ProcessInittab(gsInittabPath) != 0 )
55 // No inittab file found, default to:
56 _SysDebug("inittab '%s' is invalid, falling back to one VT", gsInittabPath);
61 char *args[] = {DEFAULT_SHELL, NULL};
62 const char *env[] = {"TERM=screen", NULL};
63 int pid = SpawnCommand(0, 1, 1, args, env);
64 // TODO: Detect errors
65 _SysWaitTID(pid, NULL);
72 // TODO: Implement message watching
76 pid = _SysWaitTID(-1, &status);
77 _SysDebug("PID %i died, looking for respawn entry", pid);
83 char *ReadQuotedString(FILE *FP)
87 while( isblank(ch = fgetc(FP)) )
96 int pos = 0, space = 0;
97 for( ; !feof(FP); ch = fgetc(FP) )
102 // Add escaped/special character
109 fseek(FP, -1, SEEK_CUR);
112 else if( ch == '\\' )
123 // Double-quoted string
128 else if( ch == '\\' )
135 // Single-quoted string
140 else if( ch == '\\' )
152 void *tmp = realloc(retstr, space+1);
154 _SysDebug("ReadQuotedString - realloc(%i) failure", space+1);
168 char **ReadCommand(FILE *FP)
172 char **ret = malloc(space*sizeof(char*));
175 arg = ReadQuotedString(FP);
178 if( pos == space - 1 ) {
179 _SysDebug("Too many arguments %i", pos);
185 } while(arg != NULL);
196 void FreeCommand(char **Command)
199 while( Command[pos] )
207 int ProcessInittab(const char *Path)
210 FILE *fp = fopen(Path, "r");
222 if( (rv = fscanf(fp, "%64s%*[ \t]", cmdbuf)) != 1 ) {
223 _SysDebug("fscanf rv %i != exp 1", rv);
228 if( cmdbuf[0] == '#' ) {
229 while( !feof(fp) && fgetc(fp) != '\n' )
233 if( cmdbuf[0] == '\0' ) {
235 if( ch != '\n' && ch != -1 ) {
237 _SysDebug("Unexpected char 0x%x, expecting EOL", ch);
238 return 2; // Unexpected character?
244 if( strcmp(cmdbuf, "ktty") == 0 ) {
245 // ktty <ID> <command...>
246 // - Spins off a console on the specified kernel TTY
248 if( fscanf(fp, "%d ", &id) != 1 ) {
249 _SysDebug("init[ktty] - TTY ID read failed");
252 char **command = ReadCommand(fp);
254 _SysDebug("init[ktty] - Command read failure");
257 AddKTerminal(id, command);
259 else if(strcmp(cmdbuf, "stty") == 0 ) {
260 // stty <devpath> [78][NOE][012][bB]<baud> <command...>
262 char modespec[4+6+1];
263 if( fscanf(fp, "%32s %10s ", path_seg, modespec) != 2 ) {
266 char **command = ReadCommand(fp);
269 AddSerialTerminal(path_seg, modespec, command);
271 else if(strcmp(cmdbuf, "daemon") == 0 ) {
272 // daemon <stdout> <stderr> <command...>
273 // - Runs a daemon (respawning) that logs to the specified files
274 // - Will append a header whenever the daemon starts
275 char *stdout_path = ReadQuotedString(fp);
278 char *stderr_path = ReadQuotedString(fp);
281 char **command = ReadCommand(fp);
285 AddDaemon(stdout_path, stderr_path, command);
287 else if(strcmp(cmdbuf, "exec") == 0 ) {
289 // - Runs a command and waits for it to complete before continuing
290 // - NOTE: No other commands will respawn while this is running
291 char **command = ReadCommand(fp);
295 int handles[] = {0, 1, 1};
296 int pid = _SysSpawn(command[0], (const char **)command, NULL, 3, handles, NULL);
298 _SysWaitTID(pid, &retstatus);
299 _SysDebug("Command '%s' returned %i", command[0], retstatus);
301 FreeCommand(command);
305 _SysDebug("Unknown command '%s'", cmdbuf);
311 _SysDebug("label lineError: goto'd - line %i, cmdbuf='%s'", line_num, cmdbuf);
312 while( !feof(fp) && fgetc(fp) != '\n' )
319 if( gpInitPrograms == NULL )
325 tInitProgram *AllocateProgram(char **Command, enum eProgType Type, size_t ExtraSpace)
329 ret = malloc( sizeof(tInitProgram) - sizeof(union uProgTypes) + ExtraSpace );
333 ret->Command = Command;
336 ret->Next = gpInitPrograms;
337 gpInitPrograms = ret;
342 void RespawnProgam(tInitProgram *Program)
345 switch(Program->Type)
347 case PT_KTERM: rv = SpawnKTerm(Program); break;
348 case PT_STERM: rv = SpawnSTerm(Program); break;
349 case PT_DAEMON: rv = SpawnDaemon(Program); break;
351 _SysDebug("BUGCHECK - Program Type %i unknown", Program->Type);
355 _SysDebug("Respawn failure!");
356 // TODO: Remove from list?
360 int AddKTerminal(int TerminalID, char **Command)
362 // TODO: Smarter validation
363 if( TerminalID < 0 || TerminalID > 7 )
366 tInitProgram *ent = AllocateProgram(Command, PT_KTERM, sizeof(struct sKTerm));
367 ent->TypeInfo.KTerm.ID = TerminalID;
373 int AddSerialTerminal(const char *DevPathSegment, const char *ModeStr, char **Command)
375 char dbit, parity, sbit;
379 if( sscanf(ModeStr, "%1[78]%1[NOE]%1[012]%*1[bB]%d", &dbit, &parity, &sbit, &baud) != 4 ) {
381 _SysDebug("Serial mode string is invalid ('%s')", ModeStr);
385 // Validate baud rate / build mode word
386 // TODO: Does baud rate need validation?
387 uint32_t modeword = 0;
388 modeword |= (dbit == '7' ? 1 : 0) << 0;
389 modeword |= (parity == 'O' ? 1 : (parity == 'E' ? 2 : 0)) << 1;
390 modeword |= (sbit - '0') << 3;
393 const char DEVPREFIX[] = "/Devices/pts/serial";
394 int pathlen = sizeof(DEVPREFIX) + strlen(DevPathSegment);
395 tInitProgram *ent = AllocateProgram(Command, PT_STERM, sizeof(struct sSTerm)+pathlen);
396 ent->TypeInfo.STerm.FormatBits = modeword;
397 ent->TypeInfo.STerm.BaudRate = baud;
398 strcpy(ent->TypeInfo.STerm.Path, DEVPREFIX);
399 strcat(ent->TypeInfo.STerm.Path, DevPathSegment);
405 int AddDaemon(char *StdoutPath, char *StderrPath, char **Command)
407 tInitProgram *ent = AllocateProgram(Command, PT_DAEMON, sizeof(struct sDaemon));
408 ent->TypeInfo.Daemon.StdoutPath = StdoutPath;
409 ent->TypeInfo.Daemon.StderrPath = StderrPath;
415 int SpawnCommand(int c_stdin, int c_stdout, int c_stderr, char **ArgV, const char **EnvP)
417 int handles[] = {c_stdin, c_stdout, c_stderr};
419 _SysDebug("Spawning '%s'", ArgV[0]);
422 _SysDebug("SpawnCommand: stdin is invalid");
426 _SysDebug("SpawnCommand: stdout is invalid");
430 _SysDebug("SpawnCommand: stderr is invalid");
434 int rv = _SysSpawn(ArgV[0], (const char **)ArgV, EnvP, 3, handles, NULL);
437 if( c_stdout != c_stdin )
439 if( c_stderr != c_stdin && c_stderr != c_stdout )
445 int SpawnKTerm(tInitProgram *Program)
447 const char fmt[] = "/Devices/pts/vt%i";
448 const char *env[] = {"TERM=screen", NULL};
449 char path[sizeof(fmt)];
451 snprintf(path, sizeof(path), fmt, Program->TypeInfo.KTerm.ID);
453 int in = _SysOpen(path, OPENFLAG_READ);
454 int out = _SysOpen(path, OPENFLAG_WRITE);
456 _SysDebug("Spawning virtual terminal '%s' with term '%s'",
457 path, Program->Command[0]);
458 return SpawnCommand(in, out, out, Program->Command, env);
461 int SpawnSTerm(tInitProgram *Program)
463 int in = _SysOpen(Program->TypeInfo.STerm.Path, OPENFLAG_READ);
464 int out = _SysOpen(Program->TypeInfo.STerm.Path, OPENFLAG_WRITE);
466 if(in == -1 || out == -1 ) {
467 _SysDebug("Unable to open serial port '%s'", Program->TypeInfo.STerm.Path);
472 if( _SysIOCtl(in, 0, NULL) != DRV_TYPE_SERIAL )
477 _SysIOCtl(in, SERIAL_IOCTL_GETSETBAUD, &Program->TypeInfo.STerm.BaudRate);
478 _SysIOCtl(in, SERIAL_IOCTL_GETSETFORMAT, &Program->TypeInfo.STerm.FormatBits);
481 _SysDebug("Spawning serial terminal '%s' with term '%s'",
482 Program->TypeInfo.STerm.Path, Program->Command[0]);
483 return SpawnCommand(in, out, out, Program->Command, NULL);
486 int SpawnDaemon(tInitProgram *Program)
488 int in = _SysOpen("/Devices/null", OPENFLAG_READ);
489 int out = _SysOpen(Program->TypeInfo.Daemon.StdoutPath, OPENFLAG_WRITE);
490 int err = _SysOpen(Program->TypeInfo.Daemon.StderrPath, OPENFLAG_WRITE);
492 if( in < 0 || out < 0 || err < 0 ) {
493 perror("SpawnDaemon");
503 size_t len = snprintf(buffer, 100, "[%"PRIi64"] init spawning ", _SysTimestamp());
504 _SysWrite(out, buffer, len);
505 for( int i = 0; Program->Command[i]; i ++ )
507 _SysWrite(out, "'", 1);
508 _SysWrite(out, Program->Command[i], strlen(Program->Command[i]));
509 _SysWrite(out, "'", 1);
511 _SysWrite(out, "\n", 1);
514 return SpawnCommand(in, out, err, Program->Command, NULL);