diff --git a/README.md b/README.md
index 802cae74a..f89f9081a 100644
--- a/README.md
+++ b/README.md
@@ -164,7 +164,7 @@ Congratulations, you have just compiled and run your own Hello world application
### AppKit
-AppKit is still highly expiramental and incomplete, but to work on it you need to configure CMake with `-DFRAMEWORK_APPKIT=1` and install some additional packages.
+AppKit is still highly expiramental and incomplete, but to work on it you need to configure CMake with `-DFRAMEWORK_APPKIT=1` and install some additional packages.
Ubuntu 16.04:
```
diff --git a/src/dyld/darling.c b/src/dyld/darling.c
index c58ac4832..6593b02ca 100644
--- a/src/dyld/darling.c
+++ b/src/dyld/darling.c
@@ -38,94 +38,230 @@ along with Darling. If not, see .
#include "darling-config.h"
const char* DARLING_INIT_COMM = "darling-init";
-uid_t g_originalUid;
+char *prefix;
+uid_t g_originalUid, g_originalGid;
int main(int argc, const char** argv)
{
- const char* dprefix;
- int pidInit;
-
+ pid_t pidInit, pidChild;
+ char path[4096];
+ int wstatus;
+
if (argc <= 1)
{
showHelp(argv[0]);
return 1;
}
-
- /*if (geteuid() != 0)
+
+ if (geteuid() != 0)
{
missingSetuidRoot();
return 1;
- }*/
-
+ }
+
if (loadKernelModule())
return 1;
- // Temporarily drop root privileges
g_originalUid = getuid();
- seteuid(getuid());
- setegid(getgid());
-
- dprefix = getenv("DPREFIX");
- if (!dprefix)
- dprefix = defaultPrefixPath();
- if (!dprefix)
+ g_originalGid = getgid();
+
+ prefix = getenv("DPREFIX");
+ if (!prefix)
+ prefix = defaultPrefixPath();
+ if (!prefix)
return 1;
- checkPrefixOwner(dprefix);
-
- pidInit = getInitProcess(dprefix);
-
+ setenv("DPREFIX", prefix, 0);
+
+ if (!checkPrefixDir())
+ setupPrefix();
+ checkPrefixOwner();
+
+ pidInit = getInitProcess();
+
// If prefix's init is not running, start it up
if (pidInit == 0)
{
- char* opts;
-
- createDir(dprefix);
- setupWorkdir(dprefix);
-
- // Since overlay cannot be mounted inside user namespaces, we have to setup a new mount namespace
- // and do the mount while we can be root
- //seteuid(0);
- if (unshare(CLONE_NEWNS) != 0)
- {
- fprintf(stderr, "Cannot unshare(CLONE_NEWNS): %s\n", strerror(errno));
- return 1;
- }
-
- // Because IDIOTIC systemd marks / as MS_SHARED and we would inherit this into the overlay mount,
- // causing it not to be unmounted once the init process dies.
- if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
- {
- fprintf(stderr, "Cannot remount / as private: %s\n", strerror(errno));
- return 1;
- }
-
- opts = (char*) malloc(strlen(dprefix)*2 + sizeof(LIBEXEC_PATH) + 50);
- sprintf(opts, "lowerdir=%s,upperdir=%s,workdir=%s.workdir", LIBEXEC_PATH, dprefix, dprefix);
-
- // Mount overlay onto our prefix
- if (mount("overlay", dprefix, "overlay", 0, opts) != 0)
- {
- fprintf(stderr, "Cannot mount overlay: %s\n", strerror(errno));
- return 1;
- }
-
- free(opts);
- //seteuid(getuid());
-
- pidInit = spawnInitProcess(dprefix);
+ setupWorkdir();
+ pidInit = spawnInitProcess();
+ putInitPid(pidInit);
}
-
- // TODO: Spawn the executable in the namespace, wait for it and return its exit code
- unloadKernelModule();
+
+ if (strcmp(argv[1], "shell") != 0)
+ {
+ const char *argv_child[argc + 1];
+
+ argv_child[0] = "dyld";
+ for (int i = 1; i < argc; i++)
+ argv_child[i] = argv[i];
+ argv_child[argc] = NULL;
+
+ pidChild = spawnChild(pidInit, "/usr/local/bin/dyld", argv_child);
+ }
+ else
+ {
+ // Spawn the shell
+ snprintf(path, sizeof(path), "%s/bin/bash", prefix);
+ if (argc > 2)
+ {
+ size_t total_len = 0;
+ for (int i = 2; i < argc; i++)
+ total_len += strlen(argv[i]);
+
+ char buffer[total_len + argc];
+
+ char *to = buffer;
+ for (int i = 2; i < argc; i++)
+ to = stpcpy(stpcpy(to, argv[i]), " ");
+ // Overwrite the last whitespace
+ *(to - 1) = '\0';
+
+ pidChild = spawnChild(pidInit, "/usr/local/bin/dyld",
+ (const char *[5]) {"dyld", path, "-c", buffer, NULL});
+ }
+ else
+ pidChild = spawnChild(pidInit, "/usr/local/bin/dyld",
+ (const char *[3]) {"dyld", path, NULL});
+ }
+
+ // Drop the privileges so that we can be killed, etc by the user
+ seteuid(g_originalUid);
+
+ waitpid(pidChild, &wstatus, 0);
+
+ // Should we unloadKernelModule() here? Others may be still using it
+ if (WIFEXITED(wstatus))
+ return WEXITSTATUS(wstatus);
+ if (WIFSIGNALED(wstatus))
+ return WTERMSIG(wstatus);
return 0;
}
+pid_t spawnChild(int pidInit, const char *path, const char *const argv[])
+{
+ int fdNS;
+ pid_t pidChild;
+ char pathNS[4096], curPath[4096];
+
+ if (getcwd(curPath, sizeof(curPath)) == NULL)
+ {
+ fprintf(stderr, "Cannot get current directory: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/pid", pidInit);
+
+ fdNS = open(pathNS, O_RDONLY);
+
+ if (fdNS < 0)
+ {
+ fprintf(stderr, "Cannot open PID namespace file: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ // Calling setns() with a PID namespace doesn't move our process into it,
+ // but our child process will be spawned inside the namespace
+ if (setns(fdNS, CLONE_NEWPID) != 0)
+ {
+ fprintf(stderr, "Cannot join PID namespace: %s\n", strerror(errno));
+ exit(1);
+ }
+ close(fdNS);
+
+ pidChild = fork();
+ if (pidChild < 0)
+ {
+ fprintf(stderr, "Cannot spawn a child process: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (pidChild == 0)
+ {
+ // This is the child process
+
+ // We still have the outside PIDs in /proc
+ snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/mnt", pidInit);
+ fdNS = open(pathNS, O_RDONLY);
+ if (fdNS < 0)
+ {
+ fprintf(stderr, "Cannot open mount namespace file: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (setns(fdNS, CLONE_NEWNS) != 0)
+ {
+ fprintf(stderr, "Cannot join mount namespace: %s\n", strerror(errno));
+ exit(1);
+ }
+ close(fdNS);
+
+ snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/user", pidInit);
+ fdNS = open(pathNS, O_RDONLY);
+ if (fdNS < 0)
+ {
+ fprintf(stderr, "Cannot open user namespace file: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ setresuid(g_originalUid, g_originalUid, g_originalUid);
+ setresgid(g_originalGid, g_originalGid, g_originalGid);
+
+ if (setns(fdNS, CLONE_NEWUSER) != 0)
+ {
+ fprintf(stderr, "Cannot join user namespace: %s\n", strerror(errno));
+ exit(1);
+ }
+ close(fdNS);
+
+ setupChild(curPath);
+
+ execv(path, (char * const *) argv);
+
+ fprintf(stderr, "Cannot exec the target program: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ return pidChild;
+}
+
+void setupChild(const char *curPath)
+{
+ char buffer1[4096];
+ char buffer2[4096];
+
+ setenv("PATH", "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin", 1);
+
+ sscanf(getenv("HOME"), "/home/%4096s", buffer1);
+ snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1);
+ setenv("HOME", buffer2, 1);
+
+ if (sscanf(curPath, "/home/%4096s", buffer1) == 1)
+ {
+ // We're currently inside our home directory
+ snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1);
+ setenv("PWD", buffer2, 1);
+
+ snprintf(buffer2, sizeof(buffer2), "%s/Users/%s", prefix, buffer1);
+ chdir(buffer2);
+ }
+ else
+ {
+ snprintf(buffer2, sizeof(buffer2), "/system-root%s", curPath);
+ setenv("PWD", buffer2, 1);
+
+ snprintf(buffer2, sizeof(buffer2), "%s/system-root%s", prefix, curPath);
+ chdir(buffer2);
+ }
+}
+
void showHelp(const char* argv0)
{
fprintf(stderr, "This is Darling, translation layer for macOS software.\n\n");
fprintf(stderr, "Copyright (C) 2012-2016 Lubos Dolezel\n\n");
- fprintf(stderr, "Usage: %s program-path [arguments...]\n\n", argv0);
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\t%s program-path [arguments...]\n", argv0);
+ fprintf(stderr, "\t%s shell [arguments...]\n", argv0);
+ fprintf(stderr, "\n");
fprintf(stderr, "Environment variables:\n"
"DPREFIX - specifies the location of Darling prefix, defaults to ~/.darling\n");
}
@@ -134,80 +270,184 @@ void missingSetuidRoot(void)
{
char path[4096];
int len;
-
+
len = readlink("/proc/self/exe", path, sizeof(path)-1);
if (len < 0)
strcpy(path, "darling");
else
path[len] = '\0';
-
+
fprintf(stderr, "Sorry, the `%s' binary is not setuid root, which is mandatory.\n", path);
fprintf(stderr, "Darling needs this in order to create mount and PID namespaces and to perform mounts.\n");
}
-int spawnInitProcess(const char* prefix)
+pid_t spawnInitProcess(void)
{
- char* childStack;
- int pid;
- char uidmap[100];
-
- childStack = (char*) malloc(16*1024);
- childStack += 16*1024;
-
- //setuid(0);
- pid = clone(darlingPreInit, childStack, /*CLONE_NEWPID |*/ CLONE_NEWUSER, (void*) prefix);
-
- if (pid <= 0)
+ pid_t pid;
+ int pipefd[2];
+ char idmap[100];
+ char buffer[1];
+ FILE *file;
+
+ if (pipe(pipefd) == -1)
{
- fprintf(stderr, "Cannot clone() to create darling-init: %s\n", strerror(errno));
+ fprintf(stderr, "Cannot create a pipe for synchronization: %s\n", strerror(errno));
exit(1);
}
-
- sprintf(uidmap, "/proc/%d/uid_map", pid);
-
- FILE* file = fopen(uidmap, "w");
+
+ if (unshare(CLONE_NEWPID) != 0)
+ {
+ fprintf(stderr, "Cannot unshare pid namespace to create darling-init: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ pid = fork();
+
+ if (pid < 0)
+ {
+ fprintf(stderr, "Cannot fork() to create darling-init: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (pid == 0)
+ {
+ // The child
+
+ char *opts;
+
+ // Since overlay cannot be mounted inside user namespaces, we have to setup a new mount namespace
+ // and do the mount while we can be root
+ if (unshare(CLONE_NEWNS) != 0)
+ {
+ fprintf(stderr, "Cannot unshare mount namespace: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ // Because systemd marks / as MS_SHARED and we would inherit this into the overlay mount,
+ // causing it not to be unmounted once the init process dies.
+ if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) != 0)
+ {
+ fprintf(stderr, "Cannot remount / as slave: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ opts = (char*) malloc(strlen(prefix)*2 + sizeof(LIBEXEC_PATH) + 50);
+ sprintf(opts, "lowerdir=%s,upperdir=%s,workdir=%s.workdir", LIBEXEC_PATH, prefix, prefix);
+
+ // Mount overlay onto our prefix
+ if (mount("overlay", prefix, "overlay", 0, opts) != 0)
+ {
+ fprintf(stderr, "Cannot mount overlay: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ free(opts);
+
+ // Drop the privileges
+ setresuid(g_originalUid, g_originalUid, g_originalUid);
+ setresgid(g_originalGid, g_originalGid, g_originalGid);
+ prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+
+ prctl(PR_SET_NAME, DARLING_INIT_COMM, 0, 0);
+
+ if (unshare(CLONE_NEWUSER) != 0)
+ {
+ fprintf(stderr, "Cannot unshare user namespace: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ // Tell the parent we're ready for it to set up UID/GID mappings
+ write(pipefd[1], buffer, 1);
+ close(pipefd[1]);
+ // And wait for it to do it
+ read(pipefd[0], buffer, 1);
+ close(pipefd[0]);
+
+ darlingPreInit();
+ // Never returns
+ }
+
+ // Wait for the child to drop UID/GIDs and unshare stuff
+ read(pipefd[0], buffer, 1);
+ close(pipefd[0]);
+
+ snprintf(idmap, sizeof(idmap), "/proc/%d/uid_map", pid);
+
+ file = fopen(idmap, "w");
if (file != NULL)
{
- fprintf(file, "0 %d 1\n", getuid()); // all users map to our user on the outside
+ fprintf(file, "0 %d 1\n", g_originalUid); // all users map to our user on the outside
fclose(file);
}
else
{
- fprintf(stderr, "Failure setting uid_map in init process\n");
+ fprintf(stderr, "Cannot set uid_map for the init process: %s\n", strerror(errno));
}
-
- seteuid(g_originalUid);
- setuid(g_originalUid);
-
+
+ snprintf(idmap, sizeof(idmap), "/proc/%d/gid_map", pid);
+
+ file = fopen(idmap, "w");
+ if (file != NULL)
+ {
+ fprintf(file, "0 %d 1\n", g_originalGid); // all groups map to our group on the outside
+ fclose(file);
+ }
+ else
+ {
+ fprintf(stderr, "Cannot set gid_map for the init process: %s\n", strerror(errno));
+ }
+
+ // Resume the child
+ write(pipefd[1], buffer, 1);
+ close(pipefd[1]);
+
return pid;
}
-int darlingPreInit(void* arg)
+void putInitPid(pid_t pidInit)
+{
+ const char pidFile[] = "/.init.pid";
+ char* pidPath;
+ FILE *fp;
+
+ pidPath = (char*) alloca(strlen(prefix) + sizeof(pidFile));
+ strcpy(pidPath, prefix);
+ strcat(pidPath, pidFile);
+
+ seteuid(g_originalUid);
+ setegid(g_originalGid);
+
+ fp = fopen(pidPath, "w");
+
+ seteuid(0);
+ setegid(0);
+
+ if (fp == NULL)
+ {
+ fprintf(stderr, "Cannot write out PID of the init process: %s\n", strerror(errno));
+ return;
+ }
+ fprintf(fp, "%d", (int) pidInit);
+ fclose(fp);
+}
+
+void darlingPreInit(void)
{
- const char* prefix = (const char*) arg;
-
- prctl(PR_SET_NAME, DARLING_INIT_COMM, 0, 0);
-
- // Wait until the parent sets our uid_map
- while (getuid() == 65534);
-
// TODO: Run /usr/libexec/makewhatis
-
+
// TODO: this is where we will exec() launchd in future.
// Instead, we just reap zombies.
while (1)
{
int status, sig;
sigset_t chld;
-
+
sigemptyset(&chld);
sigaddset(&chld, SIGCHLD);
sigwait(&chld, &sig);
-
+
while (waitpid(-1, &status, 0) != -1);
}
-
- return 0;
}
char* defaultPrefixPath(void)
@@ -215,24 +455,24 @@ char* defaultPrefixPath(void)
const char defaultPath[] = "/.darling";
const char* home = getenv("HOME");
char* buf;
-
+
if (!home)
{
fprintf(stderr, "Cannot detect your home directory!\n");
return NULL;
}
-
+
buf = (char*) malloc(strlen(home) + sizeof(defaultPath));
strcpy(buf, home);
strcat(buf, defaultPath);
-
+
return buf;
}
void createDir(const char* path)
{
struct stat st;
-
+
if (stat(path, &st) == 0)
{
if (!S_ISDIR(st.st_mode))
@@ -253,56 +493,140 @@ void createDir(const char* path)
}
else
{
- fprintf(stderr, "Problem accessing %s: %s\n", path, strerror(errno));
+ fprintf(stderr, "Cannot access %s: %s\n", path, strerror(errno));
exit(1);
}
}
}
-void setupWorkdir(const char* prefix)
+void setupWorkdir()
{
char* workdir;
const char suffix[] = ".workdir";
size_t len;
-
+
len = strlen(prefix);
workdir = (char*) alloca(len + sizeof(suffix));
strcpy(workdir, prefix);
-
+
// Remove trailing /
while (workdir[len-1] == '/')
len--;
workdir[len] = '\0';
-
+
strcat(workdir, suffix);
-
+
createDir(workdir);
}
-int getInitProcess(const char* prefix)
+int checkPrefixDir()
+{
+ struct stat st;
+
+ if (stat(prefix, &st) == 0)
+ {
+ if (!S_ISDIR(st.st_mode))
+ {
+ fprintf(stderr, "%s is a file. Remove the file.\n", prefix);
+ exit(1);
+ }
+ return 1; // OK
+ }
+ if (errno == ENOENT)
+ return 0; // not found
+ fprintf(stderr, "Cannot access %s: %s\n", prefix, strerror(errno));
+ exit(1);
+}
+
+void setupPrefix()
+{
+ char path[4096];
+
+ fprintf(stderr, "Setting up a new Darling prefix at %s\n", prefix);
+
+ seteuid(g_originalUid);
+ setegid(g_originalGid);
+
+ createDir(prefix);
+
+ snprintf(path, sizeof(path), "%s/system-root", prefix);
+ if (symlink("/", path) != 0)
+ {
+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
+
+ snprintf(path, sizeof(path), "%s/dev", prefix);
+ if (symlink("system-root/dev", path) != 0)
+ {
+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
+
+ snprintf(path, sizeof(path), "%s/tmp", prefix);
+ if (symlink("system-root/tmp", path) != 0)
+ {
+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
+
+ snprintf(path, sizeof(path), "%s/Users", prefix);
+ if (symlink("system-root/home", path) != 0)
+ {
+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
+
+ snprintf(path, sizeof(path), "%s/Volumes", prefix);
+ createDir(path);
+ snprintf(path, sizeof(path), "%s/Applications", prefix);
+ createDir(path);
+
+ snprintf(path, sizeof(path), "%s/var", prefix);
+ createDir(path);
+ snprintf(path, sizeof(path), "%s/var/root", prefix);
+ createDir(path);
+ snprintf(path, sizeof(path), "%s/var/run", prefix);
+ createDir(path);
+
+ snprintf(path, sizeof(path), "%s/var/run/syslog", prefix);
+ if (symlink("system-root/dev/log", path) != 0)
+ {
+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
+
+ seteuid(0);
+ setegid(0);
+}
+
+pid_t getInitProcess()
{
const char pidFile[] = "/.init.pid";
char* pidPath;
- int fd, rd, pid;
- char pidBuf[10];
- char exeBuf[17], procBuf[100];
-
+ pid_t pid;
+ int pid_i;
+ FILE *fp;
+ char procBuf[100];
+ char *exeBuf, *statusBuf;
+ int uidMatch = 0, gidMatch = 0;
+
pidPath = (char*) alloca(strlen(prefix) + sizeof(pidFile));
strcpy(pidPath, prefix);
strcat(pidPath, pidFile);
-
- fd = open(pidPath, O_RDONLY);
- if (fd == -1)
+
+ fp = fopen(pidPath, "r");
+ if (fp == NULL)
return 0;
-
- rd = read(fd, pidBuf, sizeof(pidBuf)-1);
- close(fd);
-
- if (rd <= 0)
+
+ if (fscanf(fp, "%d", &pid_i) != 1)
+ {
+ fclose(fp);
+ unlink(pidPath);
return 0;
-
- pidBuf[rd-1] = '\0';
- pid = atoi(pidBuf);
+ }
+ fclose(fp);
+ pid = (pid_t) pid_i;
// Does the process exist?
if (kill(pid, 0) == -1)
@@ -310,42 +634,86 @@ int getInitProcess(const char* prefix)
unlink(pidPath);
return 0;
}
-
+
// Is it actually an init process?
- sprintf(procBuf, "/proc/%d/comm", pid);
- fd = open(procBuf, O_RDONLY);
- if (fd == -1)
+ snprintf(procBuf, sizeof(procBuf), "/proc/%d/comm", pid);
+ fp = fopen(procBuf, "r");
+ if (fp == NULL)
{
unlink(pidPath);
return 0;
}
-
- rd = read(fd, exeBuf, sizeof(exeBuf)-1);
- close(fd);
-
- if (rd <= 0)
+
+ if (fscanf(fp, "%ms", &exeBuf) != 1)
{
+ fclose(fp);
unlink(pidPath);
return 0;
}
-
- exeBuf[rd] = '\0';
+ fclose(fp);
+
if (strcmp(exeBuf, DARLING_INIT_COMM) != 0)
{
unlink(pidPath);
return 0;
}
-
+ free(exeBuf);
+
+ // Is it owned by the current user?
+ if (g_originalUid != 0)
+ {
+ snprintf(procBuf, sizeof(procBuf), "/proc/%d/status", pid);
+ fp = fopen(procBuf, "r");
+ if (fp == NULL)
+ {
+ unlink(pidPath);
+ return 0;
+ }
+
+ while (1)
+ {
+ statusBuf = NULL;
+ size_t len;
+ if (getline(&statusBuf, &len, fp) == -1)
+ break;
+ int rid, eid, sid, fid;
+ if (sscanf(statusBuf, "Uid: %d %d %d %d", &rid, &eid, &sid, &fid) == 4)
+ {
+ uidMatch = 1;
+ uidMatch &= rid == g_originalUid;
+ uidMatch &= eid == g_originalUid;
+ uidMatch &= sid == g_originalUid;
+ uidMatch &= fid == g_originalUid;
+ }
+ if (sscanf(statusBuf, "Gid: %d %d %d %d", &rid, &eid, &sid, &fid) == 4)
+ {
+ gidMatch = 1;
+ gidMatch &= rid == g_originalGid;
+ gidMatch &= eid == g_originalGid;
+ gidMatch &= sid == g_originalGid;
+ gidMatch &= fid == g_originalGid;
+ }
+ free(statusBuf);
+ }
+ fclose(fp);
+
+ if (!uidMatch || !gidMatch)
+ {
+ unlink(pidPath);
+ return 0;
+ }
+ }
+
return pid;
}
-void checkPrefixOwner(const char* prefix)
+void checkPrefixOwner()
{
struct stat st;
-
+
if (stat(prefix, &st) == 0)
{
- if (st.st_uid != getuid())
+ if (g_originalUid != 0 && st.st_uid != g_originalUid)
{
fprintf(stderr, "You do not own the prefix directory.\n");
exit(1);
@@ -368,6 +736,7 @@ int isModuleLoaded()
if ((fp = fopen("/proc/modules", "r")) == NULL)
{
fprintf(stderr, "Failure opening /proc/modules: %s\n", strerror(errno));
+ fclose(fp);
return 0;
}
@@ -375,9 +744,13 @@ int isModuleLoaded()
{
read = getline(&line, &len, fp);
if (read > 0 && strstr(line, "darling_mach") != NULL)
+ {
+ fclose(fp);
return 1;
+ }
}
+ fclose(fp);
return 0;
}
@@ -391,7 +764,7 @@ int loadKernelModule()
return 0;
uname(&name);
- sprintf(path, "/lib/modules/%s/kernel/misc/darling-mach.ko", name.release);
+ snprintf(path, sizeof(path), "/lib/modules/%s/kernel/misc/darling-mach.ko", name.release);
if (access(path, F_OK))
{
fprintf(stderr, "Cannot find kernel module at %s: %s\n", path, strerror(errno));
diff --git a/src/dyld/darling.h b/src/dyld/darling.h
index 0cc42abfc..74686a4c3 100644
--- a/src/dyld/darling.h
+++ b/src/dyld/darling.h
@@ -17,6 +17,8 @@ You should have received a copy of the GNU General Public License
along with Darling. If not, see .
*/
+#include
+
#ifndef _DARLING_H_
#define _DARLING_H_
@@ -27,20 +29,37 @@ void missingSetuidRoot(void);
// Returns ~/.darling with ~ expanded
char* defaultPrefixPath(void);
-void setupWorkdir(const char* prefix);
+
+void setupWorkdir(void);
+
+void setupPrefix(void);
+
+int checkPrefixDir(void);
// Creates the given directory, exit()ing if not possible
void createDir(const char* path);
-// Return the PID of the init process in prefix (in our namespace)
+// Spawn the specified proceess inside the namespaces that PID 1 is in
+// Returns the PID of the child
+// exit()s on error
+pid_t spawnChild(int pidInit, const char *path, const char *const argv[]);
+
+// Set up some environment variables
+// As well as the working directory
+// Called in the child process
+void setupChild(const char *curPath);
+
+// Returns the PID of the init process in prefix (in our namespace)
// Returns 0 if no init is running
-int getInitProcess(const char* prefix);
+pid_t getInitProcess(void);
-int spawnInitProcess(const char* prefix);
+pid_t spawnInitProcess(void);
-int darlingPreInit(void* arg);
+void putInitPid(pid_t pidInit);
-void checkPrefixOwner(const char* prefix);
+void darlingPreInit(void);
+
+void checkPrefixOwner(void);
int isModuleLoaded(void);
diff --git a/src/dyld/dirstructure.cpp b/src/dyld/dirstructure.cpp
index ce4636e54..92b338d2f 100644
--- a/src/dyld/dirstructure.cpp
+++ b/src/dyld/dirstructure.cpp
@@ -29,25 +29,26 @@ along with Darling. If not, see .
static std::string GetUserLibrary()
{
- const char* home;
+ const char *home, *prefix;
std::stringstream ss;
std::string path;
-
+
+ prefix = getenv("DPREFIX");
home = getenv("HOME");
- if (!home)
+ if (!prefix || !home)
return std::string(); // give up on this user
-
- ss << home << '/' << "Library" << '/';
+
+ ss << prefix << home << '/' << "Library" << '/';
return ss.str();
}
bool HasUserDirectoryStructure()
{
std::string path = GetUserLibrary();
-
+
if (path.empty())
return true; // give up on this user
-
+
if (::access(path.c_str(), F_OK) == -1)
return false;
else
@@ -90,25 +91,24 @@ void SetupUserDirectoryStructure()
"Spelling",
"Voices",
};
-
+
std::string path = GetUserLibrary();
-
+
if (path.empty())
return;
-
+
std::cerr << "Darling: Creating Library structure at " << path << std::endl;
-
+
if (::mkdir(path.c_str(), 0777) == -1)
std::cerr << "Darling: Cannot mkdir(" << path << "): " << strerror(errno) << std::endl;
-
+
for (const char* dir : dirs)
{
std::string s = path;
-
+
s += dir;
-
+
if (::mkdir(s.c_str(), 0777) == -1)
std::cerr << "Darling: Cannot mkdir(" << s << "): " << strerror(errno) << std::endl;
}
}
-