<pre style='margin:0'>
Clemens Lang (neverpanic) pushed a commit to branch master
in repository macports-base.

</pre>
<p><a href="https://github.com/macports/macports-base/commit/8fd95d79c87e7a7aaa5240f819a41af2404c9b7d">https://github.com/macports/macports-base/commit/8fd95d79c87e7a7aaa5240f819a41af2404c9b7d</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 8fd95d79c87e7a7aaa5240f819a41af2404c9b7d
</span>Author: Clemens Lang <cal@macports.org>
AuthorDate: Sat Dec 19 04:58:39 2020 +0100

<span style='display:block; white-space:pre;color:#404040;'>    darwintrace: Add automated tests
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Some of the corner cases (such as very long paths, for example) are hard
</span><span style='display:block; white-space:pre;color:#404040;'>    to test manually, or at least you don't know exactly whether a specific
</span><span style='display:block; white-space:pre;color:#404040;'>    code path was covered just from installing a port.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Improve this situation by adding automated tests to darwintrace.
</span>---
 .gitignore                                   |   4 +
 configure                                    |   3 +-
 configure.ac                                 |   1 +
 src/darwintracelib1.0/.gitignore             |   3 +
 src/darwintracelib1.0/Makefile.in            |   3 +
 src/darwintracelib1.0/coverage.sh            |  13 ++
 src/darwintracelib1.0/tests/.gitignore       |  16 ++
 src/darwintracelib1.0/tests/Makefile.in      |  56 ++++++
 src/darwintracelib1.0/tests/access.c         |  26 +++
 src/darwintracelib1.0/tests/access.test      |  37 ++++
 src/darwintracelib1.0/tests/close.c          |  37 ++++
 src/darwintracelib1.0/tests/close.test       |  17 ++
 src/darwintracelib1.0/tests/darwintrace.test | 171 ++++++++++++++++++
 src/darwintracelib1.0/tests/dup2.c           |  52 ++++++
 src/darwintracelib1.0/tests/dup2.test        |  14 ++
 src/darwintracelib1.0/tests/execve.c         |  43 +++++
 src/darwintracelib1.0/tests/fork.c           |  43 +++++
 src/darwintracelib1.0/tests/lstat.c          |  23 +++
 src/darwintracelib1.0/tests/mkdir.c          |  27 +++
 src/darwintracelib1.0/tests/mkdir.test       |  43 +++++
 src/darwintracelib1.0/tests/open.c           |  41 +++++
 src/darwintracelib1.0/tests/open.test        |  52 ++++++
 src/darwintracelib1.0/tests/posix_spawn.c    |  55 ++++++
 src/darwintracelib1.0/tests/proc.test        | 251 +++++++++++++++++++++++++++
 src/darwintracelib1.0/tests/readdir.c        |  35 ++++
 src/darwintracelib1.0/tests/readdir.test     |  62 +++++++
 src/darwintracelib1.0/tests/readlink.c       |  31 ++++
 src/darwintracelib1.0/tests/readlink.test    |  66 +++++++
 src/darwintracelib1.0/tests/rename.c         |  25 +++
 src/darwintracelib1.0/tests/rename.test      |  64 +++++++
 src/darwintracelib1.0/tests/rmdir.c          |  22 +++
 src/darwintracelib1.0/tests/rmdir.test       |  52 ++++++
 src/darwintracelib1.0/tests/stat.c           |  23 +++
 src/darwintracelib1.0/tests/stat.test        |  66 +++++++
 src/darwintracelib1.0/tests/testlib.tcl      | 189 ++++++++++++++++++++
 src/darwintracelib1.0/tests/threadsetup.tcl  |  36 ++++
 src/darwintracelib1.0/tests/unlink.c         |  22 +++
 src/darwintracelib1.0/tests/unlink.test      |  49 ++++++
 38 files changed, 1772 insertions(+), 1 deletion(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/.gitignore b/.gitignore
</span><span style='display:block; white-space:pre;color:#808080;'>index eb0723ef6..061a9cbb9 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/.gitignore
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/.gitignore
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -22,6 +22,10 @@ src/*
</span> src/*/*_autoconf.tcl
 src/cregistry/macports.sqlext
 src/darwintracelib1.0/*.d
<span style='display:block; white-space:pre;background:#e0ffe0;'>+src/darwintracelib1.0/tests/*.d
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+src/darwintracelib1.0/tests/lstat
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+src/darwintracelib1.0/tests/readdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+src/darwintracelib1.0/tests/stat
</span> src/darwintracelib1.0/sip_copy_proc.[ch]
 src/machista1.0/tests/libmachista-test
 src/port/*
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/configure b/configure
</span><span style='display:block; white-space:pre;color:#808080;'>index a614be827..e0051b90b 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/configure
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/configure
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -9387,7 +9387,7 @@ printf "%s\n" "yes" >&6; }
</span> 
 
 # Output
<span style='display:block; white-space:pre;background:#ffe0e0;'>-ac_config_files="$ac_config_files Doxyfile Makefile Mk/macports.autoconf.mk doc/Makefile doc/base.mtree doc/macosx.mtree doc/macports.conf doc/prefix.mtree doc/pubkeys.conf portmgr/dmg/postflight setupenv.bash src/Makefile src/cregistry/Makefile src/compat/Makefile src/darwintracelib1.0/Makefile src/machista1.0/Makefile src/macports1.0/Makefile src/macports1.0/macports_autoconf.tcl src/macports1.0/macports_test_autoconf.tcl src/mpcommon1.0/Makefile src/package1.0/Makefile src/package1.0/ [...]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ac_config_files="$ac_config_files Doxyfile Makefile Mk/macports.autoconf.mk doc/Makefile doc/base.mtree doc/macosx.mtree doc/macports.conf doc/prefix.mtree doc/pubkeys.conf portmgr/dmg/postflight setupenv.bash src/Makefile src/cregistry/Makefile src/compat/Makefile src/darwintracelib1.0/Makefile src/darwintracelib1.0/tests/Makefile src/machista1.0/Makefile src/macports1.0/Makefile src/macports1.0/macports_autoconf.tcl src/macports1.0/macports_test_autoconf.tcl src/mpcommon1.0/Makefile sr [...]
</span> 
 
 ac_config_files="$ac_config_files vendor/tclsh"
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -10105,6 +10105,7 @@ do
</span>     "src/cregistry/Makefile") CONFIG_FILES="$CONFIG_FILES src/cregistry/Makefile" ;;
     "src/compat/Makefile") CONFIG_FILES="$CONFIG_FILES src/compat/Makefile" ;;
     "src/darwintracelib1.0/Makefile") CONFIG_FILES="$CONFIG_FILES src/darwintracelib1.0/Makefile" ;;
<span style='display:block; white-space:pre;background:#e0ffe0;'>+    "src/darwintracelib1.0/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/darwintracelib1.0/tests/Makefile" ;;
</span>     "src/machista1.0/Makefile") CONFIG_FILES="$CONFIG_FILES src/machista1.0/Makefile" ;;
     "src/macports1.0/Makefile") CONFIG_FILES="$CONFIG_FILES src/macports1.0/Makefile" ;;
     "src/macports1.0/macports_autoconf.tcl") CONFIG_FILES="$CONFIG_FILES src/macports1.0/macports_autoconf.tcl" ;;
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/configure.ac b/configure.ac
</span><span style='display:block; white-space:pre;color:#808080;'>index 9f5eb4e5e..6d9b37458 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/configure.ac
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/configure.ac
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -410,6 +410,7 @@ AC_CONFIG_FILES([
</span>   src/cregistry/Makefile
        src/compat/Makefile
        src/darwintracelib1.0/Makefile
<span style='display:block; white-space:pre;background:#e0ffe0;'>+        src/darwintracelib1.0/tests/Makefile
</span>   src/machista1.0/Makefile
        src/macports1.0/Makefile
        src/macports1.0/macports_autoconf.tcl
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/.gitignore b/src/darwintracelib1.0/.gitignore
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..e47a5e84a
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/.gitignore
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,3 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+report.html
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+dtrace.*.rawprof
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+dtrace.profdata
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/Makefile.in b/src/darwintracelib1.0/Makefile.in
</span><span style='display:block; white-space:pre;color:#808080;'>index be77bdf89..078f879fd 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/darwintracelib1.0/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -3,6 +3,8 @@ VPATH  = @srcdir@
</span> 
 include ../../Mk/macports.autoconf.mk
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+SUBDIR = tests
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> # This Makefile will only be run on Darwin systems; we can safely use
 # Apple-specifics here
 SRCS = \
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -77,6 +79,7 @@ install:: all
</span>   $(INSTALL)    -o "$(DSTUSR)" -g "$(DSTGRP)" -m 444 "$(SHLIB_NAME)" "$(DESTDIR)$(INSTALLDIR)"
 
 test::
<span style='display:block; white-space:pre;background:#e0ffe0;'>+        $(MAKE) -C tests/ test
</span> 
 ifeq (,$(findstring clean,$(MAKECMDGOALS)))
 # Include dependency information
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/coverage.sh b/src/darwintracelib1.0/coverage.sh
</span>new file mode 100755
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..13e4208c4
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/coverage.sh
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,13 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#!/bin/sh
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set -x
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+make CC=clang-mp-17 LD=clang-mp-17 CFLAGS="-g -O2 -std=c99 -Wextra -Wall -fPIC -arch arm64 -arch x86_64 -DHAVE_CONFIG_H -fprofile-instr-generate -fcoverage-mapping"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+export LLVM_PROFILE_FILE="${PWD}/dtrace.%p.rawprof"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+rm -f "${PWD}"/*.rawprof
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+make test CC=clang-mp-17 LD=clang-mp-17
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+llvm-profdata-mp-17 merge -sparse "${PWD}"/*.rawprof -o "${PWD}/dtrace.profdata"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+llvm-cov-mp-17 show -arch x86_64 -format=html darwintrace.dylib -instr-profile="${PWD}/dtrace.profdata" > report.html
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+llvm-cov-mp-17 report -arch x86_64 darwintrace.dylib -instr-profile="${PWD}/dtrace.profdata"
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/.gitignore b/src/darwintracelib1.0/tests/.gitignore
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..747dbc1db
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/.gitignore
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,16 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+access
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+close
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+dup2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+env
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+execve
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+fork
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+lstat
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+mkdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+open
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+posix_spawn
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+readdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+readlink
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+rename
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+rmdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+stat
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+unlink
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/Makefile.in b/src/darwintracelib1.0/tests/Makefile.in
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..47df74db0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,56 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+srcdir = @srcdir@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+VPATH  = @srcdir@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+include ../../../Mk/macports.autoconf.mk
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+SRCS = \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   access.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   close.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   dup2.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   execve.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   fork.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   lstat.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   mkdir.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   open.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   posix_spawn.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   readdir.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   readlink.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   rename.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   rmdir.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   stat.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unlink.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+OBJS = $(SRCS:%.c=%.o)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+BINS = $(SRCS:%.c=%)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+TESTS = $(sort $(wildcard *.test))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Create a copy of env that doesn't have Apple's restricted bits set in order
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# to preserve DYLD* variables.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+env:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   dd if=/usr/bin/env of=env
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   chmod +x env
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+%: %.o ../darwintrace.dylib
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   $(CC) -o $@ $^
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Generate dependency information
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+%.d : %.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   $(CC) -MM -MP $(CPPFLAGS) $< > $@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+.PHONY: all clean distclean install test codesign
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+all::
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+clean::
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   rm -f $(BINS) $(OBJS) $(SRCS:%.c=%.d)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+distclean:: clean
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   rm -f Makefile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test:: env $(BINS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   $(foreach test,$(TESTS),DARWINTRACE_SIP_WORKAROUND_PATH=@DARWINTRACE_SIP_WORKAROUND_PATH@ LC_ALL=C $(TCLSH) "$(srcdir)/$(test)";)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ifeq (,$(findstring clean,$(MAKECMDGOALS)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Include dependency information
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-include $(SRCS:%.c=%.d)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+endif
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/access.c b/src/darwintracelib1.0/tests/access.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..fba7689c8
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/access.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,26 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: access PATH...\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (int idx = 1; idx < argc; ++idx) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (-1 == access(argv[idx], F_OK)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   fprintf(stderr, "access(%s): %s\n", argv[idx], strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/access.test b/src/darwintracelib1.0/tests/access.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..dfc604016
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/access.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,37 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test access_allows_denied_dirs "Test that access(2) allows accesses to all directories" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./access /usr /usr/bin /bin 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test access_denies_outside_sandbox "Test that access(2) hides files outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "$cwd/access"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./access ./access 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "access(./access): No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test access_allowed_inside_sandbox "Test that access(2) does not hide files inside the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow "$cwd/access"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./access ./access 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test access_allowed_when_uninitialized "Test that access(2) does not hide files when darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set output [exec -ignorestderr -- ./access ./access 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $output
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/close.c b/src/darwintracelib1.0/tests/close.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..b9d9562a3
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/close.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,37 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void) argc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void) argv;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   __darwintrace_setup();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // close non-dt socket
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   close(255);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   FILE *stream = __darwintrace_sock();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (stream == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "__darwintrace_sock() returned NULL\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int fd = fileno(stream);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == close(fd)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "close(%d): %s\n", fd, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == close(fd)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "uninitialized close(%d): %s\n", fd, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/close.test b/src/darwintracelib1.0/tests/close.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..e4e4c841b
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/close.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,17 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test close_dt_socket "Test that closing the darwintrace socket is not possible" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./close 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -match glob \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "close(*): Bad file descriptor"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/darwintrace.test b/src/darwintracelib1.0/tests/darwintrace.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..c30baf130
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/darwintrace.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,171 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_hides_files "Test that a file on the blacklist isn't stat(2)able" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny $cwd]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "$cwd/stat"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat stat 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_hides_symlinks "Test that a symlink on the blacklist isn't stat(2)able, even if its target is" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file link -symbolic link .
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny "$cwd/link" allow $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force link
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/link"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./lstat link 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "lstat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_long_filenames "Test that a long filename does not trigger the stack canary" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow $cwd]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat [string repeat "ab/de/ghi/" 102] 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_works_across_fork "Test that darwintrace works across fork(2)" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny "$cwd/access.c" allow $cwd]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "$cwd/access.c"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./fork ./access.c 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [join [list "access(./access.c): No such file or directory" "access(./access.c): No such file or directory"] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_allow_root "Test that access to / is always possible" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat / 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_empty_path "Test that access to and empty path isn't hindered by darwintrace" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat "" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_up_beyond_root_absolute "Test that walking up beyond the root with absolute paths works" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny "/"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "/bin/sh"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat "/bin/..//..//../bin/sh" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_up_beyond_root_relative "Test that walking up beyond the root with relative paths works" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny "/"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "/bin/sh"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set levels [llength [regexp -all -inline -- "/" $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set path [file join [string repeat "../" [expr {$levels + 2}]] bin sh]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./stat "$path" 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_ignores_rsrc_forks "Test that resource forks are ignored" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny "/"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "/bin/sh"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat "/bin/sh/..namedfork/rsrc" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_on_volfs "Test that /.vol/device/inode works" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny "/"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "/bin/sh"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file stat "/bin/sh" st
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./stat "/.vol/${st(dev)}/${st(ino)}" 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_on_looping_symlinks "Test that self-symlinks are handled" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set levels [llength [regexp -all -inline -- "/" $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set path [file join [string repeat "../" [expr {$levels + 2}]] $cwd symlink]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ln -s $path symlink
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow "/"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force symlink
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat "$cwd/symlink" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: Too many levels of symbolic links"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_checks_symlink_path "Test that accessing a symlink fails, even if the target is in the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny "$cwd/symlink" allow $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file link -symbolic symlink stat
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/symlink"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force symlink
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat "$cwd/symlink" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_access_through_symlink_checks_target_permission "Test that file through a symlink checks whether the target is in the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny "$cwd/stat" allow $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        # while we're here, let's also test absolute symlinks
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file link -symbolic symlink "$cwd/stat"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/stat"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force symlink
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat "$cwd/symlink" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_relative_symlink_at_top_level "Test that a relative symlink at the top level works as expected" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat "/tmp" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_relative_symlinks "Test that resolution of relative symlinks works as expected" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set levels [llength [regexp -all -inline -- "/" $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set path "[string repeat "../" [expr {$levels + 2}]]$cwd//./stat"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow "$cwd/symlink"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ln -s $path symlink
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force symlink
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/stat"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat "$cwd/symlink" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_long_symlinks "Test that resolution of long symlinks does not trigger the stack canary" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -- ln -s [string repeat "ab/de/ghi/" 102] longlink
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force longlink
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./stat "$cwd/longlink" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_without_log_env_fails "Test that injecting the lib without setting DARWINTRACE_LOG fails" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DYLD_INSERT_LIBRARIES) $darwintrace_lib
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./stat . 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -returnCodes [list 1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "darwintrace: trace library loaded, but DARWINTRACE_LOG not set\nchild killed: SIGABRT"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_with_incorrect_log_env_fails "Test that DARWINTRACE_LOG pointing to a non-socket fails" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DYLD_INSERT_LIBRARIES) $darwintrace_lib
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_LOG) "GARBAGE.RANDOM.DOES.NOT.EXIST"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./stat . 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -returnCodes [list 1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "darwintrace: connect: No such file or directory\nchild killed: SIGABRT"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/dup2.c b/src/darwintracelib1.0/tests/dup2.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..fdf9c292e
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/dup2.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,52 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void) argc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void) argv;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   __darwintrace_setup();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // dup2 non-dt socket
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == dup2(STDOUT_FILENO, 255)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "dup2(STDOUT_FILENO, 255): %s\n", strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   FILE *stream = __darwintrace_sock();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (stream == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "__darwintrace_sock() returned NULL\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int fd = fileno(stream);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == dup2(STDOUT_FILENO, fd)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "dup2(STDOUT_FILENO, %d): %s\n", fd, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   FILE *newstream = __darwintrace_sock();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (newstream == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "__darwintrace_sock() returned NULL after dup2(2)\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int newfd = fileno(newstream);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (fd == newfd) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "__darwintrace_sock() fd did not change from %d, even though we dup(2)'d over it\n", fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == dup2(STDOUT_FILENO, newfd)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "uninitialized dup2(STDOUT_FILENO, %d): %s\n", newfd, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/dup2.test b/src/darwintracelib1.0/tests/dup2.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..525220764
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/dup2.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,14 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test dup2_dt_socket "Test that dup(2) over the darwintrace socket moves the socket" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./dup2 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/execve.c b/src/darwintracelib1.0/tests/execve.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..e74e98aea
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/execve.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,43 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/wait.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[], char* envp[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: execve PROGRAM ARGS...\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   pid_t pid = fork();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int status = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   switch (pid) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case -1:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   perror("fork");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case 0:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   execve(argv[1], argv + 1, envp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   perror("execve");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (pid != waitpid(pid, &status, 0)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           perror("waitpid");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (WIFEXITED(status)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           exit(WEXITSTATUS(status));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   } else if (WIFSIGNALED(status)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           fprintf(stderr, "%s killed with signal %d\n", argv[1], WTERMSIG(status));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   fprintf(stderr, "%s: unexpected exit status %d\n", argv[1], status);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/fork.c b/src/darwintracelib1.0/tests/fork.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..728955347
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/fork.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,43 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/wait.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: fork PATH\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (access(argv[1], F_OK) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "access(%s): %s\n", argv[1], strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   pid_t pid = fork();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int status = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   switch (pid) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case -1:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   perror("fork");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case 0:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (access(argv[1], F_OK) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           fprintf(stderr, "access(%s): %s\n", argv[1], strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (pid != waitpid(pid, &status, 0)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           perror("waitpid");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (WIFEXITED(status)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           exit(WEXITSTATUS(status));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   } else if (WIFSIGNALED(status)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           fprintf(stderr, "%s killed with signal %d\n", argv[1], WTERMSIG(status));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   fprintf(stderr, "%s: unexpected exit status %d\n", argv[1], status);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/lstat.c b/src/darwintracelib1.0/tests/lstat.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..664907da2
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/lstat.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,23 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: lstat PATH\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct stat st;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == lstat(argv[1], &st)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("lstat");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/mkdir.c b/src/darwintracelib1.0/tests/mkdir.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..77037e79d
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/mkdir.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,27 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: mkdir PATH...\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (int idx = 1; idx < argc; ++idx) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (-1 == mkdir(argv[idx], 0777)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   fprintf(stderr, "mkdir(%s): %s\n", argv[idx], strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/mkdir.test b/src/darwintracelib1.0/tests/mkdir.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..a31f372e8
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/mkdir.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,43 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test mkdir_allows_existing_dirs "Test that mkdir(2) succeeds outside sandbox, if the directory exists" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "/usr" "/usr/bin" "/bin"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./mkdir /usr /usr/bin /bin 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test mkdir_denies_outside_sandbox "Test that mkdir(2) fails if attempted outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force "$cwd/testdirectory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/testdirectory"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./mkdir "$cwd/testdirectory" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "mkdir($cwd/testdirectory): Permission denied"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test mkdir_allowed_inside_sandbox "Test that mkdir(2) succeeds inside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow "$cwd"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force "$cwd/testdirectory2"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./mkdir "$cwd/testdirectory2" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test mkdir_allowed_when_uninitialized "Test that mkdir(2) succeeds outside of the sandbox when darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set output [exec -ignorestderr -- ./mkdir /usr 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $output
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "mkdir(/usr): File exists"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/open.c b/src/darwintracelib1.0/tests/open.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..9a2b327a1
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/open.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,41 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 3) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: open {-create|-read} PATH...\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int flags = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   mode_t mode = 0666;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (strcmp(argv[1], "-create") == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           flags |= O_RDWR | O_CREAT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else if (strcmp(argv[1], "-read") == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           flags |= O_RDONLY;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "open: unsupported mode '%s'. Choose one of '-create', '-read'.\n", argv[1]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (int idx = 2; idx < argc; ++idx) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           int fd = open(argv[idx], flags, mode);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (-1 == fd) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   fprintf(stderr, "open(%s): %s\n", argv[idx], strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   close(fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/open.test b/src/darwintracelib1.0/tests/open.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..9f466e75e
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/open.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,52 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test open_succeeds_on_dirs "Test that open(2) succeeds on directories even outside the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./open -read /usr} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test open_fails_outside_sandbox "Test that open(O_RDONLY) fails outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "$cwd/open"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./open -read "$cwd/open" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "open($cwd/open): No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test open_write_fails_outside_sandbox "Test that open(O_RDWR|O_CREAT) fails outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "$cwd/open"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./open -create "$cwd/open" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "open($cwd/open): Permission denied"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test open_succeeds_inside_sandbox "Test that open(O_RDONLY) succeeds inside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow "$cwd"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./open -read "$cwd/open" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test open_write_succeeds_inside_sandbox "Test that open(O_RDWR|O_CREAT) succeeds inside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow "$cwd"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force "$cwd/opentest"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./open -create "$cwd/opentest" 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test open_succeeds_when_uninitialized "Test that open(2) succeeds outside of the sandbox when darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set output [exec -ignorestderr -- ./open -read ./open 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $output
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/posix_spawn.c b/src/darwintracelib1.0/tests/posix_spawn.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..5f999a335
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/posix_spawn.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,55 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <spawn.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdbool.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/wait.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[], char* envp[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: posix_spawn PROGRAM ARGS...\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   bool use_spawn_setexec = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_SPAWN_SETEXEC") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           use_spawn_setexec = true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   pid_t pid;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   posix_spawnattr_t attr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (0 != (errno = posix_spawnattr_init(&attr))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("posix_spawnattr_init");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (0 != (errno = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("posix_spawnattr_setflags");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (0 != (errno = posix_spawn(&pid, argv[1], NULL, use_spawn_setexec ? &attr : NULL, argv + 1, envp))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("posix_spawn");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           int status;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (pid != waitpid(pid, &status, 0)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   perror("waitpid");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (WIFEXITED(status)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   exit(WEXITSTATUS(status));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else if (WIFSIGNALED(status)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   fprintf(stderr, "%s killed with signal %d\n", argv[1], WTERMSIG(status));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "%s: unexpected exit status %d\n", argv[1], status);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/proc.test b/src/darwintracelib1.0/tests/proc.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..74d889a96
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/proc.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,251 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require Pextlib 1.0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test execve_selfpreserving_env "Test that you cannot get out of the sandbox by unsetting environment variables" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow $cwd]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [split [exec -ignorestderr -- ./env DYLD_INSERT_LIBRARIES=foo DARWINTRACE_LOG=bar ./env] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set result {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach line $lines {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[string match "DYLD_INSERT_LIBRARIES=*" $line] || [string match "DARWINTRACE_LOG=*" $line]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                lappend result $line
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [lsort $result]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -match glob \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [list "DARWINTRACE_LOG=/tmp/macports-test-*" "DYLD_INSERT_LIBRARIES=$darwintrace_lib"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test execve_preserves_environment "Test that execve(2) will restore DYLD_INSERT_LIBRARIES and DARWINTRACE_LOG when deleted" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow $cwd]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [split [exec -ignorestderr -- ./env -u DYLD_INSERT_LIBRARIES -u DARWINTRACE_LOG ./env] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set result {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach line $lines {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[string match "DYLD_INSERT_LIBRARIES=*" $line] || [string match "DARWINTRACE_LOG=*" $line]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                lappend result $line
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [lsort $result]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -match glob \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [list "DARWINTRACE_LOG=/tmp/macports-test-*" "DYLD_INSERT_LIBRARIES=$darwintrace_lib"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test execve_outside_sandbox "Test that you cannot run tools outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect "$cwd/stat"] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./execve ./stat ./stat.c 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "execve: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test spawn_outside_sandbox "Test that you cannot run tools outside of the sandbox with posix_spawn(2)" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect "$cwd/stat"] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./stat ./stat.c 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_SPAWN_SETEXEC) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./stat ./stat.c 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_SPAWN_SETEXEC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $lines
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [lrepeat 2 "posix_spawn: No such file or directory"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test execve_uninitialized "Test that execve(2) outside the sandbox succeeds if darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set output [exec -ignorestderr -- ./execve ./stat ./stat.c 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $output
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test spawn_uninitialized "Test that posix_spawn(2) outside the sandbox succeeds if darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./stat ./stat.c 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_SPAWN_SETEXEC) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./stat ./stat.c 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_SPAWN_SETEXEC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $lines
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [lrepeat 2 ""]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test execve_inside_sandbox "Test that execve(2) inside the sandbox succeeds" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny "$cwd/stat.c" allow $cwd]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect "$cwd/stat.c"] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./execve ./stat ./stat.c 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "stat: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test spawn_inside_sandbox "Test that posix_spawn(2) inside the sandbox succeeds" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny "$cwd/stat.c" allow $cwd]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect "$cwd/stat.c"] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./stat ./stat.c 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_SPAWN_SETEXEC) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./stat ./stat.c 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_SPAWN_SETEXEC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $lines
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [lrepeat 2 "stat: No such file or directory"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test execve_interpreter_outside_sandbox "Test that execve(2) on a script with an interpreter outside of the sandbox fails" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set fd [open "execve_script" w 0700]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $fd "#!  \t  ${cwd}/stat stat.c"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        close $fd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny "$cwd/stat" allow $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force execve_script
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/stat"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./execve ./execve_script 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "execve: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test spawn_interpreter_outside_sandbox "Test that posix_spawn(2) on a script with an interpreter outside of the sandbox fails" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set fd [open "execve_script" w 0700]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $fd "#!  \t  ${cwd}/stat stat.c"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        close $fd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny "$cwd/stat" allow $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force execve_script
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/stat"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./execve_script 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_SPAWN_SETEXEC) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./execve_script 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_SPAWN_SETEXEC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $lines
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [lrepeat 2 "posix_spawn: No such file or directory"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test execve_non_interpreter "Test that execve(2) on a script with broken shebang does not produce violations" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set fd [open "execve_script" w 0700]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $fd "#"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        close $fd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force execve_script
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./execve ./execve_script 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "execve: Exec format error"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test spawn_non_interpreter "Test that posix_spawn(2) on a script with broken shebang does not produce violations" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set fd [open "execve_script" w 0700]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts $fd "#"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        close $fd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force execve_script
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./execve_script 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_SPAWN_SETEXEC) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./execve_script 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_SPAWN_SETEXEC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $lines
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [lrepeat 2 "posix_spawn: Exec format error"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test execve_non_existing_inside_sandbox "Test that execve(2) on a non-existing file inside the sandbox does not produce violations" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./execve ./execve_non_existing_binary 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "execve: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test spawn_non_existing_inside_sandbox "Test that posix_spawn(2) on a non-existing file inside the sandbox does not produce violations" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./execve_non_existing_binary 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_SPAWN_SETEXEC) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend lines [exec -ignorestderr -- ./posix_spawn ./execve_non_existing_binary 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_SPAWN_SETEXEC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $lines
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [lrepeat 2 "posix_spawn: No such file or directory"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test spawn_sip_binary "Test that posix_spawn(2) works on a SIP-protected binary (which will make a copy)" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force [file join $::env(DARWINTRACE_SIP_WORKAROUND_PATH) [getuid] usr/bin/env]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [split [exec -ignorestderr -- ./posix_spawn /usr/bin/env] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set result {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach line $lines {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[string match "DYLD_INSERT_LIBRARIES=*" $line] || [string match "DARWINTRACE_LOG=*" $line]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                lappend result $line
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [concat [lsort $result] [file exists [file join $::env(DARWINTRACE_SIP_WORKAROUND_PATH) [getuid] usr/bin/env]]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -match glob \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [list "DARWINTRACE_LOG=/tmp/macports-test-*" "DYLD_INSERT_LIBRARIES=$darwintrace_lib" 1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test spawn_sip_script "Test that posix_spawn(2) works on a SIP-protected shell script (which will copy the interpreter)" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./posix_spawn /usr/bin/umask} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -match regexp \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "0\[0-7]{3}"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test spawn_sip_suid_binary "Test that posix_spawn(2) works on a SIP-protected SUID binary (which will not be copied)" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set status 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if {[catch {exec -ignorestderr -- ./posix_spawn /usr/bin/crontab -l} results options]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            puts $::errorInfo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            set details [dict get $options -errorcode]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[lindex $details 0] eq "CHILDSTATUS"} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                set status [lindex $details 2]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                return -options $options -level 0 $results
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $status
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/readdir.c b/src/darwintracelib1.0/tests/readdir.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..2ce37e87b
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/readdir.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,35 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <dirent.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: readdir PATH\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   DIR* dir = opendir(argv[1]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (dir == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("opendir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct dirent *d;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   while (errno = 0, (d = readdir(dir)) != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           printf("%s\n", d->d_name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (errno != 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("readdir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/readdir.test b/src/darwintracelib1.0/tests/readdir.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..fb674af66
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/readdir.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,62 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_hides_files_in_readdir "Test that a file on the blacklist does not show up in readdir(3)" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny "$cwd/stat.c" allow $cwd]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [split [exec -ignorestderr -- ./readdir . 2>@1] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [lsearch -all -inline $lines stat.c]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test readdir_allowed_inside_sandbox "Test that files inside the sandbox show up in readdir(3)" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow "$cwd/stat.c"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [split [exec -ignorestderr -- ./readdir . 2>@1] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [lsearch -all -inline $lines stat.c]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [list stat.c]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test readdir_allowed_when_uninitialized "Test that files outside the sandbox show up in readdir() when darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny "$cwd/stat.c" allow $cwd]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [split [exec -ignorestderr -- ./readdir . 2>@1] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [lsearch -all -inline $lines stat.c]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [list stat.c]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test darwintrace_readdir_at_maxpathlen "Test that readdir(3) with a directory at MAXPATHLEN doesn't trigger the stack canary" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        global dirname filename
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set dirname [string repeat "ab/de/ghi/" 90]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set filename [string repeat "a" 200]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file mkdir $dirname
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set saved [pwd]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        cd $dirname
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- touch $filename >/dev/null
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        cd $saved
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- rm -rf ab
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set lines [split [exec -ignorestderr -- ./readdir $dirname 2>@1] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [lsearch -inline -all $lines "a*"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [string repeat a 200]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/readlink.c b/src/darwintracelib1.0/tests/readlink.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..cdc386558
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/readlink.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,31 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/param.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc != 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: readlink PATH\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char buf[MAXPATHLEN];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ssize_t len = readlink(argv[1], buf, sizeof(buf) - 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == len) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "readlink(%s): %s\n", argv[1], strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           buf[len] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           printf("%s\n", buf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/readlink.test b/src/darwintracelib1.0/tests/readlink.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..69f07a8de
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/readlink.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,66 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test readlink_denies_outside_sandbox "Test that readlink(2) fails outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file link -symbolic link .
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force link
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/link"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./readlink link 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "readlink(link): No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test readlink_succeeds_inside_sandbox "Test that readlink(2) succeeds inside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file link -symbolic link readlink.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        # note the link target is outside of the sandbox ...
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny "$cwd/readlink.c" allow "$cwd"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force link
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        # ... but this does not produce a violation
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./readlink link 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "readlink.c"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test readlink_succeeds_on_missing_file "Test that readlink(2) does not care whether the target exists" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        # Tcl's file link -symbolic will fail on links targets that don't exist
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ln -s this_file_does_not_exist link
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force link
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./readlink link 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "this_file_does_not_exist"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test readlink_succeeds_when_uninitialized "Test that readlink(2) succeeds outside of the sandbox when darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file link -symbolic link .
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force link
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set output [exec -ignorestderr -- ./readlink link 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $output
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/rename.c b/src/darwintracelib1.0/tests/rename.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..45bf2eb68
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/rename.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,25 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc != 3) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: rename SRC TGT\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == rename(argv[1], argv[2])) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "rename(%s, %s): %s\n", argv[1], argv[2], strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/rename.test b/src/darwintracelib1.0/tests/rename.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..3b7d17b65
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/rename.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,64 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test rename_fails_source_outside_sandbox "Test that rename(2) fails if the source is outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- touch rename_src_file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny "$cwd/rename_src_file" allow $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force rename_src_file rename_tgt_file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/rename_src_file"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./rename rename_src_file rename_tgt_file 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "rename(rename_src_file, rename_tgt_file): No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test rename_fails_target_outside_sandbox "Test that rename(2) fails if the target is outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- touch rename_src_file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny "$cwd/rename_tgt_file" allow $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force rename_src_file rename_tgt_file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/rename_tgt_file"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./rename rename_src_file rename_tgt_file 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "rename(rename_src_file, rename_tgt_file): Permission denied"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test rename_succeeds_inside_sandbox "Test that rename(2) succeeds if source and target are inside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- touch rename_src_file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow $cwd]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force rename_src_file rename_tgt_file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./rename rename_src_file rename_tgt_file 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [file exists rename_tgt_file]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test rename_succeeds_when_uninitialized "Test that rename(2) succeeds with source and target outside of the sandbox when darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- touch rename_src_file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force rename_src_file rename_tgt_file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./rename rename_src_file rename_tgt_file 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [file exists rename_tgt_file]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/rmdir.c b/src/darwintracelib1.0/tests/rmdir.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..2b40d9348
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/rmdir.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,22 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: rmdir PATH\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == rmdir(argv[1])) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("rmdir");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/rmdir.test b/src/darwintracelib1.0/tests/rmdir.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..c0a88f200
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/rmdir.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,52 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test rmdir_outside_sandbox "Test that rmdir(2) does not work outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file mkdir rmdirme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force rmdirme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/rmdirme"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./rmdir rmdirme 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "rmdir: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test rmdir_inside_sandbox "Test that rmdir(2) works inside the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file mkdir rmdirme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force rmdirme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./rmdir rmdirme 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [file isdirectory rmdirme]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test rmdir_uninitialized "Test that rmdir(2) works outside the sandbox if darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file mkdir rmdirme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force rmdirme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -ignorestderr -- ./rmdir rmdirme 2>@1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return [file isdirectory rmdirme]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/stat.c b/src/darwintracelib1.0/tests/stat.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..82414b7c4
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/stat.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,23 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: stat PATH\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct stat st;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == stat(argv[1], &st)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("stat");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/stat.test b/src/darwintracelib1.0/tests/stat.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..0b7533ba5
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/stat.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,66 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test stat_denies_dirs "Test that stat(2)/lstat(2) deny access to directories" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list deny /]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        join [list \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./stat /usr 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./lstat /usr 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ] "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test stat_denies_outside_sandbox "Test that stat(2)/lstat(2) hide files outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect [list "$cwd/stat"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        join [list \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./stat ./stat 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./lstat ./stat 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ] "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result [join [list "stat: No such file or directory" "lstat: No such file or directory"] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test stat_allowed_inside_sandbox "Test that stat(2)/lstat(2) do not hide files inside the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow "$cwd/stat"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        join [list \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./stat ./stat 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./lstat ./stat 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ] "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test stat_allow_all_wildcard "Test the allow-all wildcard shortcut" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup [list allow "/"]] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        join [list \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./stat ./stat 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./lstat ./stat 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ] "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test stat_uninitialized "Test that stat(2)/lstat(2) do not hide files outside of the sandbox if darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup [setup {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup [expect {}] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set result [join [list \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./stat ./stat 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            [exec -ignorestderr -- ./lstat ./stat 2>@1] \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ] "\n"]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $result
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/testlib.tcl b/src/darwintracelib1.0/tests/testlib.tcl
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..15d791190
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/testlib.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,189 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require struct::set
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require Pextlib 1.0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require Thread
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set cwd [file normalize [file dirname [info script]]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+set darwintrace_lib [file join $cwd .. darwintrace.dylib]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc appendEntry {sandbox path action} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    upvar 2 $sandbox sndbxlst
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set mapping {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # Escape backslashes with backslashes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    lappend mapping "\\" "\\\\"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # Escape colons with \:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    lappend mapping ":" "\\:"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # Escape equal signs with \=
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    lappend mapping "=" "\\="
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # file normalize will leave symlinks as the very last
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # path component intact. This will, for instance, prevent /tmp from
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # being resolved to /private/tmp.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # Use realpath to avoid this behavior.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set normalizedPath [file normalize $path]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # realpath only works on files that exist
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {![catch {file type $normalizedPath}]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set normalizedPath [realpath $normalizedPath]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    lappend sndbxlst "[string map $mapping $path]=$action"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {$normalizedPath ne $path} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        lappend sndbxlst "[string map $mapping $normalizedPath]=$action"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+##
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Append a trace sandbox entry suitable for allowing access to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# a directory to a given sandbox list.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# @param sandbox The name of the sandbox list variable
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# @param path The path that should be permitted
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc allow {sandbox path} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    appendEntry $sandbox $path "+"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+##
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Append a trace sandbox entry suitable for denying access to a directory
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# (and stopping processing of the sandbox) to a given sandbox list.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# @param sandbox The name of the sandbox list variable
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# @param path The path that should be denied
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc deny {sandbox path} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    appendEntry $sandbox $path "-"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+##
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Append a trace sandbox entry suitable for deferring the access decision
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# back to MacPorts to query for dependencies to a given sandbox list.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# @param sandbox The name of the sandbox list variable
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# @param path The path that should be handed back to MacPorts for further
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#             processing.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc ask {sandbox path} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    appendEntry $sandbox $path "?"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc setup {rules} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    global sandbox
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set sandbox [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    foreach {rule path} $rules {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        switch $rule {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            allow {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                allow sandbox $path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            deny {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                deny sandbox $path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            ask {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                ask sandbox $path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return tracelib_setup
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc tracelib_setup {} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    global \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        cwd \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        darwintrace_lib \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        env \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        fifo \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        sandbox \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        thread \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        tracelib_result
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set fifo_mktemp_template "/tmp/macports-test-XXXXXX"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set fifo [mktemp $fifo_mktemp_template]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set thread [thread::create -joinable {source threadsetup.tcl}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    thread::send $thread [list setup $fifo]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tracelib setsandbox [join $sandbox :]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tracelib enablefence
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    thread::send -async $thread [list run] tracelib_result
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set ::env(DYLD_INSERT_LIBRARIES) $darwintrace_lib
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set ::env(DARWINTRACE_LOG) $fifo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc expect {{violations {}} {unknowns {}}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    global expectations
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    array set expectations {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set expectations(violations) $violations
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set expectations(unknowns) $unknowns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return tracelib_cleanup
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc tracelib_cleanup {} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    global \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        env \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        expectations \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        fifo \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        sandbox \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        thread \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        tracelib_result
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tracelib closesocket
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tracelib clean
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    file delete -force $fifo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    vwait tracelib_result
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    thread::send $thread [list set warnings] warnings
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    thread::send $thread [list set violations] violations
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    thread::send $thread [list set unknowns] unknowns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct::set add violations_set $violations
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct::set add unknowns_set $unknowns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct::set add expected_violations_set $expectations(violations)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct::set add expected_unknowns_set $expectations(unknowns)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set failed no
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    lassign [struct::set intersect3 $violations_set $expected_violations_set] _ additional_violations unexpected_violations
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    foreach violation $additional_violations {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts "Unexpected violation '$violation'"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set failed yes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    foreach violation $unexpected_violations {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts "Expected violation '$violation' did not occur"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set failed yes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    lassign [struct::set intersect3 $unknowns_set $expected_unknowns_set] _ additional_unknowns unexpected_unknowns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    foreach unknown_ $additional_unknowns {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts "Unexpected unknown '$unknown_'"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set failed yes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    foreach unknown_ $unexpected_unknowns {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts "Expected unknown '$unknown_' did not occur"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set failed yes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if {$failed} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach {name contents} [list "WARNINGS" $warnings "VIOLATIONS" $violations "UNKNOWNS" $unknowns] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if {[llength $contents] != 0} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                puts "$name"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                foreach item $contents {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    puts "  $item"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        puts "SANDBOX"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        foreach sandbox_entry $sandbox {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            puts "  $sandbox_entry"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    thread::send -async $thread [list cleanup]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    thread::join $thread
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    array unset env DYLD_INSERT_LIBRARIES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    array unset env DARWINTRACE_LOG
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/threadsetup.tcl b/src/darwintracelib1.0/tests/threadsetup.tcl
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..3cff05b03
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/threadsetup.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,36 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc ui_warn {msg} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   global warnings
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   lappend warnings $msg
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc slave_add_sandbox_violation {path} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   global violations
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   lappend violations $path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc slave_add_sandbox_unknown {path} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   global unknowns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   lappend unknowns $path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc setup {fifo} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    package require Pextlib 1.0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    global warnings violations unknowns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set warnings [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set violations [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    set unknowns [list]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tracelib setname $fifo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tracelib opensocket
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc run {} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   tracelib run
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+proc cleanup {} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   thread::unwind
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+thread::wait
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/unlink.c b/src/darwintracelib1.0/tests/unlink.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..ddc226082
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/unlink.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,22 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define DARWINTRACE_USE_PRIVATE_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "../darwintrace.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int argc, char* argv[]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (argc < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "Usage: unlink PATH\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (getenv("DARWINTRACE_UNINITIALIZE") != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           __darwintrace_initialized = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (-1 == unlink(argv[1])) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("unlink");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   exit(EXIT_SUCCESS);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/tests/unlink.test b/src/darwintracelib1.0/tests/unlink.test
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 000000000..4156ad1ba
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/tests/unlink.test
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,49 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package require tcltest 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+namespace import tcltest::*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+source "testlib.tcl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test unlink_outside_sandbox "Test that unlink(2) does not work outside of the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -- touch unlinkme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force unlinkme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect [list "$cwd/unlinkme"]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./unlink unlinkme 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result "unlink: No such file or directory"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test unlink_inside_sandbox "Test that unlink(2) works inside the sandbox" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -- touch unlinkme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list allow /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force unlinkme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {exec -ignorestderr -- ./unlink unlinkme 2>@1} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+test unlink_uninitialized "Test that unlink(2) works outside the sandbox if darwintrace is uninitialized" \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -setup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        exec -- touch unlinkme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [setup [list deny /]]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -cleanup {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        file delete -force unlinkme
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        [expect {}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -body {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set ::env(DARWINTRACE_UNINITIALIZE) 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        set output [exec -ignorestderr -- ./unlink unlinkme 2>@1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        unset ::env(DARWINTRACE_UNINITIALIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        return $output
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    -result ""
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+cleanupTests
</span></pre><pre style='margin:0'>

</pre>