mirror of
https://github.com/ish-app/ish.git
synced 2026-01-25 14:06:40 +00:00
Get alpine filesystem into iOS app
This commit is contained in:
parent
46983d5216
commit
cd370cd0cb
@ -21,12 +21,25 @@ static void ios_handle_exit(int code) {
|
||||
@implementation AppDelegate
|
||||
|
||||
- (int)startThings {
|
||||
NSString *resourcePath = NSBundle.mainBundle.resourcePath;
|
||||
int err = mount_root(&realfs, resourcePath.UTF8String);
|
||||
NSFileManager *manager = NSFileManager.defaultManager;
|
||||
NSURL *documents = [manager URLsForDirectory:NSDocumentDirectory
|
||||
inDomains:NSUserDomainMask][0];
|
||||
NSURL *alpineRoot = [documents URLByAppendingPathComponent:@"alpine"];
|
||||
if (![manager fileExistsAtPath:alpineRoot.path]) {
|
||||
NSURL *alpineMaster = [NSBundle.mainBundle URLForResource:@"alpine" withExtension:nil];
|
||||
NSError *error = nil;
|
||||
[manager copyItemAtURL:alpineMaster toURL:alpineRoot error:&error];
|
||||
if (error != nil) {
|
||||
NSLog(@"%@", error);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
alpineRoot = [alpineRoot URLByAppendingPathComponent:@"data"];
|
||||
int err = mount_root(&fakefs, alpineRoot.fileSystemRepresentation);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
char *program = "hello-libc-static";
|
||||
char *program = "/bin/ls";
|
||||
char *argv[] = {program, NULL};
|
||||
char *envp[] = {NULL};
|
||||
err = create_init_process(program, argv, envp);
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
|
||||
context:(void *)context {
|
||||
self.textView.text = [self.textView.text stringByAppendingString:self.terminal.content];
|
||||
[self.textView performSelectorOnMainThread:@selector(setText:) withObject:self.terminal.content waitUntilDone:NO];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
|
||||
52
fs/fake.c
52
fs/fake.c
@ -6,6 +6,9 @@
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "kernel/errno.h"
|
||||
#include "kernel/fs.h"
|
||||
|
||||
struct ish_stat {
|
||||
@ -34,19 +37,26 @@ static datum read_meta(struct mount *mount, const char *path, const char *type)
|
||||
return dbm_fetch(db, key);
|
||||
}
|
||||
|
||||
static int read_ish_stat(struct mount *mount, const char *path, struct ish_stat *stat) {
|
||||
datum d = read_meta(mount, path, "meta");
|
||||
if (d.dptr == NULL)
|
||||
return 0;
|
||||
assert(d.dsize == sizeof(struct ish_stat));
|
||||
*stat = *(struct ish_stat *) d.dptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fakefs_stat(struct mount *mount, char *path, struct statbuf *fake_stat, bool follow_links) {
|
||||
struct ish_stat ishstat;
|
||||
if (!read_ish_stat(mount, path, &ishstat))
|
||||
return _ENOENT;
|
||||
int err = realfs_stat(mount, path, fake_stat, follow_links);
|
||||
if (err < 0)
|
||||
return err;
|
||||
datum d = read_meta(mount, path, "meta");
|
||||
if (d.dptr != NULL) {
|
||||
assert(d.dsize == sizeof(struct ish_stat));
|
||||
struct ish_stat *ishstat = (void *) d.dptr;
|
||||
fake_stat->mode = ishstat->mode;
|
||||
fake_stat->uid = ishstat->uid;
|
||||
fake_stat->gid = ishstat->gid;
|
||||
fake_stat->rdev = ishstat->rdev;
|
||||
}
|
||||
fake_stat->mode = ishstat.mode;
|
||||
fake_stat->uid = ishstat.uid;
|
||||
fake_stat->gid = ishstat.gid;
|
||||
fake_stat->rdev = ishstat.rdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -59,12 +69,34 @@ static int fakefs_fstat(struct fd *fd, struct statbuf *fake_stat) {
|
||||
return fakefs_stat(fd->mount, path, fake_stat, false);
|
||||
}
|
||||
|
||||
ssize_t fakefs_readlink(struct mount *mount, char *path, char *buf, size_t bufsize) {
|
||||
struct ish_stat ishstat;
|
||||
if (!read_ish_stat(mount, path, &ishstat))
|
||||
return _ENOENT;
|
||||
if (!S_ISLNK(ishstat.mode))
|
||||
return _EINVAL;
|
||||
|
||||
ssize_t err = realfs_readlink(mount, path, buf, bufsize);
|
||||
if (err == _EINVAL) {
|
||||
// broken symlinks can't be included in an iOS app or else Xcode craps out
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return err_map(errno);
|
||||
int err = read(fd, buf, bufsize);
|
||||
if (err < 0)
|
||||
return err_map(errno);
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
const struct fs_ops fakefs = {
|
||||
.open = realfs_open,
|
||||
.unlink = realfs_unlink,
|
||||
.stat = fakefs_stat,
|
||||
.access = realfs_access,
|
||||
.readlink = realfs_readlink,
|
||||
.readlink = fakefs_readlink,
|
||||
.fstat = fakefs_fstat,
|
||||
.statfs = realfs_statfs,
|
||||
.flock = realfs_flock,
|
||||
|
||||
@ -50,8 +50,9 @@ struct fd *generic_openat(struct fd *at, const char *path_raw, int flags, int mo
|
||||
struct statbuf stat;
|
||||
err = fd->mount->fs->fstat(fd, &stat);
|
||||
if (err >= 0) {
|
||||
int type = stat.mode & S_IFMT;
|
||||
if (type == S_IFBLK || type == S_IFCHR) {
|
||||
assert(!S_ISLNK(stat.mode));
|
||||
if (S_ISBLK(stat.mode) || S_ISCHR(stat.mode)) {
|
||||
int type;
|
||||
if (stat.mode & S_IFBLK)
|
||||
type = DEV_BLOCK;
|
||||
else
|
||||
|
||||
41
fs/path.c
41
fs/path.c
@ -11,25 +11,27 @@ int path_normalize(struct fd *at, const char *path, char *out, bool follow_links
|
||||
|
||||
if (at != __NO_AT) {
|
||||
// start with root or cwd, depending on whether it starts with a slash
|
||||
if (*p == '/') {
|
||||
if (*p == '/')
|
||||
at = current->root;
|
||||
while (*p == '/')
|
||||
p++;
|
||||
// if it does start with a slash, make sure to skip all the slashes
|
||||
} else if (at == NULL) {
|
||||
else if (at == NULL)
|
||||
at = current->pwd;
|
||||
}
|
||||
if (at != NULL) {
|
||||
char at_path[MAX_PATH];
|
||||
int err = at->ops->getpath(at, at_path);
|
||||
if (err < 0)
|
||||
return err;
|
||||
strcpy(o, at_path);
|
||||
n -= strlen(at_path);
|
||||
o += strlen(at_path);
|
||||
assert(path_is_normalized(at_path));
|
||||
if (at_path[0] != '/' && at_path[1] != '\0') {
|
||||
strcpy(o, at_path);
|
||||
n -= strlen(at_path);
|
||||
o += strlen(at_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*p == '/')
|
||||
p++;
|
||||
|
||||
while (*p != '\0') {
|
||||
if (p[0] == '.') {
|
||||
if (p[1] == '\0' || p[1] == '/') {
|
||||
@ -72,6 +74,7 @@ int path_normalize(struct fd *at, const char *path, char *out, bool follow_links
|
||||
strcpy(possible_symlink, out);
|
||||
possible_symlink[o - out] = '\0';
|
||||
struct mount *mount = find_mount_and_trim_path(possible_symlink);
|
||||
assert(path_is_normalized(possible_symlink));
|
||||
int res = mount->fs->readlink(mount, possible_symlink, c, MAX_PATH - (c - out));
|
||||
if (res >= 0) {
|
||||
// readlink does not null terminate
|
||||
@ -81,13 +84,29 @@ int path_normalize(struct fd *at, const char *path, char *out, bool follow_links
|
||||
memmove(out, c, strlen(c) + 1);
|
||||
char *expanded_path = possible_symlink;
|
||||
strcpy(expanded_path, out);
|
||||
strcat(expanded_path, "/");
|
||||
strcat(expanded_path, p);
|
||||
// if (*p) {
|
||||
strcat(expanded_path, "/");
|
||||
strcat(expanded_path, p);
|
||||
// }
|
||||
return path_normalize(__NO_AT, expanded_path, out, follow_links);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*o = '\0';
|
||||
assert(path_is_normalized(out));
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool path_is_normalized(const char *path) {
|
||||
while (*path != '\0') {
|
||||
if (*path != '/')
|
||||
return false;
|
||||
path++;
|
||||
if (*path == '/')
|
||||
return false;
|
||||
while (*path != '/' && *path != '\0')
|
||||
path++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3,13 +3,13 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 48;
|
||||
objectVersion = 47;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
BB0FC5921F980A6C00803272 /* Terminal.m in Sources */ = {isa = PBXBuildFile; fileRef = BB0FC5911F980A6B00803272 /* Terminal.m */; };
|
||||
BB18B2871F97F6D00059FCD8 /* libsoftfloat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BB18B2741F97F1C40059FCD8 /* libsoftfloat.a */; };
|
||||
BB6CEEE61F97D69E00C07635 /* hello-libc-static in Resources */ = {isa = PBXBuildFile; fileRef = BB6CEEE51F97D69E00C07635 /* hello-libc-static */; };
|
||||
BB623CF91FA7C68800932047 /* alpine in Resources */ = {isa = PBXBuildFile; fileRef = BBF124901FA7C3100088FB50 /* alpine */; };
|
||||
BB792B551F96D90D00FFB7A4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BB792B541F96D90D00FFB7A4 /* AppDelegate.m */; };
|
||||
BB792B581F96D90D00FFB7A4 /* TerminalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BB792B571F96D90D00FFB7A4 /* TerminalViewController.m */; };
|
||||
BB792B5B1F96D90D00FFB7A4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BB792B591F96D90D00FFB7A4 /* Main.storyboard */; };
|
||||
@ -110,7 +110,6 @@
|
||||
BB0FC5911F980A6B00803272 /* Terminal.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Terminal.m; sourceTree = "<group>"; };
|
||||
BB18B2741F97F1C40059FCD8 /* libsoftfloat.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsoftfloat.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BB18B27E1F97F24D0059FCD8 /* xcode-meson.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "xcode-meson.sh"; sourceTree = "<group>"; };
|
||||
BB6CEEE51F97D69E00C07635 /* hello-libc-static */ = {isa = PBXFileReference; lastKnownFileType = file; path = "hello-libc-static"; sourceTree = "<group>"; };
|
||||
BB792B501F96D90D00FFB7A4 /* iSH.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iSH.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BB792B531F96D90D00FFB7A4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
BB792B541F96D90D00FFB7A4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
@ -123,6 +122,7 @@
|
||||
BB792B621F96D90D00FFB7A4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
BB792B721F96E2C000FFB7A4 /* libish.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libish.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BB792B891F97B3A800FFB7A4 /* no-clang-env.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "no-clang-env.sh"; sourceTree = "<group>"; };
|
||||
BBF124901FA7C3100088FB50 /* alpine */ = {isa = PBXFileReference; lastKnownFileType = folder; path = alpine; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -253,7 +253,7 @@
|
||||
BB0FC5811F98026700803272 /* fs */,
|
||||
BB0FC5631F98026700803272 /* kernel */,
|
||||
BB0FC55D1F98026600803272 /* util */,
|
||||
BB6CEEE51F97D69E00C07635 /* hello-libc-static */,
|
||||
BBF124901FA7C3100088FB50 /* alpine */,
|
||||
BB18B27F1F97F2590059FCD8 /* Scripts */,
|
||||
BB792B511F96D90D00FFB7A4 /* Products */,
|
||||
BB792B7D1F96E32B00FFB7A4 /* Frameworks */,
|
||||
@ -319,6 +319,8 @@
|
||||
buildPhases = (
|
||||
BB792B4C1F96D90D00FFB7A4 /* Sources */,
|
||||
BB792B4D1F96D90D00FFB7A4 /* Frameworks */,
|
||||
BBF1248B1FA7BF530088FB50 /* Download Alpine */,
|
||||
BBF1248A1FA7BDBA0088FB50 /* Create Alpine Filesystem */,
|
||||
BB792B4E1F96D90D00FFB7A4 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
@ -344,7 +346,7 @@
|
||||
BB0FC54C1F97FB7E00803272 /* PBXTargetDependency */,
|
||||
);
|
||||
name = libish;
|
||||
productName = iah;
|
||||
productName = ish;
|
||||
productReference = BB792B721F96E2C000FFB7A4 /* libish.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
@ -359,20 +361,23 @@
|
||||
TargetAttributes = {
|
||||
BB18B2731F97F1C40059FCD8 = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
DevelopmentTeam = W2NF7BNM62;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
BB792B4F1F96D90D00FFB7A4 = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
DevelopmentTeam = W2NF7BNM62;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
BB792B711F96E2C000FFB7A4 = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
DevelopmentTeam = W2NF7BNM62;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = BB792B491F96D8E000FFB7A4 /* Build configuration list for PBXProject "iSH" */;
|
||||
compatibilityVersion = "Xcode 8.0";
|
||||
compatibilityVersion = "Xcode 6.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
@ -396,8 +401,8 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
BB623CF91FA7C68800932047 /* alpine in Resources */,
|
||||
BB792B601F96D90D00FFB7A4 /* LaunchScreen.storyboard in Resources */,
|
||||
BB6CEEE61F97D69E00C07635 /* hello-libc-static in Resources */,
|
||||
BB792B5D1F96D90D00FFB7A4 /* Assets.xcassets in Resources */,
|
||||
BB792B5B1F96D90D00FFB7A4 /* Main.storyboard in Resources */,
|
||||
);
|
||||
@ -440,6 +445,40 @@
|
||||
shellScript = "cd $TARGET_BUILD_DIR\n$SRCROOT/xcode-meson.sh\nninja libish.a";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
BBF1248A1FA7BDBA0088FB50 /* Create Alpine Filesystem */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(SRCROOT)/tools/fakefsify.py",
|
||||
"$(DERIVED_FILE_DIR)/alpine.tar.gz",
|
||||
);
|
||||
name = "Create Alpine Filesystem";
|
||||
outputPaths = (
|
||||
"$(SRCROOT)/alpine",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "rm -rf $SRCROOT/alpine\n$SRCROOT/tools/fakefsify.py $DERIVED_FILE_DIR/alpine.tar.gz $SRCROOT/alpine";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
BBF1248B1FA7BF530088FB50 /* Download Alpine */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Download Alpine";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/alpine.tar.gz",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "curl -L http://dl-cdn.alpinelinux.org/alpine/v3.6/releases/x86/alpine-minirootfs-3.6.2-x86.tar.gz -o $DERIVED_FILE_DIR/alpine.tar.gz";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
||||
@ -178,6 +178,7 @@ void poll_destroy(struct poll *poll);
|
||||
// MAX_PATH, _ENAMETOOLONG is returned. The out buffer is expected to be at
|
||||
// least MAX_PATH in size.
|
||||
int path_normalize(struct fd *at, const char *path, char *out, bool follow_links);
|
||||
bool path_is_normalized(const char *path);
|
||||
|
||||
// real fs
|
||||
extern const struct fs_ops realfs;
|
||||
|
||||
@ -14,6 +14,7 @@ int mount_root(const struct fs_ops *fs, const char *source) {
|
||||
mounts->source = strdup(source_realpath);
|
||||
mounts->fs = fs;
|
||||
mounts->next = NULL;
|
||||
mounts->data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import struct
|
||||
import urllib
|
||||
import urllib.request
|
||||
import tarfile
|
||||
import dbm
|
||||
|
||||
@ -35,32 +35,24 @@ def extract_archive(archive, db):
|
||||
member.gid,
|
||||
rdev,
|
||||
)
|
||||
db[b'meta:' + bytes(path)] = metadata
|
||||
meta_path = path.relative_to(data)
|
||||
db[b'meta:/' + (bytes(meta_path) if meta_path.parts else b'')] = metadata
|
||||
|
||||
if member.isdir():
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
elif member.issym():
|
||||
path.symlink_to(member.linkname)
|
||||
path.write_text(member.linkname)
|
||||
elif member.isfile():
|
||||
archive.extract(member, data)
|
||||
else:
|
||||
path.touch()
|
||||
|
||||
_, archive_path, fs = sys.argv
|
||||
|
||||
fs = Path(fs)
|
||||
fs.mkdir(parents=True, exist_ok=True)
|
||||
data = fs/'data'
|
||||
data.mkdir()
|
||||
db = dbm.ndbm.open(str(fs/'meta'), 'c')
|
||||
|
||||
try:
|
||||
archive = open(archive_path, 'rb')
|
||||
except FileNotFoundError:
|
||||
archive = urllib.request.urlopen(archive_path)
|
||||
|
||||
with archive:
|
||||
archive = tarfile.open(fileobj=archive)
|
||||
with archive:
|
||||
with db:
|
||||
with open(archive_path, 'rb') as archive:
|
||||
with tarfile.open(fileobj=archive) as archive:
|
||||
with dbm.ndbm.open(str(fs/'meta'), 'c') as db:
|
||||
extract_archive(archive, db)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user