[28091] trunk/base/src
source_changes at macosforge.org
source_changes at macosforge.org
Mon Aug 20 07:48:12 PDT 2007
Revision: 28091
http://trac.macosforge.org/projects/macports/changeset/28091
Author: epimenov at macports.org
Date: 2007-08-20 07:48:10 -0700 (Mon, 20 Aug 2007)
Log Message:
-----------
Port trace: dep check, SDK redirect
Modified Paths:
--------------
trunk/base/src/darwintracelib1.0/darwintrace.c
trunk/base/src/pextlib1.0/tracelib.c
trunk/base/src/pextlib1.0/tracelib.h
trunk/base/src/port1.0/porttrace.tcl
trunk/base/src/port1.0/portutil.tcl
Modified: trunk/base/src/darwintracelib1.0/darwintrace.c
===================================================================
--- trunk/base/src/darwintracelib1.0/darwintrace.c 2007-08-20 13:11:37 UTC (rev 28090)
+++ trunk/base/src/darwintracelib1.0/darwintrace.c 2007-08-20 14:48:10 UTC (rev 28091)
@@ -443,6 +443,23 @@
}
/*
+ * return 1 if path is directory or not exists
+ * return 0 otherwise
+ */
+static int is_directory(const char * path)
+{
+#define stat(path, sb) syscall(SYS_stat, path, sb)
+ struct stat s;
+ if(stat(path, &s)==-1)
+ /* Actually is not directory, but anyway, we shouldn't test a dependency unless file exists */
+ return 1;
+
+ return S_ISDIR(s.st_mode);
+#undef stat
+}
+
+
+/*
* return 1 if path allowed, 0 otherwise
*/
static int ask_for_dependency(char * path)
@@ -450,9 +467,12 @@
char buffer[BUFFER_SIZE], *p;
int result=0;
+ if(is_directory(path))
+ return 1;
+
strcpy(buffer, "dep_check\t");
strcat(buffer, path);
- p=exchange_with_port(buffer, strlen(buffer), 1);
+ p=exchange_with_port(buffer, strlen(buffer)+1, 1);
if((int)p==-1||!p)
return 0;
@@ -504,6 +524,10 @@
int result=-1;
__darwintrace_setup();
+
+ if(!filemap)
+ return 1;
+
if(*path=='/')
p=strdup(path);
else
@@ -516,15 +540,14 @@
strncpy(_, path, BUFFER_SIZE-(_-p));
}
__darwintrace_cleanup_path(p);
- if(!filemap)
- return 1;
+
do
{
for(t=filemap; *t;)
{
if(__darwintrace_strbeginswith(p, t))
{
- t+=strlen(t);
+ t+=strlen(t)+1;
switch(*t)
{
case 0:
@@ -536,7 +559,7 @@
result=0;
break;
}
- strcpy(newpath, p+1);
+ strcpy(newpath, t+1);
_=newpath+strlen(newpath);
if(_[-1]!='/')
*_++='/';
@@ -581,6 +604,9 @@
mode_t mode;
int result;
va_list args;
+ struct stat sb;
+ char newpath[MAXPATHLEN];
+ int isInSandbox;
/* Why mode here ? */
va_start(args, flags);
@@ -588,10 +614,9 @@
va_end(args);
result = 0;
- if (flags & (O_CREAT | O_APPEND | O_RDWR | O_WRONLY | O_TRUNC)) {
- char newpath[MAXPATHLEN];
- int isInSandbox;
-
+
+ if((stat(path, &sb)!=-1 && !(sb.st_mode&S_IFDIR)) || flags & O_CREAT )
+ {
*newpath=0;
__darwintrace_setup();
isInSandbox = __darwintrace_is_in_sandbox(path, newpath);
@@ -641,10 +666,8 @@
#define __execve(x,y,z) syscall(SYS_execve, (x), (y), (z))
#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
#define close(x) syscall(SYS_close, (x))
+#define lstat(x, y) syscall(SYS_lstat, (x), (y))
int result;
-#if DARWINTRACE_SHOW_PROCESS
- int saved_pid;
-#endif
__darwintrace_setup();
if (__darwintrace_fd >= 0) {
struct stat sb;
@@ -663,8 +686,18 @@
fd = open(path, O_RDONLY, 0);
if (fd > 0) {
- char buffer[MAXPATHLEN+1];
+ char buffer[MAXPATHLEN+1], newpath[MAXPATHLEN+1];
ssize_t bytes_read;
+
+ *newpath=0;
+ if(__darwintrace_is_in_sandbox(path, newpath)==0)
+ {
+ close(fd);
+ errno=ENOENT;
+ return -1;
+ }
+ if(*newpath)
+ path=newpath;
/* once we have an open fd, if a full path was requested, do it */
__darwintrace_log_op("execve", path, fd);
@@ -706,6 +739,7 @@
/* call the original execve function, but fix the environment if required. */
result = __execve(path, argv, __darwintrace_restore_env(envp));
return result;
+#undef lstat
#undef close
#undef open
#undef execve
@@ -726,7 +760,6 @@
#undef close
}
-#if DARWINTRACE_SANDBOX
/* Trap attempts to unlink a file outside the sandbox.
*/
int unlink(const char* path) {
@@ -748,9 +781,7 @@
return result;
}
-#endif
-#if DARWINTRACE_SANDBOX
/* Trap attempts to create directories outside the sandbox.
*/
int mkdir(const char* path, mode_t mode) {
@@ -780,9 +811,7 @@
return result;
}
-#endif
-#if DARWINTRACE_SANDBOX
/* Trap attempts to remove directories outside the sandbox.
*/
int rmdir(const char* path) {
@@ -804,9 +833,7 @@
return result;
}
-#endif
-#if DARWINTRACE_SANDBOX
/* Trap attempts to rename files/directories outside the sandbox.
*/
int rename(const char* from, const char* to) {
@@ -840,4 +867,49 @@
return result;
}
-#endif
+
+int stat(const char * path, struct stat * sb)
+{
+#define stat(path, sb) syscall(SYS_stat, path, sb)
+ int result=0;
+ char newpath[260];
+
+ *newpath=0;
+ if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
+ {
+ errno=ENOENT;
+ result=-1;
+ }else
+ {
+ if(*newpath)
+ path=newpath;
+
+ result=stat(path, sb);
+ }
+
+ return result;
+#undef stat
+}
+
+int lstat(const char * path, struct stat * sb)
+{
+#define stat(path, sb) syscall(SYS_lstat, path, sb)
+ int result=0;
+ char newpath[260];
+
+ *newpath=0;
+ if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
+ {
+ errno=ENOENT;
+ result=-1;
+ }else
+ {
+ if(*newpath)
+ path=newpath;
+
+ result=stat(path, sb);
+ }
+
+ return result;
+#undef stat
+}
\ No newline at end of file
Modified: trunk/base/src/pextlib1.0/tracelib.c
===================================================================
--- trunk/base/src/pextlib1.0/tracelib.c 2007-08-20 13:11:37 UTC (rev 28090)
+++ trunk/base/src/pextlib1.0/tracelib.c 2007-08-20 14:48:10 UTC (rev 28091)
@@ -50,14 +50,24 @@
static char * filemap, * filemap_end;
static char * depends;
static int sock=-1;
+static int enable_fence=0;
static Tcl_Interp * interp;
static pthread_mutex_t sock_mutex=PTHREAD_MUTEX_INITIALIZER;
static int cleanuping=0;
+static char * sdk=
+#ifdef TRACE_SDK
+ /*"MacOSX10.4u.sdk"*/
+ TRACE_SDK
+#else
+ 0
+#endif
+;
static void send_file_map(int sock);
static void dep_check(int sock, const char * path);
static void sandbox_violation(int sock, const char * path);
static void ui_warn(const char * format, ...);
+static void ui_info(const char * format, ...);
#define MAX_SOCKETS ((FD_SETSIZE)-1)
@@ -112,27 +122,6 @@
}
/*
- * Check if file in sandbox or not
- * Return:
- * 0 - not in sandbox
- * 1 - in sandbox
- */
-static char is_in_sandbox(char * file)
-{
- char * t;
- int flen=strlen(file);
-
- for(t=sandbox; *t; t+=strlen(t)+1)
- {
- int tlen=strlen(t);
- if(!strncmp(file, t, tlen<flen?tlen:flen))
- return 1;
- }
- return 0;
-}
-
-
-/*
* receive line from socket, parse it and send answer
*/
static char process_line(int sock)
@@ -146,11 +135,14 @@
return 0;
buf[len]=0;
/* sometimes two messages come in one recv.. I ain't caring about it now, but it can be a problem */
- for(t=buf;*t&&t-buf<sizeof(buf);t+=strlen(f)+1)
+ for(t=buf;*t&&t-buf<(int)sizeof(buf);t=f+strlen(f)+1)
{
f=strchr(t, '\t');
if(!f)
+ {
+ ui_warn("malformed command %s", t);
break;
+ }
*f++=0;
if(!strcmp(t, "filemap"))
{
@@ -176,24 +168,44 @@
static void send_file_map(int sock)
{
- /*
- * TODO: redirect for SDK here
- * TODO: /opt -> path from config
- */
if(!filemap)
{
- char * t;
- char * _;
+ char * t, * _;
filemap=(char*)malloc(1024);
t=filemap;
#define append_allow(path, resolution) do{strcpy(t, path); t+=strlen(t)+1; *t++=resolution; *t++=0;}while(0);
- for(_=sandbox; *_; _+=strlen(_)+1)
- append_allow(_, 0);
- append_allow("/opt", 2);
- /*Allow /usr for now*/
- append_allow("/usr", 0);
+ if(enable_fence)
+ {
+ for(_=sandbox; *_; _+=strlen(_)+1)
+ append_allow(_, 0);
+
+ append_allow("/bin", 0);
+ append_allow("/sbin", 0);
+ append_allow("/dev", 0)
+ append_allow(Tcl_GetVar(interp, "macports::prefix", TCL_GLOBAL_ONLY), 2);
+ /* If there is no SDK we will allow everything in /usr /System/Library etc, else add binaries to allow, and redirect root to SDK. */
+ if(sdk&&*sdk)
+ {
+ char buf[260]="/Developer/SDKs/";
+ strcat(buf, sdk);
+
+ append_allow("/usr/bin", 0);
+ append_allow("/usr/sbin", 0);
+ append_allow("/usr/libexec/gcc", 0);
+ append_allow("/", 1);
+ strcpy(t-1, buf);
+ t+=strlen(t)+1;
+ }else
+ {
+ append_allow("/usr", 0);
+ append_allow("/System/Library", 0);
+ append_allow("/Library", 0);
+ append_allow("/Developer/Headers", 0);
+ }
+ }else
+ append_allow("/", 0);
filemap_end=t;
#undef append_allow
}
@@ -205,32 +217,90 @@
}
}
-static void sandbox_violation(int sock, const char * path)
+static void sandbox_violation(int sock UNUSED, const char * path)
{
- char buf[1024];
- sprintf(buf, "slave_add_sandbox_violation {%s}", path);
- Tcl_Eval(interp, buf);
+ Tcl_SetVar(interp, "path", path, 0);
+ Tcl_Eval(interp, "slave_add_sandbox_violation $path");
+ Tcl_UnsetVar(interp, "path", 0);
}
static void dep_check(int sock, const char * path)
{
+ char * port=0;
size_t len=1;
- send(sock, &len, sizeof(len), 0);
- send(sock, "+", 1, 0);
+ char resolution;
+
+ /* If there aren't deps then allow anything. (Useful for extract) */
+ if(!depends)
+ resolution='+';
+ else
+ {
+ resolution='!';
+
+ Tcl_SetVar(interp, "path", path, 0);
+ Tcl_Eval(interp, "registry::file_registered $path");
+ port=strdup(Tcl_GetStringResult(interp));
+ Tcl_UnsetVar(interp, "path", 0);
+
+ if(*port!='0'||port[1])
+ {
+ char * t;
+
+ t=depends;
+ for(;*t;t+=strlen(t)+1)
+ {
+ if(!strcmp(t, port))
+ {
+ resolution='+';
+ break;
+ }
+ }
+ }
+ }
+
+ if(resolution!='+')
+ ui_info("trace: access denied to %s (%s)", path, port);
+
+ if(port)
+ free(port);
+
+ if(send(sock, &len, sizeof(len), 0)==-1)
+ ui_warn("tracelib send failed");
+ if(send(sock, &resolution, 1, 0)==-1)
+ ui_warn("tracelib send failed");
}
+static void ui_msg(const char * severity, const char * format, va_list va)
+{
+ char buf[1024], tclcmd[32];
+
+ vsprintf(buf, format, va);
+
+ sprintf(tclcmd, "ui_%s $warn", severity);
+
+ Tcl_SetVar(interp, "warn", buf, 0);
+
+ Tcl_Eval(interp, tclcmd);
+ Tcl_UnsetVar(interp, "warn", 0);
+
+}
+
static void ui_warn(const char * format, ...)
{
- char buf[1024];
va_list va;
- strcpy(buf, "ui_warn {");
va_start(va, format);
- vsprintf(buf+strlen(buf), format, va);
+ ui_msg("warn", format, va);
va_end(va);
- strcat(buf, "}");
+}
+
+static void ui_info(const char * format, ...)
+{
+ va_list va;
- Tcl_Eval(interp, buf);
+ va_start(va, format);
+ ui_msg("msg", format, va);
+ va_end(va);
}
static int TracelibRunCmd(Tcl_Interp * in)
@@ -257,6 +327,7 @@
{
ui_warn("setrlimit failed (%d)", errno);
}
+
sun.sun_family=AF_UNIX;
strcpy(sun.sun_path, name);
@@ -311,7 +382,10 @@
if(i==max_used)
{
if(max_used==MAX_SOCKETS-1)
+ {
+ ui_warn("There is no place to store socket");
close(s);
+ }
else
socks[max_used++]=s;
}
@@ -352,7 +426,7 @@
pthread_mutex_lock(&sock_mutex);
if(sock!=-1)
{
- shutdown(sock, SHUT_RDWR);
+ /* shutdown(sock, SHUT_RDWR);*/
close(sock);
sock=-1;
}
@@ -364,6 +438,7 @@
}
if(filemap)
safe_free(filemap);
+ enable_fence=0;
#undef safe_free
cleanuping=0;
return TCL_OK;
@@ -375,7 +450,7 @@
pthread_mutex_lock(&sock_mutex);
if(sock!=-1)
{
- shutdown(sock, SHUT_RDWR);
+ /*shutdown(sock, SHUT_RDWR);*/
close(sock);
sock=-1;
}
@@ -383,17 +458,50 @@
return TCL_OK;
}
+static int TracelibSetDeps(Tcl_Interp * interp UNUSED, int objc, Tcl_Obj* CONST objv[])
+{
+ char * t, * d;
+ size_t l;
+ if(objc!=3)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "number of arguments should be exactly 3");
+ return TCL_ERROR;
+ }
+
+ d=Tcl_GetString(objv[2]);
+ l=strlen(d);
+ depends=malloc(l+2);
+ depends[l+1]=0;
+ strcpy(depends, d);
+ for(t=depends;*t;++t)
+ if(*t==' ')
+ *t++=0;
+
+ return TCL_OK;
+}
+
+static int TracelibEnableFence(Tcl_Interp * interp UNUSED)
+{
+ enable_fence=1;
+ if(filemap)
+ free(filemap);
+ filemap=0;
+ return TCL_OK;
+}
+
int TracelibCmd(ClientData clientData UNUSED, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[])
{
int result=TCL_OK;
- static const char * options[]={"setname", "run", "clean", "setsandbox", "closesocket", 0};
+ static const char * options[]={"setname", "run", "clean", "setsandbox", "closesocket", "setdeps", "enablefence", 0};
typedef enum
{
kSetName,
kRun,
kClean,
kSetSandbox,
- kCloseSocket
+ kCloseSocket,
+ kSetDeps,
+ kEnableFence
} EOptions;
EOptions current_option;
@@ -424,6 +532,12 @@
case kSetSandbox:
result=TracelibSetSandboxCmd(interp, objc, objv);
break;
+ case kSetDeps:
+ result=TracelibSetDeps(interp, objc, objv);
+ break;
+ case kEnableFence:
+ result=TracelibEnableFence(interp);
+ break;
}
}
Modified: trunk/base/src/pextlib1.0/tracelib.h
===================================================================
--- trunk/base/src/pextlib1.0/tracelib.h 2007-08-20 13:11:37 UTC (rev 28090)
+++ trunk/base/src/pextlib1.0/tracelib.h 2007-08-20 14:48:10 UTC (rev 28091)
@@ -48,6 +48,14 @@
* - run select, create a socket
* tracelib clean
* - cleanup everything
+ * tracelib setsandbox
+ * - set sandbox bounds
+ * tracelib closesocket
+ * - close socket. This makes main thread to quit from it's loop
+ * tracelib setdeps
+ * - set deps for current port
+ * tracelib enablefence
+ * - enable dep/sandbox checking
*/
int TracelibCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]);
Modified: trunk/base/src/port1.0/porttrace.tcl
===================================================================
--- trunk/base/src/port1.0/porttrace.tcl 2007-08-20 13:11:37 UTC (rev 28090)
+++ trunk/base/src/port1.0/porttrace.tcl 2007-08-20 14:48:10 UTC (rev 28091)
@@ -45,7 +45,7 @@
# Create a fifo.
# path in unix socket limited to 109 chars
# # set trace_fifo "$workpath/trace_fifo"
- set trace_fifo "/tmp/macports/[pid]"
+ set trace_fifo "/tmp/macports/[pid]_[expr {int(rand()*1000)}]"
file mkdir "/tmp/macports"
file delete -force $trace_fifo
@@ -86,7 +86,8 @@
# Only done for targets that should only happen in the sandbox.
proc trace_enable_fence {} {
global env trace_sandboxbounds
- set env(DARWINTRACE_SANDBOX_BOUNDS) $trace_sandboxbounds
+ set env(DARWINTRACE_SANDBOX_BOUNDS) $trace_sandboxbounds
+ tracelib enablefence
}
# Disable the fence.
Modified: trunk/base/src/port1.0/portutil.tcl
===================================================================
--- trunk/base/src/port1.0/portutil.tcl 2007-08-20 13:11:37 UTC (rev 28090)
+++ trunk/base/src/port1.0/portutil.tcl 2007-08-20 14:48:10 UTC (rev 28091)
@@ -1095,7 +1095,15 @@
# otherwise execute the task.
if {$skipped == 0} {
set target [ditem_key $ditem provides]
- if {([info exists ports_trace]
+
+ # Execute pre-run procedure
+ if {[ditem_contains $ditem prerun]} {
+ set result [catch {[ditem_key $ditem prerun] $name} errstr]
+ }
+
+ #start tracelib
+ if {($result ==0
+ && [info exists ports_trace]
&& $ports_trace == "yes"
&& $target != "clean")} {
trace_start $workpath
@@ -1108,49 +1116,8 @@
&& $target != "install"} {
trace_enable_fence
}
- }
-
- # Execute pre-run procedure
- if {[ditem_contains $ditem prerun]} {
- set result [catch {[ditem_key $ditem prerun] $name} errstr]
- }
- if {$result == 0} {
- foreach pre [ditem_key $ditem pre] {
- ui_debug "Executing $pre"
- set result [catch {$pre $name} errstr]
- if {$result != 0} { break }
- }
- }
-
- if {$result == 0} {
- ui_debug "Executing $name ($portname)"
- set result [catch {$procedure $name} errstr]
- }
-
- if {$result == 0} {
- foreach post [ditem_key $ditem post] {
- ui_debug "Executing $post"
- set result [catch {$post $name} errstr]
- if {$result != 0} { break }
- }
- }
- # Execute post-run procedure
- if {[ditem_contains $ditem postrun] && $result == 0} {
- set postrun [ditem_key $ditem postrun]
- ui_debug "Executing $postrun"
- set result [catch {$postrun $name} errstr]
- }
-
- # *** move it to good position
- # Why do we need it? It closes socket, and exit from our C thread
- tracelib closesocket
- # ***
-
- # Check dependencies & file creations outside workpath.
- if {[info exists ports_trace]
- && $ports_trace == "yes"
- && $target != "clean"} {
+ # collect deps
# Don't check dependencies for extract (they're not honored
# anyway). This avoids warnings about bzip2.
@@ -1192,9 +1159,50 @@
set dep_portname [lindex [split $depspec :] end]
lappend depsPorts $dep_portname
}
- trace_check_deps $target $depsPorts
+
+ set portlist [recursive_collect_deps $portname $deptypes]
+ #uniquer from http://aspn.activestate.com/ASPN/Cookbook/Tcl/Recipe/147663
+ array set a [split "[join $portlist {::}]:" {:}]
+ set depsPorts [array names a]
+
+ if {[llength $deptypes] > 0} {tracelib setdeps $depsPorts}
}
+ }
+
+ if {$result == 0} {
+ foreach pre [ditem_key $ditem pre] {
+ ui_debug "Executing $pre"
+ set result [catch {$pre $name} errstr]
+ if {$result != 0} { break }
+ }
+ }
+
+ if {$result == 0} {
+ ui_debug "Executing $name ($portname)"
+ set result [catch {$procedure $name} errstr]
+ }
+
+ if {$result == 0} {
+ foreach post [ditem_key $ditem post] {
+ ui_debug "Executing $post"
+ set result [catch {$post $name} errstr]
+ if {$result != 0} { break }
+ }
+ }
+ # Execute post-run procedure
+ if {[ditem_contains $ditem postrun] && $result == 0} {
+ set postrun [ditem_key $ditem postrun]
+ ui_debug "Executing $postrun"
+ set result [catch {$postrun $name} errstr]
+ }
+
+ # Check dependencies & file creations outside workpath.
+ if {[info exists ports_trace]
+ && $ports_trace == "yes"
+ && $target!="clean"} {
+ tracelib closesocket
+
trace_check_violations
# End of trace.
@@ -1225,6 +1233,38 @@
return $result
}
+# recursive found depends for portname
+# It isn't ideal, because it scan many ports multiple time
+proc recursive_collect_deps {portname deptypes} \
+{
+ set res [mport_search ^$portname\$]
+ if {[llength $res] < 2} \
+ {
+ return {}
+ }
+
+ set depends {}
+
+ array set portinfo [lindex $res 1]
+ foreach deptype $deptypes \
+ {
+ if {[info exists portinfo($deptype)] && $portinfo($deptype) != ""} \
+ {
+ set depends [concat $depends $portinfo($deptype)]
+ }
+ }
+
+ set portdeps {}
+ foreach depspec $depends \
+ {
+ set portname [lindex [split $depspec :] end]
+ lappend portdeps $portname
+ set portdeps [concat $portdeps [recursive_collect_deps $portname $deptypes]]
+ }
+ return $portdeps
+}
+
+
proc eval_targets {target} {
global targets target_state_fd portname
set dlist $targets
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-changes/attachments/20070820/0289d6d7/attachment.html
More information about the macports-changes
mailing list