Make the whole boot system thing happen

This commit is contained in:
Theodore Dubois 2019-05-04 23:32:24 -07:00
parent cad09c7a58
commit 894c3d2af5
11 changed files with 225 additions and 94 deletions

View File

@ -67,7 +67,9 @@ static void ios_handle_die(const char *msg) {
return err;
// need to do this first so that we can have a valid current for the generic_mknod calls
create_first_process();
err = become_first_process();
if (err < 0)
return err;
// create some device nodes
// this will do nothing if they already exist
@ -78,34 +80,14 @@ static void ios_handle_die(const char *msg) {
generic_mknod("/dev/tty4", S_IFCHR|0666, dev_make(4, 4));
generic_mknod("/dev/tty5", S_IFCHR|0666, dev_make(4, 5));
generic_mknod("/dev/tty6", S_IFCHR|0666, dev_make(4, 6));
generic_mknod("/dev/tty7", S_IFCHR|0666, dev_make(4, 7));
generic_mknod("/dev/tty", S_IFCHR|0666, dev_make(5, 0));
generic_mknod("/dev/ptmx", S_IFCHR|0666, dev_make(5, 2));
generic_mknod("/dev/random", S_IFCHR|0666, dev_make(1, 8));
generic_mknod("/dev/urandom", S_IFCHR|0666, dev_make(1, 9));
NSArray<NSString *> *command = UserPreferences.shared.launchCommand;
char argv[4096];
char *p = argv;
for (NSString *cmd in command) {
const char *c = cmd.UTF8String;
// Save space for the final NUL byte in argv
while (p < argv + sizeof(argv) - 1 && (*p++ = *c++));
// If we reach the end of the buffer, the last string still needs to be
// NUL terminated
*p = '\0';
}
// Add the final NUL byte to argv
*++p = '\0';
const char *envp = "TERM=xterm-256color\0";
err = sys_execve(argv, argv, envp);
if (err < 0)
return err;
set_console_device(4, 1);
err = create_stdio("/dev/console", &ios_tty_driver);
if (err < 0)
return err;
exit_hook = ios_handle_exit;
die_handler = ios_handle_die;
do_mount(&procfs, "proc", "/proc", 0);
do_mount(&devptsfs, "devpts", "/dev/pts", 0);
// configure dns
struct __res_state res;
@ -122,7 +104,7 @@ static void ios_handle_die(const char *msg) {
for (int i = 0; i < serversFound; i ++) {
union res_sockaddr_union s = servers[i];
if (s.sin.sin_len == 0)
continue;
continue;
getnameinfo((struct sockaddr *) &s.sin, s.sin.sin_len,
address, sizeof(address),
NULL, 0, NI_NUMERICHOST);
@ -133,14 +115,64 @@ static void ios_handle_die(const char *msg) {
fd->ops->write(fd, resolvConf.UTF8String, [resolvConf lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
fd_close(fd);
}
do_mount(&procfs, "proc", "/proc", 0);
do_mount(&devptsfs, "devpts", "/dev/pts", 0);
exit_hook = ios_handle_exit;
die_handler = ios_handle_die;
tty_drivers[TTY_CONSOLE_MAJOR] = &ios_tty_driver;
set_console_device(TTY_CONSOLE_MAJOR, 1);
err = create_stdio("/dev/console");
if (err < 0)
return err;
NSArray<NSString *> *command;
if (UserPreferences.shared.bootEnabled) {
command = UserPreferences.shared.bootCommand;
} else {
command = UserPreferences.shared.launchCommand;
}
NSLog(@"%@", command);
char argv[4096];
[self convertCommand:command toArgs:argv limitSize:sizeof(argv)];
const char *envp = "TERM=xterm-256color\0";
err = sys_execve(argv, argv, envp);
if (err < 0)
return err;
task_start(current);
if (UserPreferences.shared.bootEnabled) {
err = become_new_init_child();
if (err < 0)
return err;
err = create_stdio("/dev/tty7");
if (err < 0)
return err;
char argv[4096];
[self convertCommand:UserPreferences.shared.launchCommand toArgs:argv limitSize:sizeof(argv)];
const char *envp = "TERM=xterm-256color\0";
err = sys_execve(argv, argv, envp);
if (err < 0)
return err;
task_start(current);
}
return 0;
}
- (void)convertCommand:(NSArray<NSString *> *)command toArgs:(char *)argv limitSize:(size_t)maxSize {
char *p = argv;
for (NSString *cmd in command) {
const char *c = cmd.UTF8String;
// Save space for the final NUL byte in argv
while (p < argv + maxSize - 1 && (*p++ = *c++));
// If we reach the end of the buffer, the last string still needs to be
// NUL terminated
*p = '\0';
}
// Add the final NUL byte to argv
*++p = '\0';
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// get the network permissions popup to appear on chinese devices
[[NSURLSession.sharedSession dataTaskWithURL:[NSURL URLWithString:@"http://captive.apple.com"]] resume];

View File

@ -10,7 +10,7 @@
@interface TerminalViewController : UIViewController
@property (readonly) Terminal *terminal;
@property (nonatomic) Terminal *terminal;
@end

View File

@ -15,7 +15,6 @@
@interface TerminalViewController () <UIGestureRecognizerDelegate>
@property Terminal *terminal;
@property UITapGestureRecognizer *tapRecognizer;
@property (weak, nonatomic) IBOutlet TerminalView *termView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomConstraint;
@ -39,8 +38,11 @@
- (void)viewDidLoad {
[super viewDidLoad];
self.terminal = [Terminal terminalWithType:4 number:1];
self.termView.terminal = self.terminal;
if (UserPreferences.shared.bootEnabled) {
self.terminal = [Terminal terminalWithType:4 number:7];
} else {
self.terminal = [Terminal terminalWithType:4 number:1];
}
[self.termView becomeFirstResponder];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
@ -223,6 +225,30 @@
}
}
- (void)switchTerminal:(UIKeyCommand *)sender {
unsigned i = (unsigned) sender.input.integerValue;
self.terminal = [Terminal terminalWithType:4 number:i];
}
- (NSArray<UIKeyCommand *> *)keyCommands {
static NSMutableArray<UIKeyCommand *> *commands = nil;
if (commands == nil) {
commands = [NSMutableArray new];
for (unsigned i = 1; i <= 7; i++) {
[commands addObject:
[UIKeyCommand keyCommandWithInput:[NSString stringWithFormat:@"%d", i]
modifierFlags:UIKeyModifierCommand|UIKeyModifierAlternate|UIKeyModifierShift
action:@selector(switchTerminal:)]];
}
}
return commands;
}
- (void)setTerminal:(Terminal *)terminal {
_terminal = terminal;
self.termView.terminal = self.terminal;
}
@end
@interface BarView : UIInputView

View File

@ -181,8 +181,7 @@ static int elf_exec(struct fd *fd, const char *file, const char *argv, const cha
// killed before it even starts. please don't be too sad about it, it's
// just a process.
mm_release(current->mm);
current->mm = mm_new();
current->mem = current->cpu.mem = &current->mm->mem;
task_set_mm(current, mm_new());
write_wrlock(&current->mem->lock);
current->mm->exefile = fd_retain(fd);

View File

@ -59,8 +59,7 @@ static int copy_task(struct task *task, dword_t flags, addr_t stack, addr_t ptid
if (flags & CLONE_VM_) {
mm_retain(mm);
} else {
task->mm = mm_copy(mm);
task->mem = task->cpu.mem = &task->mm->mem;
task_set_mm(task, mm_copy(mm));
}
if (flags & CLONE_FILES_) {
@ -133,6 +132,18 @@ fail_free_mem:
return err;
}
struct task *fork_task(struct task *parent) {
struct task *task = task_create_(parent);
if (task == NULL)
return ERR_PTR(_ENOMEM);
int err = copy_task(task, SIGCHLD_, 0, 0, 0, 0);
if (err < 0) {
task_destroy(task);
return ERR_PTR(err);
}
return task;
}
dword_t sys_clone(dword_t flags, addr_t stack, addr_t ptid, addr_t tls, addr_t ctid) {
STRACE("clone(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)", flags, stack, ptid, tls, ctid);
if (flags & ~CSIGNAL_ & ~IMPLEMENTED_FLAGS) {
@ -144,14 +155,9 @@ dword_t sys_clone(dword_t flags, addr_t stack, addr_t ptid, addr_t tls, addr_t c
if (flags & CLONE_THREAD_ && !(flags & CLONE_SIGHAND_))
return _EINVAL;
struct task *task = task_create_(current);
if (task == NULL)
return _ENOMEM;
int err = copy_task(task, flags, stack, ptid, tls, ctid);
if (err < 0) {
task_destroy(task);
return err;
}
struct task *task = fork_task(current);
if (IS_ERR(task))
return PTR_ERR(task);
task->cpu.eax = 0;
struct vfork_info vfork;

View File

@ -69,16 +69,16 @@ pid_t_ sys_getpgrp() {
return sys_getpgid(0);
}
dword_t sys_setsid() {
pid_t_ task_setsid(struct task *task) {
lock(&pids_lock);
struct tgroup *group = current->group;
struct tgroup *group = task->group;
pid_t_ new_sid = group->leader->pid;
if (group->pgid == new_sid || group->sid == new_sid) {
unlock(&pids_lock);
return _EPERM;
}
struct pid *pid = pid_get(current->pid);
struct pid *pid = pid_get(task->pid);
list_remove_safe(&group->session);
list_add(&pid->session, &group->session);
group->sid = new_sid;
@ -94,7 +94,13 @@ dword_t sys_setsid() {
return new_sid;
}
dword_t sys_setsid() {
STRACE("setsid()");
return task_setsid(current);
}
dword_t sys_getsid() {
STRACE("getsid()");
lock(&pids_lock);
pid_t_ sid = current->group->sid;
unlock(&pids_lock);

View File

@ -16,19 +16,7 @@ int mount_root(const struct fs_ops *fs, const char *source) {
return 0;
}
static struct tgroup *init_tgroup() {
struct tgroup *group = malloc(sizeof(struct tgroup));
if (group == NULL)
return NULL;
*group = (struct tgroup) {};
list_init(&group->threads);
lock_init(&group->lock);
cond_init(&group->child_exit);
cond_init(&group->stopped_cond);
return group;
}
void create_first_process() {
static void establish_signal_handlers() {
extern void sigusr1_handler(int sig);
struct sigaction sigact;
sigact.sa_handler = sigusr1_handler;
@ -37,29 +25,89 @@ void create_first_process() {
sigaddset(&sigact.sa_mask, SIGUSR1);
sigaction(SIGUSR1, &sigact, NULL);
signal(SIGPIPE, SIG_IGN);
}
current = task_create_(NULL);
current->mm = mm_new();
current->mem = current->cpu.mem = &current->mm->mem;
struct tgroup *group = init_tgroup();
list_add(&group->threads, &current->group_links);
group->leader = current;
current->group = group;
current->tgid = current->pid;
// copied from include/asm-generic/resource.h in the kernel
static struct rlimit_ init_rlimits[16] = {
[RLIMIT_CPU_] = {RLIM_INFINITY, RLIM_INFINITY},
[RLIMIT_FSIZE_] = {RLIM_INFINITY, RLIM_INFINITY},
[RLIMIT_DATA_] = {RLIM_INFINITY, RLIM_INFINITY},
[RLIMIT_STACK_] = {8*1024*1024, RLIM_INFINITY},
[RLIMIT_CORE_] = {0, RLIM_INFINITY},
[RLIMIT_RSS_] = {RLIM_INFINITY, RLIM_INFINITY},
[RLIMIT_NPROC_] = {0, 0},
[RLIMIT_NOFILE_] = {1024, 4096},
[RLIMIT_MEMLOCK_] = {64*1024, 64*1024},
[RLIMIT_AS_] = {RLIM_INFINITY, RLIM_INFINITY},
[RLIMIT_LOCKS_] = {RLIM_INFINITY, RLIM_INFINITY},
[RLIMIT_SIGPENDING_] = {0, 0},
[RLIMIT_MSGQUEUE_] = {819200, 819200},
[RLIMIT_NICE_] = {0, 0},
[RLIMIT_RTPRIO_] = {0, 0},
[RLIMIT_RTTIME_] = {RLIM_INFINITY, RLIM_INFINITY},
};
struct fs_info *fs = fs_info_new();
current->fs = fs;
fs->pwd = fs->root = generic_open("/", O_RDONLY_, 0);
fs->pwd->refcount = 2;
fs->umask = 0022;
current->files = fdtable_new(3);
current->sighand = sighand_new();
for (int i = 0; i < RLIMIT_NLIMITS_; i++)
group->limits[i].cur = group->limits[i].max = RLIM_INFINITY_;
// python subprocess uses this limit as a way to close every open file
group->limits[RLIMIT_NOFILE_].cur = 1024;
current->thread = pthread_self();
sys_setsid();
// TODO error propagation
static struct task *construct_task(struct task *parent) {
struct task *task = task_create_(parent);
struct tgroup *group = malloc(sizeof(struct tgroup));
*group = (struct tgroup) {};
list_init(&group->threads);
lock_init(&group->lock);
cond_init(&group->child_exit);
cond_init(&group->stopped_cond);
memcpy(group->limits, init_rlimits, sizeof(init_rlimits));
group->leader = task;
list_add(&group->threads, &task->group_links);
task->group = group;
task->tgid = task->pid;
task_setsid(task);
task_set_mm(task, mm_new());
task->sighand = sighand_new();
task->files = fdtable_new(3); // why is there a 3 here
task->fs = fs_info_new();
task->fs->umask = 0022;
// we'll need to have current set to do the open call
struct task *old_current = current;
current = task;
task->fs->root = generic_open("/", O_RDONLY_, 0);
task->fs->pwd = fd_retain(task->fs->root);
current = old_current;
return task;
}
int become_first_process() {
// now seems like a nice time
establish_signal_handlers();
struct task *task = construct_task(NULL);
if (IS_ERR(task))
return PTR_ERR(task);
current = task;
return 0;
}
int become_new_init_child() {
// locking? who needs locking?!
struct task *init = pid_get_task(1);
assert(init != NULL);
struct task *task = construct_task(init);
if (IS_ERR(task))
return PTR_ERR(task);
// these are things we definitely don't want to inherit
task->clear_tid = 0;
task->vfork = NULL;
// TODO: think about whether it would be a good idea to inherit fs_info
current = task;
return 0;
}
extern int console_major;
@ -69,9 +117,7 @@ void set_console_device(int major, int minor) {
console_minor = minor;
}
int create_stdio(const char *file, struct tty_driver *driver) {
tty_drivers[TTY_CONSOLE_MAJOR] = driver;
int create_stdio(const char *file) {
struct fd *fd = generic_open(file, O_RDWR_, 0);
if (fd == ERR_PTR(_ENOENT)) {
// fallback to adhoc files for stdio
@ -86,10 +132,9 @@ int create_stdio(const char *file, struct tty_driver *driver) {
if (IS_ERR(fd))
return PTR_ERR(fd);
fd->refcount = 3;
current->files->files[0] = fd;
current->files->files[1] = fd;
current->files->files[2] = fd;
fd->refcount = 0;
current->files->files[0] = fd_retain(fd);
current->files->files[1] = fd_retain(fd);
current->files->files[2] = fd_retain(fd);
return 0;
}

View File

@ -3,9 +3,11 @@
#include "fs/tty.h"
// Incredibly sloppy. Please do not reference as an example of good API design.
int mount_root(const struct fs_ops *fs, const char *source);
void create_first_process(void);
void set_console_device(int major, int minor);
int create_stdio(const char *file, struct tty_driver *driver);
int become_first_process(void);
int become_new_init_child(void);
int create_stdio(const char *file);
#endif

View File

@ -67,7 +67,13 @@ struct task *task_create_(struct task *parent) {
}
unlock(&pids_lock);
task->pending = 0;
task->queued = 0;
task->clear_tid = 0;
task->robust_list = 0;
task->did_exec = false;
lock_init(&task->general_lock);
task->sockrestart = (struct task_sockrestart) {};
list_init(&task->sockrestart.listen);

View File

@ -78,6 +78,11 @@ struct task {
// if I have to stop using __thread, current will become a macro
extern __thread struct task *current;
static inline void task_set_mm(struct task *task, struct mm *mm) {
task->mm = mm;
task->mem = task->cpu.mem = &task->mm->mem;
}
// Creates a new process, initializes most fields from the parent. Specify
// parent as NULL to create the init process. Returns NULL if out of memory.
// Ends with an underscore because there's a mach function by the same name
@ -85,7 +90,9 @@ struct task *task_create_(struct task *parent);
// Removes the process from the process table and frees it. Must be called with pids_lock.
void task_destroy(struct task *task);
// misc
void vfork_notify(struct task *task);
pid_t_ task_setsid(struct task *task);
// struct thread_group is way too long to type comfortably
struct tgroup {

View File

@ -69,7 +69,8 @@ static inline int xX_main_Xx(int argc, char *const argv[], const char *envp) {
if (err < 0)
return err;
create_first_process();
become_first_process();
current->thread = pthread_self();
if (!has_root) {
char cwd[MAX_PATH + 1];
getcwd(cwd, sizeof(cwd));
@ -89,7 +90,8 @@ static inline int xX_main_Xx(int argc, char *const argv[], const char *envp) {
err = sys_execve(argv[optind], argv_copy, envp == NULL ? "\0" : envp);
if (err < 0)
return err;
err = create_stdio(console, &real_tty_driver);
tty_drivers[TTY_CONSOLE_MAJOR] = &real_tty_driver;
err = create_stdio(console);
if (err < 0)
return err;
exit_hook = exit_handler;