Hook up linux pseudoterminals

This commit is contained in:
Theodore Dubois
2021-12-31 20:49:40 -08:00
parent fc76baff3d
commit f708c812dc
14 changed files with 393 additions and 82 deletions
+1 -1
View File
@@ -65,7 +65,7 @@ static void ios_handle_die(const char *msg) {
pthread_setname_np(newName.UTF8String);
}
#elif ISH_LINUX
void ReportPanic(const char *message, void (^completion)(void)) {
void ReportPanic(const char *message) {
[NSNotificationCenter.defaultCenter postNotificationName:KernelPanicNotification object:nil userInfo:@{@"message":@(message)}];
}
#endif
+24
View File
@@ -8,6 +8,7 @@
#if ISH_LINUX
#include <Foundation/Foundation.h>
#include <pthread.h>
#include "Roots.h"
#include "LinuxInterop.h"
@@ -19,8 +20,31 @@ void ConsoleLog(const char *data, unsigned len) {
NSLog(@"%.*s", len, data);
}
nsobj_t objc_get(nsobj_t object) {
CFBridgingRetain((__bridge id) object);
return object;
}
void objc_put(nsobj_t object) {
CFBridgingRelease(object);
}
void sync_do_in_workqueue(void (^block)(void (^done)(void))) {
__block pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
__block pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
__block bool flag = false;
async_do_in_workqueue(^{
block(^{
pthread_mutex_lock(&mutex);
flag = true;
pthread_mutex_unlock(&mutex);
pthread_cond_broadcast(&cond);
});
});
pthread_mutex_lock(&mutex);
while (!flag)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
}
#endif
+63 -15
View File
@@ -8,11 +8,14 @@
#include "LinuxInterop.h"
#include <Block.h>
#include <linux/start_kernel.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/string.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/file.h>
#include <linux/umh.h>
#include <asm/irq.h>
#include <user/fs.h>
#include <user/irq.h>
@@ -24,23 +27,10 @@ void actuate_kernel(const char *cmdline) {
run_kernel();
}
void sync_do_in_ios(void (^block)(void (^done)(void))) {
DECLARE_COMPLETION(panic_report_done);
struct completion *done_ptr = &panic_report_done;
async_do_in_ios(^{
block(^{
async_do_in_irq(^{
complete(done_ptr);
});
});
});
wait_for_completion(done_ptr);
}
static int panic_report(struct notifier_block *nb, unsigned long action, void *data) {
const char *message = data;
sync_do_in_ios(^(void (^done)(void)) {
ReportPanic(message, done);
async_do_in_ios(^{
ReportPanic(message);
});
return 0;
}
@@ -77,6 +67,27 @@ void async_do_in_irq(void (^block)(void)) {
trigger_irq(CALL_BLOCK_IRQ);
}
struct ios_work {
void (^block)(void);
struct work_struct work;
};
static void do_ios_work(struct work_struct *work) {
struct ios_work *ios_work = container_of(work, struct ios_work, work);
ios_work->block();
Block_release(ios_work->block);
kfree(ios_work);
}
void async_do_in_workqueue(void (^block)(void)) {
async_do_in_irq(^{
struct ios_work *work = kzalloc(sizeof(*work), GFP_KERNEL);
work->block = Block_copy(block);
INIT_WORK(&work->work, do_ios_work);
schedule_work(&work->work);
});
}
static int __init call_block_init(void) {
int err = host_pipe(&block_request_read, &block_request_write);
if (err < 0)
@@ -90,3 +101,40 @@ static int __init call_block_init(void) {
return 0;
}
subsys_initcall(call_block_init);
struct ish_session {
struct file *tty;
nsobj_t terminal;
StartSessionDoneBlock callback;
};
static int session_init(struct subprocess_info *info, struct cred *cred) {
struct ish_session *session = info->data;
for (int fd = 0; fd <= 2; fd++) {
int err = replace_fd(fd, session->tty, 0);
if (err < 0)
return err;
}
return 0;
}
static void session_cleanup(struct subprocess_info *info) {
struct ish_session *session = info->data;
if (info->pid != 0 || info->retval != 0)
session->callback(info->retval, info->pid, objc_get(session->terminal));
else; // otherwise, there was a synchronous failure, returned directly from call_usermodehelper_exec
if (session->tty != NULL)
fput(session->tty);
objc_put(session->terminal);
kfree(session);
}
void start_session(const char *exe, const char *const *argv, const char *const *envp, StartSessionDoneBlock done) {
struct ish_session *session = kzalloc(sizeof(*session), GFP_KERNEL);
session->tty = ios_pty_open(&session->terminal);
session->callback = done;
struct subprocess_info *proc = call_usermodehelper_setup(exe, (char **) argv, (char **) envp, GFP_KERNEL, session_init, session_cleanup, session);
int err = call_usermodehelper_exec(proc, UMH_WAIT_EXEC);
if (err < 0)
done(err, 0, NULL);
}
+15 -4
View File
@@ -12,29 +12,40 @@
#include <sys/types.h>
#else
#include <linux/types.h>
#include <linux/fs.h>
#endif
void actuate_kernel(const char *cmdline);
void async_do_in_irq(void (^block)(void));
void async_do_in_workqueue(void (^block)(void));
void async_do_in_ios(void (^block)(void));
void sync_do_in_ios(void (^block)(void (^done)(void)));
void sync_do_in_workqueue(void (^block)(void (^done)(void)));
void ReportPanic(const char *message, void (^completion)(void));
void ReportPanic(const char *message);
void ConsoleLog(const char *data, unsigned len);
const char *DefaultRootPath();
const char *DefaultRootPath(void);
typedef const void *nsobj_t;
nsobj_t objc_get(nsobj_t object);
void objc_put(nsobj_t object);
struct linux_tty {
struct linux_tty_callbacks *ops;
};
struct linux_tty_callbacks {
void (*wakeup)(struct linux_tty *tty);
void (*can_output)(struct linux_tty *tty);
void (*send_input)(struct linux_tty *tty, const char *data, size_t length);
void (*hangup)(struct linux_tty *tty);
};
#ifdef __KERNEL__
struct file *ios_pty_open(nsobj_t *terminal_out);
#endif
typedef void (^StartSessionDoneBlock)(int retval, int pid, nsobj_t terminal);
void start_session(const char *exe, const char *const *argv, const char *const *envp, StartSessionDoneBlock done);
nsobj_t Terminal_terminalWithType_number(int type, int number);
void Terminal_setLinuxTTY(nsobj_t _self, struct linux_tty *tty);
int Terminal_sendOutput_length(nsobj_t _self, const char *data, int size);
+175
View File
@@ -0,0 +1,175 @@
//
// LinuxPTY.c
// libiSHLinux
//
// Created by Theodore Dubois on 12/30/21.
//
#include <linux/init.h>
#include <linux/namei.h>
#include <linux/errname.h>
#include <linux/kthread.h>
#include <linux/fs.h>
#include <linux/hashtable.h>
#include <linux/syscalls.h>
#include <linux/init_task.h>
#include <linux/termios.h>
#include <linux/fcntl.h>
#include <linux/vmalloc.h>
#include <uapi/linux/mount.h>
#include "LinuxInterop.h"
static struct path ptmx_path;
struct ios_pty_wq {
struct ios_pty *pty;
struct wait_queue_entry wq;
struct wait_queue_head *head;
};
struct ios_pty {
dev_t pts_rdev;
struct file *ptm;
nsobj_t terminal;
struct linux_tty linux_tty;
// pseudoterminals have multiple wait queues and you need a different wait_queue_entry for each one. fun fact!
int n_wqs;
struct ios_pty_wq wqs[4];
poll_table pt;
struct work_struct output_work;
struct work_struct cleanup_work;
};
static void ios_pty_output_work(struct work_struct *output_work) {
struct ios_pty *pty = container_of(output_work, struct ios_pty, output_work);
size_t room = Terminal_roomForOutput(pty->terminal);
char *buf = kvmalloc(room, GFP_KERNEL);
ssize_t size;
for (;;) {
size = kernel_read(pty->ptm, buf, PAGE_SIZE, NULL);
if (size < 0) {
printk(KERN_WARNING "ios: pty read failed: %s\n", errname(size));
break;
}
int sent = Terminal_sendOutput_length(pty->terminal, buf, size);
if (sent != size) {
printk(KERN_WARNING "ios: dropped %ld bytes of pty output\n", size - sent);
break;
}
}
kvfree(buf);
}
static void ios_pty_cleanup_work(struct work_struct *cleanup_work) {
struct ios_pty *pty = container_of(cleanup_work, struct ios_pty, cleanup_work);
for (int i = 0; i < pty->n_wqs; i++)
remove_wait_queue(pty->wqs[i].head, &pty->wqs[i].wq);
fput(pty->ptm);
nsobj_t terminal = pty->terminal;
Terminal_setLinuxTTY(terminal, NULL);
objc_put(terminal);
kfree(pty);
}
static void ios_pty_cb_can_output(struct linux_tty *linux_tty) {
struct ios_pty *pty = container_of(linux_tty, struct ios_pty, linux_tty);
schedule_work(&pty->output_work);
}
static void ios_pty_cb_send_input(struct linux_tty *linux_tty, const char *data, size_t length) {
struct ios_pty *pty = container_of(linux_tty, struct ios_pty, linux_tty);
ssize_t written = kernel_write(pty->ptm, data, length, NULL);
if (written < 0)
printk(KERN_WARNING "ios: pty input failed: %s\n", errname(written));
else if (written != length)
printk(KERN_WARNING "ios: dropped %ld bytes of pty input\n", length - written);
}
static void ios_pty_cb_hangup(struct linux_tty *linux_tty) {
}
static struct linux_tty_callbacks ios_pty_callbacks = {
.can_output = ios_pty_cb_can_output,
.send_input = ios_pty_cb_send_input,
.hangup = ios_pty_cb_hangup,
};
static int ptm_callback(struct wait_queue_entry *wq_entry, unsigned mode, int flags, void *key) {
struct ios_pty *pty = container_of(wq_entry, struct ios_pty_wq, wq)->pty;
__poll_t events = vfs_poll(pty->ptm, NULL);
if (events & EPOLLHUP)
schedule_work(&pty->cleanup_work);
if (events & EPOLLIN)
schedule_work(&pty->output_work);
return 0;
}
static void poll_callback(struct file *file, wait_queue_head_t *whead, poll_table *pt) {
struct ios_pty *pty = container_of(pt, struct ios_pty, pt);
if (pty->n_wqs >= ARRAY_SIZE(pty->wqs))
panic("ios pty: too many wait queues!");
struct ios_pty_wq *pty_wq = &pty->wqs[pty->n_wqs++];
pty_wq->pty = pty;
pty_wq->head = whead;
init_waitqueue_func_entry(&pty_wq->wq, ptm_callback);
add_wait_queue(whead, &pty_wq->wq);
}
struct file *ios_pty_open(nsobj_t *terminal_out) {
struct file *ptm_file = dentry_open(&ptmx_path, O_RDWR, current_cred());
if (IS_ERR(ptm_file))
return ptm_file;
int lock_pty = 0;
vfs_ioctl(ptm_file, TIOCSPTLCK, (unsigned long) &lock_pty);
// sadly this api can't just return a struct file *
int fd = vfs_ioctl(ptm_file, TIOCGPTPEER, O_RDWR);
if (fd < 0) {
fput(ptm_file);
return ERR_PTR(fd);
}
struct file *pts_file = fget(fd);
ksys_close(fd);
struct ios_pty *pty = kzalloc(sizeof(*pty), GFP_KERNEL);
if (pty == NULL) {
fput(pts_file);
fput(ptm_file);
return ERR_PTR(-ENOMEM);
}
pty->ptm = ptm_file;
INIT_WORK(&pty->output_work, ios_pty_output_work);
INIT_WORK(&pty->cleanup_work, ios_pty_cleanup_work);
pty->pts_rdev = pts_file->f_inode->i_rdev;
pty->terminal = Terminal_terminalWithType_number(MAJOR(pty->pts_rdev), MINOR(pty->pts_rdev));
pty->linux_tty.ops = &ios_pty_callbacks;
Terminal_setLinuxTTY(pty->terminal, &pty->linux_tty);
*terminal_out = pty->terminal;
init_poll_funcptr(&pty->pt, poll_callback);
__poll_t revents = vfs_poll(pty->ptm, &pty->pt);
if (revents)
ptm_callback(&pty->wqs[pty->n_wqs-1].wq, 0, 0, NULL);
return pts_file;
}
static __init int ios_pty_init(void) {
ksys_mkdir("/dev/pts", 0755);
int err = do_mount("devpts", "/dev/pts", "devpts", MS_SILENT, NULL);
if (err < 0) {
panic("ish: failed to mount devpts: %s", errname(err));
}
err = kern_path("/dev/pts/ptmx", 0, &ptmx_path);
if (err < 0) {
panic("ish: failed to acquire ptmx: %s", errname(err));
}
return 0;
}
device_initcall(ios_pty_init);
+2 -2
View File
@@ -19,7 +19,7 @@ static __init int ish_rootfs(void) {
const char *fakefs_path = DefaultRootPath();
int err = do_mount(fakefs_path, "/root", "fakefs", MS_SILENT, NULL);
if (err < 0) {
pr_emerg("fakefs: failed to mount root from %s: %s\n", fakefs_path, errname(err));
pr_emerg("ish: failed to mount fakefs root from %s: %s\n", fakefs_path, errname(err));
return err;
}
ksys_chdir("/root");
@@ -27,7 +27,7 @@ static __init int ish_rootfs(void) {
devtmpfs_mount();
err = do_mount("proc", "proc", "proc", MS_SILENT, NULL);
if (err < 0) {
pr_warn("procfs: failed to mount: %s", errname(err));
pr_warn("ish: failed to mount procfs: %s", errname(err));
}
do_mount(".", "/", NULL, MS_MOVE, NULL);
+11 -13
View File
@@ -42,11 +42,8 @@ static struct ios_tty ios_ttys[NUM_TTYS];
static int ios_tty_port_activate(struct tty_port *port, struct tty_struct *tty) {
BUG_ON(port != &ios_ttys[tty->index].port);
sync_do_in_ios(^(void (^done)(void)) {
port->client_data = (void *) Terminal_terminalWithType_number(TTY_MAJOR, tty->index);
Terminal_setLinuxTTY(port->client_data, &container_of(port, struct ios_tty, port)->linux_tty);
done();
});
port->client_data = (void *) Terminal_terminalWithType_number(TTY_MAJOR, tty->index);
Terminal_setLinuxTTY(port->client_data, &container_of(port, struct ios_tty, port)->linux_tty);
return 0;
}
static void ios_tty_port_destruct(struct tty_port *port) {
@@ -62,7 +59,7 @@ static struct tty_port_operations ios_tty_port_ops = {
.destruct = ios_tty_port_destruct,
};
static void ios_tty_cb_wakeup(struct linux_tty *linux_tty) {
static void ios_tty_cb_can_output(struct linux_tty *linux_tty) {
struct ios_tty *tty = container_of(linux_tty, struct ios_tty, linux_tty);
tty_port_tty_wakeup(&tty->port);
}
@@ -73,9 +70,14 @@ static void ios_tty_cb_send_input(struct linux_tty *linux_tty, const char *data,
tty_flip_buffer_push(&tty->port);
}
static void ios_tty_cb_hangup(struct linux_tty *linux_tty) {
// nah
}
static struct linux_tty_callbacks ios_tty_callbacks = {
.wakeup = ios_tty_cb_wakeup,
.can_output = ios_tty_cb_can_output,
.send_input = ios_tty_cb_send_input,
.hangup = ios_tty_cb_hangup,
};
static int ios_tty_open(struct tty_struct *tty, struct file *filp) {
@@ -87,8 +89,7 @@ static int ios_tty_write(struct tty_struct *tty, const unsigned char *data, int
}
static int ios_tty_write_room(struct tty_struct *tty) {
int room = Terminal_roomForOutput(tty->port->client_data);
return room;
return Terminal_roomForOutput(tty->port->client_data);
}
static struct tty_operations ios_tty_ops = {
@@ -98,10 +99,7 @@ static struct tty_operations ios_tty_ops = {
};
static int ios_tty_console_setup(struct console *console, char *what) {
sync_do_in_ios(^(void (^done)(void)) {
console->data = (void *) Terminal_terminalWithType_number(TTY_MAJOR, 1);
done();
});
console->data = (void *) Terminal_terminalWithType_number(TTY_MAJOR, 1);
return 0;
}
+3 -1
View File
@@ -13,8 +13,10 @@ struct tty;
@interface Terminal : NSObject
+ (Terminal *)terminalWithType:(int)type number:(int)number;
#if !ISH_LINUX
// Returns a strong struct tty and a Terminal that has a weak reference to the same tty
+ (Terminal *)createPseudoTerminal:(struct tty **)tty;
#endif
+ (Terminal *)terminalWithUUID:(NSUUID *)uuid;
@property (readonly) NSUUID *uuid;
@@ -22,7 +24,7 @@ struct tty;
+ (void)convertCommand:(NSArray<NSString *> *)command toArgs:(char *)argv limitSize:(size_t)maxSize;
- (int)sendOutput:(const void *)buf length:(int)len;
- (void)sendInput:(const char *)buf length:(size_t)len;
- (void)sendInput:(NSData *)input;
- (NSString *)arrow:(char)direction;
+56 -39
View File
@@ -28,7 +28,6 @@ typedef struct linux_tty *tty_t;
#endif
}
@property WKWebView *webView;
@property BOOL loaded;
@property (nonatomic) tty_t tty;
@property (nonatomic) NSMutableData *pendingData;
@@ -62,27 +61,39 @@ typedef struct linux_tty *tty_t;
@end
@implementation Terminal
@synthesize webView = _webView;
static const int BUF_SIZE = 4096;
static const int BUF_SIZE = 1<<14;
static NSMapTable<NSNumber *, Terminal *> *terminals;
static NSMapTable<NSUUID *, Terminal *> *terminalsByUUID;
- (instancetype)initWithType:(int)type number:(int)num {
self.terminalsKey = @(dev_make(type, num));
Terminal *terminal = [terminals objectForKey:self.terminalsKey];
if (terminal)
return terminal;
if (self = [super init]) {
self.pendingData = [[NSMutableData alloc] initWithCapacity:BUF_SIZE];
self.refreshTask = [[DelayedUITask alloc] initWithTarget:self action:@selector(refresh)];
self.scrollToBottomTask = [[DelayedUITask alloc] initWithTarget:self action:@selector(scrollToBottom)];
@synchronized (Terminal.class) {
self.terminalsKey = @(dev_make(type, num));
Terminal *terminal = [terminals objectForKey:self.terminalsKey];
if (terminal)
return terminal;
if (self = [super init]) {
self.pendingData = [[NSMutableData alloc] initWithCapacity:BUF_SIZE];
self.refreshTask = [[DelayedUITask alloc] initWithTarget:self action:@selector(refresh)];
self.scrollToBottomTask = [[DelayedUITask alloc] initWithTarget:self action:@selector(scrollToBottom)];
#if !ISH_LINUX
lock_init(&_dataLock);
cond_init(&_dataConsumed);
lock_init(&_dataLock);
cond_init(&_dataConsumed);
#endif
[terminals setObject:self forKey:self.terminalsKey];
self.uuid = [NSUUID UUID];
[terminalsByUUID setObject:self forKey:self.uuid];
}
return self;
}
}
- (WKWebView *)webView {
if (_webView == nil) {
WKWebViewConfiguration *config = [WKWebViewConfiguration new];
[config.userContentController addScriptMessageHandler:self name:@"load"];
[config.userContentController addScriptMessageHandler:self name:@"log"];
@@ -91,16 +102,12 @@ static NSMapTable<NSUUID *, Terminal *> *terminalsByUUID;
[config.userContentController addScriptMessageHandler:self name:@"propUpdate"];
// Make the web view really big so that if a program tries to write to the terminal before it's displayed, the text probably won't wrap too badly.
CGRect webviewSize = CGRectMake(0, 0, 10000, 10000);
self.webView = [[CustomWebView alloc] initWithFrame:webviewSize configuration:config];
self.webView.scrollView.scrollEnabled = NO;
_webView = [[CustomWebView alloc] initWithFrame:webviewSize configuration:config];
_webView.scrollView.scrollEnabled = NO;
NSURL *xtermHtmlFile = [NSBundle.mainBundle URLForResource:@"term" withExtension:@"html"];
[self.webView loadFileURL:xtermHtmlFile allowingReadAccessToURL:xtermHtmlFile];
[terminals setObject:self forKey:self.terminalsKey];
self.uuid = [NSUUID UUID];
[terminalsByUUID setObject:self forKey:self.uuid];
[_webView loadFileURL:xtermHtmlFile allowingReadAccessToURL:xtermHtmlFile];
}
return self;
return _webView;
}
#if !ISH_LINUX
@@ -113,7 +120,9 @@ static NSMapTable<NSUUID *, Terminal *> *terminalsByUUID;
#endif
- (void)setTty:(tty_t)tty {
_tty = tty;
@synchronized (self) {
_tty = tty;
}
dispatch_async(dispatch_get_main_queue(), ^{
[self syncWindowSize];
});
@@ -129,7 +138,7 @@ static NSMapTable<NSUUID *, Terminal *> *terminalsByUUID;
NSLog(@"%@", message.body);
} else if ([message.name isEqualToString:@"sendInput"]) {
NSData *data = [message.body dataUsingEncoding:NSUTF8StringEncoding];
[self sendInput:data.bytes length:data.length];
[self sendInput:data];
} else if ([message.name isEqualToString:@"resize"]) {
[self syncWindowSize];
} else if ([message.name isEqualToString:@"propUpdate"]) {
@@ -142,9 +151,8 @@ static NSMapTable<NSUUID *, Terminal *> *terminalsByUUID;
#if !ISH_LINUX
int cols = dimensions[0].intValue;
int rows = dimensions[1].intValue;
if (self.tty == NULL) {
if (self.tty == NULL)
return;
}
lock(&self.tty->lock);
tty_set_winsize(self.tty, (struct winsize_) {.col = cols, .row = rows});
unlock(&self.tty->lock);
@@ -193,14 +201,15 @@ static NSMapTable<NSUUID *, Terminal *> *terminalsByUUID;
}
#endif
- (void)sendInput:(const char *)buf length:(size_t)len {
- (void)sendInput:(NSData *)input {
if (self.tty == NULL)
return;
#if !ISH_LINUX
tty_input(self.tty, buf, len, 0);
tty_input(self.tty, input.bytes, input.length, 0);
#else
async_do_in_irq(^{
self.tty->ops->send_input(self.tty, buf, len);
async_do_in_workqueue(^{
NSData *inputRef = input;
self.tty->ops->send_input(self.tty, inputRef.bytes, inputRef.length);
});
#endif
[self.webView evaluateJavaScript:@"exports.setUserGesture()" completionHandler:nil];
@@ -259,7 +268,7 @@ static NSMapTable<NSUUID *, Terminal *> *terminalsByUUID;
}
if (self->_tty) {
async_do_in_irq(^{
self->_tty->ops->wakeup(self->_tty);
self->_tty->ops->can_output(self->_tty);
});
}
#endif
@@ -289,19 +298,27 @@ static NSMapTable<NSUUID *, Terminal *> *terminalsByUUID;
}
+ (Terminal *)terminalWithUUID:(NSUUID *)uuid {
return [terminalsByUUID objectForKey:uuid];
@synchronized (Terminal.class) {
return [terminalsByUUID objectForKey:uuid];
}
}
- (void)destroy {
#if !ISH_LINUX
struct tty *tty = self.tty;
tty_t tty = self.tty;
if (tty != NULL) {
lock(&tty->lock);
tty_hangup(tty);
unlock(&tty->lock);
}
#if !ISH_LINUX
if (tty != NULL) {
lock(&tty->lock);
tty_hangup(tty);
unlock(&tty->lock);
}
#else
tty->ops->hangup(tty);
#endif
[terminals removeObjectForKey:self.terminalsKey];
}
@synchronized (Terminal.class) {
[terminals removeObjectForKey:self.terminalsKey];
}
}
+ (void)initialize {
+2 -2
View File
@@ -271,7 +271,7 @@ static NSString *const HANDLERS[] = {@"syncFocus", @"focus", @"newScrollHeight",
text = [text stringByReplacingOccurrencesOfString:@"\n" withString:@"\r"];
NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
[self.terminal sendInput:data.bytes length:data.length];
[self.terminal sendInput:data];
}
- (void)insertControlChar:(char)ch {
@@ -281,7 +281,7 @@ static NSString *const HANDLERS[] = {@"syncFocus", @"focus", @"newScrollHeight",
if (ch == '6') ch = '^';
if (ch != '\0')
ch = toupper(ch) ^ 0x40;
[self.terminal sendInput:&ch length:1];
[self.terminal sendInput:[NSData dataWithBytes:&ch length:1]];
}
}
+31 -3
View File
@@ -14,6 +14,7 @@
#import "AboutViewController.h"
#import "CurrentRoot.h"
#import "NSObject+SaneKVO.h"
#import "LinuxInterop.h"
#include "kernel/init.h"
#include "kernel/task.h"
#include "kernel/calls.h"
@@ -162,6 +163,8 @@
}
- (int)startSession {
NSArray<NSString *> *command = UserPreferences.shared.launchCommand;
#if !ISH_LINUX
int err = become_new_init_child();
if (err < 0)
@@ -179,9 +182,8 @@
if (err < 0)
return err;
tty_release(tty);
char argv[4096];
NSArray<NSString *> *command = UserPreferences.shared.launchCommand;
[Terminal convertCommand:command toArgs:argv limitSize:sizeof(argv)];
const char *envp = "TERM=xterm-256color\0";
err = do_execve(command[0].UTF8String, command.count, argv, envp);
@@ -190,7 +192,33 @@
self.sessionPid = current->pid;
task_start(current);
#else
self.sessionTerminal = [Terminal terminalWithType:4 number:1];
const char *argv_arr[command.count + 1];
for (NSUInteger i = 0; i < command.count; i++)
argv_arr[i] = command[i].UTF8String;
argv_arr[command.count] = NULL;
const char *envp_arr[] = {
"TERM=xterm256-color",
NULL,
};
const char *const *argv = argv_arr;
const char *const *envp = envp_arr;
__block Terminal *terminal = nil;
__block int sessionPid = 0;
__block int err = 1;
sync_do_in_workqueue(^(void (^done)(void)) {
start_session(argv[0], argv, envp, ^(int retval, int pid, nsobj_t term) {
err = retval;
if (term)
terminal = CFBridgingRelease(term);
sessionPid = pid;
done();
});
});
NSAssert(err <= 0, @"session start did not finish??");
if (err < 0)
return err;
self.sessionTerminal = terminal;
self.sessionPid = sessionPid;
#endif
return 0;
}
Vendored
+1 -1
Submodule deps/linux updated: c96a726748...c401da8ce6
+8
View File
@@ -181,6 +181,8 @@
BBECF3AE2691330F00DEC937 /* libiSHLinux.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BBECF3A22691314C00DEC937 /* libiSHLinux.a */; };
BBECF3B9269136FB00DEC937 /* liblinux.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BBECF3B8269136E100DEC937 /* liblinux.a */; };
BBECF3BC26913F1600DEC937 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BB792B541F96D90D00FFB7A4 /* AppDelegate.m */; };
BBEEA9E8277D25090069495B /* LinuxRoot.c in Sources */ = {isa = PBXBuildFile; fileRef = BBEEA9E7277D25090069495B /* LinuxRoot.c */; };
BBEEA9EA277DAB400069495B /* LinuxPTY.c in Sources */ = {isa = PBXBuildFile; fileRef = BBEEA9E9277DAB400069495B /* LinuxPTY.c */; };
BBEF1970268066D1001225BD /* libiSHApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BBEF191E26806364001225BD /* libiSHApp.a */; };
BBEF1972268066D1001225BD /* libish_emu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BBFB2C5B2590257E00545EAB /* libish_emu.a */; };
BBEF1973268066D1001225BD /* libarchive.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BB10E5C8248DBAA1009C7A74 /* libarchive.a */; };
@@ -654,6 +656,8 @@
BBECF3A22691314C00DEC937 /* libiSHLinux.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libiSHLinux.a; sourceTree = BUILT_PRODUCTS_DIR; };
BBECF3B8269136E100DEC937 /* liblinux.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblinux.a; sourceTree = BUILT_PRODUCTS_DIR; };
BBECF3BA2691379100DEC937 /* StaticLibLinux.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = StaticLibLinux.xcconfig; sourceTree = "<group>"; };
BBEEA9E7277D25090069495B /* LinuxRoot.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = LinuxRoot.c; sourceTree = "<group>"; };
BBEEA9E9277DAB400069495B /* LinuxPTY.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = LinuxPTY.c; sourceTree = "<group>"; };
BBEF191E26806364001225BD /* libiSHApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libiSHApp.a; sourceTree = BUILT_PRODUCTS_DIR; };
BBEF192C26806546001225BD /* AppLib.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppLib.xcconfig; sourceTree = "<group>"; };
BBEF199C268066D1001225BD /* iSH.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iSH.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1193,6 +1197,8 @@
BB123ACD26C9F13500419CDA /* IOSCalls.m */,
BBECF39D2691313B00DEC937 /* LinuxInterop.c */,
BB123ACB26C9EFD900419CDA /* LinuxTTY.c */,
BBEEA9E9277DAB400069495B /* LinuxPTY.c */,
BBEEA9E7277D25090069495B /* LinuxRoot.c */,
BB8C3AFD26B7B8AF00E38DDC /* fakefs.c */,
);
name = LinuxInterop;
@@ -2017,7 +2023,9 @@
files = (
BBECF3AD269132F400DEC937 /* LinuxInterop.c in Sources */,
BB8C3AFF26B7B8CF00E38DDC /* fakefs.c in Sources */,
BBEEA9E8277D25090069495B /* LinuxRoot.c in Sources */,
BB123ACC26C9EFD900419CDA /* LinuxTTY.c in Sources */,
BBEEA9EA277DAB400069495B /* LinuxPTY.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+1 -1
View File
@@ -653,4 +653,4 @@ static int fakefs_init(void) {
return register_filesystem(&fakefs_type);
}
__initcall(fakefs_init);
fs_initcall(fakefs_init);