mirror of
https://github.com/ish-app/ish.git
synced 2026-02-01 14:32:26 +00:00
Make the whole boot system thing happen
This commit is contained in:
parent
cad09c7a58
commit
894c3d2af5
@ -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];
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
@interface TerminalViewController : UIViewController
|
||||
|
||||
@property (readonly) Terminal *terminal;
|
||||
@property (nonatomic) Terminal *terminal;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 = ¤t->mm->mem;
|
||||
task_set_mm(current, mm_new());
|
||||
write_wrlock(¤t->mem->lock);
|
||||
|
||||
current->mm->exefile = fd_retain(fd);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
129
kernel/init.c
129
kernel/init.c
@ -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 = ¤t->mm->mem;
|
||||
struct tgroup *group = init_tgroup();
|
||||
list_add(&group->threads, ¤t->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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user