Skip to content

Commit

Permalink
Get alpine filesystem into iOS app
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed Oct 31, 2017
1 parent 46983d5 commit cd370cd
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 49 deletions.
19 changes: 16 additions & 3 deletions app/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion app/TerminalViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath
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 {
Expand Down
52 changes: 42 additions & 10 deletions fs/fake.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions fs/generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 30 additions & 11 deletions fs/path.c
Original file line number Diff line number Diff line change
Expand Up @@ -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] == '/') {
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
53 changes: 46 additions & 7 deletions iSH.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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>"; };
Expand All @@ -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 */
Expand Down Expand Up @@ -253,7 +253,7 @@
BB0FC5811F98026700803272 /* fs */,
BB0FC5631F98026700803272 /* kernel */,
BB0FC55D1F98026600803272 /* util */,
BB6CEEE51F97D69E00C07635 /* hello-libc-static */,
BBF124901FA7C3100088FB50 /* alpine */,
BB18B27F1F97F2590059FCD8 /* Scripts */,
BB792B511F96D90D00FFB7A4 /* Products */,
BB792B7D1F96E32B00FFB7A4 /* Frameworks */,
Expand Down Expand Up @@ -319,6 +319,8 @@
buildPhases = (
BB792B4C1F96D90D00FFB7A4 /* Sources */,
BB792B4D1F96D90D00FFB7A4 /* Frameworks */,
BBF1248B1FA7BF530088FB50 /* Download Alpine */,
BBF1248A1FA7BDBA0088FB50 /* Create Alpine Filesystem */,
BB792B4E1F96D90D00FFB7A4 /* Resources */,
);
buildRules = (
Expand All @@ -344,7 +346,7 @@
BB0FC54C1F97FB7E00803272 /* PBXTargetDependency */,
);
name = libish;
productName = iah;
productName = ish;
productReference = BB792B721F96E2C000FFB7A4 /* libish.a */;
productType = "com.apple.product-type.library.static";
};
Expand All @@ -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 = (
Expand All @@ -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 */,
);
Expand Down Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions kernel/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions kernel/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Loading

0 comments on commit cd370cd

Please sign in to comment.