[26682] trunk/base/src

source_changes at macosforge.org source_changes at macosforge.org
Tue Jul 3 10:42:36 PDT 2007


Revision: 26682
          http://trac.macosforge.org/projects/macports/changeset/26682
Author:   epimenov at macports.org
Date:     2007-07-03 10:42:36 -0700 (Tue, 03 Jul 2007)

Log Message:
-----------
Trace lib on unix sockets. No dep check for now.

Modified Paths:
--------------
    trunk/base/src/darwintracelib1.0/darwintrace.c
    trunk/base/src/pextlib1.0/Makefile
    trunk/base/src/pextlib1.0/Pextlib.c
    trunk/base/src/port1.0/porttrace.tcl
    trunk/base/src/port1.0/portutil.tcl

Added Paths:
-----------
    trunk/base/src/pextlib1.0/tracelib.c
    trunk/base/src/pextlib1.0/tracelib.h

Modified: trunk/base/src/darwintracelib1.0/darwintrace.c
===================================================================
--- trunk/base/src/darwintracelib1.0/darwintrace.c	2007-07-03 15:21:03 UTC (rev 26681)
+++ trunk/base/src/darwintracelib1.0/darwintrace.c	2007-07-03 17:42:36 UTC (rev 26682)
@@ -57,6 +57,8 @@
 #include <sys/param.h>
 #include <sys/syscall.h>
 #include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 
 #ifndef HAVE_STRLCPY
 /* Define strlcpy if it's not available. */
@@ -119,33 +121,34 @@
  * Prototypes.
  */
 inline int __darwintrace_strbeginswith(const char* str, const char* prefix);
-inline void __darwintrace_log_op(const char* op, const char* procname, const char* path, int fd);
+inline void __darwintrace_log_op(const char* op, const char* path, int fd);
 void __darwintrace_copy_env() __attribute__((constructor));
 inline char* __darwintrace_alloc_env(const char* varName, const char* varValue);
 inline char* const* __darwintrace_restore_env(char* const envp[]);
 inline void __darwintrace_setup();
 inline void __darwintrace_cleanup_path(char *path);
+static char * exchange_with_port(const char * buf, size_t len, int answer);
 
 #define START_FD 81
-static int __darwintrace_fd = -2;
+static int __darwintrace_fd = -1;
 #define BUFFER_SIZE	1024
-#if DARWINTRACE_SHOW_PROCESS
-static char __darwintrace_progname[BUFFER_SIZE];
-static pid_t __darwintrace_pid = -1;
-#endif
-#if DARWINTRACE_SANDBOX
-static char** __darwintrace_sandbox_bounds = NULL;
-#endif
 
+/**
+ * filemap: path\0whattodo\0path\0whattodo\0\0
+ * path: begin of path (for example /opt)
+ * whattodo: 
+ *   0     -- allow
+ *   1PATH -- map 
+ *   2     -- ask for allow
+**/
+static char * filemap=0;
+
 /* copy of the global variables */
 static char* __env_dyld_insert_libraries;
 static char* __env_dyld_force_flat_namespace;
 static char* __env_darwintrace_log;
-#if DARWINTRACE_SANDBOX
-static char* __env_darwintrace_sandbox_bounds;
-#endif
 
-#if __STDC_VERSION__==199901L
+#if __STDC_VERSION__>=199901L
 #if DARWINTRACE_DEBUG_OUTPUT
 #define dprintf(...) fprintf(stderr, __VA_ARGS__)
 #else
@@ -160,6 +163,34 @@
 #endif
 
 /*
+ * char wait_for_socket(int sock, char w)
+ * Function used for read/write operation to socket...
+ * Args:
+ *  sock - socket 
+ *  w - what should socket do in next operation. 1 for write, 0 for read
+ * Return value: 
+ *  1 - everything is ok, we can read/write to/from it
+ *  0 - something's went wrong
+ */
+static int wait_for_socket(int sock, char w)
+{
+	struct timeval tv;
+	fd_set fds;
+	
+	if(sock==-1)
+		return 0;
+	
+	tv.tv_sec=10;
+	tv.tv_usec=0;
+	FD_ZERO(&fds);
+	FD_SET(sock, &fds);
+	if(select(sock+1, (w==0 ? &fds : 0), (w==1 ? &fds : 0), 0, &tv)<1)
+		return 0;
+	return FD_ISSET(sock, &fds)!=0;
+}
+
+
+/*
  * return 0 if str doesn't begin with prefix, 1 otherwise.
  */
 inline int __darwintrace_strbeginswith(const char* str, const char* prefix) {
@@ -195,14 +226,6 @@
 	} else {
 		__env_darwintrace_log = NULL;
 	}
-#if DARWINTRACE_SANDBOX
-	theValue = getenv("DARWINTRACE_SANDBOX_BOUNDS");
-	if (theValue != NULL) {
-		__env_darwintrace_sandbox_bounds = strdup(theValue);
-	} else {
-		__env_darwintrace_sandbox_bounds = NULL;
-	}
-#endif
 }
 
 /*
@@ -243,12 +266,6 @@
 		__darwintrace_alloc_env(
 			"DARWINTRACE_LOG",
 			__env_darwintrace_log);
-#if DARWINTRACE_SANDBOX
-	char* darwintrace_sandbox_bounds_ptr =	
-		__darwintrace_alloc_env(
-			"DARWINTRACE_SANDBOX_BOUNDS",
-			__env_darwintrace_sandbox_bounds);
-#endif
 
 	char* const * theEnvIter = envp;
 	int theEnvLength = 0;
@@ -276,11 +293,6 @@
 		} else if (__darwintrace_strbeginswith(theValue, "DARWINTRACE_LOG=")) {
 			theValue = darwintrace_log_ptr;
 			darwintrace_log_ptr = NULL;
-#if DARWINTRACE_SANDBOX
-		} else if (__darwintrace_strbeginswith(theValue, "DARWINTRACE_SANDBOX_BOUNDS=")) {
-			theValue = darwintrace_sandbox_bounds_ptr;
-			darwintrace_sandbox_bounds_ptr = NULL;
-#endif
 		}
 		
 		if (theValue) {
@@ -299,121 +311,48 @@
 	if (darwintrace_log_ptr) {
 		*theCopyIter++ = darwintrace_log_ptr;
 	}
-#if DARWINTRACE_SANDBOX
-	if (darwintrace_sandbox_bounds_ptr) {
-		*theCopyIter++ = darwintrace_sandbox_bounds_ptr;
-	}
-#endif
 
 	*theCopyIter = 0;
 	
 	return theCopy;
 }
 
+static void ask_for_filemap()
+{
+	filemap=exchange_with_port("filemap\t", sizeof("filemap\t"), 1);
+	if((int)filemap==-1)
+		filemap=0;
+}
+
 inline void __darwintrace_setup() {
 #define open(x,y,z) syscall(SYS_open, (x), (y), (z))
 #define close(x) syscall(SYS_close, (x))
-	if (__darwintrace_fd == -2) {
+	if (__darwintrace_fd == -1) {
 		if (__env_darwintrace_log != NULL) {
 			int olderrno = errno;
-			int fd = open(__env_darwintrace_log, O_CREAT | O_WRONLY | O_APPEND, DEFFILEMODE);
-			int newfd;
-			for(newfd = START_FD; newfd < START_FD + 21; newfd++) {
-				if(-1 == write(newfd, "", 0) && errno == EBADF) {
-					if(-1 != dup2(fd, newfd)) {
-						__darwintrace_fd = newfd;
-					}
-					close(fd);
-					fcntl(__darwintrace_fd, F_SETFD, 1); /* close-on-exec */
-					break;
-				}
-			}
+			int sock=socket(AF_UNIX, SOCK_STREAM, 0);
+			struct sockaddr_un sun;
+			sun.sun_family=AF_UNIX;
+			strcpy(sun.sun_path, __env_darwintrace_log);
+			if(connect(sock, (struct sockaddr*)&sun, strlen(__env_darwintrace_log)+1+sizeof(sun.sun_family))!=-1)
+			{
+				dprintf("darwintrace: connect successful. socket %d\n", sock);
+				__darwintrace_fd=sock;
+				ask_for_filemap();
+			}else dprintf("connect failed %d :-(\n", errno);
 			errno = olderrno;
 		}
 	}
-#if DARWINTRACE_SHOW_PROCESS
-	if (__darwintrace_pid == -1) {
-		char** progname = _NSGetProgname();
-		__darwintrace_pid = getpid();
-		if (progname && *progname) {
-			strcpy(__darwintrace_progname, *progname);
-		}
-	}
-#endif
-#if DARWINTRACE_SANDBOX
-	if (__darwintrace_sandbox_bounds == NULL) {
-		if (__env_darwintrace_sandbox_bounds != NULL) {
-			/* copy the string */
-			char* copy = strdup(__env_darwintrace_sandbox_bounds);
-			if (copy != NULL) {
-				int nbPaths = 1;
-				int nbAllocatedPaths = 5;
-				char** paths = (char**) malloc(sizeof(char*) * nbAllocatedPaths);
-				char* crsr = copy;
-				char** pathsCrsr = paths;
-				/* first path */
-				*pathsCrsr++ = crsr;
-				/* parse the paths (modify the copy) */
-				do {
-					char theChar = *crsr;
-					if (theChar == '\0') {
-						/* the end of the paths */
-						break;
-					}
-					if (theChar == ':') {
-						/* the end of this path */
-						*crsr = 0;
-						nbPaths++;
-						if (nbPaths == nbAllocatedPaths) {
-							nbAllocatedPaths += 5;
-							paths = (char**) realloc(paths, sizeof(char*) * nbAllocatedPaths);
-							/* reset the cursor in case paths pointer was moved */
-							pathsCrsr = paths + (nbPaths - 1);
-						}
-						*pathsCrsr++ = crsr + 1;
-					}
-					if (theChar == '\\') {
-						/* escape character. test next char */
-						char nextChar = crsr[1];
-						if (nextChar == '\\') {
-							/* rewrite the string */
-							char* rewriteCrsr = crsr + 1;
-							do {
-								char theChar = *rewriteCrsr;
-								rewriteCrsr[-1] = theChar;
-								rewriteCrsr++;
-							} while (theChar != 0);
-						} else if (nextChar == ':') {
-							crsr++;
-						}
-						/* otherwise, ignore (keep the backslash) */
-					}
-					
-					/* next char */
-					crsr++;
-				} while (1);
-				/* null terminate the array */
-				*pathsCrsr = 0;
-				/* resize and save it */
-				__darwintrace_sandbox_bounds = (char**) realloc(paths, sizeof(char*) * (nbPaths + 1));
-			}
-		}
-	}
-#endif
 #undef close
 #undef open
 }
 
 /* log a call and optionally get the real path from the fd if it's not 0.
  * op:			the operation (open, readlink, execve)
- * procname:	the name of the process (can be NULL)
  * path:		the path of the file
  * fd:			a fd to the file, or 0 if we don't have any.
  */
-inline void __darwintrace_log_op(const char* op, const char* procname, const char* path, int fd) {
-#if !DARWINTRACE_SHOW_PROCESS
-	#pragma unused(procname)
-#endif
+inline void __darwintrace_log_op(const char* op, const char* path, int fd) {
 	int size;
 	char somepath[MAXPATHLEN];
 	char logbuffer[BUFFER_SIZE];
@@ -446,17 +385,12 @@
 	__darwintrace_cleanup_path(somepath);
 
 	size = snprintf(logbuffer, sizeof(logbuffer),
-#if DARWINTRACE_SHOW_PROCESS
-		"%s[%d]\t"
-#endif
-		"%s\t%s\n",
-#if DARWINTRACE_SHOW_PROCESS
-		procname ? procname : __darwintrace_progname, __darwintrace_pid,
-#endif
+		"%s\t%s",
 		op, somepath );
 
-	write(__darwintrace_fd, logbuffer, size);
-	fsync(__darwintrace_fd);
+	exchange_with_port(logbuffer, size+1, 0);
+	
+	return;
 }
 
 /* remap resource fork access to the data fork.
@@ -508,36 +442,129 @@
   dprintf("darwintrace: cleanup resulted in %s\n", path);
 }
 
-#if DARWINTRACE_SANDBOX
 /*
- * return 1 if path (once normalized) is in sandbox, 0 otherwise.
- * return -1 if no sandbox is defined or if the path couldn't be normalized.
+ * return 1 if path allowed, 0 otherwise
  */
-inline int __darwintrace_is_in_sandbox(const char* path) {
-	int result = -1; /* no sandbox is defined */
+static int ask_for_dependency(char * path)
+{
+	char buffer[BUFFER_SIZE], *p;
+	int result=0;
+	
+	strcpy(buffer, "dep_check\t");
+	strcat(buffer, path);
+	p=exchange_with_port(buffer, strlen(buffer), 1);
+	if((int)p==-1||!p)
+		return 0;
+	
+	if(*p=='+')
+		result=1;
+	
+	free(p);
+	return result;
+}
+
+/*
+ * exchange_with_port - routine to send/recv from/to socket
+ * Parameters:
+ *   buf    -- buffer with data to send
+ *   len    -- length of data
+ *   answer -- 1 (yes, I want to receive answer) and 0 (no, thanks, just send)
+ * Return value:
+ *    -1     -- something went wrong
+ *    0      -- data successful sended
+ *    string -- answer (caller shoud free it)
+ */
+static char * exchange_with_port(const char * buf, size_t len, int answer)
+{
+	wait_for_socket(__darwintrace_fd, 1);
+	if(send(__darwintrace_fd, buf, len, 0)==-1)
+		return (char*)-1;
+	if(!answer)
+		return 0;
+	{
+		size_t l=0;
+		char * b;
+		
+		wait_for_socket(__darwintrace_fd, 0);
+		recv(__darwintrace_fd, &l, sizeof(l),0);
+		if(!l)
+			return 0;
+		b=(char*)malloc(l+1);
+		b[l]=0;
+		recv(__darwintrace_fd, b, l, 0);
+		return b;
+	}
+}
+
+/*
+ * return 1 if path (once normalized) is in sandbox or redirected, 0 otherwise.
+ */
+inline int __darwintrace_is_in_sandbox(const char* path, char * newpath) {
+	char * t, * p, * _;
+	int result=-1;
+	
 	__darwintrace_setup();
-	if (__darwintrace_sandbox_bounds != NULL) {
-		/* check the path */
-		char** basePathsCrsr = __darwintrace_sandbox_bounds;
-		char* basepath = *basePathsCrsr++;
-		/* normalize the path */
-		char createpath[MAXPATHLEN];
-		if (realpath(path, createpath) != NULL) {
-			__darwintrace_cleanup_path(createpath);
-			/* say it's outside unless it's proved inside */
-			result = 0;
-			while (basepath != NULL) {
-				if (__darwintrace_strbeginswith(createpath, basepath)) {
-					result = 1;
+	if(*path=='/')
+		p=strdup(path);
+	else
+	{
+		p=(char*)malloc(BUFFER_SIZE);
+		(void) getcwd(p, BUFFER_SIZE-1);
+		_=p+strlen(p)+1;
+		if(_[-1]!='/')
+			*_++='/';
+		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);
+				switch(*t)
+				{
+				case 0:
+					result=1;
 					break;
+				case 1:
+					if(!newpath)
+					{
+						result=0;
+						break;
+					}
+					strcpy(newpath, p+1);
+					_=newpath+strlen(newpath);
+					if(_[-1]!='/')
+						*_++='/';
+					strcpy(_, p);
+					result=1;
+					break;
+				case 2:
+					result=ask_for_dependency(p);
+					break;
 				}
-				basepath = *basePathsCrsr++;;
 			}
-		} /* otherwise, operation will fail anyway */
+			if(result!=-1)
+				break;
+			t+=strlen(t)+1;
+			if(*t==1)
+				t+=strlen(t)+1;
+			else
+				t+=2;
+		}
+		if(result!=-1)
+			break;
+		__darwintrace_log_op("sandbox_violation", path, 0);
+		result=0;
 	}
+	while(0);
+	free(p);
 	return result;
 }
-#endif
 
 /* Log calls to open(2) into the file specified by DARWINTRACE_LOG.
    Only logs if the DARWINTRACE_LOG environment variable is set.
@@ -555,51 +582,30 @@
 	int result;
 	va_list args;
 
+	/* Why mode here ? */
 	va_start(args, flags);
 	mode = va_arg(args, int);
 	va_end(args);
-#if DARWINTRACE_SANDBOX
+	
 	result = 0;
 	if (flags & (O_CREAT | O_APPEND | O_RDWR | O_WRONLY | O_TRUNC)) {
-		int isInSandbox = __darwintrace_is_in_sandbox(path);
-		if (isInSandbox == 1) {
-			dprintf("darwintrace: creation/writing was allowed at %s\n", path);
-		} else if (isInSandbox == 0) {
-			/* outside sandbox, but sandbox is defined: forbid */
+		char newpath[MAXPATHLEN];
+		int isInSandbox;
+		
+		*newpath=0;
+		__darwintrace_setup();
+		isInSandbox = __darwintrace_is_in_sandbox(path, newpath);
+		if (isInSandbox == 0) {
 			dprintf("darwintrace: creation/writing was forbidden at %s\n", path);
-			__darwintrace_log_op("sandbox_violation", NULL, path, 0);
 			errno = EACCES;
 			result = -1;
 		}
+		if(*newpath)
+			path=newpath;
 	}
 	if (result == 0) {
 		result = open(path, flags, mode);
 	}
-#else
-	result = open(path, flags, mode);
-#endif
-	if (result >= 0) {
-		/* check that it's a file */
-		struct stat sb;
-		fstat(result, &sb);
-		if ((sb.st_mode & S_IFDIR) == 0) {
-			if ((flags & (O_CREAT | O_WRONLY /*O_RDWR*/)) == 0 ) {
-				__darwintrace_setup();
-				if (__darwintrace_fd >= 0) {
-				    dprintf("darwintrace: original open path is %s\n", path);
-					__darwintrace_log_op("open", NULL, path, result);
-				}
-#if DARWINTRACE_LOG_CREATE
-			} else if (flags & O_CREAT) {
-				__darwintrace_setup();
-				if (__darwintrace_fd >= 0) {
-				    dprintf("darwintrace: original create path is %s\n", path);
-					__darwintrace_log_op("create", NULL, path, result);
-				}
-#endif
-			}
-		}
-	}
 	return result;
 #undef open
 }
@@ -615,14 +621,17 @@
 #endif
 #define readlink(x,y,z) syscall(SYS_readlink, (x), (y), (z))
 	ssize_t result;
+	int isInSandbox;
 
 	result = readlink(path, buf, bufsiz);
 	if (result >= 0) {
-	  __darwintrace_setup();
-	  if (__darwintrace_fd >= 0) {
-	    dprintf("darwintrace: original readlink path is %s\n", path);
-		__darwintrace_log_op("readlink", NULL, path, 0);
-	  }
+		__darwintrace_setup();
+		isInSandbox = __darwintrace_is_in_sandbox(path, 0);
+		if (!isInSandbox)
+		{
+			errno=EACCES;
+			result=-1;
+		}
 	}
 	return result;
 #undef readlink
@@ -649,7 +658,7 @@
 
 	    if(S_ISLNK(sb.st_mode)) {
 	      /* for symlinks, print both */
-		  __darwintrace_log_op("execve", NULL, path, 0);
+		  __darwintrace_log_op("execve", path, 0);
 	    }
 		
 		fd = open(path, O_RDONLY, 0);
@@ -658,7 +667,7 @@
 		  ssize_t bytes_read;
 	
 		  /* once we have an open fd, if a full path was requested, do it */
-		  __darwintrace_log_op("execve", NULL, path, fd);
+		  __darwintrace_log_op("execve", path, fd);
 
 		  /* read the file for the interpreter */
 		  bytes_read = read(fd, buffer, MAXPATHLEN);
@@ -684,19 +693,14 @@
 			}
 			/* we have liftoff */
 			if (interp && interp[0] != '\0') {
-			  const char* procname = NULL;
-#if DARWINTRACE_SHOW_PROCESS
-			  procname = strrchr(argv[0], '/') + 1;
-			  if (procname == NULL) {
-				procname = argv[0];
-			  }
-#endif
-			  __darwintrace_log_op("execve", procname, interp, 0);
+			  __darwintrace_log_op("execve", interp, 0);
 			}
 		  }
 		  close(fd);
 		}
 	  }
+	close(__darwintrace_fd);
+	__darwintrace_fd=-1;
 	}
 	
 	/* call the original execve function, but fix the environment if required. */
@@ -728,13 +732,12 @@
 int unlink(const char* path) {
 #define __unlink(x) syscall(SYS_unlink, (x))
 	int result = 0;
-	int isInSandbox = __darwintrace_is_in_sandbox(path);
+	int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
 	if (isInSandbox == 1) {
 		dprintf("darwintrace: unlink was allowed at %s\n", path);
 	} else if (isInSandbox == 0) {
 		/* outside sandbox, but sandbox is defined: forbid */
 		dprintf("darwintrace: unlink was forbidden at %s\n", path);
-		__darwintrace_log_op("sandbox_violation", NULL, path, 0);
 		errno = EACCES;
 		result = -1;
 	}
@@ -753,7 +756,7 @@
 int mkdir(const char* path, mode_t mode) {
 #define __mkdir(x,y) syscall(SYS_mkdir, (x), (y))
 	int result = 0;
-	int isInSandbox = __darwintrace_is_in_sandbox(path);
+	int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
 	if (isInSandbox == 1) {
 		dprintf("darwintrace: mkdir was allowed at %s\n", path);
 	} else if (isInSandbox == 0) {
@@ -765,7 +768,6 @@
 		if ((err == -1) && (errno == ENOENT))
 		{
 			dprintf("darwintrace: mkdir was forbidden at %s\n", path);
-			__darwintrace_log_op("sandbox_violation", NULL, path, 0);
 			errno = EACCES;
 			result = -1;
 		} /* otherwise, mkdir will do nothing (directory exists) or fail
@@ -786,13 +788,12 @@
 int rmdir(const char* path) {
 #define __rmdir(x) syscall(SYS_rmdir, (x))
 	int result = 0;
-	int isInSandbox = __darwintrace_is_in_sandbox(path);
+	int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
 	if (isInSandbox == 1) {
 		dprintf("darwintrace: rmdir was allowed at %s\n", path);
 	} else if (isInSandbox == 0) {
 		/* outside sandbox, but sandbox is defined: forbid */
 		dprintf("darwintrace: removing directory %s was forbidden\n", path);
-		__darwintrace_log_op("sandbox_violation", NULL, path, 0);
 		errno = EACCES;
 		result = -1;
 	}
@@ -811,25 +812,23 @@
 int rename(const char* from, const char* to) {
 #define __rename(x,y) syscall(SYS_rename, (x), (y))
 	int result = 0;
-	int isInSandbox = __darwintrace_is_in_sandbox(from);
+	int isInSandbox = __darwintrace_is_in_sandbox(from, 0);
 	if (isInSandbox == 1) {
 		dprintf("darwintrace: rename was allowed at %s\n", from);
 	} else if (isInSandbox == 0) {
 		/* outside sandbox, but sandbox is defined: forbid */
 		dprintf("darwintrace: renaming from %s was forbidden\n", from);
-		__darwintrace_log_op("sandbox_violation", NULL, from, 0);
 		errno = EACCES;
 		result = -1;
 	}
 
 	if (result == 0) {
-		isInSandbox = __darwintrace_is_in_sandbox(to);
+		isInSandbox = __darwintrace_is_in_sandbox(to, 0);
 		if (isInSandbox == 1) {
 			dprintf("darwintrace: rename was allowed at %s\n", to);
 		} else if (isInSandbox == 0) {
 			/* outside sandbox, but sandbox is defined: forbid */
 			dprintf("darwintrace: renaming to %s was forbidden\n", to);
-			__darwintrace_log_op("sandbox_violation", NULL, to, 0);
 			errno = EACCES;
 			result = -1;
 		}

Modified: trunk/base/src/pextlib1.0/Makefile
===================================================================
--- trunk/base/src/pextlib1.0/Makefile	2007-07-03 15:21:03 UTC (rev 26681)
+++ trunk/base/src/pextlib1.0/Makefile	2007-07-03 17:42:36 UTC (rev 26682)
@@ -1,6 +1,7 @@
 OBJS=		Pextlib.o strsed.o fgetln.o md5cmd.o setmode.o xinstall.o \
 		fs-traverse.o strcasecmp.o vercomp.o filemap.o \
-		sha1cmd.o compat.o curl.o rmd160cmd.o readline.o uid.o
+		sha1cmd.o compat.o curl.o rmd160cmd.o readline.o uid.o\
+		tracelib.o
 SHLIB_NAME=	Pextlib${SHLIB_SUFFIX}
 INSTALLDIR= ${DESTDIR}${datadir}/macports/Tcl/pextlib1.0
 export MACOSX_DEPLOYMENT_TARGET=10.3

Modified: trunk/base/src/pextlib1.0/Pextlib.c
===================================================================
--- trunk/base/src/pextlib1.0/Pextlib.c	2007-07-03 15:21:03 UTC (rev 26681)
+++ trunk/base/src/pextlib1.0/Pextlib.c	2007-07-03 17:42:36 UTC (rev 26682)
@@ -113,6 +113,7 @@
 #include "compat.h"
 #include "readline.h"
 #include "uid.h"
+#include "tracelib.h"
 
 #if HAVE_CRT_EXTERNS_H
 #include <crt_externs.h>
@@ -1165,6 +1166,8 @@
 	Tcl_CreateObjCommand(interp, "uid_to_name", uid_to_nameCmd, NULL, NULL);
 	Tcl_CreateObjCommand(interp, "name_to_gid", name_to_gidCmd, NULL, NULL);
 	Tcl_CreateObjCommand(interp, "gid_to_name", gid_to_nameCmd, NULL, NULL);
+	
+	Tcl_CreateObjCommand(interp, "tracelib", TracelibCmd, NULL, NULL);
 
 	if (Tcl_PkgProvide(interp, "Pextlib", "1.0") != TCL_OK)
 		return TCL_ERROR;

Added: trunk/base/src/pextlib1.0/tracelib.c
===================================================================
--- trunk/base/src/pextlib1.0/tracelib.c	                        (rev 0)
+++ trunk/base/src/pextlib1.0/tracelib.c	2007-07-03 17:42:36 UTC (rev 26682)
@@ -0,0 +1,431 @@
+/*
+ * tracelib.c
+ * $Id$
+ *
+ * Copyright (c) 2007 Eugene Pimenov (GSoC), MacPorts team
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Darwinports Team nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/un.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <pthread.h>
+#include "tracelib.h"
+
+static char * name;
+static char * sandbox;
+static char * filemap, * filemap_end;
+static char * depends;	
+static int sock=-1;
+static Tcl_Interp * interp;
+static pthread_mutex_t sock_mutex=PTHREAD_MUTEX_INITIALIZER;
+static int cleanuping=0;
+
+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, ...);
+
+#define MAX_SOCKETS ((FD_SETSIZE)-1)
+
+static int TracelibSetNameCmd(Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[])
+{
+	if (objc != 3)
+	{
+		Tcl_WrongNumArgs(interp, 2, objv, "number of arguments should be exactly 3");
+		return TCL_ERROR;
+	}
+	
+	name=strdup(Tcl_GetString(objv[2]));
+	
+	return TCL_OK;
+}
+
+/*
+ * Save sandbox path into memory and prepare it for checks.
+ * For now it just change : to \0, and add last \0
+ * Input:
+ *  /dev/null:/dev/tty:/tmp
+ * In variable;
+ * /dev/null\0/dev/tty\0/tmp\0\0
+ */
+static int TracelibSetSandboxCmd(Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[])
+{
+	int len;
+	char * t;
+	
+	if (objc != 3)
+	{
+		Tcl_WrongNumArgs(interp, 2, objv, "number of arguments should be exactly 3");
+		return TCL_ERROR;
+	}
+	
+	len=strlen(Tcl_GetString(objv[2]))+2;
+	sandbox=(char*)malloc(len);
+	memset(sandbox, 0, len);
+	strcpy(sandbox, Tcl_GetString(objv[2]));
+	for(t=sandbox;(t=strchr(t+1, ':'));)
+	{
+		/* : -> \0 */
+		if(t[-1]!='\\')
+			*t=0;
+		else
+			/* \: -> : */
+			/* TODO \\: -> \: */
+			memmove(t-1, t, strlen(t));
+	}
+	
+	return TCL_OK;
+}
+
+/*
+ * 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)
+{
+	char * t, buf[1024]={0}, *f;
+	int len;
+	
+	if((len=recv(sock, buf, sizeof(buf), 0))==-1)
+		return 0;
+	if(!len)
+		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)
+	{
+		f=strchr(t, '\t');
+		if(!f)
+			break;
+		*f++=0;
+		if(!strcmp(t, "filemap"))
+		{
+			send_file_map(sock);
+		}else if(!strcmp(t, "sandbox_violation"))
+		{
+			sandbox_violation(sock, f);
+		}else if(!strcmp(t, "dep_check"))
+		{
+			dep_check(sock, f);
+		}else if(!strcmp(t, "execve"))
+		{
+			/* ====================== */
+			/* = TODO: do something = */
+			/* ====================== */
+		}else
+		{
+			ui_warn("unknown command %s (%s)", t, f);
+		}
+	}
+	return 1;
+}
+
+static void send_file_map(int sock)
+{
+	/*
+	 * TODO: redirect for SDK here 
+	 * TODO: /opt -> path from config
+	 */
+	if(!filemap)
+	{
+		char * t;
+		char * _;
+		
+		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);
+		filemap_end=t;
+		#undef append_allow
+	}
+	
+	{
+		size_t s=filemap_end-filemap;
+		send(sock, &s, sizeof(s), 0);
+		send(sock, filemap, s, 0);
+	}
+}
+
+static void sandbox_violation(int sock, const char * path)
+{
+	char buf[1024];
+	sprintf(buf, "slave_add_sandbox_violation {%s}", path);
+	Tcl_Eval(interp, buf);
+}
+
+static void dep_check(int sock, const char * path)
+{
+	size_t len=1;
+	send(sock, &len, sizeof(len), 0);
+	send(sock, "+", 1, 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);
+	va_end(va);
+	strcat(buf, "}");
+	
+	Tcl_Eval(interp, buf);
+}
+
+static int TracelibRunCmd(Tcl_Interp * in)
+{
+	struct sockaddr_un sun;
+	fd_set fdr;
+	int i;
+	int max_fd, max_used, socks[MAX_SOCKETS];
+	struct rlimit rl;
+	
+	pthread_mutex_lock(&sock_mutex);
+	if(cleanuping)
+	{
+		pthread_mutex_unlock(&sock_mutex);
+		return 0;
+	}
+	sock=socket(AF_UNIX, SOCK_STREAM, 0);
+	pthread_mutex_unlock(&sock_mutex);
+	
+	interp=in;
+	
+	rl.rlim_cur=rl.rlim_max=RLIM_INFINITY;
+	if(setrlimit(RLIMIT_NOFILE, &rl)==-1)
+	{
+		ui_warn("setrlimit failed (%d)", errno);
+	}
+	
+	sun.sun_family=AF_UNIX;
+	strcpy(sun.sun_path, name);
+	if(bind(sock, (struct sockaddr*)&sun, sizeof(sun))==-1)
+	{
+		Tcl_SetResult(interp, "Cannot bind socket", TCL_STATIC);
+		return TCL_ERROR;
+	}
+	
+	listen(sock, 5);
+	max_used=0;
+	max_fd=sock;
+	
+	for(;sock!=-1&&!cleanuping;)
+	{
+		FD_ZERO(&fdr);
+		FD_SET(sock, &fdr);
+		for(i=0;i<max_used;++i)
+			FD_SET(socks[i], &fdr);
+				
+		if(select(max_fd+1, &fdr, 0, 0, 0)<1)
+		{
+			continue;
+		}
+		if(sock==-1)
+		{
+			break;
+		}
+		if(FD_ISSET(sock, &fdr))
+		{
+			int s;
+			s=accept(sock, 0, 0);
+			
+			if(s==-1)
+			{
+				if(cleanuping)
+					break;
+				else
+					ui_warn("tracelib: accept return -1 (errno: %d)", errno);
+				/* failed sometimes and i dunno why*/
+				continue;
+			}
+			/* Temporary solution, it's better to regenerate this variable in each iteration, because when closing socket we'll get it too high */				
+			if(s>max_fd)
+				max_fd=s;
+			for(i=0;i<max_used;++i)
+				if(!socks[i])
+				{
+					socks[i]=s;
+					break;
+				}
+			if(i==max_used)
+			{
+				if(max_used==MAX_SOCKETS-1)
+					close(s);
+				else
+					socks[max_used++]=s;
+			}
+		}
+		
+		for(i=0;i<max_used;++i)
+		{
+			if(!socks[i])
+				continue;
+			if(FD_ISSET(socks[i], &fdr))
+			{
+				if(!process_line(socks[i]))
+				{
+					close(socks[i]);
+					socks[i]=0;
+					continue;
+				}
+			}
+		}
+	}
+	
+	for(i=0;i<max_used;++i)
+	{
+		if(socks[i])
+		{
+			close(socks[i]);
+			socks[i]=0;
+		}
+	}
+	
+	return TCL_OK;
+}
+
+static int TracelibCleanCmd(Tcl_Interp * interp UNUSED)
+{
+	#define safe_free(x) do{free(x); x=0;}while(0);
+	cleanuping=1;
+	pthread_mutex_lock(&sock_mutex);
+	if(sock!=-1)
+	{
+		shutdown(sock, SHUT_RDWR);
+		close(sock);
+		sock=-1;
+	}
+	pthread_mutex_unlock(&sock_mutex);
+	if(name)
+	{
+		unlink(name);
+		safe_free(name);
+	}
+	if(filemap)
+		safe_free(filemap);
+	#undef safe_free
+	cleanuping=0;
+	return TCL_OK;
+}
+
+static int TracelibCloseSocketCmd(Tcl_Interp * interp UNUSED)
+{
+	cleanuping=1;
+	pthread_mutex_lock(&sock_mutex);
+	if(sock!=-1)
+	{
+		shutdown(sock, SHUT_RDWR);
+		close(sock);
+		sock=-1;
+	}
+	pthread_mutex_unlock(&sock_mutex);
+	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};
+	typedef enum 
+	{
+		kSetName,
+		kRun,
+		kClean,
+		kSetSandbox,
+		kCloseSocket
+	} EOptions;
+	EOptions current_option;
+	
+	/* There is no args for commands now. */
+	if (objc <2)
+	{
+		Tcl_WrongNumArgs(interp, 1, objv, "option");
+		return TCL_ERROR;
+	}
+	
+	result=Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, (int*)&current_option);
+	if(result==TCL_OK)
+	{
+		switch(current_option)
+		{
+		case kSetName:
+			result=TracelibSetNameCmd(interp, objc, objv);
+			break;
+		case kRun:
+			result=TracelibRunCmd(interp);
+			break;
+		case kClean:
+			result=TracelibCleanCmd(interp);
+			break;
+		case kCloseSocket:
+			result=TracelibCloseSocketCmd(interp);
+			break;
+		case kSetSandbox:
+			result=TracelibSetSandboxCmd(interp, objc, objv);
+			break;
+		}
+	}
+	
+	return result;
+}

Added: trunk/base/src/pextlib1.0/tracelib.h
===================================================================
--- trunk/base/src/pextlib1.0/tracelib.h	                        (rev 0)
+++ trunk/base/src/pextlib1.0/tracelib.h	2007-07-03 17:42:36 UTC (rev 26682)
@@ -0,0 +1,55 @@
+/*
+ * tracelib.h
+ * $Id$
+ *
+ * Copyright (c) 2007 Eugene Pimenov (GSoC), MacPorts team
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Darwinports Team nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PEXTLIB_TRACELIB_H
+#define _PEXTLIB_TRACELIB_H
+
+#include <tcl.h>
+
+/**
+ *
+ * Command to handle trace lib
+ *
+ * It is *NOT* thread safe
+ * 
+ * Syntax:
+ *  	tracelib setname name
+ *			- return path of unix socket
+ *		tracelib run
+ *			- run select, create a socket
+ *		tracelib clean
+ *			- cleanup everything
+ */
+int TracelibCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]);
+
+#endif
+		/* _PEXTLIB_TRACELIB_H */

Modified: trunk/base/src/port1.0/porttrace.tcl
===================================================================
--- trunk/base/src/port1.0/porttrace.tcl	2007-07-03 15:21:03 UTC (rev 26681)
+++ trunk/base/src/port1.0/porttrace.tcl	2007-07-03 17:42:36 UTC (rev 26682)
@@ -43,9 +43,11 @@
 		} else {
 			global env trace_fifo trace_sandboxbounds
 			# Create a fifo.
-			set trace_fifo "$workpath/trace_fifo"
+			# path in unix socket limited to 109 chars
+			# # set trace_fifo "$workpath/trace_fifo"
+			set trace_fifo "/tmp/macports/[pid]" 
+			file mkdir "/tmp/macports"
 			file delete -force $trace_fifo
-			mkfifo $trace_fifo 0600
 			
 			# Create the thread/process.
 			create_slave $workpath $trace_fifo
@@ -75,6 +77,7 @@
 			if {[info exists env(TMPDIR)]} {
 				set trace_sandboxbounds "${trace_sandboxbounds}:$env(TMPDIR)"
 			}
+			tracelib setsandbox $trace_sandboxbounds
 		}
 	}
 }
@@ -141,6 +144,9 @@
 		if [info exists env(DARWINTRACE_SANDBOX_BOUNDS)] {
 			unset env(DARWINTRACE_SANDBOX_BOUNDS)
 		}
+		
+		#kill socket
+		tracelib clean
 
 		# Clean up.
 		slave_send slave_stop
@@ -181,6 +187,8 @@
 proc slave_send {command} {
 	global trace_thread
 
+	# ui_warn "slave send $command ?"
+
 	thread::send $trace_thread "$command" result
 	return $result
 }
@@ -258,24 +266,15 @@
 # Private.
 # Slave init method.
 proc slave_start {fifo p_workpath} {
-	global ports_list trace_filemap sandbox_violation_list trace_fifo_r_chan \
-		trace_fifo_w_chan workpath
+	global ports_list trace_filemap sandbox_violation_list 
 	# Save the workpath.
 	set workpath $p_workpath
 	# Create a virtual filemap.
 	filemap create trace_filemap
 	set ports_list {}
 	set sandbox_violation_list {}
-	set trace_fifo_r_chan [open $fifo {RDONLY NONBLOCK}]
-	# To prevent EOF when darwintrace closes the file, I also open the pipe
-	# myself as write only.
-	# This is quite ugly. The clean way to do would be to only install the
-	# fileevent handler when the pipe is opened on the other end, but I don't
-	# know how to wait for this while still being interruptable (i.e. while
-	# still being able to get commands thru thread::send). Thoughts, anyone?
-	set trace_fifo_w_chan [open $fifo w]
-	fconfigure $trace_fifo_r_chan -blocking 0 -buffering line
-	fileevent $trace_fifo_r_chan readable [list slave_read_line $trace_fifo_r_chan]
+	tracelib setname $fifo
+	tracelib run
 }
 
 # Private.
@@ -285,8 +284,6 @@
 	# Close the virtual filemap.
 	filemap close trace_filemap
 	# Close the pipe (both ends).
-	close $trace_fifo_r_chan
-	close $trace_fifo_w_chan
 }
 
 # Private.
@@ -302,3 +299,8 @@
 	global sandbox_violation_list
 	return $sandbox_violation_list
 }
+
+proc slave_add_sandbox_violation {path} {
+	global sandbox_violation_list
+	lappend sandbox_violation_list $path
+}

Modified: trunk/base/src/port1.0/portutil.tcl
===================================================================
--- trunk/base/src/port1.0/portutil.tcl	2007-07-03 15:21:03 UTC (rev 26681)
+++ trunk/base/src/port1.0/portutil.tcl	2007-07-03 17:42:36 UTC (rev 26682)
@@ -1143,6 +1143,11 @@
 			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"

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-changes/attachments/20070703/f89526da/attachment.html


More information about the macports-changes mailing list