portmaster-1.12 で非 root が ports の管理をできるようにするパッチ。
root 権限が必要な場面で自動的に su して root パスワードを聞くようになる。
su でなく sudo を使いたい場合は /etc/make.conf で SU_CMD を設定すること。
自分の使っている範囲では問題はないようだが、もしかしたらどこかに
見逃している部分があるかもしれないので注意。

古いパッケージをアンインストールする前に pkg_create してバックアップするが、
このときは root にならない。そのため、portmaster を実行しているユーザの
権限で読めないファイルがあると pkg_create に失敗する。エラーを無視するか
作業を中止するか聞いてくるのでどちらか適当な方を選べ。

root のパスワードを間違えると古いパッケージの削除に失敗するが、
それでも新バージョンのインストールをなぜか強行するので、新旧のバージョンが
同居してしまうという不具合あり。パスワード間違えるな:-)


--- sysutils/portmaster/files/portmaster.sh.in	Wed Jan 10 07:07:34 2007
+++ portmaster	Tue Jan 16 20:03:27 2007
@@ -217,14 +217,13 @@
 	tempfile=`mktemp -t tempfile-${new_port}`
 
 	sed "s/@pkgdep $1/@pkgdep $2/" $dep_port_contents > $tempfile &&
-	    mv $tempfile $pdb/$dep_port/+CONTENTS
-	    chmod 644 $pdb/$dep_port/+CONTENTS
+	    do_root install -C -o root -m 644 $tempfile $pdb/$dep_port/+CONTENTS
+	    rm $tempfile
 
 	if [ -n "$oldportdir" ]; then
 		sed "s%N:${oldportdir}\$%N:${newportdir}%" $dep_port_contents > $tempfile &&
-		    mv $tempfile $pdb/$dep_port/+CONTENTS
-		    chmod 644 $pdb/$dep_port/+CONTENTS
-
+		    do_root install -C -o root -m 644 $tempfile $pdb/$dep_port/+CONTENTS
+		    rm $tempfile
 	fi
 }
 
@@ -902,6 +901,19 @@
 	cont_distfiles=${cont_distfiles# }
 }
 
+case `id -u` in
+0)     ;;
+*)     su="`make $MAKE_ARGS -f $pd/Mk/bsd.port.mk -V SU_CMD`";;
+esac
+do_root () {
+	case "$su" in
+	"")	$@;;
+	*)	echo "===>>>  Switching to root credentials for '$@'"
+		$su "$*"
+		echo "===>>>  Returning to user credentials";;
+	esac
+}
+
 if [ -n "$EXPUNGE" ]; then
 	if [ -d "$pdb/$EXPUNGE" ]; then
 		origin=`origin_from_pdb $pdb/$EXPUNGE`
@@ -917,7 +929,7 @@
 		find_contents_distfiles $EXPUNGE
 
 		echo "===>>> Running pkg_delete -f $EXPUNGE"
-		pkg_delete -f $EXPUNGE
+		do_root pkg_delete -f $EXPUNGE
 		if [ -z "$DONT_SCRUB_DISTFILES" ]; then
 			delete_all_distfiles $origin
 		fi
@@ -961,7 +973,7 @@
 			find_contents_distfiles $iport
 
 			echo "===>>> Running pkg_delete -f $iport"
-			pkg_delete -f ${iport}
+			do_root pkg_delete -f ${iport}
 			if [ -z "$DONT_SCRUB_DISTFILES" ]; then
 				delete_all_distfiles $origin
 			fi
@@ -970,7 +982,7 @@
 		*) echo -n "	===>>> Remove empty +REQUIRED_BY file? [n] "
 			read DELORNOT
 			case "$DELORNOT" in
-			[yY])	rm -f $file ;;
+			[yY])	do_root rm -f $file ;;
 			*)	do_not_delete="${do_not_delete}${iport}:" ;;
 			esac
 			;;
@@ -1420,17 +1432,17 @@
 	if [ -z "$NO_BACKUP" ]; then
 		backup_package $upg_port
 	fi
-	pkg_delete -f $upg_port || fail 'pkg_delete failed'
+	do_root pkg_delete -f $upg_port || fail 'pkg_delete failed'
 
 	if [ -n "$REPLACE_ORIGIN" ]; then
 		installed_newport=`iport_from_origin ${newportdir}`
 		if [ -n "$installed_newport" ]; then
-			pkg_delete -f $installed_newport
+			do_root pkg_delete -f $installed_newport
 		fi
 	fi
 fi
 
-make $MAKE_ARGS install clean NOCLEANDEPENDS=yes || {
+do_root make $MAKE_ARGS install clean NOCLEANDEPENDS=yes || {
     if [ -z "$NO_BACKUP" -a -n "$upg_port" ]; then
 	echo ''
 	echo "===>>> A backup package for $portdir should be located in $pkgrep"
@@ -1450,7 +1462,7 @@
 		size=`grep "^SIZE (${ds}${file})" $distinfo | cut -f4 -d' '`
 		sha256=`grep "^SHA256 (${ds}${file})" $distinfo | cut -f4 -d' '`
 		md5=`grep "^MD5 (${ds}${file})" $distinfo | cut -f4 -d' '`
-		echo "@comment DISTFILE:${ds}${file}:SIZE=${size}:SHA256=${sha256}:MD5=${md5}" >> $pdb/$new_port/+CONTENTS
+		do_root echo "@comment DISTFILE:${ds}${file}:SIZE=${size}:SHA256=${sha256}:MD5=${md5}" '>>' $pdb/$new_port/+CONTENTS
 	done
 fi
 
@@ -1489,9 +1501,9 @@
 	done < $req_deps
 }
 	update_dep_entries
-	mv $req_deps $pdb/$new_port/+REQUIRED_BY
+	do_root install -C -o root -m 644 $req_deps $pdb/$new_port/+REQUIRED_BY
+	rm $req_deps
 	unset req_deps
-	chmod 644 $pdb/$new_port/+REQUIRED_BY
 
 	if [ -n "$REPLACE_ORIGIN" ]; then
 		req_deps=`mktemp -t req-deps-${short_port}`
@@ -1499,7 +1511,7 @@
 		grep -l DEPORIGIN:$newportdir$ $pdb/*/+CONTENTS |
 		    cut -f 5 -d '/' | sort -u > $req_deps
 		update_dep_entries $new_port
-		cat $req_deps >> $pdb/$new_port/+REQUIRED_BY
+		do_root cat $req_deps '>>' $pdb/$new_port/+REQUIRED_BY
 	fi
 fi
 
