+ retstr[pos] = '\0';
+ return retstr;
+}
+
+char **ReadCommand(FILE *FP)
+{
+ const int space = 8;
+ int pos = 0;
+ char **ret = malloc(space*sizeof(char*));
+ char *arg;
+ do {
+ arg = ReadQuotedString(FP);
+ if(arg == NULL)
+ break;
+ if( pos == space - 1 ) {
+ _SysDebug("Too many arguments %i", pos);
+ ret[pos] = NULL;
+ FreeCommand(ret);
+ return NULL;
+ }
+ ret[pos++] = arg;
+ } while(arg != NULL);
+ ret[pos] = NULL;
+ return ret;
+}
+
+void FreeCommand(char **Command)
+{
+ int pos = 0;
+ while( Command[pos] )
+ {
+ free(Command[pos]);
+ pos ++;
+ }
+ free(Command);
+}
+
+int ProcessInittab(const char *Path)
+{
+ FILE *fp = fopen(Path, "r");
+
+ if( !fp )
+ return 1;
+
+ while(!feof(fp))
+ {
+ char cmdbuf[64+1];
+
+ int rv;
+ if( (rv = fscanf(fp, "%64s%*[ \t]", &cmdbuf)) != 1 ) {
+ _SysDebug("fscanf rv %i != exp 1", rv);
+ break;
+ }
+
+ // Clear comments
+ if( cmdbuf[0] == '#' ) {
+ while( !feof(fp) && fgetc(fp) != '\n' )
+ ;
+ continue ;
+ }
+ if( cmdbuf[0] == '\0' ) {
+ char ch = fgetc(fp);
+ if( ch != '\n' && ch != -1 ) {
+ fclose(fp);
+ _SysDebug("Unexpected char 0x%x, expecting EOL", ch);
+ return 2; // Unexpected character?
+ }
+ continue ;
+ }
+
+ // Check commands
+ if( strcmp(cmdbuf, "ktty") == 0 ) {
+ // ktty <ID> <command...>
+ // - Spins off a console on the specified kernel TTY
+ int id = 0;
+ if( fscanf(fp, "%d ", &id) != 1 ) {
+ _SysDebug("init[ktty] - TTY ID read failed");
+ goto lineError;
+ }
+ char **command = ReadCommand(fp);
+ if( !command ) {
+ _SysDebug("init[ktty] - Command read failure");
+ goto lineError;
+ }
+ AddKTerminal(id, command);
+ free(command);
+ }
+ else if(strcmp(cmdbuf, "stty") == 0 ) {
+ // stty <devpath> [78][NOE][012][bB]<baud> <command...>
+ char path_seg[32+1];
+ char modespec[4+6+1];
+ if( fscanf(fp, "%32s %6s ", &path_seg, &modespec) != 2 ) {
+ goto lineError;
+ }
+ char **command = ReadCommand(fp);
+ if( !command )
+ goto lineError;
+ AddSerialTerminal(path_seg, modespec, command);
+ }
+ else if(strcmp(cmdbuf, "daemon") == 0 ) {
+ // daemon <stdout> <stderr> <command...>
+ // - Runs a daemon (respawning) that logs to the specified files
+ // - Will append a header whenever the daemon starts
+ char *stdout_path = ReadQuotedString(fp);
+ char *stderr_path = ReadQuotedString(fp);
+ char **command = ReadCommand(fp);
+
+ AddDaemon(stdout_path, stderr_path, command);
+ }
+ else if(strcmp(cmdbuf, "exec") == 0 ) {
+ // exec <command...>
+ // - Runs a command and waits for it to complete before continuing
+ // - NOTE: No other commands will respawn while this is running
+ char **command = ReadCommand(fp);
+ if(!command)
+ goto lineError;
+
+ int handles[] = {0, 1, 2};
+ int pid = _SysSpawn(command[0], (const char **)command, NULL, 3, handles, NULL);
+ int retstatus;
+ _SysWaitTID(pid, &retstatus);
+ _SysDebug("Command '%s' returned %i", command[0], retstatus);
+
+ FreeCommand(command);
+ }
+ else {
+ // Unknown command.
+ _SysDebug("Unknown command '%s'", cmdbuf);
+ goto lineError;
+ }
+ fscanf(fp, " ");
+ continue;
+ lineError:
+ _SysDebug("label lineError: goto'd");
+ while( !feof(fp) && fgetc(fp) != '\n' )
+ ;
+ continue ;
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+tInitProgram *AllocateProgram(char **Command, enum eProgType Type, size_t ExtraSpace)
+{
+ tInitProgram *ret;