2 * Acess2 System Init Task
12 #define DEFAULT_SHELL "/Acess/SBin/login"
13 #define INITTAB_FILE "/Acess/Config/inittab"
15 #define ARRAY_SIZE(x) ((sizeof(x))/(sizeof((x)[0])))
18 int ProcessInittab(const char *Path);
19 char *ReadQuotedString(FILE *FP);
20 char **ReadCommand(FILE *FP);
21 void FreeCommand(char **Command);
23 tInitProgram *AllocateProgram(char **Command, enum eProgType Type, size_t ExtraSpace);
24 void RespawnProgam(tInitProgram *Program);
26 int AddKTerminal(int TerminalSpec, char **Command);
27 int AddSerialTerminal(const char *DevPathSegment, const char *ModeStr, char **Command);
28 int AddDaemon(char *StdoutPath, char *StderrPath, char **Command);
30 int SpawnCommand(int c_stdin, int c_stdout, int c_stderr, char **ArgV);
31 int SpawnKTerm(tInitProgram *Program);
32 int SpawnSTerm(tInitProgram *Program);
33 int SpawnDaemon(tInitProgram *Program);
36 const char *gsInittabPath = INITTAB_FILE;
37 tInitProgram *gpInitPrograms;
41 * \fn int main(int argc, char *argv[])
44 int main(int argc, char *argv[])
46 // Parse commandline args
49 // TODO: Behave differently if not invoked as first process?
52 if( ProcessInittab(gsInittabPath) != 0 )
54 // No inittab file found, default to:
55 _SysDebug("inittab '%s' is invalid, falling back to one VT", gsInittabPath);
59 int pid = SpawnCommand(0, 1, 1, (char *[]){DEFAULT_SHELL, NULL});
60 _SysWaitTID(pid, NULL);
62 // TODO: Detect errors
65 // TODO: Implement message watching
69 pid = _SysWaitTID(0, &status);
70 _SysDebug("PID %i died, looking for respawn entry", pid);
76 char *ReadQuotedString(FILE *FP)
79 while( isblank(ch = fgetc(FP)) )
87 int pos = 0, space = 0;
88 for( ; !feof(FP); ch = fgetc(FP) )
93 // Add escaped/special character
101 else if( ch == '\\' )
112 // Double-quoted string
117 else if( ch == '\\' )
124 // Single-quoted string
129 else if( ch == '\\' )
141 void *tmp = realloc(retstr, space+1);
155 char **ReadCommand(FILE *FP)
159 char **ret = malloc(space*sizeof(char*));
162 arg = ReadQuotedString(FP);
163 if( pos == space - 1 ) {
169 } while(arg != NULL);
174 void FreeCommand(char **Command)
177 while( Command[pos] )
185 int ProcessInittab(const char *Path)
187 FILE *fp = fopen(Path, "r");
195 if( fscanf(fp, "%64s%*[ \t]", &cmdbuf) != 1 )
199 if( cmdbuf[0] == '#' ) {
200 while( !feof(fp) && fgetc(fp) != '\n' )
204 if( cmdbuf[0] == '\0' ) {
205 if( fgetc(fp) != '\n' ) {
207 return 2; // Unexpected character?
213 if( strcmp(cmdbuf, "ktty") == 0 ) {
214 // ktty <ID> <command...>
215 // - Spins off a console on the specified kernel TTY
217 if( fscanf(fp, "%d ", &id) != 1 )
219 char **command = ReadCommand(fp);
222 AddKTerminal(id, command);
225 else if(strcmp(cmdbuf, "stty") == 0 ) {
226 // stty <devpath> [78][NOE][012][bB]<baud> <command...>
228 char modespec[4+6+1];
229 if( fscanf(fp, "%32s %6s ", &path_seg, &modespec) != 2 ) {
232 char **command = ReadCommand(fp);
235 AddSerialTerminal(path_seg, modespec, command);
237 else if(strcmp(cmdbuf, "daemon") == 0 ) {
238 // daemon <stdout> <stderr> <command...>
239 // - Runs a daemon (respawning) that logs to the specified files
240 // - Will append a header whenever the daemon starts
241 char *stdout_path = ReadQuotedString(fp);
242 char *stderr_path = ReadQuotedString(fp);
243 char **command = ReadCommand(fp);
245 AddDaemon(stdout_path, stderr_path, command);
247 else if(strcmp(cmdbuf, "exec") == 0 ) {
249 // - Runs a command and waits for it to complete before continuing
250 // - NOTE: No other commands will respawn while this is running
251 char **command = ReadCommand(fp);
255 int handles[] = {0, 1, 2};
256 int pid = _SysSpawn(command[0], (const char **)command, NULL, 3, handles, NULL);
257 _SysWaitTID(pid, NULL);
259 FreeCommand(command);
266 while( !feof(fp) && fgetc(fp) != '\n' )
275 tInitProgram *AllocateProgram(char **Command, enum eProgType Type, size_t ExtraSpace)
279 ret = malloc( sizeof(tInitProgram) - sizeof(union uProgTypes) + ExtraSpace );
283 ret->Command = Command;
286 ret->Next = gpInitPrograms;
287 gpInitPrograms = ret;
292 void RespawnProgam(tInitProgram *Program)
295 switch(Program->Type)
297 case PT_KTERM: rv = SpawnKTerm(Program); break;
298 case PT_STERM: rv = SpawnSTerm(Program); break;
299 case PT_DAEMON: rv = SpawnDaemon(Program); break;
301 _SysDebug("BUGCHECK - Program Type %i unknown", Program->Type);
305 _SysDebug("Respawn failure!");
306 // TODO: Remove from list?
310 int AddKTerminal(int TerminalID, char **Command)
312 // TODO: Smarter validation
313 if( TerminalID < 0 || TerminalID > 7 )
316 tInitProgram *ent = AllocateProgram(Command, PT_KTERM, sizeof(struct sKTerm));
317 ent->TypeInfo.KTerm.ID = TerminalID;
323 int AddSerialTerminal(const char *DevPathSegment, const char *ModeStr, char **Command)
325 char dbit, parity, sbit;
329 if( sscanf(ModeStr, "%1[78]%1[NOE]%1[012]%*1[bB]%d", &dbit, &parity, &sbit, &baud) != 5 ) {
334 // Validate baud rate / build mode word
335 // TODO: Does baud rate need validation?
336 uint32_t modeword = 0;
337 modeword |= (dbit == '7' ? 1 : 0) << 0;
338 modeword |= (parity == 'O' ? 1 : (parity == 'E' ? 2 : 0)) << 1;
339 modeword |= (sbit - '0') << 3;
342 const char DEVPREFIX[] = "/Devices/";
343 int pathlen = sizeof(DEVPREFIX) + strlen(DevPathSegment);
344 tInitProgram *ent = AllocateProgram(Command, PT_STERM, sizeof(struct sSTerm)+pathlen);
345 ent->TypeInfo.STerm.FormatBits = modeword;
346 ent->TypeInfo.STerm.BaudRate = baud;
347 strcpy(ent->TypeInfo.STerm.Path, DEVPREFIX);
348 strcat(ent->TypeInfo.STerm.Path, DevPathSegment);
354 int AddDaemon(char *StdoutPath, char *StderrPath, char **Command)
356 tInitProgram *ent = AllocateProgram(Command, PT_DAEMON, sizeof(struct sDaemon));
357 ent->TypeInfo.Daemon.StdoutPath = StdoutPath;
358 ent->TypeInfo.Daemon.StderrPath = StderrPath;
364 int SpawnCommand(int c_stdin, int c_stdout, int c_stderr, char **ArgV)
366 int handles[] = {c_stdin, c_stdout, c_stderr};
368 int rv = _SysSpawn(ArgV[0], (const char **)ArgV, NULL, 3, handles, NULL);
371 if( c_stdout != c_stdin )
373 if( c_stderr != c_stdin && c_stderr != c_stdin )
379 int SpawnKTerm(tInitProgram *Program)
381 const char fmt[] = "/Devices/VTerm/%i";
382 char path[sizeof(fmt)];
384 snprintf(path, sizeof(path), fmt, Program->TypeInfo.KTerm.ID);
386 int in = _SysOpen(path, OPENFLAG_READ);
387 int out = _SysOpen(path, OPENFLAG_WRITE);
389 return SpawnCommand(in, out, out, Program->Command);
392 int SpawnSTerm(tInitProgram *Program)
394 int in = _SysOpen(Program->TypeInfo.STerm.Path, OPENFLAG_READ);
395 int out = _SysOpen(Program->TypeInfo.STerm.Path, OPENFLAG_WRITE);
398 if( _SysIOCtl(in, 0, NULL) != DRV_TYPE_SERIAL )
403 _SysIOCtl(in, SERIAL_IOCTL_GETSETBAUD, &Program->TypeInfo.STerm.BaudRate);
404 _SysIOCtl(in, SERIAL_IOCTL_GETSETFORMAT, &Program->TypeInfo.STerm.FormatBits);
407 return SpawnCommand(in, out, out, Program->Command);
410 int SpawnDaemon(tInitProgram *Program)
412 int in = _SysOpen("/Devices/null", OPENFLAG_READ);
413 int out = _SysOpen(Program->TypeInfo.Daemon.StdoutPath, OPENFLAG_WRITE);
414 int err = _SysOpen(Program->TypeInfo.Daemon.StderrPath, OPENFLAG_WRITE);
416 if( in == -1 || out == -1 || err == -1 ) {
423 return SpawnCommand(in, out, err, Program->Command);