diff --git a/CHANGELOG b/CHANGELOG index 0b014d1f1..06515aa3b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ # Nmap Changelog ($Id$); -*-text-*- +o Switch to using gtk-mac-bundler and jhbuild for building the OS X installer. + This promises to reduce a lot of the problems we've had with local paths and + dependencies using the py2app and macports build system. + Nmap 7.00 [2015-11-19] o This is the most important release since Nmap 6.00 back in May 2012! diff --git a/macosx/Makefile b/macosx/Makefile index 6fe469a14..ed6759d88 100644 --- a/macosx/Makefile +++ b/macosx/Makefile @@ -29,6 +29,9 @@ NPING_STAGING_DIR = Nping NMAP_UPDATE_BUILD_DIR = nmap-update-build NMAP_UPDATE_STAGING_DIR = nmap-update +JHBUILD_PREFIX=$(HOME)/gtk/inst +# MACPORTS_PREFIX is still here because of nmap-update, which needs +# libsvn and libapr, which jhbuild doesn't support yet. MACPORTS_PREFIX=$(HOME)/macports-10.8 PREFIX = /usr/local @@ -52,7 +55,8 @@ UNIVERSAL_ARCHFLAGS = -arch i386 UNIVERSAL_CPPFLAGS = -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk UNIVERSAL_CFLAGS = $(UNIVERSAL_CPPFLAGS) -mmacosx-version-min=10.8 $(UNIVERSAL_ARCHFLAGS) UNIVERSAL_CXXFLAGS = $(UNIVERSAL_CFLAGS) -UNIVERSAL_LDFLAGS = -Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk -mmacosx-version-min=10.8 $(UNIVERSAL_ARCHFLAGS) +# https://stackoverflow.com/questions/19637164/c-linking-error-after-upgrading-to-mac-os-x-10-9-xcode-5-0-1/19637199#19637199 +UNIVERSAL_LDFLAGS = -stdlib=libstdc++ -Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk -mmacosx-version-min=10.9 $(UNIVERSAL_ARCHFLAGS) CC = $(UNIVERSAL_CC) CXX = $(UNIVERSAL_CXX) @@ -63,8 +67,8 @@ CFLAGS += $(UNIVERSAL_CFLAGS) CXXFLAGS += $(UNIVERSAL_CXXFLAGS) LDFLAGS += $(UNIVERSAL_LDFLAGS) -PYTHON = $(MACPORTS_PREFIX)/bin/python2.7 -OPENSSL_STATIC = $(MACPORTS_PREFIX)/lib/libssl.a $(MACPORTS_PREFIX)/lib/libcrypto.a $(MACPORTS_PREFIX)/lib/libz.a +PYTHON = $(JHBUILD_PREFIX)/bin/python2.7 +OPENSSL_STATIC = $(JHBUILD_PREFIX)/lib/libssl.a $(JHBUILD_PREFIX)/lib/libcrypto.a $(IMAGE_NAME): $(IMAGE_STAGING_DIR)/$(PKG_NAME) rm -f $@ @@ -76,7 +80,7 @@ $(IMAGE_STAGING_DIR)/$(PKG_NAME): check-nmap check-ncat check-ndiff check-zenmap $(PACKAGEMAKER) --doc nmap.pmdoc --title "Nmap $(NMAP_VERSION)" --no-relocate -o $@ check-%: stage-% - if (find $* -perm -a+x -type f | xargs otool -L | grep "$(MACPORTS_PREFIX)"); then false; else echo "Libs are clean"; fi + if (find $* -perm -a+x -type f | xargs otool -L | grep "$(JHBUILD_PREFIX)"); then false; else echo "Libs are clean"; fi export-%: rm -rf $* @@ -84,28 +88,28 @@ export-%: svn export .. $* stage-nmap: export-$(NMAP_BUILD_DIR) - cd $(NMAP_BUILD_DIR) && ./configure --without-zenmap --without-ncat --without-ndiff --without-nping --without-nmap-update --with-openssl="$(MACPORTS_PREFIX)" $(CONFIGURE_ARGS) + cd $(NMAP_BUILD_DIR) && ./configure --without-zenmap --without-ncat --without-ndiff --without-nping --without-nmap-update --with-openssl="$(JHBUILD_PREFIX)" $(CONFIGURE_ARGS) make -C $(NMAP_BUILD_DIR) OPENSSL_LIBS="$(OPENSSL_STATIC)" rm -rf $(NMAP_STAGING_DIR) make -C $(NMAP_BUILD_DIR) install DESTDIR="`pwd`/$(NMAP_STAGING_DIR)" OPENSSL_LIBS="$(OPENSSL_STATIC)" stage-ncat: export-$(NCAT_BUILD_DIR) - cd $(NCAT_BUILD_DIR) && ./configure --without-zenmap --with-ncat --without-ndiff --without-nping --without-nmap-update --with-openssl="$(MACPORTS_PREFIX)" $(CONFIGURE_ARGS) - make -d -C $(NCAT_BUILD_DIR) build-ncat OPENSSL_LIBS="$(OPENSSL_STATIC)" + cd $(NCAT_BUILD_DIR) && ./configure --without-zenmap --with-ncat --without-ndiff --without-nping --without-nmap-update --with-openssl="$(JHBUILD_PREFIX)" $(CONFIGURE_ARGS) + make -C $(NCAT_BUILD_DIR) build-ncat OPENSSL_LIBS="$(OPENSSL_STATIC)" rm -rf $(NCAT_STAGING_DIR) - make -d -C $(NCAT_BUILD_DIR) install-ncat DESTDIR="`pwd`/$(NCAT_STAGING_DIR)" OPENSSL_LIBS="$(OPENSSL_STATIC)" + make -C $(NCAT_BUILD_DIR) install-ncat DESTDIR="`pwd`/$(NCAT_STAGING_DIR)" OPENSSL_LIBS="$(OPENSSL_STATIC)" stage-nping: export-$(NPING_BUILD_DIR) - cd $(NPING_BUILD_DIR) && ./configure --without-zenmap --without-ncat --without-ndiff --with-nping --without-nmap-update --with-openssl="$(MACPORTS_PREFIX)" $(CONFIGURE_ARGS) + cd $(NPING_BUILD_DIR) && ./configure --without-zenmap --without-ncat --without-ndiff --with-nping --without-nmap-update --with-openssl="$(JHBUILD_PREFIX)" $(CONFIGURE_ARGS) make -C $(NPING_BUILD_DIR) build-nping OPENSSL_LIBS="$(OPENSSL_STATIC)" rm -rf $(NPING_STAGING_DIR) make -C $(NPING_BUILD_DIR) install-nping DESTDIR="`pwd`/$(NPING_STAGING_DIR)" OPENSSL_LIBS="$(OPENSSL_STATIC)" stage-nmap-update: export-$(NMAP_UPDATE_BUILD_DIR) - cd $(NMAP_UPDATE_BUILD_DIR) && ./configure --without-zenmap --without-ncat --without-ndiff --without-nping --with-nmap-update --with-apr=$(MACPORTS_PREFIX) --with-subversion=$(MACPORTS_PREFIX) --with-openssl="$(MACPORTS_PREFIX)" $(CONFIGURE_ARGS) - make -C $(NMAP_UPDATE_BUILD_DIR) build-nmap-update OPENSSL_LIBS="$(OPENSSL_STATIC)" + cd $(NMAP_UPDATE_BUILD_DIR) && ./configure --without-zenmap --without-ncat --without-ndiff --without-nping --with-nmap-update --with-apr=$(MACPORTS_PREFIX) --with-subversion=$(MACPORTS_PREFIX) $(CONFIGURE_ARGS) + make -C $(NMAP_UPDATE_BUILD_DIR) build-nmap-update rm -rf $(NMAP_UPDATE_STAGING_DIR) - make -C $(NMAP_UPDATE_BUILD_DIR) install-nmap-update DESTDIR="`pwd`/$(NMAP_UPDATE_STAGING_DIR)" OPENSSL_LIBS="$(OPENSSL_STATIC)" + make -C $(NMAP_UPDATE_BUILD_DIR) install-nmap-update DESTDIR="`pwd`/$(NMAP_UPDATE_STAGING_DIR)" install_name_tool -change "$(MACPORTS_PREFIX)/lib/libapr-1.0.dylib" "/usr/lib/libapr-1.0.dylib" "$(NMAP_UPDATE_STAGING_DIR)/usr/local/bin/nmap-update" install_name_tool -change "$(MACPORTS_PREFIX)/lib/libsvn_client-1.0.dylib" "/usr/lib/libsvn_client-1.0.dylib" "$(NMAP_UPDATE_STAGING_DIR)/usr/local/bin/nmap-update" install_name_tool -change "$(MACPORTS_PREFIX)/lib/libsvn_subr-1.0.dylib" "/usr/lib/libsvn_subr-1.0.dylib" "$(NMAP_UPDATE_STAGING_DIR)/usr/local/bin/nmap-update" diff --git a/macosx/openssl.modules b/macosx/openssl.modules new file mode 100644 index 000000000..236ad96f2 --- /dev/null +++ b/macosx/openssl.modules @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/zenmap/install_scripts/macosx/Info.plist b/zenmap/install_scripts/macosx/Info.plist index a1d666797..f0e07f8c3 100644 --- a/zenmap/install_scripts/macosx/Info.plist +++ b/zenmap/install_scripts/macosx/Info.plist @@ -1,5 +1,5 @@ - + CFBundleIdentifier @@ -7,6 +7,26 @@ CFBundleName Zenmap NSHumanReadableCopyright - © Insecure.Com LLC + ${APP_COPYRIGHT} + CFBundleDevelopmentRegion + English + CFBundleExecutable + Zenmap + CFBundleGetInfoString + ${VERSION}, ${APP_COPYRIGHT} ${APP_WEB_SITE} + CFBundleIconFile + zenmap.icns + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + ${VERSION} + CFBundleSignature + ???? + CFBundleVersion + ${VERSION} + LSMinimumSystemVersion + 10.9 diff --git a/zenmap/install_scripts/macosx/README b/zenmap/install_scripts/macosx/README index 7dfb9330e..32cbd611b 100644 --- a/zenmap/install_scripts/macosx/README +++ b/zenmap/install_scripts/macosx/README @@ -3,32 +3,34 @@ to do with packaging on Mac OS X. They are useful only for those wanting to build binary distributions of Zenmap for Mac OS X. == Info.plist -A properties list file that whose contents are merged with the default -properties added by py2app. +A properties list file template that is filled out by make-bundle.sh == make-bundle.sh This script builds a .app bundle. It must be run from the root of the Zenmap source tree. The finished bundle is put in dist/Zenmap.app. -== test_wrapper.py -This file contains unit tests for zenmap_wrapper.py, because it needs to -do some tricky escaping and substitution of configuration files. - == zenmap.icns The icon file for the bundle. It was created using the Icon Composer utility (open -a "Icon Composer"). == zenmap_auth.c -This is a simple wrapper program that attempts to run zenmap_wrapper.py +This is a simple wrapper program that attempts to run launcher.sh with privileges. -== zenmap_wrapper.py -This is a wrapper script that gets installed in the application bundle. -It sets up an execution environment and then calls the main zenmap -executable. +== launcher.sh +A launcher script that configures the environment for Zenmap, Python, and GTK +before launching the main Zenmap script file. + +== zenmap.bundle +An XML config file for gtk-mac-bundler which specifies files and metadata for +the application bundle. https://wiki.gnome.org/Projects/GTK%2B/OSX/Building + == MacPorts-ports.diff +*** Note: The MacPorts tree is only currently used for building libsvn and +libapr for nmap-update, and will hopefully be removed in future releases. + This patch against a MacPorts ports tree contains various changes needed to install dependencies in a sufficiently portable way. The main thing accomplished by this patch is to avoid building a MacPorts libiconv. @@ -36,15 +38,15 @@ libcups depends on libiconv, but it depends on an Apple version of libconv, and MacPorts doesn't have a port for libcups. The MacPorts libiconv is incompatible and causes a dynamic linker error at runtime. -The following instructions show how to make a 10.5-compatible +The following instructions show how to make a 10.9-compatible environment suitable for building Zenmap packages. It will be a separate -installation in $HOME/macports-10.5 that won't interfere with your +installation in $HOME/macports-10.9 that won't interfere with your normal MacPorts installation in /opt/local. These instructions were done with MacPorts 2.3.3 on Mac OS X 10.9.5. 1. Install MacPorts. export PATH=/usr/bin:/bin:/usr/sbin:/sbin - export PREFIX=$HOME/macports-10.8 + export PREFIX=$HOME/macports-10.9 tar xzvf MacPorts-2.3.3.tar.gz cd MacPorts-2.3.3 ./configure --with-no-root-privileges --prefix=$PREFIX --with-applications-dir=$PREFIX/Applications @@ -56,12 +58,12 @@ with MacPorts 2.3.3 on Mac OS X 10.9.5. Uncomment the line build_arch i386 Add this line at the bottom: - macosx_deployment_target 10.8 + macosx_deployment_target 10.9 4. Make a local patched ports tree. cd $PREFIX mkdir ports ln -s var/macports/sources/rsync.macports.org/release/tarballs/ports ports.orig - for x in archivers/xz editors/vim devel/apr-util devel/atk devel/gettext devel/glib2 gnome/gtk2 graphics/fontconfig graphics/gdk-pixbuf2 mail/libidn perl/p5-locale-gettext python/py-gobject python/py-libxml2 textproc/help2man textproc/libxml2 textproc/libxslt x11/pango; do + for x in archivers/xz editors/vim devel/apr-util devel/atk devel/gettext mail/libidn perl/p5-locale-gettext textproc/help2man; do mkdir -v -p ports/$x; cp -R ports.orig/$x ports/$(dirname $x); done @@ -71,10 +73,10 @@ with MacPorts 2.3.3 on Mac OS X 10.9.5. $PREFIX/bin/portindex 6. Edit the file $PREFIX/etc/macports/sources.conf. Add a line - file:///Users/user/macports-10.8/ports + file:///Users/user/macports-10.9/ports above the rsync line. (Replace "user" with your user name.) 7. Install the dependencies of Zenmap. - $PREFIX/bin/port install py26-pygtk py26-py2app apr apr-util + $PREFIX/bin/port install apr apr-util openssl Here are instructions for updating the patch to keep up with MacPorts changes. First, sync the original ports tree. @@ -84,7 +86,7 @@ Restore a pristine partial ports tree: # rsync handles deleting deleted files, but can't pick up new ones like this... rsync -rv --existing --delete --exclude=PortIndex ports.orig/ ports/ # ...so we copy everything over again. - for x in archivers/xz editors/vim devel/apr-util devel/atk devel/gettext devel/glib2 gnome/gtk2 graphics/fontconfig graphics/gdk-pixbuf2 mail/libidn perl/p5-locale-gettext python/py-gobject python/py-libxml2 textproc/help2man textproc/libxml2 textproc/libxslt x11/pango; do + for x in archivers/xz editors/vim devel/apr-util devel/atk devel/gettext mail/libidn perl/p5-locale-gettext textproc/help2man; do cp -R ports.orig/$x ports/$(dirname $x); done Reapply the patch. Resolve any conflicts. diff --git a/zenmap/install_scripts/macosx/launcher.sh b/zenmap/install_scripts/macosx/launcher.sh new file mode 100755 index 000000000..2f6b48984 --- /dev/null +++ b/zenmap/install_scripts/macosx/launcher.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +name=`basename "$0"` +tmp="$0" +tmp=`dirname "$tmp"` +tmp=`dirname "$tmp"` +bundle=`dirname "$tmp"` +bundle_contents="$bundle"/Contents +bundle_res="$bundle_contents"/Resources +bundle_lib="$bundle_res"/lib +bundle_bin="$bundle_res"/bin +bundle_data="$bundle_res"/share +bundle_etc="$bundle_res"/etc + +export DYLD_LIBRARY_PATH="$bundle_lib" +export XDG_CONFIG_DIRS="$bundle_etc"/xdg +export XDG_DATA_DIRS="$bundle_data" +export GTK_DATA_PREFIX="$bundle_res" +export GTK_EXE_PREFIX="$bundle_res" +export GTK_PATH="$bundle_res" + +export GTK2_RC_FILES="$bundle_etc/gtk-2.0/gtkrc" +export GTK_IM_MODULE_FILE="$bundle_etc/gtk-2.0/gtk.immodules" +export GDK_PIXBUF_MODULE_FILE="$bundle_lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" +export PANGO_LIBDIR="$bundle_lib" +export PANGO_SYSCONFDIR="$bundle_etc" + +#Set $PYTHON to point inside the bundle +export PYTHON="$bundle_contents/MacOS/python" +#Add the bundle's python modules +PYTHONHOME="$bundle_res" +export PYTHONHOME +PYTHONPATH="$bundle_res/lib/zenmap" +export PYTHONPATH + +# We need a UTF-8 locale. +if test "x$LANG" == "x"; then +lang=`defaults read .GlobalPreferences AppleLocale 2>/dev/null` +if test "$?" != "0"; then + lang=`defaults read .GlobalPreferences AppleCollationOrder 2>/dev/null | sed 's/_.*//'` +fi +if test "$?" == "0"; then + export LANG="`grep \"\`echo $lang\`_\" /usr/share/locale/locale.alias | \ + tail -n1 | sed 's/\./ /' | awk '{print $2}'`.UTF-8" +fi +fi + +if test -f "$bundle_lib/charset.alias"; then + export CHARSETALIASDIR="$bundle_lib" +fi + +# Extra arguments can be added in environment.sh. +EXTRA_ARGS= +if test -f "$bundle_res/environment.sh"; then + source "$bundle_res/environment.sh" +fi + +# Strip out the argument added by the OS. +if /bin/expr "x$1" : "x-psn_.*" > /dev/null; then + shift 1 +fi + +# Make the real UID equal the effective UID. They are unequal when running +# with privileges under AuthorizationExecuteWithPrivileges. GTK+ refuses to +# run if they are different +# Note that we're calling $PYTHON here to override the version in zenmap's shebang. +$EXEC $PYTHON -c $'import os\nif os.getuid()!=os.geteuid():os.setuid(os.geteuid())\n'"os.execl(\"$PYTHON\",\"$PYTHON\",\"$bundle_bin/zenmap\")" diff --git a/zenmap/install_scripts/macosx/make-bundle.sh b/zenmap/install_scripts/macosx/make-bundle.sh index b8020f579..5919bc5df 100755 --- a/zenmap/install_scripts/macosx/make-bundle.sh +++ b/zenmap/install_scripts/macosx/make-bundle.sh @@ -1,35 +1,15 @@ #!/bin/sh -e +set -x # make-bundle.sh -# David Fifield -# -# This script works the magic needed to build Zenmap into a .app bundle for Mac -# OS X. It's complicated because py2app doesn't really support Pango or PyGTK. -# -# It is based on the osx-app.sh script used by Wireshark, which contains the -# following notice: -# -# AUTHORS -# Kees Cook -# Michael Wybrow -# Jean-Olivier Irisson -# -# Copyright (C) 2005 Kees Cook -# Copyright (C) 2005-2007 Michael Wybrow -# Copyright (C) 2007 Jean-Olivier Irisson -# -# Released under GNU GPL, read the file 'COPYING' for more information - -# This script relies on having an installation of MacPorts in $(LIBPREFIX), -# configured as you wish. See README for instructions on how to make a build -# environment. You need to have installed the packages py26-gtk and -# py26-py2app. - -LIBPREFIX=$HOME/macports-10.8 -PYTHON=$LIBPREFIX/bin/python2.7 -PKG_CONFIG=$LIBPREFIX/bin/pkg-config APP_NAME=Zenmap -BASE=dist/$APP_NAME.app/Contents +ZENMAP_DIST_DIR=$PWD/dist +ZENMAP_BUILD_DIR=$PWD/build + +export ZENMAP_DIST_DIR +export ZENMAP_BUILD_DIR + +BASE=$ZENMAP_DIST_DIR/$APP_NAME.app/Contents SCRIPT_DIR=`dirname "$0"` CC=${CC:-gcc} @@ -38,48 +18,63 @@ CFLAGS=${CFLAGS:--Wall -arch i386} echo "Running $0." echo "Removing old build." -rm -rf build dist +rm -rf "$ZENMAP_DIST_DIR" "$ZENMAP_BUILD_DIR" -echo "Compiling using py2app." -$PYTHON setup.py py2app --arch=i386 --no-strip +echo "Building bundle" +# jhbuild bootstrap +# jhbuild build meta-gtk-osx-bootstrap +# jhbuild build meta-gtk-osx-core +# jhbuild build meta-gtk-osx-python +gtk-mac-bundler "$SCRIPT_DIR/zenmap.bundle" -# Delete a library that causes compatibility problems with OS X 10.9. -# http://seclists.org/nmap-dev/2013/q4/85 -rm -f $BASE/Frameworks/libxml2.2.dylib - -mkdir -p $BASE/Resources/etc -mkdir -p $BASE/Resources/lib - -gtk_version=`$PKG_CONFIG --variable=gtk_binary_version gtk+-2.0` -echo "Copying GTK+ $gtk_version files." -mkdir -p $BASE/Resources/lib/gtk-2.0/$gtk_version -cp -R $LIBPREFIX/lib/gtk-2.0/$gtk_version/* $BASE/Resources/lib/gtk-2.0/$gtk_version/ - -mkdir -p $BASE/Resources/etc/gtk-2.0 -cp $SCRIPT_DIR/gtkrc $BASE/Resources/etc/gtk-2.0/ - -echo "Updating paths in GTK+ .so files" -ESCAPED_LIBPREFIX=$(echo $LIBPREFIX | sed 's/\([\/\\.]\)/\\\1/g') -find $BASE/Resources/lib/gtk-2.0/$gtk_version/ -type f -name '*.so' | while read so; do - otool -L "$so" | awk "/$ESCAPED_LIBPREFIX/{print \$1}" | while read dep; do - install_name_tool -change $dep $(echo $dep | sed "s/$ESCAPED_LIBPREFIX\/lib/@executable_path\/..\/Frameworks/") "$so" - done +echo "Stripping unoptimized Python libraries" +#Remove some stuff that is unneeded. This cuts 40M off the installed size. +rm -rf $BASE/Resources/lib/python2.7/test/ +rm -rf $BASE/Resources/lib/python2.7/config/ +rm -rf $BASE/Resources/lib/python2.7/idlelib/ +rm -rf $BASE/Resources/lib/python2.7/lib-tk/ +rm -rf $BASE/Resources/lib/python2.7/lib2to3/ +rm -f $BASE/Resources/lib/python2.7/site-packages/*.a +find "$BASE/Resources/lib/python2.7" -type f -name '*.py' | while read py; do +# If the .pyc exists, delete the .py + test -f "${py}c" && rm -v "$py" +done +find "$BASE/Resources/lib/python2.7" -type f -name '*.pyo' | while read py; do + # If the .pyc exists, delete the .pyo + test -f "${py/%o/c}" && rm -v "$py" done -echo "Copying Fontconfig files." -cp -R $LIBPREFIX/etc/fonts $BASE/Resources/etc/ -# Remove the dir and cachedir under $LIBPREFIX. The cachedir ~/.fontconfig remains. -sed -i "" 's/ *'$(echo "$LIBPREFIX" | sed -e 's/\([^a-zA-Z0-9]\)/\\\1/g')'\/share\/fonts<\/dir>//g' $BASE/Resources/etc/fonts/fonts.conf -sed -i "" '/'$(echo "$LIBPREFIX" | sed -e 's/\([^a-zA-Z0-9]\)/\\\1/g')'\/var\/cache\/fontconfig<\/cachedir>/d' $BASE/Resources/etc/fonts/fonts.conf -# Disable hinting to better match the Mac GUI. -cp $LIBPREFIX/share/fontconfig/conf.avail/10-unhinted.conf $BASE/Resources/etc/fonts/conf.d +echo "Building using distutils" +python setup.py build --executable "/usr/bin/env python" +python setup.py install vanilla --prefix "$BASE/Resources" + +# This isn't truly necessary, but it allows us to do a simpler check for problems later. +echo "Rewriting linker paths to pass checks" +ESCAPED_LIBBASE=$(echo "$BASE/Resources/" | sed 's/\([\/\\.]\)/\\\1/g') +find $BASE/Resources/lib -type f -name '*.dylib' | while read so; do + dep=$(echo "$so" | sed "s/$ESCAPED_LIBBASE//") + install_name_tool -id "@executable_path/../Resources/$dep" "$so" +done echo "Renaming main Zenmap executable." mv $BASE/MacOS/$APP_NAME $BASE/MacOS/zenmap.bin - -echo "Installing wrapper script." -cp $SCRIPT_DIR/zenmap_wrapper.py $BASE/MacOS/ +# This is a dummy script, so we'll clean it up: +rm $BASE/MacOS/$APP_NAME-bin echo "Compiling and installing authorization wrapper." -echo $CC $CPPFLAGS $CFLAGS $LDFLAGS -framework Security -o $BASE/MacOS/$APP_NAME $SCRIPT_DIR/zenmap_auth.c -$CC $CPPFLAGS $CFLAGS $LDFLAGS -framework Security -o $BASE/MacOS/$APP_NAME $SCRIPT_DIR/zenmap_auth.c +echo $CC $CPPFLAGS $CFLAGS $LDFLAGS -framework Security -o "$BASE/MacOS/$APP_NAME" "$SCRIPT_DIR/zenmap_auth.c" +$CC $CPPFLAGS $CFLAGS $LDFLAGS -framework Security -o "$BASE/MacOS/$APP_NAME" "$SCRIPT_DIR/zenmap_auth.c" + +echo "Filling out Info.plist" +python - "$SCRIPT_DIR/Info.plist" >"$BASE/Info.plist" <<'EOF' +import sys +from string import Template +from zenmapCore.Version import * +from zenmapCore.Name import * +with open(sys.argv[1],"r") as f: + sys.stdout.write(Template(f.read()).substitute( + VERSION=VERSION, + APP_WEB_SITE=APP_WEB_SITE, + APP_COPYRIGHT=APP_COPYRIGHT + )) +EOF diff --git a/zenmap/install_scripts/macosx/test_wrapper.py b/zenmap/install_scripts/macosx/test_wrapper.py deleted file mode 100755 index a6e671d69..000000000 --- a/zenmap/install_scripts/macosx/test_wrapper.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -# This is a test class for the non-trivial escaping done by zenmap_wrapper.py. - -import unittest - -import zenmap_wrapper - -class test_key_file(unittest.TestCase): - def test_escape(self): - TESTS = ( - ("", ""), - ("a", "a"), - ("a\nb\tc\rd\\e", "a\\nb\\tc\\rd\\\\e"), - ("a\"b", "a\"b") - ) - for test_line, expected in TESTS: - actual = zenmap_wrapper.escape_key_file_value(test_line) - self.assertEqual(expected, actual) - - def test_escape_first_space(self): - # Check first-character space escaping. - self.assert_(zenmap_wrapper.escape_key_file_value(" abc").startswith("\\s")) - - def test_substitute(self): - original = "abc" - replacements = {"b": "\"\\\t\r\ndef"} - expected = "a\"\\\\\\t\\r\\ndefc" - actual = zenmap_wrapper.substitute_key_file_line(original, replacements) - self.assertEqual(expected, actual) - -unittest.main() diff --git a/zenmap/install_scripts/macosx/zenmap.bundle b/zenmap/install_scripts/macosx/zenmap.bundle new file mode 100644 index 000000000..7e3fb4ef2 --- /dev/null +++ b/zenmap/install_scripts/macosx/zenmap.bundle @@ -0,0 +1,158 @@ + + + + + + ${env:JHBUILD_PREFIX} + + + ${env:ZENMAP_DIST_DIR} + + + + + + ${project}/launcher.sh + + + + + + + ${project}/Info.plist + + + + ${prefix}/bin/pygtk-demo + + + + + ${prefix}/bin/python + + + + + ${prefix}/lib/libpyglib-2.0-python.0.dylib + + + + ${prefix}/lib/libgtk-quartz-${gtkversion}.0.dylib + + + + + ${prefix}/lib/${gtkdir}/modules/*.so + + + + + ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/engines/*.so + + + ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/printbackends/*.so + + + + + ${prefix}/lib/gdk-pixbuf-2.0/${pkg:gdk-pixbuf-2.0:gdk_pixbuf_binary_version}/loaders/*.so + + + + ${prefix}/lib/pango/${pkg:pango:pango_module_version}/modules/*.so + + + + + ${prefix}/share/locale + + + + + ${prefix}/lib/python2.7/lib-dynload/*.so + ${prefix}/lib/python2.7/site-packages/*.so + ${prefix}/lib/python2.7/site-packages/cairo/*.so + ${prefix}/lib/python2.7/site-packages/glib/*.so + ${prefix}/lib/python2.7/site-packages/gobject/*.so + ${prefix}/lib/python2.7/site-packages/gtk-2.0/*.so + ${prefix}/lib/python2.7/site-packages/gtk-2.0/gtk/*.so + ${prefix}/lib/python2.7/site-packages/gtkmacintegration/*.so + ${prefix}/lib/python2.7/site-packages/gtkosx_application/*.so + + ${prefix}/lib/python2.7/ + + + + + ${prefix}/share/themes + + + + + ${project}/zenmap.icns + + + + + + ${project}/gtkrc + + + + + diff --git a/zenmap/install_scripts/macosx/zenmap_auth.c b/zenmap/install_scripts/macosx/zenmap_auth.c index 97c8d8404..8c378ebb1 100644 --- a/zenmap/install_scripts/macosx/zenmap_auth.c +++ b/zenmap/install_scripts/macosx/zenmap_auth.c @@ -18,7 +18,7 @@ #include #include -#define EXECUTABLE_NAME "zenmap_wrapper.py" +#define EXECUTABLE_NAME "zenmap.bin" int main(int argc, char *argv[]) { AuthorizationItem items[] = { diff --git a/zenmap/install_scripts/macosx/zenmap_wrapper.py b/zenmap/install_scripts/macosx/zenmap_wrapper.py deleted file mode 100755 index 8689e73aa..000000000 --- a/zenmap/install_scripts/macosx/zenmap_wrapper.py +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env python - -# This is a wrapper script around the zenmap executable, used in a Mac OS X -# .app bundle. It sets environment variables, fills in template configuration -# files, starts X11 if necessary, and execs the real zenmap executable. -# -# This program is the second link in the chain -# zenmap_auth -> zenmap_wrapper.py -> zenmap.bin - -import errno -import os -import os.path -import sys - -HOME = os.path.expanduser("~") - - -def create_dir(path): - """Create a directory with os.makedirs without raising an error if the - directory already exists.""" - try: - os.makedirs(path) - except OSError, e: - if e.errno != errno.EEXIST: - raise - -# We will need to rewrite some configuration files to refer to directories -# inside the application bundle, wherever it may be. This is tricky because of -# escaping issues in the formats of the configuration files. The following -# functions handle it. - -# The format of pango/pangorc is called "key file." It's described at -# http://library.gnome.org/devel/glib/stable/glib-Key-value-file-parser. - - -# Escape a string as appropriate for a "key file." -def escape_key_file_value(value): - result = [] - for c in value: - if c == "\n": - c = "\\n" - elif c == "\t": - c = "\\t" - elif c == "\r": - c = "\\r" - elif c == "\\": - c = "\\\\" - result.append(c) - if len(result) > 0 and result[0] == " ": - result[0] = "\\s" - result = "".join(result) - return result - - -def substitute_key_file_line(line, replacements): - for text, rep in replacements.items(): - line = line.replace(text, escape_key_file_value(rep)) - return line - - -# Substitute a dict of replacements into a "key file." -def substitute_key_file(in_file_name, out_file_name, replacements): - in_file = open(in_file_name, "r") - out_file = open(out_file_name, "w") - for line in in_file: - out_file.write(substitute_key_file_line(line, replacements)) - in_file.close() - out_file.close() - - -def escape_shell(arg): - """Escape a string to be a shell argument.""" - result = [] - for c in arg: - if c in "$`\"\\": - c = "\\" + c - result.append(c) - return "\"" + "".join(result) + "\"" - - -def hack_xinitrc(system_xinitrc_filename, home_xinitrc_filename): - """Hack the system xinitrc file and put the modified contents into another - file. The parameter names reflect the fact that this is intended to copy - the system xinitrc into ~/.xinitrc. The modified xinitrc will delete itself - on its first invocation and will not run any instances of xterm. This is - necessary on Mac OS X 10.4 and earlier, which include a call to xterm in - the system xinitrc.""" - system_xinitrc = open(system_xinitrc_filename, "r") - home_xinitrc = open(home_xinitrc_filename, "w") - lines = iter(system_xinitrc) - # Look for the first non-comment line so we don't preempt the #! line. - for line in lines: - if not line.lstrip().startswith("#"): - break - home_xinitrc.write(line) - # Write the self-destruct line. - home_xinitrc.write("\n") - home_xinitrc.write("rm -f %s\n" % escape_shell(home_xinitrc_filename)) - home_xinitrc.write(line) - # Copy the rest, removing any calls to xterm - for line in lines: - if line.lstrip().startswith("xterm"): - line = "# " + line - home_xinitrc.write(line) - system_xinitrc.close() - home_xinitrc.close() - - -def start_x11(): - """Start the X11 server if necessary and set the DISPLAY environment as - appropriate. If the user hasn't set up a custom ~/.xinitrc, call - hack_xinitrc to make a ~/.xinitrc that will not start an xterm along with - the application. A similar approach is taken by Wireshark and Inkscape.""" - if "DISPLAY" in os.environ: - return - system_xinitrc_filename = "/usr/X11R6/lib/X11/xinit/xinitrc" - home_xinitrc_filename = os.path.join(HOME, ".xinitrc") - if (os.path.exists(system_xinitrc_filename) and not - os.path.exists(home_xinitrc_filename)): - hack_xinitrc(system_xinitrc_filename, home_xinitrc_filename) - os.system("open -a X11") - os.environ["DISPLAY"] = ":0" - -if __name__ == "__main__": - # Make the real UID equal the effective UID. They are unequal when running - # with privileges under AuthorizationExecuteWithPrivileges. GTK+ refuses to - # run if they are different. - if os.getuid() != os.geteuid(): - os.setuid(os.geteuid()) - - # Paths within the application bundle. - currentdir = os.path.dirname(os.path.abspath(sys.argv[0])) - parentdir = os.path.dirname(currentdir) - resourcedir = os.path.join(parentdir, "Resources") - - # A directory where we put automatically generated GTK+ and Pango files. - # This could be something different like /tmp or "~/Library/Application - # Support/Zenmap". It is put somewhere other than within the application - # bundle to allow running from a read-only filesystem. - etcdir = os.path.join(HOME, ".zenmap-etc") - - # See http://library.gnome.org/devel/gtk/2.12/gtk-running.html for the - # meaning of the GTK+ environment variables. These files are static and - # live inside the application bundle. - os.environ["GTK_DATA_PREFIX"] = resourcedir - os.environ["GTK_EXE_PREFIX"] = resourcedir - os.environ["GTK_PATH"] = resourcedir - os.environ["FONTCONFIG_PATH"] = os.path.join(resourcedir, "etc", "fonts") - # Use the packaged gtkrc only if the user doesn't have a custom one. - if not os.path.exists(os.path.expanduser("~/.gtkrc-2.0")): - os.environ["GTK2_RC_FILES"] = os.path.join( - resourcedir, "etc", "gtk-2.0", "gtkrc") - - # The following environment variables refer to files within ~/.zenmap-etc - # that are automatically generated from templates. - os.environ["PANGO_RC_FILE"] = os.path.join(etcdir, "pango", "pangorc") - - # Create the template directory. - create_dir(os.path.join(etcdir, "pango")) - - REPLACEMENTS = { - "${RESOURCES}": resourcedir, - "${ETC}": etcdir - } - - # Fill in the templated configuration files with the correct substitutions. - KEY_FILE_TEMPLATES = ( - "pango/pangorc", - ) - for f in KEY_FILE_TEMPLATES: - in_file_name = os.path.join(resourcedir, "etc", f + ".in") - out_file_name = os.path.join(etcdir, f) - substitute_key_file(in_file_name, out_file_name, REPLACEMENTS) - - start_x11() - - # exec the real program. - os.execl( - os.path.join(os.path.dirname(sys.argv[0]), "zenmap.bin"), - *sys.argv - ) diff --git a/zenmap/setup.py b/zenmap/setup.py index 68e60825a..fd0280140 100755 --- a/zenmap/setup.py +++ b/zenmap/setup.py @@ -629,6 +629,9 @@ elif 'py2app' in sys.argv: } setup_args.update(MACOSX_SETUP_ARGS) +elif 'vanilla' in sys.argv: + # Don't create uninstaller, don't fix paths. Used for bundling on OS X + sys.argv.remove('vanilla') else: # Default args. DEFAULT_SETUP_ARGS = { diff --git a/zenmap/zenmapCore/Paths.py b/zenmap/zenmapCore/Paths.py index 404d7ced2..a1195a177 100644 --- a/zenmap/zenmapCore/Paths.py +++ b/zenmap/zenmapCore/Paths.py @@ -139,7 +139,7 @@ from zenmapCore.Name import APP_NAME # http://mail.python.org/pipermail/pythonmac-sig/2004-November/012121.html. def get_prefix(): frozen = getattr(sys, "frozen", None) - if frozen == "macosx_app": + if frozen == "macosx_app" or "Zenmap.app" in sys.executable: # A py2app .app bundle. return os.path.join(dirname(fs_dec(sys.executable)), "..", "Resources") elif frozen is not None: