macos: use pkgbuild to build the package on 10.10/10.11 39/12239/6
authorMarcio Barbosa <mbarbosa@sinenomine.net>
Fri, 15 Jul 2016 15:22:11 +0000 (12:22 -0300)
committerBenjamin Kaduk <kaduk@mit.edu>
Sun, 17 Jul 2016 17:44:48 +0000 (13:44 -0400)
PackageMaker is no longer part of OS X. As a result, it
is not possible to build the package on OS X 10.10 and
OS X 10.11 using the existing code.

To solve this problem, a new script, along with a couple
of new files, are provided.

- pkgbuild.sh

This script uses the command line tools pkgbuild and
productbuild to build the package on OS X 10.10 and
OS X 10.11. By default, the package built by this
script will not be signed. Optionally, the package
might be signed.

- Distribution.xml

This file is nothing more than an XML file used by
productbuild. It is mainly used to configure how the
installer will look and behave.

- conclusion.txt

Contains the text that is displayed by Installer at
the end of the installation process. Only used by
El Capitan and further.

- Uninstall.14.15

This script can be used by OS X 10.10/10.11 users
to uninstall OpenAFS.

Notes:

- This work is based on a patch made by Brandon Allbery
  <ballbery@sinenomine.net> with fixes and updates from
  Andrew Deason <adeason@dson.org>.

- El Capitan and further prevent us from touching
  /usr/bin directly. As a result, /opt is used.

- If the package is not signed, the user will have
  to disable the OS X security protections. Otherwise,
  the client will not work.

- Now we have two different scripts to build the
  package on OS X. For OS X 10.10 and newer versions,
  pkgbuild.sh will be used. For older versions,
  the existing buildpkg.sh will be used.

Change-Id: If8320666c553b82af450c0263f5e80a00c33e3b8
Reviewed-on: https://gerrit.openafs.org/12239
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

Makefile.in
configure.ac
src/afsd/afs.rc.darwin
src/packaging/MacOS/Distribution.xml.in [new file with mode: 0644]
src/packaging/MacOS/OpenAFS.post_install
src/packaging/MacOS/Uninstall.14.15 [new file with mode: 0755]
src/packaging/MacOS/conclusion.txt [new file with mode: 0644]
src/packaging/MacOS/pkgbuild.sh.in [new file with mode: 0644]

index 4298775..aac826f 100644 (file)
@@ -93,8 +93,10 @@ dest_only_libafs: only_libafs dest_dirs
 
 packages: dest
        @case ${SYS_NAME} in \
-       *_darwin_* ) \
+       *_darwin_1[2-4] | *_darwin_[6-9]0 | *_darwin_1[0-3]0 ) \
                ${COMPILE_PART1} packaging/MacOS && bash ./buildpkg.sh ${DEST} ;; \
+       *_darwin_* ) \
+               ${COMPILE_PART1} packaging/MacOS && bash ./pkgbuild.sh ${DEST} ;; \
        hp_ux110 ) \
                ${COMPILE_PART1} packaging/HP-UX && swpackage -s  psf-1.2.10-transarc-paths-11.00 ;; \
        hp_ux11i ) \
index 8138480..a00a6fd 100644 (file)
@@ -234,6 +234,7 @@ AC_OUTPUT([
     src/packaging/MacOS/OpenAFS.Info.plist
     src/packaging/MacOS/OpenAFS.info
     src/packaging/MacOS/buildpkg.sh
+    src/packaging/MacOS/pkgbuild.sh
     src/pam/Makefile
     src/platform/Makefile
     src/platform/${MKAFS_OSTYPE}/Makefile
index 177a625..6457ac7 100644 (file)
@@ -25,6 +25,9 @@ AFSD=$VICEETC/afsd
 if [ -r /var/db/openafs ]; then
     VICEETC=/var/db/openafs/etc
     AFSD=/usr/sbin/afsd
+    if [ -x /opt/openafs/sbin/afsd ] ; then
+       AFSD=/opt/openafs/sbin/afsd
+    fi
 fi
 
 CONFIG=$VICEETC/config
diff --git a/src/packaging/MacOS/Distribution.xml.in b/src/packaging/MacOS/Distribution.xml.in
new file mode 100644 (file)
index 0000000..96a2d8f
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<installer-gui-script minSpecVersion="2">
+    <options rootVolumeOnly="true" />
+    <volume-check>
+       <allowed-os-versions>
+           <os-version min="10.%%OSX_MAJOR_CUR%%.0" before="10.%%OSX_MAJOR_NEXT%%.0"/>
+       </allowed-os-versions>
+    </volume-check>
+    <installation-check>
+       <ram min-gb="2.00"/>
+    </installation-check>
+    <!--+==========================+
+        |       Presentation       |
+        +==========================+-->
+    <title>OpenAFS</title>
+    <background file="background.jpg" scaling="proportional" alignment="bottomleft"/>
+    <readme file="ReadMe.rtf"/>
+    <license file="License.rtf"/>
+    %%PRES_EXTRA%%
+    <!--+==========================+
+        |         Installer        |
+        +==========================+-->
+    <choices-outline>
+       <line choice="installer_normal"/>
+       <line choice="installer_debug"/>
+    </choices-outline>
+    <choice id="installer_normal" title="OpenAFS client" enabled="false" selected="true"
+           description="This provides the OpenAFS client, kernel module, and utilities.
+           Everything you need to run a client normally.">
+       <pkg-ref id="org.openafs.OpenAFS.pkg"/>
+    </choice>
+    <choice id="installer_debug" title="OpenAFS kernel debug info" start_selected="true"
+           description="Installing this provides some extra files that are useful for
+           debugging issues with the OpenAFS client. You can safely leave this out to
+           save disk space, but it does no harm to install it.">
+       <pkg-ref id="org.openafs.OpenAFS-debug.pkg"/>
+    </choice>
+    <!--+==========================+
+        |    Package References    |
+        +==========================+-->
+    <pkg-ref id="org.openafs.OpenAFS.pkg">
+       #OpenAFS-dist.pkg
+    </pkg-ref>
+    <pkg-ref id="org.openafs.OpenAFS-debug.pkg">
+       #OpenAFS-debug-extension.pkg
+    </pkg-ref>
+    <product version="%%OPENAFS_VERSION%%"/>
+</installer-gui-script>
index fcb1469..b9ef27b 100644 (file)
@@ -127,8 +127,10 @@ fi
 # properly, we should acquire a certificate from a real CA and ship 
 # signed binaries. for now, make Application Firewall (Security prefs pane)
 # happy like this. See TN2206
-if [ -f /usr/bin/codesign ]; then
-  codesign -s - /usr/sbin/afsd
+if [ $majorvers -lt 14 ]; then
+    if [ -f /usr/bin/codesign ]; then
+       codesign -s - /usr/sbin/afsd
+    fi
 fi
 
 #here we should run tools which configure the client, and then if it's enabled:
diff --git a/src/packaging/MacOS/Uninstall.14.15 b/src/packaging/MacOS/Uninstall.14.15
new file mode 100755 (executable)
index 0000000..460fceb
--- /dev/null
@@ -0,0 +1,357 @@
+#!/usr/bin/perl -w
+# real Perl code begins here
+#
+# Adapted from Apple's uninstall-devtools.pl (Version 7 for Xcode Tools 1.2)
+#
+# BSD License: c.f. <http://www.opensource.org/licenses/bsd-license>
+#
+
+use strict;
+use warnings;
+use File::Basename;
+
+use vars qw ($do_nothing $print_donothing_removals $receipts_dir $verbose $noisy_warnings);
+use vars qw ($suppress_spin $spin_counter $spin_state $spin_slower_downer);
+use vars qw (%exception_list $gen_dirs @gen_files @rmfiles @rmdirs @rmpkg);
+
+#----------------------------------------------------------------------------------------
+
+$do_nothing = 0;
+$print_donothing_removals = 1;
+$verbose = 1;
+$noisy_warnings = 0;
+
+# One of rm -rf in this script uses $receipts_dir -- change with care.
+$receipts_dir = "/Library/Receipts";
+
+%exception_list = (
+);
+
+$gen_dirs = { };
+
+@gen_files = (
+    "/var/db/openafs/etc/cacheinfo",
+    "/var/db/openafs/etc/ThisCell",
+    "/var/db/openafs/etc/config/afsd.options",
+    "/var/db/openafs/etc/config/afs.conf",
+    "/var/db/openafs/etc/CellServDB.save",
+    "/var/db/openafs/etc/CellServDB.master.last",
+    "/var/db/openafs/etc/CellServDB",
+    "/var/db/openafs/etc/config/settings.plist",
+);
+
+#----------------------------------------------------------------------------------------
+
+$| = 1;
+
+sub main {
+    # commandline args:
+    #     0: dir of packages to remove
+    #     1: flag indicating whether to keep package receipts
+    #     2: flag indicating whether to supress spin indicator
+
+    if (!@ARGV) {
+       use FindBin qw($Bin);
+       @ARGV = ("$Bin/..", 0, 0);
+    }
+    $suppress_spin = defined ($ARGV[2]) && $ARGV[2];
+
+    $spin_counter = 0;
+    $spin_state = 0;
+    spin_rate_slow ();
+
+    pre_print ();
+    print "Uninstalling OpenAFS package:\n\n";
+
+    remove_generated_files ();
+    remove_main_packages ();
+    remove_generated_directories ();
+
+    if ($do_nothing == 0) {
+       # When osascript runs some shell commands, newlines are printed as just
+       # \r instead of \n for some reason, so anything output kinda overwrites
+       # earlier output. The final 'tr' in the pipeline here turns them back
+       # into \n newlines. pkgutil --forget at least will print output like
+       # "Forgot package 'foo'".
+       my $rmcmd = "osascript -e 'do shell script \"/bin/rm -f @rmfiles; " .
+                   "/bin/rmdir @rmdirs; echo @rmpkg | xargs -n 1 " .
+                   "/usr/sbin/pkgutil --forget\" with administrator " .
+                   "privileges' | tr '\\r' '\\n'";
+       system $rmcmd;
+       my $retcode = $? >> 8;
+       if ($retcode != 0) {
+           print_warning ("Warning:  There may have been a problem uninstalling\n");
+       }
+    }
+
+    pre_print ();
+    print "\nFinished uninstalling.\n";
+}
+
+sub remove_main_packages {
+     my @pkglist = ("org.openafs.OpenAFS-debug.pkg",
+                   "org.openafs.OpenAFS.pkg",
+                   );
+
+    foreach (@pkglist) {
+       s/\.pkg$//;
+       my $pkgname = $_;
+       my $pkg = $pkgname.".pkg";
+       my $bomroot;
+
+       if (not open(INFO, '-|', "/usr/sbin/pkgutil --pkg-info $pkg | " .
+                                "grep ^volume: | cut -d' ' -f2-")) {
+           print_warning("Warning: Could not get pkg info for $pkg " .
+                         "(maybe it's not installed?)\n");
+           next;
+       }
+
+       $bomroot = <INFO>;
+       if ((not close(INFO)) or (!defined($bomroot))) {
+           print_warning("Warning: Could not get pkg info for $pkg " .
+                         "(maybe it's not installed?)\n");
+           next;
+       }
+
+       chomp $bomroot;
+
+       pre_print();
+       print "\nFound pkg install root $bomroot for $pkg\n";
+
+       spin_rate_slow ();
+
+       if (not open (LSBOM, '-|', "/usr/sbin/pkgutil --only-files --files $pkg")) {
+           print_warning("Warning: Error running pkgutil --only-files --files $pkg\n");
+           next;
+       }
+
+       while (<LSBOM>) {
+           chomp;
+           m#^(.*/.*)$#;
+           next if (!defined ($1) || $1 eq "");
+           my $filename = $bomroot . $1;
+
+           remove_a_file ($filename);
+       }
+       close (LSBOM);
+
+       my $rooth = { };
+
+       if (not open (LSBOM, '-|', "/usr/sbin/pkgutil --only-dirs --files $pkg")) {
+           print_warning("Warning: Error running pkgutil --only-dirs --files $pkg\n");
+           next;
+       }
+
+       while (<LSBOM>) {
+           chomp;
+           m#^(.*/.*)$#;
+           next if (!defined ($1) || $1 eq "");
+           my $directory = $bomroot . $1;
+           if (-d $directory) {
+               $rooth = add_directory_to_tree ($directory, $rooth);
+           } else {
+               if ($noisy_warnings) {
+                   print_warning ("Warning: \"$directory\" listed in BOM " .
+                                  "but not present on system.\n");
+               }
+           }
+       }
+       close (LSBOM);
+
+       spin_rate_fast ();
+       remove_empty_directories ($rooth, $bomroot);
+
+       remove_package_receipts($pkg) if (!defined ($ARGV[1]) || !$ARGV[1]);
+    }
+}
+
+sub remove_generated_files {
+    foreach (@gen_files) {
+       remove_a_file ($_);
+    }
+}
+
+sub remove_generated_directories {
+    remove_empty_directories ($gen_dirs, "/");
+}
+
+sub add_directory_to_tree {
+    my $dir = shift;
+    my $rooth = shift;
+    my $p = $rooth;
+
+    my @pathcomp = split /\//, $dir;
+
+    progress_point ();
+    foreach (@pathcomp) {
+       my $cur_name = $_;
+       if ($cur_name eq "" || !defined ($cur_name)) {
+           $cur_name = "/";
+       }
+       if (!defined ($p->{"$cur_name"})) {
+           $p->{$cur_name} = { };
+       }
+       $p = $p->{$cur_name};
+    }
+    return $rooth;
+}
+
+sub remove_empty_directories {
+    my $rooth = shift;
+    my $path = shift;
+    my $children = (scalar (keys %{$rooth}));
+    my $dirs_remain = 0;
+
+    if ($children > 0) {
+       foreach my $dirname (sort keys %{$rooth}) {
+           my $printpath;
+           $printpath = "$path/$dirname";
+           $printpath =~ s#^/*#/#;
+           remove_empty_directories ($rooth->{$dirname}, "$printpath");
+           $dirs_remain = 1 if (-d "$printpath");
+       }
+    }
+
+    if ($dirs_remain == 0) {
+       maybe_remove_ds_store ("$path");
+    }
+
+    remove_a_dir ("$path");
+}
+
+sub remove_a_file {
+    my $fn = shift;
+    my $dirname = dirname ($fn);
+    my $basename = basename ($fn);
+    my $ufs_rsrc_file = "$dirname/._$basename";
+
+    progress_point ();
+    return if (!defined ($fn) || $fn eq "");
+
+    # Leave any files that are shared between packages alone.
+    if (defined($exception_list{$fn})) {
+       if ($noisy_warnings) {
+           print_warning ("Warning: file \"$fn\" intentionally not removed, " .
+                          "even though it's in the BOM.\n");
+       }
+       return;
+    }
+
+    if (! -f $fn && ! -l $fn) {
+       if ($noisy_warnings) {
+           print_warning ("Warning: file \"$fn\" present in BOM but not found on disc.\n");
+       }
+       return;
+    }
+
+    if ($do_nothing == 1) {
+       print_donothing ("rm $fn\n");
+       print_donothing ("rm $ufs_rsrc_file\n") if ( -f $ufs_rsrc_file);
+    } else {
+       unshift(@rmfiles, "$fn");
+       unshift(@rmfiles, "$ufs_rsrc_file") if ( -f $ufs_rsrc_file);
+    }
+}
+
+sub remove_a_dir {
+    my $dir = shift;
+
+    progress_point ();
+    return if (!defined ($dir) || $dir eq "" || $dir eq "/" || $dir eq "/usr");
+    if (! -d $dir) {
+       if ($noisy_warnings) {
+           print_warning ("Warning: directory \"$dir\" present in BOM " .
+                          "but not found on disc.\n");
+       }
+       return;
+    }
+
+    if ($do_nothing == 1) {
+       print_donothing ("rmdir $dir\n");
+    } else {
+       push(@rmdirs, "$dir");
+    }
+}
+
+sub remove_package_receipts {
+    my $pkgname = shift;
+    $pkgname =~ s#/##g;  # There shouldn't be any path seps in the pkg name...
+    return if (!defined ($pkgname) || $pkgname eq ""
+              || $pkgname eq "." || $pkgname eq "..");
+
+    if ($do_nothing == 1) {
+       print_donothing("pkgutil --forget $pkgname\n");
+    } else {
+       push(@rmpkg, $pkgname);
+    }
+}
+
+sub maybe_remove_ds_store {
+    my $path = shift;
+    my $filecount = 0;
+    return if (!defined ($path) || $path eq "" || $path eq "/" || $path eq "/usr");
+    return if (! -f "$path/.DS_Store");
+
+    open (LS, "/bin/ls -a '$path' |");
+    while (<LS>) {
+       chomp;
+       next if (m#^\.$# || m#^\.\.$#);
+       $filecount++;
+    }
+    close (LS);
+
+    if ($filecount == 1) {
+       remove_a_file ("$path/.DS_Store");
+    }
+}
+
+sub print_donothing {
+    my $msg = shift;
+    return if ($print_donothing_removals != 1);
+    pre_print ();
+    print $msg;
+}
+
+sub print_verbose {
+    my $msg = shift;
+    return if ($verbose != 1);
+    pre_print ();
+    print $msg;
+}
+
+sub print_warning {
+    my $msg = shift;
+    pre_print ();
+    print STDERR $msg;
+}
+
+sub print_error {
+    my $msg = shift;
+    pre_print ();
+    print STDERR $msg;
+}
+
+sub pre_print {
+    print " \b" unless ($suppress_spin);
+}
+
+sub spin_rate_slow {
+    $spin_slower_downer = 150;
+}
+
+sub spin_rate_fast {
+    $spin_slower_downer = 75;
+}
+
+sub progress_point {
+    return if ($suppress_spin);
+    $spin_counter++;
+    if (($spin_counter % $spin_slower_downer) == 0) {
+       my $spin_chars = "|/-\\";
+       my $c = substr ($spin_chars, $spin_state % 4, 1);
+       $spin_state++;
+       print "\e[7m$c\e[m\b";
+    }
+}
+
+main ();
diff --git a/src/packaging/MacOS/conclusion.txt b/src/packaging/MacOS/conclusion.txt
new file mode 100644 (file)
index 0000000..60ff1ea
--- /dev/null
@@ -0,0 +1,3 @@
+OpenAFS commands have been installed into /opt/openafs/, instead of the old locations in /usr/bin/ and /usr/sbin/. You must start a new shell for your PATH to be automatically updated to find these commands.
+
+Alternatively, you can just add /opt/openafs/bin and /opt/openafs/sbin into your PATH manually.
diff --git a/src/packaging/MacOS/pkgbuild.sh.in b/src/packaging/MacOS/pkgbuild.sh.in
new file mode 100644 (file)
index 0000000..67f3cc9
--- /dev/null
@@ -0,0 +1,495 @@
+#!/bin/bash
+# Portions Copyright (c) 2003, 2006 Apple Computer, Inc.  All rights reserved.
+echo '**BUILDPKG**' "$@"
+
+usage() {
+    exec >&2
+
+    echo 'Usage: pkgbuild.sh [-x] [--app-key <appkey>] [--inst-key <instkey>]'
+    echo '                   [--pass N] [--csdb <CellServDB>] <binary-dir>'
+    echo
+    echo '--app-key and --inst-key are for signing. -x prints all comamnds as '
+    echo 'they are run.'
+    echo
+    echo 'By default, all passes are run. Available passes:'
+    echo '    --pass 1: prepare pkgroot'
+    echo '    --pass 2: create packages/installer from pkgroot'
+    echo 'If you want to alter the pkgroot, run pass 1, then alter what you'
+    echo 'want, and then run pass 2 to create the resulting packages.'
+    echo 'The --pass argument may be given multiple times.'
+    exit 1
+}
+
+if [ x"$#" = x0 ]; then
+    usage
+fi
+
+anypass=0
+PASS1=
+PASS2=
+
+APP_KEY=
+INST_KEY=
+DEST_DIR=
+CSDB=
+
+while [ x"$#" != x0 ] ; do
+    key="$1"
+    shift
+
+    case "$key" in
+    --app-key)
+       APP_KEY="$1"
+       shift
+       ;;
+    --inst-key)
+       INST_KEY="$1"
+       shift
+       ;;
+    --csdb)
+       CSDB="$1"
+       shift
+       ;;
+    --pass)
+       anypass=1
+       pass_arg="$1"
+       shift
+       case "$pass_arg" in
+       1)
+           PASS1=1
+           ;;
+       2)
+           PASS2=1
+           ;;
+       *)
+           echo "Unknown pass $pass_arg" >&2
+           exit 1
+           ;;
+       esac
+       ;;
+    -x)
+       DO_X=1
+       ;;
+    *)
+       if [ x"$DEST_DIR" = x ] ; then
+           DEST_DIR="$key"
+       else
+           echo "Error: Unknown arg $key" >&2
+           usage
+       fi
+       ;;
+    esac
+done
+
+if [ x"$anypass" = x0 ] ; then
+    PASS1=1
+    PASS2=1
+fi
+
+if [ x"$DEST_DIR" = x ] ; then
+    echo "Error: binary 'dest' dir not given"
+    usage
+fi
+
+set -e
+
+if [ x"$DO_X" = x1 ] ; then
+    set -x
+fi
+
+BINDEST=`cd "$DEST_DIR" && pwd`
+CURDIR=`pwd`
+RESSRC=`dirname "$0"`
+RESSRC=`cd "$RESSRC" && pwd`
+majorvers=`uname -r | cut -d. -f1`
+
+if [ x"$majorvers" = x10 ]; then
+    RELNAME="Snowleopard"
+    THISREL=6
+
+elif [ x"$majorvers" = x11 ]; then
+    RELNAME="Lion"
+    THISREL=7
+
+elif [ x"$majorvers" = x12 ]; then
+    RELNAME="MountainLion"
+    THISREL=8
+
+elif [ x"$majorvers" = x13 ]; then
+    RELNAME="Mavericks"
+    THISREL=9
+
+elif [ x"$majorvers" = x14 ]; then
+    RELNAME="Yosemite"
+    THISREL=10
+
+elif [ x"$majorvers" = x15 ]; then
+    RELNAME="ElCapitan"
+    THISREL=11
+
+elif [ x"$majorvers" = x ] ; then
+    echo "Error running uname" >&2
+    exit 1
+
+else
+    echo "Unknown major version $majorvers" >&2
+    exit 1
+fi
+
+SEP=:
+
+PKGROOT="$CURDIR"/pkgroot
+PKGRES="$CURDIR"/pkgres
+DPKGROOT="$CURDIR"/dpkgroot
+PLUGINS="$CURDIR"/plugins
+if test -e /usr/bin/pkgbuild; then
+    :
+else
+    echo pkgbuild not found >&2
+    exit 1
+fi
+if test -e /usr/bin/productbuild; then
+    :
+else
+    echo productbuild not found >&2
+    exit 1
+fi
+
+if [ x"$PASS1" = x1 ]; then
+    if [ -x /usr/bin/curl ] && [ x"$CSDB" = x ]; then
+       echo "No CellServDB provided; downloading one from central.org"
+       /usr/bin/curl -f -O https://www.central.org/dl/cellservdb/CellServDB
+       if [ -f "$CURDIR"/CellServDB ] ; then
+           CSDB="$CURDIR"/CellServDB
+       fi
+    fi
+
+    if [ x"$CSDB" = x ]; then
+       echo "A CellServDB file must be provided with --csdb" >&2
+       die=1
+    else
+       # Turn CSDB into an absolute path
+       case "$CSDB" in
+       /*)
+           ;;
+       *)
+           CSDB="$CURDIR/$CSDB"
+           ;;
+       esac
+
+       if grep -q 'GCO Public CellServDB' "$CSDB" ; then
+           touch "$CSDB"
+       else
+           echo "A proper CellServDB file must be provided" >&2
+           die=1
+       fi
+    fi
+
+    for f in ReadMe.rtf."$majorvers" \
+            License.rtf \
+            CellServDB.list \
+            OpenAFS.info \
+            OpenAFS.post_install \
+            OpenAFS.pre_upgrade \
+            csrvdbmerge.pl \
+            2.0.txt
+    do
+       if [ ! -f "$RESSRC/$f" ]; then
+           echo "file missing: $RESSRC/$f" >&2
+           die=1
+       fi
+    done
+    if [ x"$die" = x1 ]; then
+       echo "Correct above errors; then retry" >&2
+       exit 1
+    fi
+
+    for f in "$BINDEST"/bin/translate_et \
+            "$BINDEST/root.client/usr/vice/etc/afs.kext/Contents/MacOS/afs"
+    do
+       if [ ! -f "$f" ] ; then
+           echo "dest file missing: $f" >&2
+           die=1
+       fi
+    done
+    if [ x"$die" = x1 ]; then
+       echo $BINDEST " is not a valid binary dir. it should be the result of" >&2
+       echo "make dest" >&2
+       exit 1
+    fi
+
+    rm -rf "$PKGROOT" "$PLUGINS"
+    mkdir "$PKGROOT"
+    mkdir "$PLUGINS"
+
+    mkdir -p "$PKGROOT"/Library
+    mkdir -p "$PKGROOT"/Library/PreferencePanes
+    mkdir -p "$PKGROOT"/Library/Security/SecurityAgentPlugins
+
+    chown -R root${SEP}admin "$PKGROOT"
+    chmod -R 755 "$PKGROOT"
+
+    (cd "$BINDEST"/tools && pax -rw OpenAFS.prefPane "$PKGROOT"/Library/PreferencePanes/)
+    (cd "$BINDEST"/tools && pax -rw aklog.bundle \
+    "$PKGROOT"/Library/Security/SecurityAgentPlugins/)
+
+    mkdir -p "$PKGROOT"/Library/OpenAFS/Tools
+    (cd "$BINDEST" && pax -rw * "$PKGROOT"/Library/OpenAFS/Tools)
+
+    cd "$RESSRC"
+    mv "$PKGROOT"/Library/OpenAFS/Tools/installer/* "$PLUGINS"/
+
+    mkdir -p "$PKGROOT"/Library/LaunchDaemons
+    chmod -R o-w "$PKGROOT"/Library
+    chmod -R g-w "$PKGROOT"/Library
+
+    cp openafs.launchd.plist "$PKGROOT"/Library/LaunchDaemons/org.openafs.filesystems.afs.plist
+    chmod 644 "$PKGROOT"/Library/LaunchDaemons/org.openafs.filesystems.afs.plist
+
+    chown root${SEP}admin "$PKGROOT"/Library
+    chown -R root${SEP}wheel "$PKGROOT"/Library/LaunchDaemons
+    chown -R root${SEP}wheel "$PKGROOT"/Library/OpenAFS/Tools
+    chmod -R og-w "$PKGROOT"/Library/OpenAFS/Tools
+
+    mkdir -p "$PKGROOT"/private/var/db/openafs/cache
+    mkdir -p "$PKGROOT"/private/var/db/openafs/etc/config
+
+    cp openafs.launchdaemon "$PKGROOT"/private/var/db/openafs/etc/launchafs.sh
+    chmod 755 "$PKGROOT"/private/var/db/openafs/etc/launchafs.sh
+
+    cp "$CSDB" "$PKGROOT"/private/var/db/openafs/etc/CellServDB.master
+    echo grand.central.org > "$PKGROOT"/private/var/db/openafs/etc/ThisCell.sample
+    echo /afs:/var/db/openafs/cache:100000 > \
+        "$PKGROOT"/private/var/db/openafs/etc/cacheinfo.sample
+
+    cp -RP "$PKGROOT"/Library/OpenAFS/Tools/etc/afssettings \
+          "$PKGROOT"/private/var/db/openafs/etc/config
+    cp settings.plist "$PKGROOT"/private/var/db/openafs/etc/config/settings.plist.orig
+    cp afs.conf "$PKGROOT"/private/var/db/openafs/etc/config/afs.conf.sample
+    cp krb5-weak.conf "$PKGROOT"/private/var/db/openafs/etc/krb5-weak.conf
+
+    cp decode-panic "$PKGROOT"/Library/OpenAFS/Tools/tools
+    chmod a+x "$PKGROOT"/Library/OpenAFS/Tools/tools/decode-panic
+
+    rm -rf "$DPKGROOT"
+    mkdir "$DPKGROOT"
+    mkdir -p "$DPKGROOT"/Library/OpenAFS/Debug
+
+    mv "$PKGROOT"/Library/OpenAFS/Tools/root.client/usr/vice/etc/afs.kext.dSYM \
+       "$DPKGROOT"/Library/OpenAFS/Debug/
+    cp -RP "$PKGROOT"/Library/OpenAFS/Tools/root.client/usr/vice/etc/afs.kext \
+          "$DPKGROOT"/Library/OpenAFS/Debug/
+    chown -R root${SEP}wheel "$DPKGROOT"/Library/OpenAFS/Debug
+    chmod -R og-w "$DPKGROOT"/Library/OpenAFS/Debug
+
+    strip -X -S \
+       "$PKGROOT"/Library/OpenAFS/Tools/root.client/usr/vice/etc/afs.kext/Contents/MacOS/afs
+
+    mkdir -p "$PKGROOT"/private/var/db/openafs
+
+    cp -RP "$PKGROOT"/Library/OpenAFS/Tools/root.client/usr/vice/etc/afs.kext \
+          "$PKGROOT"/Library/OpenAFS/Tools/root.client/usr/vice/etc/C \
+          "$PKGROOT"/private/var/db/openafs/etc
+
+    chown -R root${SEP}wheel "$PKGROOT"/private
+    chmod -R og-w "$PKGROOT"/private
+
+    chown -R root${SEP}wheel "$PKGROOT"/private
+    chmod -R og-w "$PKGROOT"/private
+    chmod  og-rx "$PKGROOT"/private/var/db/openafs/cache
+
+    if [ x"$APP_KEY" != x ] ; then
+       # Sign each 'thing' that we have (commands, kexts, etc)
+       for obj in "$DPKGROOT"/Library/OpenAFS/Debug/afs.kext \
+                  "$PKGROOT"/Library/OpenAFS/Tools/root.client/usr/vice/etc/afs.kext \
+                  "$PKGROOT"/private/var/db/openafs/etc/afs.kext \
+                  "$PKGROOT"/Library/PreferencePanes/OpenAFS.prefPane/Contents/Resources/AFSBackgrounder.app \
+                  "$PKGROOT"/Library/PreferencePanes/OpenAFS.prefPane \
+                  "$PKGROOT"/Library/Security/SecurityAgentPlugins/aklog.bundle \
+                  "$PKGROOT"/Library/OpenAFS/Tools/tools/growlagent-openafs.app \
+                  "$PKGROOT"/Library/OpenAFS/Tools/tools/aklog.bundle \
+                  "$PLUGINS"/afscell.bundle
+       do
+           codesign --verbose --force --timestamp --sign "$APP_KEY" "$obj"
+       done
+
+       # Check if our signatures for our kexts are valid. 'kextutil' will exit
+       # with an error and print out a message if something is wrong with the
+       # signature. Note that a code signing cert must have the
+       # 1.2.840.113635.100.6.1.18 extension present to be used for kexts
+       # (most code signing certs cannot be used for kexts).
+       for kext in "$DPKGROOT"/Library/OpenAFS/Debug/afs.kext \
+                   "$PKGROOT"/Library/OpenAFS/Tools/root.client/usr/vice/etc/afs.kext \
+                   "$PKGROOT"/private/var/db/openafs/etc/afs.kext
+       do
+           kextutil -no-load -print-diagnostics "$kext"
+       done
+    fi
+
+    if [ $majorvers -ge 15 ]; then
+       # El Capitan and further prevent us from touching /usr/bin directly
+       PREFIX=/opt
+       USRBIN=/opt/openafs/bin
+       USRBIN2TOOLS=../../../Library/OpenAFS/Tools
+
+       USRSBIN=/opt/openafs/sbin
+       USRSBIN2TOOLS=../../../Library/OpenAFS/Tools
+
+       MANDIR=/opt/openafs/share/man
+       MANDIR2TOOLS=../../../../Library/OpenAFS/Tools
+
+       # Add our bin, sbin, and man directories to the default search path
+       mkdir -p "$PKGROOT"/etc/paths.d "$PKGROOT"/etc/manpaths.d
+       echo "$USRBIN" > "$PKGROOT"/etc/paths.d/40-openafs
+       echo "$USRSBIN" >> "$PKGROOT"/etc/paths.d/40-openafs
+       echo "$MANDIR" > "$PKGROOT"/etc/manpaths.d/40-openafs
+    else
+       PREFIX=/usr
+       USRBIN=/usr/bin
+       USRBIN2TOOLS=../../Library/OpenAFS/Tools
+
+       USRSBIN=/usr/sbin
+       USRSBIN2TOOLS="$USRBIN2TOOLS"
+
+       MANDIR=/usr/share/man
+       MANDIR2TOOLS=../../../Library/OpenAFS/Tools
+    fi
+
+    mkdir -p "$PKGROOT$USRBIN" \
+            "$PKGROOT$USRSBIN" \
+            "$PKGROOT$MANDIR"/man1 \
+            "$PKGROOT$MANDIR"/man5 \
+            "$PKGROOT$MANDIR"/man8
+
+    BINLIST="fs klog klog.krb pagsh pagsh.krb pts sys tokens tokens.krb unlog unlog.krb aklog"
+    ETCLIST="vos"
+
+    if [ x"$DO_X" = x1 ] ; then
+       # Don't print out every single 'ln -s'... that's kinda useless
+       : 'Symlinking commands and manpages into place...'
+       set +x
+    fi
+
+    for f in $BINLIST; do
+       ln -s "$USRBIN2TOOLS"/bin/"$f" "$PKGROOT$USRBIN/$f"
+    done
+    for f in $ETCLIST; do
+       ln -s "$USRSBIN2TOOLS"/etc/"$f" "$PKGROOT$USRSBIN/$f"
+    done
+
+    for section in man1 man5 man8 ; do
+       for f in $(ls $PKGROOT/Library/OpenAFS/Tools/man/$section); do
+
+           if [ -L "$PKGROOT/Library/OpenAFS/Tools/man/$section/$f" ] ; then
+               # If this manpage is a symlink, just change where it's pointing,
+               # and rename the link; don't actually 'gzip' it.
+               link=$(readlink "$PKGROOT/Library/OpenAFS/Tools/man/$section/$f")
+               rm -f "$PKGROOT/Library/OpenAFS/Tools/man/$section/$f"
+               ln -s "$link".gz "$PKGROOT/Library/OpenAFS/Tools/man/$section/$f".gz
+
+           else
+               gzip -9 "$PKGROOT/Library/OpenAFS/Tools/man/$section/$f"
+           fi
+           ln -s ../"$MANDIR2TOOLS"/man/"$section/$f".gz \
+                 "$PKGROOT$MANDIR/$section/$f".gz
+       done
+    done
+
+    if [ x"$DO_X" = x1 ] ; then
+       set -x
+    fi
+
+    ln -s "$USRBIN2TOOLS"/bin/kpasswd "$PKGROOT$USRBIN"/kpasswd.afs
+
+    ln -s "$USRSBIN2TOOLS"/root.client/usr/vice/etc/afsd "$PKGROOT$USRSBIN"/afsd
+
+    chown -R root${SEP}wheel "$PKGROOT$PREFIX"
+    chmod -R og-w "$PKGROOT$PREFIX"
+fi
+
+if [ x"$PASS2" = x1 ]; then
+    rm -rf "$PKGRES"
+    mkdir "$PKGRES"
+    cd "$RESSRC"
+
+    rm -rf "$CURDIR"/OpenAFS-debug-extension.pkg
+    /usr/bin/pkgbuild --root "$DPKGROOT" --id org.openafs.OpenAFS-debug.pkg \
+                     --version '@VERSION@' \
+            "$CURDIR"/OpenAFS-debug-extension.pkg
+
+    cd "$RESSRC"
+    cp OpenAFS.post_install "$PKGRES"/postinstall
+    cp OpenAFS.pre_upgrade "$PKGRES"/preupgrade
+    cp OpenAFS.post_install "$PKGRES"/postupgrade
+    cp csrvdbmerge.pl "$PKGRES"
+
+    chmod a+x "$PKGRES"/csrvdbmerge.pl \
+             "$PKGRES"/postinstall \
+             "$PKGRES"/postupgrade \
+             "$PKGRES"/preupgrade
+
+    cp CellServDB.list "$PKGRES"
+    chown -R root${SEP}wheel "$PKGRES"
+
+    rm -rf "$CURDIR"/OpenAFS-dist.pkg
+    /usr/bin/pkgbuild --root "$PKGROOT" --id org.openafs.OpenAFS.pkg \
+                     --version '@VERSION@' \
+                     --scripts "$PKGRES" "$CURDIR"/OpenAFS-dist.pkg
+
+    rm -rf "$PKGRES"
+    mkdir "$PKGRES"
+    cp background.jpg "$PKGRES"/background.jpg
+    cp License.rtf "$PKGRES"
+    cp ReadMe.rtf."$majorvers" "$PKGRES"/ReadMe.rtf
+    chown -R root${SEP}wheel "$PKGRES"
+
+    if [ $majorvers -ge 15 ] ; then
+       # For El Capitan and further, we have some extra information to tell
+       # the user at the end of the installation process.
+       cp conclusion.txt "$PKGRES"/conclusion.txt
+       PRES_EXTRA="<conclusion file=\"conclusion.txt\"/>"
+    fi
+
+    # generate Distribution.xml from Distribution.xml.in -- nonstandard substs
+    sed -e "s/%%OSX_MAJOR_CUR%%/$THISREL/g" \
+       -e "s/%%OSX_MAJOR_NEXT%%/$(( $THISREL + 1 ))/g" \
+       -e "s,%%PRES_EXTRA%%,$PRES_EXTRA,g" \
+       -e "s/%%OPENAFS_VERSION%%/@VERSION@/g" \
+       < Distribution.xml.in > Distribution.xml
+
+    rm -rf "$CURDIR/prod"
+    mkdir "$CURDIR/prod"
+    mv "$CURDIR"/OpenAFS-dist.pkg "$CURDIR"/OpenAFS-debug-extension.pkg "$CURDIR"/prod
+    /usr/bin/productbuild --distribution Distribution.xml --resources "$PKGRES" \
+                         --plugins "$PLUGINS" --package-path "$CURDIR"/prod "$CURDIR"/OpenAFS.pkg
+
+    if [ x"$INST_KEY" != x ] ; then
+       mv "$CURDIR"/OpenAFS.pkg "$CURDIR"/OpenAFS-unsigned.pkg
+       productsign --timestamp --sign "$INST_KEY" "$CURDIR"/OpenAFS-unsigned.pkg \
+                   "$CURDIR"/OpenAFS.pkg
+       rm -f "$CURDIR"/OpenAFS-unsigned.pkg
+    fi
+
+    rm -rf "$CURDIR/dmg"
+    rm -f "$CURDIR/TMP.dmg"
+    rm -rf "$CURDIR/OpenAFS-@VERSION@-$RELNAME.dmg"
+
+    mkdir "$CURDIR"/dmg
+    mv "$CURDIR"/OpenAFS.pkg "$CURDIR"/dmg
+    cp "$RESSRC"/Uninstall.14.15 "$CURDIR"/dmg/Uninstall.command
+    cp "$RESSRC"/DS_Store "$CURDIR"/dmg/.DS_Store
+    mkdir "$CURDIR"/dmg/.background
+    cp "$RESSRC"/afslogo.jpg "$CURDIR"/dmg/.background
+
+    if [ x"$APP_KEY" != x ] ; then
+       codesign --verbose --force --timestamp --sign "$APP_KEY" "$CURDIR"/dmg/Uninstall.command
+    fi
+
+    hdiutil create -srcfolder "$CURDIR"/dmg -volname OpenAFS \
+           -o "$CURDIR"/TMP.dmg
+    hdiutil convert -format UDZO "$CURDIR"/TMP.dmg \
+           -o "$CURDIR/OpenAFS-@VERSION@-$RELNAME".dmg
+
+    echo
+    echo "Created $CURDIR/OpenAFS-@VERSION@-$RELNAME".dmg
+fi