[46954] trunk/base

jmr at macports.org jmr at macports.org
Wed Feb 18 01:32:50 PST 2009


Revision: 46954
          http://trac.macports.org/changeset/46954
Author:   jmr at macports.org
Date:     2009-02-18 01:32:43 -0800 (Wed, 18 Feb 2009)
Log Message:
-----------
Merge gsoc08-privileges branch into trunk.

Modified Paths:
--------------
    trunk/base/ChangeLog
    trunk/base/Makefile.in
    trunk/base/aclocal.m4
    trunk/base/configure
    trunk/base/configure.ac
    trunk/base/doc/macports.conf.in
    trunk/base/doc/portfile.7
    trunk/base/src/macports1.0/macports.tcl
    trunk/base/src/port/port.tcl
    trunk/base/src/port1.0/port_autoconf.tcl.in
    trunk/base/src/port1.0/portbuild.tcl
    trunk/base/src/port1.0/portclean.tcl
    trunk/base/src/port1.0/portconfigure.tcl
    trunk/base/src/port1.0/portdestroot.tcl
    trunk/base/src/port1.0/portextract.tcl
    trunk/base/src/port1.0/portfetch.tcl
    trunk/base/src/port1.0/portinstall.tcl
    trunk/base/src/port1.0/portmain.tcl
    trunk/base/src/port1.0/portpatch.tcl
    trunk/base/src/port1.0/portutil.tcl

Property Changed:
----------------
    trunk/base/


Property changes on: trunk/base
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/variant-descs-14482/base:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes:45682-46060
/users/perry/base-select:44044-44692
   + /branches/gsoc08-privileges/base:37343-46937
/branches/variant-descs-14482/base:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes:45682-46060
/users/perry/base-select:44044-44692

Modified: trunk/base/ChangeLog
===================================================================
--- trunk/base/ChangeLog	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/ChangeLog	2009-02-18 09:32:43 UTC (rev 46954)
@@ -5,6 +5,43 @@
 
 
 Release 1.8.0 (unreleased):
+    - MacPorts now performs fetch, extract, patch, configure and build in a
+      user rather than system owned location. By default, this is
+      ~/.macports/opt. This allows MacPorts to do all but the install of the
+      port without root privileges. (gsoc08-privileges)
+
+    - MacPorts now automatically drops privileges whenever possible so as to
+      avoid running as root whenever possible. (gsoc08-privileges)
+
+    - MacPorts will prompt for the root password if you attempt to install a
+      port into the /opt hierarchy and did not start MacPorts with sudo. It
+      will not do so however until the install stage. The fetch, extract,
+      patch, configure and build will proceed first under the privileges
+      MacPorts is started with. (gsoc08-privileges)
+
+    - The Portfile format has a number of new boolean attributes to indicate
+      when an action should or should not be run with root privileges:
+      'patch.asroot', 'build.asroot', 'configure.asroot', 'destroot.asroot',
+      and 'install.asroot'. The default for all is "no". If the prefix folder
+      (by default /opt/local) is not writable, MacPorts will attempt to
+      elevate privileges to root for the install phase. (gsoc08-privileges)
+
+    - A "make group" command has been added to the Makefile and a
+      "--with-shared-directory" switch to the configure script. Running "make
+      group" will create a macports group. "--with-shared-directory" will let
+      let the group specified by "--with-install-group" have full read write
+      access to the /opt/local hierarchy. This will allow users who are
+      members of the new macports group to have full write permissions to /opt
+      and its subfolders, and hence to install ports which only affect that
+      hierarchy to install those ports without requiring root privileges. 
+      (gsoc08-privileges)
+
+    - A switch called "--with-no-root-privileges" has been added for use by
+      user installing MacPorts for their own use only. An example configure
+      command would be "./configure
+      --prefix=/Users/{your-user-name-here}/.macports/opt
+      --with-no-root-privileges" (gsoc08-privileges)
+
     - Add new "use_7z yes" port option to allow distfiles in 7z format
       (#18521, ryandesign)
 

Modified: trunk/base/Makefile.in
===================================================================
--- trunk/base/Makefile.in	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/Makefile.in	2009-02-18 09:32:43 UTC (rev 46954)
@@ -50,6 +50,13 @@
 	@echo "Please read \"man port\", the MacPorts guide at http://guide.macports.org/ and Wiki at http://trac.macports.org/ for full documentation."; echo ""
 	@echo "Stray sources might have been left in the legacy ${localstatedir}/db/dports directory after this upgrade, which moved most of what it could to ${localstatedir}/macports, so you might want to look in the former and cleanup manually."; echo ""
 
+group::
+	@echo "creating a macports group..." && sudo dseditgroup -o create -n . macports && echo "done! use './configure --with-install-group=macports --with-shared-directory' if you haven't already"
+
+rmgroup::
+	@echo "deleting macports group..." && sudo dseditgroup -o delete -n . macports && echo "done! use 'make group' to re-create"
+
+
 clean::
 
 distclean::

Modified: trunk/base/aclocal.m4
===================================================================
--- trunk/base/aclocal.m4	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/aclocal.m4	2009-02-18 09:32:43 UTC (rev 46954)
@@ -288,6 +288,86 @@
 
 	])
 
+
+# MP_CHECK_NOROOTPRIVILEGES
+#-------------------------------------------------
+AC_DEFUN([MP_CHECK_NOROOTPRIVILEGES],[
+	dnl if with user specifies --with-no-root-privileges,
+	dnl use current user and group.
+	dnl use ~/Library/Tcl as Tcl package directory
+		AC_REQUIRE([MP_PATH_MPCONFIGDIR])
+
+	AC_ARG_WITH(no-root-privileges, [AC_HELP_STRING([--with-no-root-privileges], [Specify that MacPorts should be installed in your home directory])], [ROOTPRIVS=$withval] )
+
+	if test "${ROOTPRIVS+set}" = set; then
+
+		# Set install-user to current user
+		AC_MSG_CHECKING([for install user])
+		DSTUSR=`id -un`
+		AC_MSG_RESULT([$DSTUSR])
+		AC_SUBST(DSTUSR)
+		
+		# Set install-group to current user
+		AC_MSG_CHECKING([for install group])
+		DSTGRP=`id -gn`
+		AC_MSG_RESULT([$DSTGRP])
+		AC_SUBST(DSTGRP)
+
+		# Set Tcl package directory to ~/Library/Tcl
+	    AC_MSG_CHECKING(for Tcl package directory)
+		ac_cv_c_tclpkgd="~$DSTUSR/Library/Tcl"
+	    # Convert to a native path and substitute into the output files.
+	    PACKAGE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclpkgd}`
+	    TCL_PACKAGE_DIR=${PACKAGE_DIR_NATIVE}
+	    AC_SUBST(TCL_PACKAGE_DIR)
+		if test x"${ac_cv_c_tclpkgd}" = x ; then
+			AC_MSG_ERROR(Tcl package directory not found.  Please specify its location with --with-tclpackage)
+	    else
+			AC_MSG_RESULT(${ac_cv_c_tclpkgd})
+	    fi
+	fi
+
+])
+
+# MP_CHECK_RUNUSER
+#-------------------------------------------------
+AC_DEFUN([MP_CHECK_RUNUSER],[
+	dnl if with user specifies --with-macports-user,
+	dnl use it. otherwise default to platform defaults
+       AC_REQUIRE([MP_PATH_MPCONFIGDIR])
+
+	AC_ARG_WITH(macports-user, [AC_HELP_STRING([--with-macports-user=USER], [Specify user to drop privileges to, if possible, during compiles etc.])], [ RUNUSR=$withval ] )
+	
+	AC_MSG_CHECKING([for macports user])
+	if test "x$RUNUSR" = "x" ; then
+# dropping root privs is still buggy
+#	   RUNUSR=`id -un`
+	   RUNUSR=root
+	fi
+
+	AC_MSG_RESULT([$RUNUSR])
+	AC_SUBST(RUNUSR)
+])
+
+
+# MP_SHARED_DIRECTORY
+#-------------------------------------------------
+AC_DEFUN([MP_SHARED_DIRECTORY],[
+	dnl if with user specifies --with-shared-directory,
+	dnl use 0775 permissions for ${prefix} directories
+        AC_REQUIRE([MP_PATH_MPCONFIGDIR])
+
+	AC_ARG_WITH(shared-directory, [AC_HELP_STRING([--with-shared-directory], [Use 0775 permissions for installed directories])], [ SHAREDIR=$withval ] )
+
+	if test "${SHAREDIR+set}" = set; then	
+		AC_MSG_CHECKING([whether to share the install directory with all members of the install group])
+	    DSTMODE=0775
+
+		AC_MSG_RESULT([$DSTMODE])
+		AC_SUBST(DSTMODE)
+	fi
+])
+
 # MP_CHECK_INSTALLUSER
 #-------------------------------------------------
 AC_DEFUN([MP_CHECK_INSTALLUSER],[

Modified: trunk/base/configure
===================================================================
--- trunk/base/configure	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/configure	2009-02-18 09:32:43 UTC (rev 46954)
@@ -661,7 +661,6 @@
 LDFLAGS_LIBCURL
 CFLAGS_LIBCURL
 CURL_CONFIG
-TCL_PACKAGE_DIR
 TCLSH
 TCL_INCLUDES
 TCL_STUB_LIB_SPEC
@@ -689,6 +688,8 @@
 MPFRAMEWORKSDIR
 MPAPPLICATIONSDIR
 DSTMODE
+RUNUSR
+TCL_PACKAGE_DIR
 DSTGRP
 DSTUSR
 MPCONFIGDIR
@@ -807,9 +808,12 @@
 with_objc_runtime
 with_objc_foundation
 with_ports_dir
+with_no_root_privileges
 with_install_user
 with_install_group
+with_macports_user
 with_directory_mode
+with_shared_directory
 with_applications_dir
 with_frameworks_dir
 with_universal_target
@@ -1495,12 +1499,19 @@
   --with-objc-runtime     Specify either "GNU" or "apple"
   --with-objc-foundation  Specify either "GNUstep" or "apple"
   --with-ports-dir=DIR    Specify alternate ports directory
+  --with-no-root-privileges
+                          Specify that MacPorts should be installed in your
+                          home directory
   --with-install-user=USER
                           Specify user ownership of installed files
   --with-install-group=GROUP
                           Specify group ownership of installed files
+  --with-macports-user=USER
+                          Specify user to drop privileges to, if possible,
+                          during compiles etc.
   --with-directory-mode=MODE
                           Specify directory mode of installed directories
+  --with-shared-directory Use 0775 permissions for installed directories
   --with-applications-dir Applications installation directory.
   --with-frameworks-dir   Frameworks installation directory.
   --with-universal-target=MDT
@@ -6947,6 +6958,55 @@
 
 
 
+# Check whether to install without root privileges
+
+
+
+
+# Check whether --with-no-root-privileges was given.
+if test "${with_no_root_privileges+set}" = set; then
+  withval=$with_no_root_privileges; ROOTPRIVS=$withval
+fi
+
+
+	if test "${ROOTPRIVS+set}" = set; then
+
+		# Set install-user to current user
+		{ $as_echo "$as_me:$LINENO: checking for install user" >&5
+$as_echo_n "checking for install user... " >&6; }
+		DSTUSR=`id -un`
+		{ $as_echo "$as_me:$LINENO: result: $DSTUSR" >&5
+$as_echo "$DSTUSR" >&6; }
+
+
+		# Set install-group to current user
+		{ $as_echo "$as_me:$LINENO: checking for install group" >&5
+$as_echo_n "checking for install group... " >&6; }
+		DSTGRP=`id -gn`
+		{ $as_echo "$as_me:$LINENO: result: $DSTGRP" >&5
+$as_echo "$DSTGRP" >&6; }
+
+
+		# Set Tcl package directory to ~/Library/Tcl
+	    { $as_echo "$as_me:$LINENO: checking for Tcl package directory" >&5
+$as_echo_n "checking for Tcl package directory... " >&6; }
+		ac_cv_c_tclpkgd="~$DSTUSR/Library/Tcl"
+	    # Convert to a native path and substitute into the output files.
+	    PACKAGE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclpkgd}`
+	    TCL_PACKAGE_DIR=${PACKAGE_DIR_NATIVE}
+
+		if test x"${ac_cv_c_tclpkgd}" = x ; then
+			{ { $as_echo "$as_me:$LINENO: error: Tcl package directory not found.  Please specify its location with --with-tclpackage" >&5
+$as_echo "$as_me: error: Tcl package directory not found.  Please specify its location with --with-tclpackage" >&2;}
+   { (exit 1); exit 1; }; }
+	    else
+			{ $as_echo "$as_me:$LINENO: result: ${ac_cv_c_tclpkgd}" >&5
+$as_echo "${ac_cv_c_tclpkgd}" >&6; }
+	    fi
+	fi
+
+
+
 # Check for install ownership
 
 
@@ -7006,6 +7066,28 @@
 
 
 
+# Check whether --with-macports-user was given.
+if test "${with_macports_user+set}" = set; then
+  withval=$with_macports_user;  RUNUSR=$withval
+fi
+
+
+	{ $as_echo "$as_me:$LINENO: checking for macports user" >&5
+$as_echo_n "checking for macports user... " >&6; }
+	if test "x$RUNUSR" = "x" ; then
+# dropping root privs is still buggy
+#	   RUNUSR=`id -un`
+	   RUNUSR=root
+	fi
+
+	{ $as_echo "$as_me:$LINENO: result: $RUNUSR" >&5
+$as_echo "$RUNUSR" >&6; }
+
+
+
+
+
+
 # Check whether --with-directory-mode was given.
 if test "${with_directory_mode+set}" = set; then
   withval=$with_directory_mode;  DSTMODE=$withval
@@ -7023,6 +7105,26 @@
 
 
 
+
+
+
+# Check whether --with-shared-directory was given.
+if test "${with_shared_directory+set}" = set; then
+  withval=$with_shared_directory;  SHAREDIR=$withval
+fi
+
+
+	if test "${SHAREDIR+set}" = set; then
+		{ $as_echo "$as_me:$LINENO: checking whether to share the install directory with all members of the install group" >&5
+$as_echo_n "checking whether to share the install directory with all members of the install group... " >&6; }
+	    DSTMODE=0775
+
+		{ $as_echo "$as_me:$LINENO: result: $DSTMODE" >&5
+$as_echo "$DSTMODE" >&6; }
+
+	fi
+
+
 # Check for default directories
 
 

Modified: trunk/base/configure.ac
===================================================================
--- trunk/base/configure.ac	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/configure.ac	2009-02-18 09:32:43 UTC (rev 46954)
@@ -139,10 +139,15 @@
 MP_PATH_PORTSDIR([$PORTS_DIR_DEFAULT])
 MP_PATH_MPCONFIGDIR
 
+# Check whether to install without root privileges
+MP_CHECK_NOROOTPRIVILEGES
+
 # Check for install ownership
 MP_CHECK_INSTALLUSER
 MP_CHECK_INSTALLGROUP
+MP_CHECK_RUNUSER
 MP_DIRECTORY_MODE
+MP_SHARED_DIRECTORY
 
 # Check for default directories
 MP_PATH_APPLICATIONS

Modified: trunk/base/doc/macports.conf.in
===================================================================
--- trunk/base/doc/macports.conf.in	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/doc/macports.conf.in	2009-02-18 09:32:43 UTC (rev 46954)
@@ -4,6 +4,9 @@
 # Set the directory in which to install ports
 prefix			@prefix_expanded@
 
+# Set the user to run MacPorts compiles, etc as when privileges are dropped during an install
+macportsuser	@RUNUSR@
+
 # Where to store MacPorts working data
 portdbpath		@localstatedir_expanded@/macports
 

Modified: trunk/base/doc/portfile.7
===================================================================
--- trunk/base/doc/portfile.7	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/doc/portfile.7	2009-02-18 09:32:43 UTC (rev 46954)
@@ -322,6 +322,13 @@
 .Cm test .
 The hooks are:
 .Bl -tag -width lc
+.It Va target Ns Ic .asroot
+Run the 
+.Va target
+with root privileges.
+.br
+.Sy Example:
+.Dl install.asroot yes
 .It Va target Ns Ic .dir
 Directory in which to run the
 .Va target .

Modified: trunk/base/src/macports1.0/macports.tcl
===================================================================
--- trunk/base/src/macports1.0/macports.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/macports1.0/macports.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -45,7 +45,8 @@
         porttrace portverbose destroot_umask variants_conf rsync_server rsync_options \
         rsync_dir startupitem_type place_worksymlink xcodeversion xcodebuildcmd \
         mp_remote_url mp_remote_submit_url configureccache configuredistcc configurepipe buildnicevalue buildmakejobs \
-        applications_dir frameworks_dir universal_target universal_sysroot universal_archs"
+        applications_dir frameworks_dir universal_target universal_sysroot universal_archs \
+        macportsuser"
     variable user_options "submitter_name submitter_email submitter_key"
     variable portinterp_options "\
         portdbpath porturl portpath portbuildpath auto_path prefix prefix_frozen x11prefix portsharepath \
@@ -332,6 +333,7 @@
     global macports::destroot_umask
     global macports::libpath
     global macports::prefix
+    global macports::macportsuser
     global macports::prefix_frozen
     global macports::x11prefix
     global macports::registry.installtype

Modified: trunk/base/src/port/port.tcl
===================================================================
--- trunk/base/src/port/port.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port/port.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -367,7 +367,11 @@
             array set options $portspec(options)
         }
         uplevel 1 $block
-        cd $savedir
+        if {[file exists $savedir]} {
+        	cd $savedir
+        } else {
+        	cd ~
+        }
     }
 }
 
@@ -2053,6 +2057,16 @@
         if { [catch {portuninstall::uninstall $portname [composite_version $portversion [array get variations]] [array get options]} result] } {
             global errorInfo
             ui_debug "$errorInfo"
+
+			# start gsoc08-privileges	
+			if { [string first "permission denied" $result] != -1 } {
+				set result "port requires root privileges for this action and needs you to execute 'sudo port uninstall $portname' to continue."
+				#ui_msg [exec sudo port uninstall $portname]
+				# The above line is what should be here to let the user simply enter his/her password to uninstall as root.
+				# However, for some as yet unknown reason, executing it here will not work.
+			}
+			# end gsoc08-privileges
+
             break_softcontinue "port uninstall failed: $result" 1 status
         }
     }
@@ -2783,6 +2797,25 @@
 
         mportclose $workername
         
+        # start gsoc08-privileges
+		if { [geteuid] != 0 && $result == 2} {
+			# mportexec will return an error result code 2 if eval_targets fails due to insufficient privileges.
+
+			set portbinary "${macports::prefix}/bin/port"
+			
+			ui_info "Attempting port action with 'sudo port': 'sudo $portbinary $target $portname'."
+			set result 0
+			if {[catch {set sudomsgs [exec sudo $portbinary $target $portname]} sudomsgs]} {
+	            global errorInfo
+	            ui_debug "$errorInfo"
+				break_softcontinue "Unable to execute port: $errorInfo" 1 status
+	        }
+			
+			ui_msg $sudomsgs
+			ui_debug "'sudo $portbinary $target $portname' has completed."
+		}
+		# end gsoc08-privileges
+        
         # Process any error that wasn't thrown and handled already
         if {$result} {
             break_softcontinue "Status $result encountered during processing." 1 status

Modified: trunk/base/src/port1.0/port_autoconf.tcl.in
===================================================================
--- trunk/base/src/port1.0/port_autoconf.tcl.in	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/port_autoconf.tcl.in	2009-02-18 09:32:43 UTC (rev 46954)
@@ -46,5 +46,6 @@
 	variable install_user "@DSTUSR@"
 	variable install_group "@DSTGRP@"
 	variable prefix "@prefix_expanded@"
+	variable macportsuser "@RUNUSR@"
 	variable x11prefix "@x11prefix@"
 }

Modified: trunk/base/src/port1.0/portbuild.tcl
===================================================================
--- trunk/base/src/port1.0/portbuild.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portbuild.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -42,8 +42,10 @@
 options build.target
 options build.nice
 options build.jobs
+options build.asroot
 commands build parallel_build
 # defaults
+default build.asroot no
 default build.dir {${workpath}/${worksrcdir}}
 default build.cmd {[build_getmaketype]}
 default build.nice {${buildnicevalue}}
@@ -133,9 +135,17 @@
 }
 
 proc build_start {args} {
-    global UI_PREFIX
+    global UI_PREFIX build.asroot
     
     ui_msg "$UI_PREFIX [format [msgcat::mc "Building %s"] [option portname]]"
+    
+    # start gsoc08-privileges
+    if { [tbool build.asroot] } {
+	# if port is marked as needing root	
+		elevateToRoot "build"
+	}
+	# end gsoc08-privileges
+    
 }
 
 proc build_main {args} {

Modified: trunk/base/src/port1.0/portclean.tcl
===================================================================
--- trunk/base/src/port1.0/portclean.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portclean.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -54,7 +54,7 @@
 proc clean_main {args} {
     global UI_PREFIX
 	global ports_clean_dist ports_clean_work ports_clean_archive
-	global ports_clean_all
+	global ports_clean_all usealtworkpath
 
 	if {[info exists ports_clean_all] && $ports_clean_all == "yes" || \
 		[info exists ports_clean_dist] && $ports_clean_dist == "yes"} {
@@ -74,9 +74,34 @@
 		 clean_work
 	}
 
+	# start gsoc-08 privileges
+	if {$usealtworkpath == "yes"} {
+		ui_info "$UI_PREFIX [format [msgcat::mc "Removing alt source directory for %s"] [option portname]]"
+		clean_altsource
+	}
+	# end gsoc-08 privileges
+	
     return 0
 }
 
+proc clean_altsource {args} {
+    global usealtworkpath worksymlink
+    
+    set sourcepath [string map {"work" ""} $worksymlink] 
+
+	if {[file isdirectory $sourcepath]} {
+		ui_debug "Removing directory: ${sourcepath}"
+		if {[catch {delete $sourcepath} result]} {
+			ui_debug "$::errorInfo"
+			ui_error "$result"
+		}
+	} else {
+		ui_debug "No alt source directory found to remove."
+	}
+
+	return 0
+}
+
 #
 # Remove the directory where the distfiles reside.
 # This is crude, but works.
@@ -104,7 +129,7 @@
 	if {$count > 0} {
 		ui_debug "$count distfile(s) removed."
 	} else {
-		ui_debug "No distfiles found to remove."
+		ui_debug "No distfiles found to remove at $distpath"
 	}
 
 	# next remove dist_subdir if only needed for this port,
@@ -158,7 +183,7 @@
 			ui_error "$result"
 		}
 	} else {
-		ui_debug "No work directory found to remove."
+		ui_debug "No work directory found to remove at: ${portbuildpath}"
 	}
 
 	# Clean symlink, if necessary
@@ -215,7 +240,7 @@
 	if {$count > 0} {
 		ui_debug "$count archive(s) removed."
 	} else {
-		ui_debug "No archives found to remove."
+		ui_debug "No archives found to remove at $archivepath"
 	}
 
 	return 0

Modified: trunk/base/src/port1.0/portconfigure.tcl
===================================================================
--- trunk/base/src/port1.0/portconfigure.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portconfigure.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -78,6 +78,9 @@
     }
 }
 
+options configure.asroot
+default configure.asroot no
+
 # Configure special environment variables.
 # We could have m32/m64/march/mtune be global configurable at some point.
 options configure.m32 configure.m64 configure.march configure.mtune
@@ -188,6 +191,13 @@
         default { return -code error "Invalid value for configure.compiler" }
     }
     ui_debug "Using compiler '$name'"
+    
+    # start gsoc08-privileges
+    if { [tbool configure.asroot] } {
+	# if port is marked as needing root	
+		elevateToRoot "configure"
+	}
+	# end gsoc08-privileges
 }
 
 # internal function to determine canonical system name for configure

Modified: trunk/base/src/port1.0/portdestroot.tcl
===================================================================
--- trunk/base/src/port1.0/portdestroot.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portdestroot.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -42,7 +42,7 @@
 
 # define options
 options destroot.target destroot.destdir destroot.clean destroot.keepdirs destroot.umask
-options destroot.violate_mtree
+options destroot.violate_mtree destroot.asroot
 options startupitem.create startupitem.requires startupitem.init
 options startupitem.name startupitem.start startupitem.stop startupitem.restart
 options startupitem.type startupitem.executable
@@ -51,6 +51,7 @@
 commands destroot
 
 # Set defaults
+default destroot.asroot no
 default destroot.dir {${build.dir}}
 default destroot.cmd {${build.cmd}}
 default destroot.pre_args {${destroot.target}}
@@ -87,11 +88,38 @@
 
 proc destroot_start {args} {
     global UI_PREFIX prefix portname porturl destroot os.platform destroot.clean portsharepath
-    global destroot::oldmask destroot.umask
+    global destroot::oldmask destroot.umask destroot.asroot macportsuser euid egid usealtworkpath altprefix
     global applications_dir frameworks_dir
     
     ui_msg "$UI_PREFIX [format [msgcat::mc "Staging %s into destroot"] ${portname}]"
 
+	# start gsoc08-privileges
+	if { [getuid] == 0 && [geteuid] == [name_to_uid "$macportsuser"] } { 
+	# if started with sudo but have dropped the privileges
+		ui_debug "Can't run destroot under sudo without elevated privileges (due to mtree)."
+		ui_debug "Run destroot without sudo to avoid root privileges."
+		ui_debug "Going to escalate privileges back to root."
+		setegid $egid	
+		seteuid $euid	
+		ui_debug "euid changed to: [geteuid]. egid changed to: [getegid]."
+	}
+	
+	if { [tbool destroot.asroot] && [getuid] != 0 } {
+		global errorisprivileges
+		set errorisprivileges yes
+		return -code error "You can not run this port without elevated privileges. You need to re-run with 'sudo port'.";
+	}
+	
+	if {$usealtworkpath} {
+	    # rewrite destroot.args
+	    set argprefix "=[option prefix]"
+	    set newargprefix "=${altprefix}[option prefix]"
+	    set newdestrootargs [string map [list $argprefix $newargprefix] [option destroot.args]]
+	    option destroot.args $newdestrootargs
+	}
+	
+	# end gsoc08-privileges
+
     set oldmask [umask ${destroot.umask}]
     set mtree ${portutil::autoconf::mtree_path}
     
@@ -293,6 +321,10 @@
 
     # Restore umask
     umask $oldmask
+    
+    # start gsoc08-privileges
+	chownAsRoot $destroot
+	# end gsoc08-privileges
 
     return 0
 }

Modified: trunk/base/src/port1.0/portextract.tcl
===================================================================
--- trunk/base/src/port1.0/portextract.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portextract.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -98,7 +98,7 @@
 }
 
 proc extract_main {args} {
-    global UI_PREFIX filespath
+    global UI_PREFIX filespath worksrcpath
 
     if {![exists distfiles] && ![exists extract.only]} {
         # nothing to do
@@ -115,6 +115,11 @@
         if {[catch {command_exec extract} result]} {
             return -code error "$result"
         }
+	
+	# start gsoc08-privileges
+	chownAsRoot $worksrcpath
+	# end gsoc08-privileges
+	
     }
     return 0
 }

Modified: trunk/base/src/port1.0/portfetch.tcl
===================================================================
--- trunk/base/src/port1.0/portfetch.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portfetch.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -723,8 +723,18 @@
 # Initialize fetch target and call checkfiles.
 proc fetch_init {args} {
     global distfiles distname distpath all_dist_files dist_subdir fetch.type fetch_init_done
+    global altprefix usealtworkpath
     
     if {[info exists distpath] && [info exists dist_subdir] && ![info exists fetch_init_done]} {
+
+		# start gsoc08-privileges
+    	if { $usealtworkpath } {
+    	# I have removed ![file writable $distpath] from the if condition as
+    	# the writable condition seems to get confused by effective uids.
+			set distpath "$altprefix/[ string range $distpath 1 end ]"
+			ui_debug "Going to use $distpath for fetch."
+    	}
+    	# end gsoc08-privileges
 	    set distpath ${distpath}/${dist_subdir}
 	    set fetch_init_done yes
     }

Modified: trunk/base/src/port1.0/portinstall.tcl
===================================================================
--- trunk/base/src/port1.0/portinstall.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portinstall.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -44,11 +44,29 @@
 }
 target_prerun ${org.macports.install} install_start
 
+# define options
+options install.asroot
+
+# Set defaults
+default install.asroot no
+
 set_ui_prefix
 
 proc install_start {args} {
 	global UI_PREFIX portname portversion portrevision variations portvariants
+	global install.asroot prefix
 	ui_msg "$UI_PREFIX [format [msgcat::mc "Installing %s @%s_%s%s"] $portname $portversion $portrevision $portvariants]"
+	
+	# start gsoc08-privileges
+	if { [tbool install.asroot] } {
+		# if port is marked as needing root	
+		elevateToRoot "install"
+	} elseif { ![file writable $prefix] } {
+		# if install location is not writable, need root privileges to install
+		elevateToRoot "install"
+	}
+	# end gsoc08-privileges
+	
 }
 
 proc install_element {src_element dst_element} {

Modified: trunk/base/src/port1.0/portmain.tcl
===================================================================
--- trunk/base/src/port1.0/portmain.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portmain.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -41,7 +41,7 @@
 target_state ${org.macports.main} no
 
 # define options
-options prefix name version revision epoch categories maintainers
+options prefix macportsuser name version revision epoch categories maintainers
 options long_description description homepage
 options worksrcdir filesdir distname portdbpath libpath distpath sources_conf os.platform os.version os.major os.arch os.endian platforms default_variants install.user install.group macosx_deployment_target
 options universal_variant os.universal_supported
@@ -72,6 +72,7 @@
 default worksrcpath {[file join $workpath $worksrcdir]}
 
 # Configure settings
+default macportsuser {${portutil::autoconf::macportsuser}}
 default install.user {${portutil::autoconf::install_user}}
 default install.group {${portutil::autoconf::install_group}}
 

Modified: trunk/base/src/port1.0/portpatch.tcl
===================================================================
--- trunk/base/src/port1.0/portpatch.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portpatch.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -41,7 +41,10 @@
 
 # Add command patch
 commands patch
+
+options patch.asroot
 # Set up defaults
+default patch.asroot no
 default patch.dir {${worksrcpath}}
 default patch.cmd patch
 default patch.pre_args -p0
@@ -55,6 +58,13 @@
     }
     
 	ui_msg "$UI_PREFIX [format [msgcat::mc "Applying patches to %s"] [option portname]]"
+	
+	# start gsoc08-privileges
+    if { [tbool patch.asroot] } {
+	# if port is marked as needing root	
+		elevateToRoot "patch"
+	}
+	# end gsoc08-privileges
 
     foreach patch [option patchfiles] {
     set patch_file [getdistname $patch]

Modified: trunk/base/src/port1.0/portutil.tcl
===================================================================
--- trunk/base/src/port1.0/portutil.tcl	2009-02-18 09:03:06 UTC (rev 46953)
+++ trunk/base/src/port1.0/portutil.tcl	2009-02-18 09:32:43 UTC (rev 46954)
@@ -768,6 +768,8 @@
 # reinplace
 # Provides "sed in place" functionality
 proc reinplace {args}  {
+	global euid macportsuser
+
     set extended 0
     while 1 {
         set arg [lindex $args 0]
@@ -827,6 +829,10 @@
     
         close $tmpfd
     
+		# start gsoc08-privileges
+		chownAsRoot $file	
+		# end gsoc08-privileges
+    
         set attributes [file attributes $file]
         # We need to overwrite this file
         if {[catch {file attributes $file -permissions u+w} error]} {
@@ -1146,7 +1152,7 @@
 set ports_dry_last_skipped ""
 
 proc target_run {ditem} {
-    global target_state_fd portpath portname portversion portrevision portvariants ports_force variations workpath ports_trace PortInfo ports_dryrun ports_dry_last_skipped
+    global target_state_fd portpath portname portversion portrevision portvariants ports_force variations workpath ports_trace PortInfo ports_dryrun ports_dry_last_skipped errorisprivileges
     set result 0
     set skipped 0
     set procedure [ditem_key $ditem procedure]
@@ -1358,7 +1364,11 @@
             write_statefile target $name $target_state_fd
             }
         } else {
-            ui_error "Target $name returned: $errstr"
+        	if {$errorisprivileges != "yes"} {
+            	ui_error "Target $name returned: $errstr"
+            } else {
+            	ui_msg "Target $name returned: $errstr"
+            }
             set result 1
         }
     
@@ -1408,8 +1418,9 @@
 
 
 proc eval_targets {target} {
-    global targets target_state_fd portname
+    global targets target_state_fd portname errorisprivileges
     set dlist $targets
+    set errorisprivileges "no"
     
     # Select the subset of targets under $target
     if {$target != ""} {
@@ -1438,6 +1449,12 @@
         set result 0
     }
     
+    # start gsoc08-privileges
+    if { $result == 1 && $errorisprivileges == "yes" } {
+    	set result 2
+    }
+    # end gsoc08-privileges
+    
     return $result
 }
 
@@ -1445,7 +1462,87 @@
 # open file to store name of completed targets
 proc open_statefile {args} {
     global workpath worksymlink place_worksymlink portname portpath ports_ignore_older
+    global altprefix usealtworkpath env applications_dir portbuildpath distpath
     
+	# start gsoc08-privileges
+
+	# descalate privileges - only ran if macports stated with sudo
+	dropPrivileges
+    
+    if { ![file exists $workpath] } {
+        if {[catch {set result [file mkdir $workpath]} result]} {
+            global errorInfo
+            ui_debug "mkdir $workpath: $errorInfo"
+        }
+    }
+    
+    # if unable to write to workpath, implies running without either root privileges 
+    # or a shared directory owned by the group so use ~/.macports
+    if { ![file writable $workpath] } {
+    
+    	set userid [getuid]
+    	set username [uid_to_name $userid]
+
+    	if { $userid !=0 } {
+    		ui_msg "MacPorts running without privileges.\
+					You may be prompted for your sudo password in order to complete certain actions (eg install)."
+		}
+    	
+    	# set global variable indicating to other functions to use ~/.macports as well
+    	set usealtworkpath yes
+    
+		# do tilde expansion manually - tcl won't expand tildes automatically for curl, etc.
+		if {[info exists env(HOME)]} {
+			# HOME environment var is set, use it.
+			set userhome "$env(HOME)"
+		} else {
+			# the environment var isn't set, make an educated guess
+			if {[option os.platform] == "darwin"} {
+			    set userhome "/Users/${username}"
+			} else {
+			    set userhome "/home/${username}"
+			}
+		}
+		
+		# set alternative prefix global variables
+		set altprefix "$userhome/.macports"
+		
+		# get alternative paths
+		set newworkpath "$altprefix$workpath"
+		set newworksymlink "$altprefix$worksymlink"
+		set newportbuildpath "$altprefix$portbuildpath"
+		set newdistpath "$altprefix$distpath"
+		
+		set sourcepath [string map {"work" ""} $worksymlink] 
+		set newsourcepath "$altprefix/[ string range $sourcepath 1 end ]"
+
+		# copy Portfile (and patch files) if not there already
+		# note to maintainers/devs: the original portfile in /opt is ALWAYS the one that will be 
+		#	 read by macports. The copying of the portfile is done to preserve the symlink provided
+		#	 historically by macports from the portfile directory to the work directory.
+		#	 It is NOT read by MacPorts.
+		if {![file exists ${newsourcepath}Portfile] } {
+			file mkdir $newsourcepath
+			ui_debug "$newsourcepath created"
+			ui_debug "Going to copy: ${sourcepath}Portfile"
+			file copy ${sourcepath}Portfile $newsourcepath
+			if {[file exists ${sourcepath}files] } {
+				ui_debug "Going to copy: ${sourcepath}files"
+				file copy ${sourcepath}files $newsourcepath
+			}
+		}
+		
+		set workpath $newworkpath
+		set worksymlink $newworksymlink
+		set portbuildpath $newportbuildpath
+		set distpath $newdistpath
+		
+		ui_debug "Going to use $newworkpath for statefile."
+    } else {
+    	set usealtworkpath no
+    }
+    # end gsoc08-privileges
+
     if {![file isdirectory $workpath]} {
         file mkdir $workpath
     }
@@ -1465,6 +1562,7 @@
 
     # Create a symlink to the workpath for port authors 
     if {[tbool place_worksymlink] && ![file isdirectory $worksymlink]} {
+        ui_debug "Attempting ln -sf $workpath $worksymlink"
         ln -sf $workpath $worksymlink
     }
     
@@ -2253,3 +2351,95 @@
     return $str
 }
 
+##
+# Recusively chown the given file or directory to the specified user.
+#
+# @param path the file/directory to be chowned
+# @param user the user to chown file to
+proc chown {path user} {
+	file attributes $path -owner [name_to_uid "$user"]
+	
+    if {[file isdirectory $path]} {
+		fs-traverse myfile ${path} {
+			file attributes $myfile -owner [name_to_uid "$user"]
+		}
+    }
+    
+}
+
+##
+# Recusively chown the given file or directory to $macportsuser, using root privileges.
+#
+# @param path the file/directory to be chowned
+proc chownAsRoot {path} {
+    global euid macportsuser
+
+	if { [getuid] == 0 && [geteuid] == [name_to_uid "$macportsuser"] } {
+	# if started with sudo but have dropped the privileges
+		seteuid $euid	
+		ui_debug "euid changed to: [geteuid]"
+		chown  ${path} ${macportsuser}
+		ui_debug "chowned $path to $macportsuser"
+		seteuid [name_to_uid "$macportsuser"]
+		ui_debug "euid changed to: [geteuid]"
+	} elseif { [getuid] == 0 } {
+	# if started with sudo but have elevated back to root already
+		chown  ${path} ${macportsuser}
+	} else {
+		ui_debug "no need to chown $path. uid=[getuid]. euid=[geteuid]."
+	}
+}
+
+##
+# Elevate privileges back to root.
+#
+# @param action the action for which privileges are being elevated
+proc elevateToRoot {action} {
+	global euid egid macportsuser errorisprivileges
+	
+	if { [getuid] == 0 && [geteuid] == [name_to_uid "$macportsuser"] } { 
+	# if started with sudo but have dropped the privileges
+		ui_debug "Can't run $action on this port without elevated privileges. Escalating privileges back to root."
+		setegid $egid	
+		seteuid $euid	
+		ui_debug "euid changed to: [geteuid]. egid changed to: [getegid]."
+	}
+	
+	if { [getuid] != 0 } {
+		set errorisprivileges yes
+		return -code error "port requires root privileges for this action and needs you to type your password for sudo.";
+	}
+}
+
+##
+# Descalate privileges from root to those of $macportsuser.
+#
+proc dropPrivileges {} {
+	global euid egid macportsuser workpath
+	if { [geteuid] == 0 } {
+		if { [catch {
+				set euid [geteuid]
+				set egid [getegid]
+				ui_debug "changing euid/egid - current euid: $euid - current egid: $egid"
+	
+				#seteuid [name_to_uid [file attributes $workpath -owner]]
+				#setegid [name_to_gid [file attributes $workpath -group]]
+	
+				setegid [name_to_gid "$macportsuser"]
+				seteuid [name_to_uid "$macportsuser"]
+				ui_debug "egid changed to: [getegid]" 
+				ui_debug "euid changed to: [geteuid]"
+				
+				if {![file writable $workpath]} {
+					ui_debug "Privileges successfully descalated. Unable to write to default workpath."
+				}
+			}]
+		} {
+			ui_debug "$::errorInfo"
+			ui_error "Failed to descalate privileges."
+		}
+	} else {
+		ui_debug "Privilege desclation not attempted as not running as root."
+	}
+}
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macports-changes/attachments/20090218/0a776bd7/attachment-0001.html>


More information about the macports-changes mailing list