···11-#!/bin/bash
22-#
33-# This file is part of Darling.
44-#
55-# Copyright (C) 2015 Lubos Dolezel
66-#
77-# Darling is free software: you can redistribute it and/or modify
88-# it under the terms of the GNU General Public License as published by
99-# the Free Software Foundation, either version 3 of the License, or
1010-# (at your option) any later version.
1111-#
1212-# Darling is distributed in the hope that it will be useful,
1313-# but WITHOUT ANY WARRANTY; without even the implied warranty of
1414-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515-# GNU General Public License for more details.
1616-#
1717-# You should have received a copy of the GNU General Public License
1818-# along with Darling. If not, see <http://www.gnu.org/licenses/>.
1919-#
2020-2121-export PATH="/bin:/sbin:/usr/bin:/usr/local/bin"
2222-2323-SCRIPT=$(readlink -f "$0")
2424-SCRIPTPATH=$(dirname "$SCRIPT")
2525-DARLING_PREFIX=$(realpath "$SCRIPTPATH/..")
2626-2727-selfmtime=$(stat -c %Y "$DARLING_PREFIX/bin/darling")
2828-2929-check_prefix() {
3030-3131- if [ ! -d "$DPREFIX" -o ! -f "$DPREFIX/.update-timestamp" ]; then
3232- setup_prefix "$DPREFIX"
3333- else
3434-3535- updatets=$(cat $DPREFIX/.update-timestamp)
3636- case $updatets in
3737- disable*)
3838- ;;
3939- ''|*[!0-9]*)
4040- setup_prefix "$DPREFIX"
4141- ;;
4242- *)
4343- [ $updatets -lt $selfmtime ] && setup_prefix "$DPREFIX"
4444- ;;
4545- esac
4646-4747- return 0
4848- fi
4949-}
5050-5151-setup_prefix() {
5252- prefix_pkg="/tmp/prefix.$$.pkg"
5353-5454- >&2 echo "Setting up prefix at $1"
5555- >&2 echo
5656-5757- mkdir -p "$1"
5858- rm -f "$1/darling-prefix"
5959-6060- rm -f "$1/system-root"
6161- ln -s / "$1/system-root"
6262-6363- rm -f "$1/darling-prefix"
6464- ln -s "system-root${DARLING_PREFIX}" "$1/darling-prefix"
6565-6666- rm -f "$1/dev"
6767- ln -sf "system-root/dev" "$1/dev"
6868-6969- rm -f "$1/home"
7070- ln -sf "system-root/home" "$1/home"
7171-7272- rm -f "$1/Users"
7373- ln -sf "home" "$1/Users"
7474-7575- rm -f "$1/tmp"
7676- ln -sf "system-root/tmp" "$1/tmp"
7777-7878- rm -f "$1/etc" 2>/dev/null || true
7979- mkdir -p "$1/etc"
8080- ln -sf "../system-root/etc/timezone" "$1/etc/timezone"
8181- ln -sf "../system-root/etc/resolv.conf" "$1/etc/resolv.conf"
8282- ln -sf "../system-root/etc/passwd" "$1/etc/passwd"
8383- ln -sf "../system-root/etc/group" "$1/etc/group"
8484- ln -sf "../system-root/etc/hosts" "$1/etc/hosts"
8585- ln -sf "../system-root/etc/localtime" "$1/etc/localtime" || true
8686-8787- mkdir -p "$1/usr/share"
8888- rm -f "$1/usr/share/zoneinfo" 2>/dev/null || true
8989- ln -sf "../../system-root/usr/share/zoneinfo" "$1/usr/share/zoneinfo"
9090-9191- mkdir -p "$1/Volumes" "$1/Applications" "$1/var/root" || true
9292- mkdir -p "$1/var/run" || true
9393- ln -sf "../../system-root/dev/log" "$1/var/run/syslog" || true
9494-9595- # Clean up old cruft (symlinks)
9696- rm -f "$1/bin" "$1/usr/bin" "$1/etc" "$1/System/Library/Frameworks" "$1/System/Library/PrivateFrameworks" 2>/dev/null || true
9797- cp -rf "${DARLING_PREFIX}/libexec/darling/"* "$1"
9898- echo -n "$selfmtime" > "$1/.update-timestamp"
9999-100100- install_pkg "org.darlinghq.pkg.OpenSSLCertificates"
101101-102102- >&2 echo "Building manpage database..."
103103- "${dexec_path}" "${DPREFIX}/bin/bash" -c "/usr/libexec/makewhatis"
104104-105105- >&2 echo "Prefix is ready."
106106-}
107107-108108-install_pkg() {
109109- temp="/tmp/pkgs.$$"
110110- mkdir "$temp" || true
111111-112112- >&2 echo "Getting latest version of $1..."
113113- version=$(wget "http://packages.darlinghq.org/${1}/latest.txt" -O- 2>/dev/null)
114114- pkgpath="$temp/${1}-${version}.pkg"
115115-116116- >&2 echo "Downloading $1 (version $version)..."
117117- wget "http://packages.darlinghq.org/${1}/${1}-${version}.pkg" -O "$pkgpath" 2>/dev/null
118118-119119- "${DARLING_PREFIX}/libexec/darling/usr/bin/installer" -pkg "/system-root${pkgpath}" -target /
120120-121121- rm -rf "$temp"
122122-}
123123-124124-is_sudo_allowed() {
125125- if type -p sudo &> /dev/null; then
126126- sudo -nl "$@" &> /dev/null && return 0
127127- fi
128128- return 1
129129-}
130130-131131-launch_with_su() {
132132- if [ "$(id -u)" = 0 ]; then
133133- "$@"
134134- elif is_sudo_allowed; then
135135- sudo "$@"
136136- else
137137- local cmd=$(printf '%q ' "$@")
138138- su --shell=$BASH --command "$cmd"
139139- fi
140140-}
141141-142142-darling_check() {
143143- # Returning values:
144144- # 0: module is loaded, file permissions are good
145145- # 1: module is loaded, file permissions are wrong
146146- # 2: module is not loaded
147147- grep -q darling_mach "/proc/modules"
148148- if [ $? -eq 0 ]; then
149149- [ -r "/dev/mach" -a -w "/dev/mach" ] && return 0 || return 1
150150- else
151151- return 2
152152- fi
153153-}
154154-155155-darling_load() {
156156- if $(darling_check); then
157157- >&2 echo "Module is already loaded."
158158- else
159159- >&2 echo -n "Loading module... "
160160- launch_with_su modprobe darling-mach && >&2 echo "Done." || >&2 echo "Fail."
161161- sleep 1 # Wait for module loading
162162- launch_with_su chmod a+rw "/dev/mach"
163163- fi
164164-165165-}
166166-167167-darling_unload() {
168168- if $(darling_check); then
169169- >&2 echo -n "Unloading module... "
170170- launch_with_su rmmod darling-mach && >&2 echo "Done." || >&2 echo "Fail."
171171- else
172172- >&2 echo "Module is not loaded, so it can't be unloaded."
173173- fi
174174-}
175175-176176-if [ $# -eq 0 ]; then
177177- >&2 echo "This is Darling, a runtime environment for OS X applications."
178178- >&2 echo
179179- >&2 echo "Copyright (C) 2012-2015 Lubos Dolezel"
180180- >&2 echo "Includes software components which are Copyright (C) Apple Computer, Inc. and many others."
181181- >&2 echo
182182- >&2 echo -e "Usage:\tdarling PROGRAM [ARGUMENTS...]\tRun the specified program"
183183- >&2 echo -e "\tdarling shell\t\t\tStart bash shell in prefix"
184184- #>&2 echo -e "\tdarling hdiutil\t\t\tMount DMG disk images"
185185- #>&2 echo -e "\tdarling pkgutil\t\t\tInstall PKG packages"
186186- >&2 echo -e "\tdarling load\t\t\tLoad kernel module"
187187- >&2 echo -e "\tdarling unload\t\t\tUnload kernel module"
188188- >&2 echo
189189- >&2 echo "The prefix is specified by the DPREFIX environment variable."
190190- >&2 echo "The default DPREFIX is \$HOME/.darling"
191191- exit 1
192192-fi
193193-194194-set -e
195195-196196-if [ -z "$DPREFIX" ]; then
197197- export DPREFIX="$HOME/.darling"
198198-fi
199199-200200-if ! $(darling_check) && [ "$1" != "load" ] && [ "$1" != "unload" ]; then
201201- 2>&1 echo "Cannot open /dev/mach, running 'darling load'."
202202- darling_load
203203-fi
204204-205205-dexec_path="${0%darling}dyld"
206206-#dexec_path="${DARLING_PREFIX}/bin/darling-exec"
207207-208208-case "$1" in
209209-"shell")
210210- check_prefix
211211-212212- if [ $# -gt 1 ]; then
213213- exec "${dexec_path}" "${DPREFIX}/bin/bash" -c "${*:2}"
214214- else
215215- exec "${dexec_path}" "${DPREFIX}/bin/bash"
216216- fi
217217- ;;
218218-#"hdiutil")
219219-# exec "${DPREFIX}/usr/bin/hdiutil" "${@:2}"
220220-# exit $?
221221-# ;;
222222-#"pkgutil")
223223-# >2& echo "Not implemented yet"
224224-# exit 1
225225-# ;;
226226-"load")
227227- darling_load
228228- ;;
229229-"unload")
230230- darling_unload
231231- ;;
232232-*)
233233- check_prefix
234234- exec "${dexec_path}" "$1" "${@:2}"
235235- ;;
236236-esac
+17-1
src/dyld/darling-so-start.S
···3344.text
5566+// For running executables from inside the prefix
67dyld_path:
88+.ascii SYSTEM_ROOT
99+.string DYLD_PATH
1010+1111+// Additionally, we support running them from the host system
1212+dyld_host_path:
713.string DYLD_PATH
814915proc_self_exe:
···5662 movl $__NR_execve, %eax
5763 syscall
58646565+ // If we failed to find dyld under the system root,
6666+ // try again without it
6767+ leaq dyld_host_path(%rip), %rdi // exec path
6868+ movq %rsp, %rsi // argv
6969+ movl 0(%rsp), %ecx // argc
7070+ leaq 16(%rsp, %rcx, 8), %rdx // envp
7171+ movq %rdi, (%rsi) // overwrite argc with dyld_path
7272+7373+ movl $__NR_execve, %eax
7474+ syscall
7575+5976fail:
6077 movl $2, %edi
6178 leaq failure_msg(%rip), %rsi
···6481 syscall
65826683 ud2
6767-
+85-59
src/dyld/darling.c
···3737#include "darling.h"
3838#include "darling-config.h"
39394040-// Path where the system root gets "mounted" inside the prefix
4141-#define SYSTEM_ROOT "/system-root"
42404341const char* DARLING_INIT_COMM = "darling-init";
4442char *prefix;
···4745int main(int argc, const char** argv)
4846{
4947 pid_t pidInit, pidChild;
5050- char path[4096];
5148 int wstatus;
52495350 if (argc <= 1)
···7370 prefix = defaultPrefixPath();
7471 if (!prefix)
7572 return 1;
7676- setenv("DPREFIX", prefix, 0);
7373+ unsetenv("DPREFIX");
77747875 if (!checkPrefixDir())
7976 setupPrefix();
···81788279 pidInit = getInitProcess();
83808181+ if (strcmp(argv[1], "shutdown") == 0)
8282+ {
8383+ if (pidInit == 0)
8484+ {
8585+ fprintf(stderr, "Darling container is not running\n");
8686+ return 1;
8787+ }
8888+8989+ // TODO: when we have a working launchd,
9090+ // this is where we ask it to shut down nicely
9191+9292+ kill(pidInit, SIGKILL);
9393+ return 0;
9494+ }
9595+8496 // If prefix's init is not running, start it up
8597 if (pidInit == 0)
8698 {
···9110392104 if (strcmp(argv[1], "shell") != 0)
93105 {
106106+ char *path = realpath(argv[1], NULL);
107107+ char *fullPath;
108108+109109+ if (path == NULL)
110110+ {
111111+ fprintf(stderr, "Cannot resolve path: %s\n", strerror(errno));
112112+ exit(1);
113113+ }
114114+94115 const char *argv_child[argc + 1];
951169696- argv_child[0] = "dyld";
9797- for (int i = 1; i < argc; i++)
117117+ argv_child[0] = SYSTEM_ROOT DYLD_PATH;
118118+119119+ fullPath = malloc(strlen(SYSTEM_ROOT) + strlen(path) + 1);
120120+ strcpy(fullPath, SYSTEM_ROOT);
121121+ strcat(fullPath, path);
122122+ argv_child[1] = fullPath;
123123+124124+ for (int i = 2; i < argc; i++)
98125 argv_child[i] = argv[i];
99126 argv_child[argc] = NULL;
100127101101- pidChild = spawnChild(pidInit, DYLD_PATH, argv_child);
128128+ pidChild = spawnChild(pidInit, SYSTEM_ROOT DYLD_PATH, argv_child);
129129+ free(path);
130130+ free(fullPath);
102131 }
103132 else
104133 {
105134 // Spawn the shell
106106- snprintf(path, sizeof(path), "%s/bin/bash", prefix);
107135 if (argc > 2)
108136 {
109137 size_t total_len = 0;
···118146 // Overwrite the last whitespace
119147 *(to - 1) = '\0';
120148121121- pidChild = spawnChild(pidInit, DYLD_PATH,
122122- (const char *[5]) {"dyld", path, "-c", buffer, NULL});
149149+ pidChild = spawnChild(pidInit, SYSTEM_ROOT DYLD_PATH,
150150+ (const char *[5]) {SYSTEM_ROOT DYLD_PATH, "/bin/bash", "-c", buffer, NULL});
123151 }
124152 else
125125- pidChild = spawnChild(pidInit, DYLD_PATH,
126126- (const char *[3]) {"dyld", path, NULL});
153153+ pidChild = spawnChild(pidInit, SYSTEM_ROOT DYLD_PATH,
154154+ (const char *[3]) {SYSTEM_ROOT DYLD_PATH, "/bin/bash", NULL});
127155 }
128156129157 // Drop the privileges so that we can be killed, etc by the user
···197225 }
198226 close(fdNS);
199227200200- snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/user", pidInit);
228228+ /*
229229+ snprintf(pathNS, sizeof(pathNS), SYSTEM_ROOT "/proc/%d/ns/user", pidInit);
201230 fdNS = open(pathNS, O_RDONLY);
202231 if (fdNS < 0)
203232 {
204233 fprintf(stderr, "Cannot open user namespace file: %s\n", strerror(errno));
205234 exit(1);
206235 }
236236+ */
207237208238 setresuid(g_originalUid, g_originalUid, g_originalUid);
209239 setresgid(g_originalGid, g_originalGid, g_originalGid);
210240241241+ /*
211242 if (setns(fdNS, CLONE_NEWUSER) != 0)
212243 {
213244 fprintf(stderr, "Cannot join user namespace: %s\n", strerror(errno));
214245 exit(1);
215246 }
216247 close(fdNS);
248248+ */
217249218250 setupChild(curPath);
219251···231263 char buffer1[4096];
232264 char buffer2[4096];
233265234234- setenv("PATH", "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin", 1);
266266+ setenv("PATH",
267267+ "/usr/bin:"
268268+ "/bin:"
269269+ "/usr/sbin:"
270270+ "/sbin:"
271271+ "/usr/local/bin",
272272+ 1);
273273+274274+ setenv("LD_LIBRARY_PATH",
275275+ SYSTEM_ROOT LIB_PATH,
276276+ 1);
235277236278 sscanf(getenv("HOME"), "/home/%4096s", buffer1);
237279 snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1);
···242284 // We're currently inside our home directory
243285 snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1);
244286 setenv("PWD", buffer2, 1);
245245-246246- snprintf(buffer2, sizeof(buffer2), "%s/Users/%s", prefix, buffer1);
247287 chdir(buffer2);
248288 }
249289 else
250290 {
251291 snprintf(buffer2, sizeof(buffer2), SYSTEM_ROOT "%s", curPath);
252292 setenv("PWD", buffer2, 1);
253253-254254- snprintf(buffer2, sizeof(buffer2), "%s" SYSTEM_ROOT "%s", prefix, curPath);
255293 chdir(buffer2);
256294 }
257295}
···288326{
289327 pid_t pid;
290328 int pipefd[2];
291291- char idmap[100];
329329+ // char idmap[100];
292330 char buffer[1];
293331 FILE *file;
294332···317355 // The child
318356319357 char *opts;
358358+ char putOld[4096];
320359321360 // Since overlay cannot be mounted inside user namespaces, we have to setup a new mount namespace
322361 // and do the mount while we can be root
···334373 exit(1);
335374 }
336375337337- opts = (char*) malloc(strlen(prefix)*2 + sizeof(LIBEXEC_PATH) + 50);
376376+ opts = (char*) malloc(strlen(prefix)*2 + sizeof(LIBEXEC_PATH) + 100);
338377 sprintf(opts, "lowerdir=%s,upperdir=%s,workdir=%s.workdir", LIBEXEC_PATH, prefix, prefix);
339378340379 // Mount overlay onto our prefix
···346385347386 free(opts);
348387388388+ snprintf(putOld, sizeof(putOld), "%s" SYSTEM_ROOT, prefix);
389389+390390+ if (syscall(SYS_pivot_root, prefix, putOld) != 0)
391391+ {
392392+ fprintf(stderr, "Cannot pivot_root: %s\n", strerror(errno));
393393+ exit(1);
394394+ }
395395+396396+ // mount procfs for our new PID namespace
397397+ if (mount("proc", "/proc", "proc", 0, "") != 0)
398398+ {
399399+ fprintf(stderr, "Cannot mount procfs: %s\n", strerror(errno));
400400+ exit(1);
401401+ }
402402+349403 // Drop the privileges
350404 setresuid(g_originalUid, g_originalUid, g_originalUid);
351405 setresgid(g_originalGid, g_originalGid, g_originalGid);
···353407354408 prctl(PR_SET_NAME, DARLING_INIT_COMM, 0, 0);
355409410410+ /*
356411 if (unshare(CLONE_NEWUSER) != 0)
357412 {
358413 fprintf(stderr, "Cannot unshare user namespace: %s\n", strerror(errno));
359414 exit(1);
360415 }
416416+ */
361417362362- // Tell the parent we're ready for it to set up UID/GID mappings
418418+ // Tell the parent we're ready
363419 write(pipefd[1], buffer, 1);
364420 close(pipefd[1]);
365421 // And wait for it to do it
···374430 read(pipefd[0], buffer, 1);
375431 close(pipefd[0]);
376432433433+ /*
377434 snprintf(idmap, sizeof(idmap), "/proc/%d/uid_map", pid);
378435379436 file = fopen(idmap, "w");
···399456 {
400457 fprintf(stderr, "Cannot set gid_map for the init process: %s\n", strerror(errno));
401458 }
459459+ */
402460403461 // Resume the child
404462 write(pipefd[1], buffer, 1);
···552610553611 createDir(prefix);
554612555555- snprintf(path, sizeof(path), "%s" SYSTEM_ROOT, prefix);
556556- if (symlink("/", path) != 0)
557557- {
558558- fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
559559- exit(1);
560560- }
561561-562562- snprintf(path, sizeof(path), "%s/dev", prefix);
563563- if (symlink(SYSTEM_ROOT "/dev" + 1, path) != 0)
564564- {
565565- fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
566566- exit(1);
567567- }
568568-569569- snprintf(path, sizeof(path), "%s/tmp", prefix);
570570- if (symlink(SYSTEM_ROOT "/tmp" + 1, path) != 0)
571571- {
572572- fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
573573- exit(1);
574574- }
575575-576576- snprintf(path, sizeof(path), "%s/Users", prefix);
577577- if (symlink(SYSTEM_ROOT "/home" + 1, path) != 0)
578578- {
579579- fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
580580- exit(1);
581581- }
582582-613613+ // The user needs to be able to create mountpoints,
583614 snprintf(path, sizeof(path), "%s/Volumes", prefix);
584615 createDir(path);
616616+ // ... to install applications,
585617 snprintf(path, sizeof(path), "%s/Applications", prefix);
586618 createDir(path);
587619588588- snprintf(path, sizeof(path), "%s/var", prefix);
620620+ // ... and to put stuff in /usr/local
621621+ snprintf(path, sizeof(path), "%s/usr", prefix);
589622 createDir(path);
590590- snprintf(path, sizeof(path), "%s/var/root", prefix);
623623+ snprintf(path, sizeof(path), "%s/usr/local", prefix);
591624 createDir(path);
592592- snprintf(path, sizeof(path), "%s/var/run", prefix);
625625+ snprintf(path, sizeof(path), "%s/usr/local/share", prefix);
593626 createDir(path);
594594-595595- snprintf(path, sizeof(path), "%s/var/run/syslog", prefix);
596596- if (symlink("../.." SYSTEM_ROOT "/dev/log", path) != 0)
597597- {
598598- fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
599599- exit(1);
600600- }
601627602628 seteuid(0);
603629 setegid(0);
+2-3
src/dyld/dirstructure.cpp
···3333 std::stringstream ss;
3434 std::string path;
35353636- prefix = getenv("DPREFIX");
3736 home = getenv("HOME");
3838- if (!prefix || !home)
3737+ if (!home)
3938 return std::string(); // give up on this user
40394141- ss << prefix << home << '/' << "Library" << '/';
4040+ ss << home << '/' << "Library" << '/';
4241 return ss.str();
4342}
4443
···2323#include <iostream>
2424#include "MachOObject.h"
2525#include "MachOMgr.h"
2626-#include "VirtualPrefix.h"
2726//#include "DummyObject.h"
2827#include <regex.h>
2928#include <unistd.h>
···3938{
4039 try
4140 {
4242- if (__prefix_get() != nullptr)
4343- m_config = new IniConfig(__prefix_translate_path(ETC_DARLING_PATH "/dylib.conf"));
4444- else
4545- m_config = new IniConfig(LIBEXEC_PATH ETC_DARLING_PATH "/dylib.conf");
4141+ m_config = new IniConfig(ETC_DARLING_PATH "/dylib.conf");
4642 }
4743 catch (const std::exception& e)
4844 {
···8581 if (dylib.compare(0, 16, "@executable_path") == 0)
8682 {
8783 MachOObject* mainModule = MachOMgr::instance()->mainModule();
8888-8484+8985 if (!mainModule)
9086 throw std::runtime_error("Cannot resolve @executable_path without a main module");
9191-8787+9288 dylib.replace(0, 16, mainModule->directory());
9389 }
9490 else if (dylib.compare(0, 12, "@loader_path") == 0)
···10096 return resolveViaRpath(dylib, requester);
10197 }
10298 }
103103-9999+104100 // Search in configuration
105101 if (const char* aliasTarget = resolveAlias(dylib))
106102 {
107103 std::string p;
108108-104104+109105 if (!strchr(aliasTarget, '/'))
110106 {
111111- p = LIB_PATH;
107107+ p = SYSTEM_ROOT LIB_PATH;
112108 p += '/';
113109 p += aliasTarget;
114110 // std::cout << p << std::endl;
115111 }
116116-112112+117113 return p;
118114 }
119119-115115+120116 // Search in extra paths
121117 std::string epath;
122118 epath = resolveInPathList(dylib, m_extraPaths);
123119 if (!epath.empty())
124120 return epath;
125125-121121+126122 // Search in DYLD_LIBRARY_PATH
127123 epath = resolveInLdPath(dylib);
128124 if (!epath.empty())
129125 return epath;
130130-126126+131127 // Try the path as is
132128 epath = checkPresence(dylib);
133129 if (!epath.empty())
···136132 // If absolute, search in sysroot
137133 if (dylib[0] == '/')
138134 {
139139- const char* prefix = __prefix_get();
140140-135135+141136 if (!MachOMgr::instance()->sysRoot().empty())
142137 {
143138 std::vector<std::string> roots = string_explode(MachOMgr::instance()->sysRoot(), ':');
···145140 for (const std::string& in_path : roots)
146141 {
147142 std::string path;
148148-149149- if (prefix != nullptr)
150150- path = prefix;
151151-143143+152144 path += in_path;
153145 path += '/';
154146 path += dylib;
···158150 return epath;
159151 }
160152 }
161161- if (prefix != nullptr)
162162- {
163163- std::string path = prefix;
164164- path += dylib;
165165-166166- epath = checkPresence(path);
167167- if (!epath.empty())
168168- return epath;
169169- }
170153 }
171171-154154+172155 /*if (MachOMgr::instance()->ignoreMissingDependencies())
173156 {
174174-157157+175158 }*/
176159177160 return std::string();
···180163std::string DylibSearch::checkPresence(const std::string& path)
181164{
182165 std::string str = path;
183183-166166+184167 if (::access(str.c_str(), F_OK) == 0)
185168 return str;
186186-169169+187170 str += ".dylib";
188188-171171+189172 if (::access(str.c_str(), F_OK) == 0)
190173 return str;
191191-174174+192175 for (const std::string& suffix : m_suffixes)
193176 {
194177 str = path + suffix;
195195-178178+196179 if (::access(str.c_str(), F_OK) == 0)
197180 return str;
198181 }
199199-182182+200183 return std::string();
201184}
202185···209192 return std::string();
210193211194 elems = string_explode(name, ':');
212212-195195+213196 return resolveInPathList(name, elems);
214197}
215198216199std::string DylibSearch::resolveInPathList(std::string name, const std::vector<std::string>& paths)
217200{
218218- const char* prefix = __prefix_get();
219201 for (const std::string& e : paths)
220202 {
221203 std::string path;
222222-223223- if (prefix)
224224- path = prefix;
225225-204204+226205 path += e + "/" + name;
227206228207 if (::access(path.c_str(), F_OK) == 0)
···249228 if (std::regex_match(library, match, m_reFrameworkPath))
250229 {
251230 std::string name, version;
252252-231231+253232 name = match[1];
254233 version = match[2];
255255-234234+256235 if (m_config->hasSection(name))
257236 {
258237 const IniConfig::ValueMap* m = m_config->getSection(name);
259238 auto it = m->find(version);
260260-239239+261240 if (it != m->end())
262241 return it->second.c_str();
263242 }
264243 }
265265-244244+266245 if (std::regex_match(library, match, m_reDefaultFrameworkPath))
267246 {
268247 std::string name;
269269-248248+270249 name = match[1];
271271-250250+272251 if (m_config->hasSection(name))
273252 {
274253 const IniConfig::ValueMap* m = m_config->getSection(name);
275254 auto it = m->find("default");
276276-255255+277256 if (it != m->end())
278257 return it->second.c_str();
279258 else
280259 return m->begin()->second.c_str();
281260 }
282261 }
283283-262262+284263 return nullptr;
285264}
286265···301280 {
302281 std::string expanded = name;
303282 std::string result;
304304-283283+305284 expanded.replace(0, 6, rpath);
306285307286 if (print)
308287 std::cerr << "dyld: Expanding \"" << name << "\" -> \"" << expanded << "\"\n";
309288310289 result = resolve(expanded, requester);
311311-290290+312291 if (!result.empty())
313292 {
314293 if (print)
···321300 std::cerr << "dyld: @rpath expansion not successful\n";
322301 }
323302 }
324324-303303+325304 return std::string();
326305}
327306···329308{
330309 char* real;
331310 std::string rv;
332332-311311+333312 real = ::realpath(path.c_str(), nullptr);
334334-313313+335314 if (real)
336315 {
337316 rv = real;
338338-317317+339318 free(real);
340319 return rv;
341320 }
-523
src/libdyld/VirtualPrefix.cpp
···11-/*
22-This file is part of Darling.
33-44-Copyright (C) 2015 Lubos Dolezel
55-66-Darling is free software: you can redistribute it and/or modify
77-it under the terms of the GNU General Public License as published by
88-the Free Software Foundation, either version 3 of the License, or
99-(at your option) any later version.
1010-1111-Darling is distributed in the hope that it will be useful,
1212-but WITHOUT ANY WARRANTY; without even the implied warranty of
1313-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414-GNU General Public License for more details.
1515-1616-You should have received a copy of the GNU General Public License
1717-along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818-*/
1919-2020-#include "darling-config.h"
2121-#include "VirtualPrefix.h"
2222-#include <string>
2323-#include <cstring>
2424-#include <pthread.h>
2525-#include <list>
2626-#include <cassert>
2727-#include <unistd.h>
2828-#include <sys/stat.h>
2929-#include <iostream>
3030-#include <cstdio>
3131-#include <dirent.h>
3232-3333-static std::string g_prefix;
3434-static std::list<std::string> g_prefixComponents;
3535-static std::string g_cwd;
3636-static pthread_rwlock_t g_cwdLock = PTHREAD_RWLOCK_INITIALIZER;
3737-static const char SYSTEM_ROOT[] = __SYSTEM_ROOT;
3838-3939-static std::list<std::string> explode_path(const std::string& path);
4040-static std::string join_path(const std::list<std::string>& path_components);
4141-4242-static std::list<std::string>& canonicalize_path(std::list<std::string>& path_components);
4343-static std::string resolve_path(std::list<std::string>& path_components, bool symlink);
4444-static const char* translate_path_common(const char* path, bool symlink);
4545-4646-void __prefix_set(const char* path)
4747-{
4848- char cwd[256];
4949- size_t pos = 0, last_pos;
5050-5151- getcwd(cwd, sizeof(cwd));
5252-5353- assert(path[0] == '/');
5454- assert(g_prefix.empty());
5555-5656- g_prefix = path;
5757- g_prefixComponents.clear();
5858-5959- while (pos != std::string::npos)
6060- {
6161- size_t len;
6262- last_pos = pos + 1;
6363-6464- pos = g_prefix.find('/', last_pos);
6565- len = (pos == std::string::npos) ? pos : (pos - last_pos);
6666- g_prefixComponents.push_back(g_prefix.substr(last_pos, len));
6767- }
6868-6969- if (g_prefix[g_prefix.length()-1] != '/')
7070- g_prefix += '/';
7171-7272- if (strncmp(cwd, path, strlen(path)) == 0)
7373- {
7474- g_cwd = cwd + strlen(path);
7575- if (g_cwd.empty() || g_cwd[g_cwd.length()-1] != '/')
7676- g_cwd += "/";
7777- }
7878- else
7979- {
8080- g_cwd = SYSTEM_ROOT;
8181- g_cwd += cwd;
8282- g_cwd += '/';
8383- }
8484-8585- // std::cout << "### Prefix initialized with cwd " << g_cwd << " from " << cwd << std::endl;
8686-}
8787-8888-const char* __prefix_get(void)
8989-{
9090- if (g_prefix.empty())
9191- return nullptr;
9292- else
9393- return g_prefix.c_str();
9494-}
9595-9696-const char* translate_path_common(const char* path, bool symlink)
9797-{
9898- static thread_local char resolved_path[1024];
9999- std::string str;
100100- std::list<std::string> path_components;
101101-102102- if (!path)
103103- return nullptr;
104104-105105- if (g_prefix.empty())
106106- return path;
107107-108108- // std::cout << "\tCWD is " << g_cwd << std::endl;
109109-110110- if (path[0] != '/')
111111- {
112112- pthread_rwlock_rdlock(&g_cwdLock);
113113- str = g_cwd;
114114- pthread_rwlock_unlock(&g_cwdLock);
115115- }
116116- str += path;
117117- // std::cout << "*** Before explode: " << str << std::endl;
118118-119119- path_components = explode_path(str);
120120- str = resolve_path(path_components, symlink);
121121-122122- strncpy(resolved_path, str.c_str(), sizeof(resolved_path)-1);
123123- resolved_path[sizeof(resolved_path)-1] = '\0';
124124-125125- // std::cout << "*** In: " << path << "; out: " << resolved_path << std::endl;
126126-127127- return resolved_path;
128128-}
129129-130130-const char* __prefix_translate_path(const char* path)
131131-{
132132- return translate_path_common(path, false);
133133-}
134134-135135-const char* __prefix_translate_path_link(const char* path)
136136-{
137137- return translate_path_common(path, true);
138138-}
139139-140140-const char* __prefix_untranslate_path(const char* path, unsigned long count)
141141-{
142142- static thread_local char resolved_path[1024];
143143- size_t test_len;
144144-145145- // FIXME: The following strcmp is a bit of a hack needed for isatty()
146146- // and friends.
147147- if (g_prefix.empty() || !count || path[0] != '/'
148148- || strncmp(path, "/dev/", 5) == 0)
149149- {
150150- memcpy(resolved_path, path, count);
151151- resolved_path[count] = '\0';
152152- return resolved_path;
153153- }
154154-155155- test_len = (path[count-1] != '/') ? (g_prefix.length()-1)
156156- : (g_prefix.length());
157157-158158- if (strncmp(path, g_prefix.c_str(), test_len) == 0)
159159- {
160160- size_t len = count - (g_prefix.length()-1);
161161- memcpy(resolved_path, path + g_prefix.length() - 1,
162162- count - (g_prefix.length() - 1));
163163-164164- if (len > 0)
165165- resolved_path[len] = '\0';
166166- else
167167- strcpy(resolved_path, "/");
168168- }
169169- else
170170- {
171171- size_t len = std::min<size_t>(sizeof(resolved_path)
172172- - sizeof(SYSTEM_ROOT), count);
173173-174174- strcpy(resolved_path, SYSTEM_ROOT);
175175- strncat(resolved_path, path, len);
176176- resolved_path[len + sizeof(SYSTEM_ROOT)-1] = '\0';
177177- }
178178-179179- // std::cout << "*** UNTRANSLATE: " << path << " -> " << resolved_path << std::endl;
180180-181181- return resolved_path;
182182-}
183183-184184-void __prefix_cwd(const char* in_path)
185185-{
186186- if (!*in_path)
187187- return;
188188-189189- std::string path;
190190- std::list<std::string> path_components;
191191-192192- // std::cout << "CWD to " << in_path << std::endl;
193193-194194- pthread_rwlock_wrlock(&g_cwdLock);
195195- if (in_path[0] != '/')
196196- {
197197- path = g_cwd;
198198- path += in_path;
199199- }
200200- else
201201- path = in_path;
202202-203203- path_components = explode_path(path);
204204- g_cwd = join_path(canonicalize_path(path_components));
205205-206206- if (g_cwd[g_cwd.length()-1] != '/')
207207- g_cwd += '/';
208208-209209- // std::cout << "\t+++ CWD In: " << in_path << "; out: " << g_cwd << std::endl;
210210-211211- pthread_rwlock_unlock(&g_cwdLock);
212212-}
213213-214214-void __prefix_cwd_fd(int fd)
215215-{
216216- char path[1024];
217217- int count;
218218-219219- if (g_prefix.empty())
220220- return;
221221-222222- sprintf(path, "/proc/self/fd/%d", fd);
223223- count = readlink(path, path, sizeof(path)-1);
224224-225225- if (count < 0)
226226- return;
227227-228228- __prefix_cwd(__prefix_untranslate_path(path, count));
229229-}
230230-231231-bool __prefix_is_system_root(const char* path)
232232-{
233233- return strcmp(__prefix_translate_path(path), "/") == 0;
234234-}
235235-236236-int __prefix_get_dyld_path(char* buf, unsigned long size)
237237-{
238238- int len;
239239- len = readlink("/proc/self/exe", buf, size);
240240-241241- if (len < 0)
242242- buf[0] = '\0';
243243- else
244244- buf[len] = '\0';
245245-246246- return len;
247247-}
248248-249249-std::list<std::string> explode_path(const std::string& path)
250250-{
251251- std::list<std::string> path_components;
252252- size_t pos = 0, last_pos;
253253-254254- if (path.empty())
255255- return path_components;
256256-257257- while (pos != std::string::npos)
258258- {
259259- size_t len;
260260-261261- if (pos != 0 || path[0] == '/')
262262- last_pos = pos + 1; // skip first slash
263263- else
264264- last_pos = pos;
265265-266266- pos = path.find('/', last_pos);
267267- len = (pos == std::string::npos) ? pos : (pos - last_pos);
268268- path_components.push_back(path.substr(last_pos, len));
269269- }
270270-271271- return path_components;
272272-}
273273-274274-std::string join_path(const std::list<std::string>& path_components)
275275-{
276276- std::string path;
277277-278278- for (const std::string& comp : path_components)
279279- {
280280- path += '/';
281281- path += comp;
282282- }
283283-284284- return path;
285285-}
286286-287287-std::list<std::string>& canonicalize_path(std::list<std::string>& path_components)
288288-{
289289- for (std::list<std::string>::iterator it = path_components.begin();
290290- it != path_components.end(); )
291291- {
292292- if (*it == "." || it->empty())
293293- {
294294- it = path_components.erase(it);
295295- }
296296- else if (*it == "..")
297297- {
298298- if (it != path_components.begin())
299299- {
300300- it--;
301301- it = path_components.erase(it);
302302- }
303303- it = path_components.erase(it);
304304- }
305305- else
306306- it++;
307307- }
308308-309309- return path_components;
310310-}
311311-312312-std::string resolve_path(std::list<std::string>& path_components, bool symlink)
313313-{
314314- std::string path, real_path;
315315- bool had_failure = false;
316316-317317- real_path = g_prefix;
318318-319319- // The resolution process is restarted when a symlink is encountered
320320-restart_process:
321321-322322- canonicalize_path(path_components);
323323- path.clear();
324324-325325- for (std::list<std::string>::iterator it = path_components.begin();
326326- it != path_components.end(); it++)
327327- {
328328- std::string& comp = *it;
329329-330330- path += '/';
331331-332332- if (!had_failure) // check if there is any sense in using opendir() or lstat() again
333333- {
334334- DIR* dir;
335335- struct dirent* ent;
336336- struct stat st;
337337- bool isLink = false;
338338- bool is_system_root;
339339-340340- real_path.replace(g_prefix.size(), std::string::npos, path);
341341- real_path += comp;
342342-343343- // Do NOT perform symlink resolution on /system-root,
344344- // because that should look like a bind mount rather than
345345- // a symlink from inside the DPREFIX
346346- is_system_root = (it == path_components.begin())
347347- && (comp == (SYSTEM_ROOT+1));
348348-349349- // We try an lstat() first as an optimization,
350350- // because the opendir() path below is VERY slow on NFS mounts.
351351- if (lstat(real_path.c_str(), &st) == 0)
352352- {
353353- isLink = S_ISLNK(st.st_mode);
354354- }
355355- else
356356- {
357357- // std::cout << "*** opendir: " << real_path << std::endl;
358358- real_path.resize(real_path.length() - comp.length());
359359-360360- dir = opendir(real_path.c_str());
361361-362362- if (dir != nullptr)
363363- {
364364- std::string best_match;
365365- unsigned char best_match_type;
366366-367367- while ((ent = readdir(dir)) != nullptr)
368368- {
369369- // Commented out: replaced with lstat() above
370370- /* if (comp == ent->d_name)
371371- break;
372372- else*/ if (strcasecmp(comp.c_str(), ent->d_name) == 0)
373373- {
374374- best_match = ent->d_name;
375375- best_match_type = ent->d_type;
376376- }
377377- }
378378-379379- if (ent != nullptr || !best_match.empty())
380380- {
381381- if (ent == nullptr)
382382- {
383383- // correct the case
384384- comp = best_match;
385385- }
386386- else
387387- best_match_type = ent->d_type;
388388-389389- if (best_match_type == DT_LNK && !is_system_root)
390390- {
391391- isLink = true;
392392- real_path += comp;
393393- }
394394- }
395395- else
396396- had_failure = true;
397397-398398- closedir(dir);
399399- }
400400- else
401401- had_failure = true;
402402- }
403403-404404- if (symlink && it == --path_components.end())
405405- isLink = false;
406406-407407- // Perform symlink resolution
408408- if (isLink && !is_system_root)
409409- {
410410- char link[4096];
411411- int len;
412412-413413- // std::cout << "*** readlink: " << real_path << std::endl;
414414- len = readlink(real_path.c_str(), link, sizeof(link)-1);
415415-416416- if (len > 0)
417417- {
418418- std::list<std::string> link_components;
419419-420420- link[len] = '\0';
421421-422422- /*
423423- if (strncmp(link, "@darling_prefix@", 16) == 0)
424424- {
425425- std::string copy;
426426-427427- copy = link;
428428- copy.replace(0, 16, INSTALL_PREFIX);
429429-430430- strcpy(link, copy.c_str());
431431- }
432432- */
433433- link_components = explode_path(link);
434434-435435- if (link[0] == '/')
436436- {
437437- // absolute symlink
438438- it++;
439439- it = path_components.erase(path_components.begin(), it);
440440- }
441441- else
442442- {
443443- // relative symlink
444444- it = path_components.erase(it);
445445- }
446446-447447- path_components.insert(it,
448448- link_components.begin(),
449449- link_components.end());
450450-451451- // We always restart the process
452452- // 1) For absolute symlinks, because we're moving to a completely different path
453453- // 2) For relative symlinks, because they may contain '..'
454454- goto restart_process;
455455- }
456456- }
457457- }
458458-459459- path += comp;
460460- }
461461-462462- if (!path_components.empty())
463463- {
464464- if (*path_components.begin() == "proc" || path == "/dev/mach")
465465- {
466466- return path;
467467- }
468468- else if (*path_components.begin() == (SYSTEM_ROOT+1))
469469- {
470470- if (!symlink || path_components.size() > 1)
471471- {
472472- // Exit virtual prefix
473473- path = path.substr(sizeof(SYSTEM_ROOT)-1);
474474-475475- if (path.empty())
476476- return "/";
477477- else
478478- return path;
479479- }
480480- }
481481- }
482482- if (path.compare(0, sizeof(SHARE_PATH "/")-1, SHARE_PATH "/") == 0)
483483- {
484484- return path;
485485- }
486486-487487- // Apply virtual prefix
488488- real_path.replace(g_prefix.size(), std::string::npos, path);
489489- return real_path;
490490-}
491491-492492-/*
493493-void path_to_string(const std::list<std::string>& path, char* outPath,
494494- size_t maxLen)
495495-{
496496- size_t lenSoFar = 1;
497497-498498- if (maxLen < 2)
499499- return;
500500-501501- outPath[0] = '\0';
502502-503503- for (const std::string& comp : path)
504504- {
505505- if (lenSoFar+1 > maxLen)
506506- break;
507507-508508- strcat(outPath, "/");
509509- lenSoFar++;
510510-511511- if (lenSoFar + comp.length() > maxLen)
512512- {
513513- strncat(outPath, comp.c_str(), maxLen - lenSoFar);
514514- break;
515515- }
516516- else
517517- {
518518- strcat(outPath, comp.c_str());
519519- lenSoFar += comp.length();
520520- }
521521- }
522522-}
523523-*/
-66
src/libdyld/VirtualPrefix.h
···11-/*
22-This file is part of Darling.
33-44-Copyright (C) 2015 Lubos Dolezel
55-66-Darling is free software: you can redistribute it and/or modify
77-it under the terms of the GNU General Public License as published by
88-the Free Software Foundation, either version 3 of the License, or
99-(at your option) any later version.
1010-1111-Darling is distributed in the hope that it will be useful,
1212-but WITHOUT ANY WARRANTY; without even the implied warranty of
1313-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414-GNU General Public License for more details.
1515-1616-You should have received a copy of the GNU General Public License
1717-along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818-*/
1919-2020-#ifndef VIRTUALPREFIX_H
2121-#define VIRTUALPREFIX_H
2222-#include <stdbool.h>
2323-2424-#ifdef __cplusplus
2525-extern "C" {
2626-#endif
2727-2828-#define __SYSTEM_ROOT "/system-root"
2929-3030-// Set prefix path. Should be run only once at startup.
3131-// If this is never called, then __prefix_translate_path()
3232-// is a no-op.
3333-void __prefix_set(const char* path);
3434-3535-// Returns the current prefix or NULL;
3636-const char* __prefix_get(void);
3737-3838-// Translate from path in prefix to physical path.
3939-const char* __prefix_translate_path(const char* path);
4040-4141-// Translate from path in prefix to physical path, treat the leaf node
4242-// as a symlink.
4343-const char* __prefix_translate_path_link(const char* path);
4444-4545-// Translate from physical path to path in prefix.
4646-// The path is expected to be canonical.
4747-const char* __prefix_untranslate_path(const char* path, unsigned long count);
4848-4949-// Called whenever current working directory changes.
5050-// This is used to resolve relative paths passed to
5151-// __prefix_translate_path().
5252-void __prefix_cwd(const char* path);
5353-5454-void __prefix_cwd_fd(int fd);
5555-5656-// Is the given path equivalent to __SYSTEM_ROOT?
5757-bool __prefix_is_system_root(const char* path);
5858-5959-int __prefix_get_dyld_path(char* buf, unsigned long size);
6060-6161-#ifdef __cplusplus
6262-}
6363-#endif
6464-6565-#endif /* VIRTUALPREFIX_H */
6666-
+12
src/setup-ld-so.sh
···11+#! /bin/bash
22+33+# This runs as root,
44+# with the current directory set to ${CMAKE_INSTALL_PREFIX}/libexec/darling
55+66+for file in /etc/ld.so.conf $(find /etc/ld.so.conf.d/ -type f); do
77+ # Copy lines from e.g. /etc/ld.so.conf into ./etc/ld.so.conf,
88+ # prepending "/Volumes/SystemRoot" to each line that starts with a slash
99+ awk '/^\// { print "/Volumes/SystemRoot" $0 }; /^[^/]/' $file > .$file
1010+done
1111+1212+unshare --mount bash -c "mount --rbind / Volumes/SystemRoot && ldconfig -r . -X"