15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/perl
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ***** BEGIN LICENSE BLOCK *****
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Version: MPL 1.1/GPL 2.0/LGPL 2.1
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The contents of this file are subject to the Mozilla Public License Version
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1.1 (the "License"); you may not use this file except in compliance with
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the License. You may obtain a copy of the License at
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# http://www.mozilla.org/MPL/
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Software distributed under the License is distributed on an "AS IS" basis,
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# for the specific language governing rights and limitations under the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# License.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The Original Code is pkg-dmg, a Mac OS X disk image (.dmg) packager
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The Initial Developer of the Original Code is
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Mark Mentovai <mark@moxienet.com>.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Portions created by the Initial Developer are Copyright (C) 2005
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the Initial Developer. All Rights Reserved.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Contributor(s):
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Alternatively, the contents of this file may be used under the terms of
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# either the GNU General Public License Version 2 or later (the "GPL"), or
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# in which case the provisions of the GPL or the LGPL are applicable instead
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# of those above. If you wish to allow use of your version of this file only
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# under the terms of either the GPL or the LGPL, and not to allow others to
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# use your version of this file under the terms of the MPL, indicate your
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# decision by deleting the provisions above and replace them with the notice
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# and other provisions required by the GPL or the LGPL. If you do not delete
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the provisions above, a recipient may use your version of this file under
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the terms of any one of the MPL, the GPL or the LGPL.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ***** END LICENSE BLOCK *****
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)use strict;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)use warnings;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=pod
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 NAME
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)B<pkg-dmg> - Mac OS X disk image (.dmg) packager
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 SYNOPSIS
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)B<pkg-dmg>
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)B<--source> I<source-folder>
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)B<--target> I<target-image>
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--format> I<format>]
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--volname> I<volume-name>]
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--tempdir> I<temp-dir>]
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--mkdir> I<directory>]
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--copy> I<source>[:I<dest>]]
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--symlink> I<source>[:I<dest>]]
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--license> I<file>]
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--resource> I<file>]
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--icon> I<icns-file>]
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--attribute> I<a>:I<file>[:I<file>...]
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--idme>]
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--sourcefile>]
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--verbosity> I<level>]
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)[B<--dry-run>]
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 DESCRIPTION
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)I<pkg-dmg> takes a directory identified by I<source-folder> and transforms
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)it into a disk image stored as I<target-image>.  The disk image will
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)occupy the least space possible for its format, or the least space that the
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)authors have been able to figure out how to achieve.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 OPTIONS
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=over 5
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)==item B<--source> I<source-folder>
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Identifies the directory that will be packaged up.  This directory is not
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)touched, a copy will be made in a temporary directory for staging purposes.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)See B<--tempdir>.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)==item B<--target> I<target-image>
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The disk image to create.  If it exists and is not in use, it will be
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)overwritten.  If I<target-image> already contains a suitable extension,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)it will be used unmodified.  If no extension is present, or the extension
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)is incorrect for the selected format, the proper extension will be added.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)See B<--format>.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)==item B<--format> I<format>
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The format to create the disk image in.  Valid values for I<format> are:
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     - UDZO - zlib-compressed, read-only; extension I<.dmg>
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     - UDBZ - bzip2-compressed, read-only; extension I<.dmg>;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              create and use on 10.4 ("Tiger") and later only
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     - UDRO - uncompressed, read-only; extension I<.dmg>
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     - UDRW - uncompressed, read-write; extension I<.dmg>
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     - UDSP - uncompressed, read-write, sparse; extension I<.sparseimage>
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UDZO is the default format.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)See L<hdiutil(1)> for a description of these formats.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--volname> I<volume-name>
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The name of the volume in the disk image.  If not specified, I<volume-name>
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)defaults to the name of the source directory from B<--source>.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--tempdir> I<temp-dir>
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)A temporary directory to stage intermediate files in.  I<temp-dir> must
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)have enough space available to accommodate twice the size of the files
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)being packaged.  If not specified, defaults to the same directory that
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the I<target-image> is to be placed in.  B<pkg-dmg> will remove any
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)temporary files it places in I<temp-dir>.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--mkdir> I<directory>
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Specifies a directory that should be created in the disk image.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)I<directory> and any ancestor directories will be created.  This is
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)useful in conjunction with B<--copy>, when copying files to directories
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)that may not exist in I<source-folder>.  B<--mkdir> may appear multiple
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)times.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--copy> I<source>[:I<dest>]
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Additional files to copy into the disk image.  If I<dest> is
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)specified, I<source> is copied to the location I<dest> identifies,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)otherwise, I<source> is copied to the root of the new volume.  B<--copy>
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)provides a way to package up a I<source-folder> by adding files to it
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)without modifying the original I<source-folder>.  B<--copy> may appear
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)multiple times.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This option is useful for adding .DS_Store files and window backgrounds
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to disk images.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--symlink> I<source>[:I<dest>]
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Like B<--copy>, but allows symlinks to point out of the volume. Empty symlink
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)destinations are interpreted as "like the source path, but inside the dmg"
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This option is useful for adding symlinks to external resources,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)e.g. to /Applications.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--license> I<file>
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)A plain text file containing a license agreement to be displayed before
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the disk image is mounted.  English is the only supported language.  To
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)include license agreements in other languages, in multiple languages,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)or to use formatted text, prepare a resource and use L<--resource>.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--resource> I<file>
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)A resource file to merge into I<target-image>.  If I<format> is UDZO, UDBZ,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)or UDRO, the disk image will be flattened to a single-fork file that contains
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the resource but may be freely transferred without any special encodings.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)I<file> must be in a format suitable for L<Rez(1)>.  See L<Rez(1)> for a
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)description of the format, and L<hdiutil(1)> for a discussion on flattened
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)disk images.  B<--resource> may appear multiple times.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This option is useful for adding license agreements and other messages
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to disk images.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--icon> I<icns-file>
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Specifies an I<icns> file that will be used as the icon for the root of
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the volume.  This file will be copied to the new volume and the custom
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)icon attribute will be set on the root folder.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--attribute> I<a>:I<file>[:I<file>...]
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Sets the attributes of I<file> to the attribute list in I<a>.  See
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)L<SetFile(1)>
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--idme>
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Enable IDME to make the disk image "Internet-enabled."  The first time
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the image is mounted, if IDME processing is enabled on the system, the
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)contents of the image will be copied out of the image and the image will
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)be placed in the trash with IDME disabled.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--sourcefile>
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)If this option is present, I<source-folder> is treated as a file, and is
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)placed as a file within the volume's root folder.  Without this option,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)I<source-folder> is treated as the volume root itself.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--verbosity> I<level>
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Adjusts the level of loudness of B<pkg-dmg>.  The possible values for
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)I<level> are:
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     0 - Only error messages are displayed.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     1 - Print error messages and command invocations.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     2 - Print everything, including command output.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The default I<level> is 2.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item B<--dry-run>
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)When specified, the commands that would be executed are printed, without
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)actually executing them.  When commands depend on the output of previous
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)commands, dummy values are displayed.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=back
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 NON-OPTIONS
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=over 5
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Resource forks aren't copied.
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The root folder of the created volume is designated as the folder
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to open when the volume is mounted.  See L<bless(8)>.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)All files in the volume are set to be world-readable, only writable
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)by the owner, and world-executable when appropriate.  All other
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)permissions bits are cleared.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)When possible, disk images are created without any partition tables.  This
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)is what L<hdiutil(1)> refers to as I<-layout NONE>, and saves a handful of
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)kilobytes.  The alternative, I<SPUD>, contains a partition table that
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)is not terribly handy on disk images that are not intended to represent any
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)physical disk.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=item
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Read-write images are created with journaling off.  Any read-write image
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)created by this tool is expected to be transient, and the goal of this tool
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)is to create images which consume a minimum of space.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=back
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 EXAMPLE
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pkg-dmg --source /Applications/DeerPark.app --target ~/DeerPark.dmg
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --sourcefile --volname DeerPark --icon ~/DeerPark.icns
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --mkdir /.background
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --copy DeerParkBackground.png:/.background/background.png
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --copy DeerParkDSStore:/.DS_Store
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  --symlink /Applications:"/Drag to here"
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 REQUIREMENTS
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)I<pkg-dmg> has been tested with Mac OS X releases 10.2 ("Jaguar")
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)through 10.4 ("Tiger").  Certain adjustments to behavior are made
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)depending on the host system's release.  Mac OS X 10.3 ("Panther") or
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)later are recommended.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 LICENSE
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MPL 1.1/GPL 2.0/LGPL 2.1.  Your choice.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 AUTHOR
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Mark Mentovai
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=head1 SEE ALSO
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)L<bless(8)>, L<diskutil(8)>, L<hdid(8)>, L<hdiutil(1)>, L<Rez(1)>,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)L<rsync(1)>, L<SetFile(1)>
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)=cut
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)use Fcntl;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)use POSIX;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)use Getopt::Long;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub argumentEscape(@);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub cleanupDie($);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub command(@);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandInternal($@);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandInternalVerbosity($$@);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandOutput(@);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandOutputVerbosity($@);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandVerbosity($@);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub copyFiles($@);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub diskImageMaker($$$$$$$$);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub giveExtension($$);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub hdidMountImage($@);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub isFormatReadOnly($);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub licenseMaker($$);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub pathSplit($);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub setAttributes($@);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub trapSignal($);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub usage();
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Variables used as globals
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my(@gCleanup, %gConfig, $gDarwinMajor, $gDryRun, $gVerbosity);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use the commands by name if they're expected to be in the user's
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $PATH (/bin:/sbin:/usr/bin:/usr/sbin).  Otherwise, go by absolute
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# path.  These may be overridden with --config.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)%gConfig = ('cmd_bless'          => 'bless',
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_chmod'          => 'chmod',
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_diskutil'       => 'diskutil',
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_du'             => 'du',
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_hdid'           => 'hdid',
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_hdiutil'        => 'hdiutil',
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_mkdir'          => 'mkdir',
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_mktemp'         => 'mktemp',
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_Rez'            => '/usr/bin/Rez',
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_rm'             => 'rm',
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_rsync'          => 'rsync',
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'cmd_SetFile'        => '/usr/bin/SetFile',
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # create_directly indicates whether hdiutil create supports
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # -srcfolder and -srcdevice.  It does on >= 10.3 (Panther).
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # This is fixed up for earlier systems below.  If false,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # hdiutil create is used to create empty disk images that
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # are manually filled.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'create_directly'    => 1,
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # If hdiutil attach -mountpoint exists, use it to avoid
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # mounting disk images in the default /Volumes.  This reduces
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # the likelihood that someone will notice a mounted image and
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # interfere with it.  Only available on >= 10.3 (Panther),
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # fixed up for earlier systems below.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            #
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # This is presently turned off for all systems, because there
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # is an infrequent synchronization problem during ejection.
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # diskutil eject might return before the image is actually
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # unmounted.  If pkg-dmg then attempts to clean up its
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # temporary directory, it could remove items from a read-write
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # disk image or attempt to remove items from a read-only disk
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # image (or a read-only item from a read-write image) and fail,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # causing pkg-dmg to abort.  This problem is experienced
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # under Tiger, which appears to eject asynchronously where
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # previous systems treated it as a synchronous operation.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # Using hdiutil attach -mountpoint didn't always keep images
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # from showing up on the desktop anyway.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'hdiutil_mountpoint' => 0,
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # hdiutil makehybrid results in optimized disk images that
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # consume less space and mount more quickly.  Use it when
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # it's available, but that's only on >= 10.3 (Panther).
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # If false, hdiutil create is used instead.  Fixed up for
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # earlier systems below.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'makehybrid'         => 1,
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # hdiutil create doesn't allow specifying a folder to open
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # at volume mount time, so those images are mounted and
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # their root folders made holy with bless -openfolder.  But
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # only on >= 10.3 (Panther).  Earlier systems are out of luck.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # Even on Panther, bless refuses to run unless root.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # Fixed up below.
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'openfolder_bless'   => 1,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # It's possible to save a few more kilobytes by including the
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # partition only without any partition table in the image.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # This is a good idea on any system, so turn this option off.
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            #
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # Except it's buggy.  "-layout NONE" seems to be creating
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # disk images with more data than just the partition table
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # stripped out.  You might wind up losing the end of the
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # filesystem - the last file (or several) might be incomplete.
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'partition_table'    => 1,
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # To create a partition table-less image from something
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # created by makehybrid, the hybrid image needs to be
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # mounted and a new image made from the device associated
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # with the relevant partition.  This requires >= 10.4
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # (Tiger), presumably because earlier systems have
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # problems creating images from devices themselves attached
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # to images.  If this is false, makehybrid images will
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # have partition tables, regardless of the partition_table
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # setting.  Fixed up for earlier systems below.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'recursive_access'   => 1);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# --verbosity
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$gVerbosity = 2;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# --dry-run
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$gDryRun = 0;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# %gConfig fix-ups based on features and bugs present in certain releases.
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my($ignore, $uname_r, $uname_s);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)($uname_s, $ignore, $uname_r, $ignore, $ignore) = POSIX::uname();
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if($uname_s eq 'Darwin') {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($gDarwinMajor, $ignore) = split(/\./, $uname_r, 2);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # $major is the Darwin major release, which for our purposes, is 4 higher
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # than the interesting digit in a Mac OS X release.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if($gDarwinMajor <= 6) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # <= 10.2 (Jaguar)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # hdiutil create does not support -srcfolder or -srcdevice
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $gConfig{'create_directly'} = 0;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # hdiutil attach does not support -mountpoint
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $gConfig{'hdiutil_mountpoint'} = 0;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # hdiutil mkhybrid does not exist
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $gConfig{'makehybrid'} = 0;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if($gDarwinMajor <= 7) {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # <= 10.3 (Panther)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Can't mount a disk image and then make a disk image from the device
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $gConfig{'recursive_access'} = 0;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # bless does not support -openfolder on 10.2 (Jaguar) and must run
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # as root under 10.3 (Panther)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $gConfig{'openfolder_bless'} = 0;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)else {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # If it's not Mac OS X, just assume all of those good features are
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # available.  They're not, but things will fail long before they
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # have a chance to make a difference.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Now, if someone wanted to document some of these private formats...
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print STDERR ($0.": warning, not running on Mac OS X, ".
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   "this could be interesting.\n");
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Non-global variables used in Getopt
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my(@attributes, @copyFiles, @createSymlinks, $iconFile, $idme, $licenseFile,
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @makeDirs, $outputFormat, @resourceFiles, $sourceFile, $sourceFolder,
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $targetImage, $tempDir, $volumeName);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# --format
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$outputFormat = 'UDZO';
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# --idme
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$idme = 0;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# --sourcefile
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$sourceFile = 0;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Leaving this might screw up the Apple tools.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)delete $ENV{'NEXT_ROOT'};
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This script can get pretty messy, so trap a few signals.
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$SIG{'INT'} = \&trapSignal;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$SIG{'HUP'} = \&trapSignal;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$SIG{'TERM'} = \&trapSignal;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Getopt::Long::Configure('pass_through');
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GetOptions('source=s'    => \$sourceFolder,
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'target=s'    => \$targetImage,
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'volname=s'   => \$volumeName,
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'format=s'    => \$outputFormat,
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'tempdir=s'   => \$tempDir,
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'mkdir=s'     => \@makeDirs,
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'copy=s'      => \@copyFiles,
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'symlink=s'   => \@createSymlinks,
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'license=s'   => \$licenseFile,
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'resource=s'  => \@resourceFiles,
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'icon=s'      => \$iconFile,
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'attribute=s' => \@attributes,
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'idme'        => \$idme,
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'sourcefile'  => \$sourceFile,
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'verbosity=i' => \$gVerbosity,
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'dry-run'     => \$gDryRun,
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'config=s'    => \%gConfig); # "hidden" option not in usage()
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(@ARGV) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # All arguments are parsed by Getopt
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage();
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  exit(1);
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if($gVerbosity<0 || $gVerbosity>2) {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage();
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  exit(1);
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(!defined($sourceFolder) || $sourceFolder eq '' ||
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !defined($targetImage) || $targetImage eq '') {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # --source and --target are required arguments
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage();
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  exit(1);
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Make sure $sourceFolder doesn't contain trailing slashes.  It messes with
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# rsync.
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)while(substr($sourceFolder, -1) eq '/') {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chop($sourceFolder);
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(!defined($volumeName)) {
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Default volumeName is the name of the source directory.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@components);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @components = pathSplit($sourceFolder);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $volumeName = pop(@components);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my(@tempDirComponents, $targetImageFilename);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@tempDirComponents = pathSplit($targetImage);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$targetImageFilename = pop(@tempDirComponents);
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(defined($tempDir)) {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @tempDirComponents = pathSplit($tempDir);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)else {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Default tempDir is the same directory as what is specified for
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # targetImage
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $tempDir = join('/', @tempDirComponents);
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Ensure that the path of the target image has a suitable extension.  If
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# it didn't, hdiutil would add one, and we wouldn't be able to find the
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# file.
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Note that $targetImageFilename is not being reset.  This is because it's
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# used to build other names below, and we don't need to be adding all sorts
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# of extra unnecessary extensions to the name.
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my($originalTargetImage, $requiredExtension);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$originalTargetImage = $targetImage;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if($outputFormat eq 'UDSP') {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $requiredExtension = '.sparseimage';
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)else {
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $requiredExtension = '.dmg';
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$targetImage = giveExtension($originalTargetImage, $requiredExtension);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if($targetImage ne $originalTargetImage) {
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print STDERR ($0.": warning: target image extension is being added\n");
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print STDERR ('  The new filename is '.
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   giveExtension($targetImageFilename,$requiredExtension)."\n");
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Make a temporary directory in $tempDir for our own nefarious purposes.
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my(@output, $tempSubdir, $tempSubdirTemplate);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$tempSubdirTemplate=join('/', @tempDirComponents,
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'pkg-dmg.'.$$.'.XXXXXXXX');
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(!(@output = commandOutput($gConfig{'cmd_mktemp'}, '-d',
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $tempSubdirTemplate)) || $#output != 0) {
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cleanupDie('mktemp failed');
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if($gDryRun) {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (@output)=($tempSubdirTemplate);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)($tempSubdir) = @output;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)push(@gCleanup,
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempSubdir);});
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my($tempMount, $tempRoot, @tempsToMake);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$tempRoot = $tempSubdir.'/stage';
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$tempMount = $tempSubdir.'/mount';
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)push(@tempsToMake, $tempRoot);
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if($gConfig{'hdiutil_mountpoint'}) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push(@tempsToMake, $tempMount);
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(command($gConfig{'cmd_mkdir'}, @tempsToMake) != 0) {
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cleanupDie('mkdir tempRoot/tempMount failed');
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This cleanup object is not strictly necessary, because $tempRoot is inside
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# of $tempSubdir, but the rest of the script relies on this object being
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# on the cleanup stack and expects to remove it.
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)push(@gCleanup,
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempRoot);});
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If $sourceFile is true, it means that $sourceFolder is to be treated as
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# a file and placed as a file within the volume root, as opposed to being
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# treated as the volume root itself.  rsync will do this by default, if no
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# trailing '/' is present.  With a trailing '/', $sourceFolder becomes
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $tempRoot, instead of becoming an entry in $tempRoot.
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(command($gConfig{'cmd_rsync'}, '-aC', '--include', '*.so',
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '--copy-unsafe-links', $sourceFolder.($sourceFile?'':'/'),$tempRoot) != 0) {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cleanupDie('rsync failed');
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(@makeDirs) {
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($makeDir, @tempDirsToMake);
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  foreach $makeDir (@makeDirs) {
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($makeDir =~ /^\//) {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      push(@tempDirsToMake, $tempRoot.$makeDir);
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else {
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      push(@tempDirsToMake, $tempRoot.'/'.$makeDir);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(command($gConfig{'cmd_mkdir'}, '-p', @tempDirsToMake) != 0) {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cleanupDie('mkdir failed');
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# copy files and/or create symlinks
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)copyFiles($tempRoot, 'copy', @copyFiles);
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)copyFiles($tempRoot, 'symlink', @createSymlinks);
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if($gConfig{'create_directly'}) {
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # If create_directly is false, the contents will be rsynced into a
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # disk image and they would lose their attributes.
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setAttributes($tempRoot, @attributes);
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(defined($iconFile)) {
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(command($gConfig{'cmd_rsync'}, '-aC', '--include', '*.so',
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   '--copy-unsafe-links', $iconFile, $tempRoot.'/.VolumeIcon.icns') != 0) {
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cleanupDie('rsync failed for volume icon');
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # It's pointless to set the attributes of the root when diskutil create
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # -srcfolder is being used.  In that case, the attributes will be set
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # later, after the image is already created.
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(isFormatReadOnly($outputFormat) &&
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   (command($gConfig{'cmd_SetFile'}, '-a', 'C', $tempRoot) != 0)) {
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cleanupDie('SetFile failed');
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(command($gConfig{'cmd_chmod'}, '-R', 'a+rX,a-st,u+w,go-w',
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $tempRoot) != 0) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cleanupDie('chmod failed');
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)my($unflattenable);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(isFormatReadOnly($outputFormat)) {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $unflattenable = 1;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)else {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $unflattenable = 0;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)diskImageMaker($tempRoot, $targetImage, $outputFormat, $volumeName,
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $tempSubdir, $tempMount, $targetImageFilename, defined($iconFile));
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(defined($licenseFile) && $licenseFile ne '') {
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($licenseResource);
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $licenseResource = $tempSubdir.'/license.r';
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(!licenseMaker($licenseFile, $licenseResource)) {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cleanupDie('licenseMaker failed');
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push(@resourceFiles, $licenseResource);
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Don't add a cleanup object because licenseResource is in tempSubdir.
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(@resourceFiles) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Add resources, such as a license agreement.
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Only unflatten read-only and compressed images.  It's not supported
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # on other image times.
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if($unflattenable &&
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   (command($gConfig{'cmd_hdiutil'}, 'unflatten', $targetImage)) != 0) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cleanupDie('hdiutil unflatten failed');
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Don't push flatten onto the cleanup stack.  If we fail now, we'll be
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # removing $targetImage anyway.
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Type definitions come from Carbon.r.
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(command($gConfig{'cmd_Rez'}, 'Carbon.r', @resourceFiles, '-a', '-o',
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   $targetImage) != 0) {
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cleanupDie('Rez failed');
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Flatten.  This merges the resource fork into the data fork, so no
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # special encoding is needed to transfer the file.
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if($unflattenable &&
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   (command($gConfig{'cmd_hdiutil'}, 'flatten', $targetImage)) != 0) {
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cleanupDie('hdiutil flatten failed');
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $tempSubdir is no longer needed.  It's buried on the stack below the
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# rm of the fresh image file.  Splice in this fashion is equivalent to
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# pop-save, pop, push-save.
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)splice(@gCleanup, -2, 1);
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# No need to remove licenseResource separately, it's in tempSubdir.
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if(command($gConfig{'cmd_rm'}, '-rf', $tempSubdir) != 0) {
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cleanupDie('rm -rf tempSubdir failed');
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if($idme) {
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(command($gConfig{'cmd_hdiutil'}, 'internet-enable', '-yes',
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   $targetImage) != 0) {
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cleanupDie('hdiutil internet-enable failed');
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Done.
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)exit(0);
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# argumentEscape(@arguments)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Takes a list of @arguments and makes them shell-safe.
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub argumentEscape(@) {
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@arguments);
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @arguments = @_;
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($argument, @argumentsOut);
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  foreach $argument (@arguments) {
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $argument =~ s%([^A-Za-z0-9_\-/.=+,])%\\$1%g;
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push(@argumentsOut, $argument);
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return @argumentsOut;
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# cleanupDie($message)
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Displays $message as an error message, and then runs through the
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# @gCleanup stack, performing any cleanup operations needed before
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# exiting.  Does not return, exits with exit status 1.
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub cleanupDie($) {
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($message);
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($message) = @_;
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print STDERR ($0.': '.$message.(@gCleanup?' (cleaning up)':'')."\n");
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while(@gCleanup) {
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my($subroutine);
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $subroutine = pop(@gCleanup);
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    &$subroutine;
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  exit(1);
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# command(@arguments)
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Runs the specified command at the verbosity level defined by $gVerbosity.
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Returns nonzero on failure, returning the exit status if appropriate.
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Discards command output.
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub command(@) {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@arguments);
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @arguments = @_;
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return commandVerbosity($gVerbosity,@arguments);
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# commandInternal($command, @arguments)
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Runs the specified internal command at the verbosity level defined by
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $gVerbosity.
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Returns zero(!) on failure, because commandInternal is supposed to be a
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# direct replacement for the Perl system call wrappers, which, unlike shell
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# commands and C equivalent system calls, return true (instead of 0) to
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# indicate success.
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandInternal($@) {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@arguments, $command);
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($command, @arguments) = @_;
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return commandInternalVerbosity($gVerbosity, $command, @arguments);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# commandInternalVerbosity($verbosity, $command, @arguments)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Run an internal command, printing a bogus command invocation message if
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $verbosity is true.
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If $command is unlink:
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Removes the files specified by @arguments.  Wraps unlink.
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If $command is symlink:
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Creates the symlink specified by @arguments. Wraps symlink.
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandInternalVerbosity($$@) {
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@arguments, $command, $verbosity);
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($verbosity, $command, @arguments) = @_;
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if($command eq 'unlink') {
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($verbosity || $gDryRun) {
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print(join(' ', 'rm', '-f', argumentEscape(@arguments))."\n");
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($gDryRun) {
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return $#arguments+1;
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return unlink(@arguments);
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elsif($command eq 'symlink') {
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($verbosity || $gDryRun) {
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print(join(' ', 'ln', '-s', argumentEscape(@arguments))."\n");
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($gDryRun) {
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1;
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my($source, $target);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ($source, $target) = @arguments;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return symlink($source, $target);
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# commandOutput(@arguments)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Runs the specified command at the verbosity level defined by $gVerbosity.
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Output is returned in an array of lines.  undef is returned on failure.
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The exit status is available in $?.
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandOutput(@) {
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@arguments);
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @arguments = @_;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return commandOutputVerbosity($gVerbosity, @arguments);
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# commandOutputVerbosity($verbosity, @arguments)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Runs the specified command at the verbosity level defined by the
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $verbosity argument.  Output is returned in an array of lines.  undef is
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# returned on failure.  The exit status is available in $?.
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If an error occurs in fork or exec, an error message is printed to
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# stderr and undef is returned.
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If $verbosity is 0, the command invocation is not printed, and its
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# stdout is not echoed back to stdout.
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If $verbosity is 1, the command invocation is printed.
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If $verbosity is 2, the command invocation is printed and the output
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# from stdout is echoed back to stdout.
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regardless of $verbosity, stderr is left connected.
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandOutputVerbosity($@) {
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@arguments, $verbosity);
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($verbosity, @arguments) = @_;
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($pid);
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if($verbosity || $gDryRun) {
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print(join(' ', argumentEscape(@arguments))."\n");
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if($gDryRun) {
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return(1);
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!defined($pid = open(*COMMAND, '-|'))) {
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf STDERR ($0.': fork: '.$!."\n");
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return undef;
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elsif ($pid) {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # parent
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my(@lines);
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while(!eof(*COMMAND)) {
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      my($line);
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chop($line = <COMMAND>);
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if($verbosity > 1) {
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print($line."\n");
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      push(@lines, $line);
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(*COMMAND);
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ($? == -1) {
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf STDERR ($0.': fork: '.$!."\n");
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return undef;
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elsif ($? & 127) {
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf STDERR ($0.': exited on signal '.($? & 127).
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ($? & 128 ? ', core dumped' : '')."\n");
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return undef;
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return @lines;
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else {
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # child; this form of exec is immune to shell games
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!exec {$arguments[0]} (@arguments)) {
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf STDERR ($0.': exec: '.$!."\n");
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      exit(-1);
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# commandVerbosity($verbosity, @arguments)
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Runs the specified command at the verbosity level defined by the
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $verbosity argument.  Returns nonzero on failure, returning the exit
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# status if appropriate.  Discards command output.
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub commandVerbosity($@) {
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@arguments, $verbosity);
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($verbosity, @arguments) = @_;
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(!defined(commandOutputVerbosity($verbosity, @arguments))) {
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return $?;
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# copyFiles($tempRoot, $method, @arguments)
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copies files or create symlinks in the disk image.
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# See --copy and --symlink descriptions for details.
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If $method is 'copy', @arguments are interpreted as source:target, if $method
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# is 'symlink', @arguments are interpreted as symlink:target.
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub copyFiles($@) {
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@fileList, $method, $tempRoot);
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($tempRoot, $method, @fileList) = @_;
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($file, $isSymlink);
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $isSymlink = ($method eq 'symlink');
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  foreach $file (@fileList) {
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my($source, $target);
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ($source, $target) = split(/:/, $file);
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!defined($target) and $isSymlink) {
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # empty symlink targets would result in an invalid target and fail,
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # but they shall be interpreted as "like source path, but inside dmg"
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $target = $source;
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!defined($target)) {
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $target = $tempRoot;
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elsif($target =~ /^\//) {
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $target = $tempRoot.$target;
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else {
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $target = $tempRoot.'/'.$target;
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my($success);
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($isSymlink) {
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $success = commandInternal('symlink', $source, $target);
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else {
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $success = !command($gConfig{'cmd_rsync'}, '-aC', '--include', '*.so',
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          '--copy-unsafe-links', $source, $target);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!$success) {
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cleanupDie('copyFiles failed for method '.$method);
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# diskImageMaker($source, $destination, $format, $name, $tempDir, $tempMount,
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#  $baseName, $setRootIcon)
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Creates a disk image in $destination of format $format corresponding to the
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# source directory $source.  $name is the volume name.  $tempDir is a good
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# place to write temporary files, which should be empty (aside from the other
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# things that this script might create there, like stage and mount).
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# $tempMount is a mount point for temporary disk images.  $baseName is the
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# name of the disk image, and is presently unused.  $setRootIcon is true if
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# a volume icon was added to the staged $source and indicates that the
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# custom volume icon bit on the volume root needs to be set.
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub diskImageMaker($$$$$$$$) {
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($baseName, $destination, $format, $name, $setRootIcon, $source,
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   $tempDir, $tempMount);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($source, $destination, $format, $name, $tempDir, $tempMount,
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   $baseName, $setRootIcon) = @_;
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(isFormatReadOnly($format)) {
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my($uncompressedImage);
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($gConfig{'makehybrid'}) {
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      my($hybridImage);
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $hybridImage = giveExtension($tempDir.'/hybrid', '.dmg');
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_hdiutil'}, 'makehybrid', '-hfs',
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       '-hfs-volume-name', $name,
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ($gConfig{'openfolder_bless'} ? ('-hfs-openfolder', $source) : ()),
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       '-ov', $source, '-o', $hybridImage) != 0) {
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('hdiutil makehybrid failed');
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $uncompressedImage = $hybridImage;
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # $source is no longer needed and will be removed before anything
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # else can fail.  splice in this form is the same as pop/push.
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      splice(@gCleanup, -1, 1,
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       sub {commandInternalVerbosity(0, 'unlink', $hybridImage);});
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) {
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('rm -rf failed');
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(!$gConfig{'partition_table'} && $gConfig{'recursive_access'}) {
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Even if we do want to create disk images without partition tables,
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # it's impossible unless recursive_access is set.
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        my($rootDevice, $partitionDevice, $partitionMountPoint);
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if(!(($rootDevice, $partitionDevice, $partitionMountPoint) =
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         hdidMountImage($tempMount, '-readonly', $hybridImage))) {
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          cleanupDie('hdid mount failed');
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        push(@gCleanup, sub {commandVerbosity(0,
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);});
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        my($udrwImage);
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $udrwImage = giveExtension($tempDir.'/udrw', '.dmg');
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', 'UDRW',
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         '-ov', '-srcdevice', $partitionDevice, $udrwImage) != 0) {
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          cleanupDie('hdiutil create failed');
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $uncompressedImage = $udrwImage;
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Going to eject before anything else can fail.  Get the eject off
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # the stack.
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pop(@gCleanup);
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # $hybridImage will be removed soon, but until then, it needs to
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # stay on the cleanup stack.  It needs to wait until after
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # ejection.  $udrwImage is staying around.  Make it appear as
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # though it's been done before $hybridImage.
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        #
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # splice in this form is the same as popping one element to
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # @tempCleanup and pushing the subroutine.
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        my(@tempCleanup);
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @tempCleanup = splice(@gCleanup, -1, 1,
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         sub {commandInternalVerbosity(0, 'unlink', $udrwImage);});
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        push(@gCleanup, @tempCleanup);
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) {
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          cleanupDie('diskutil eject failed');
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Pop unlink of $uncompressedImage
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pop(@gCleanup);
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if(commandInternal('unlink', $hybridImage) != 1) {
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          cleanupDie('unlink hybridImage failed: '.$!);
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else {
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # makehybrid is not available, fall back to making a UDRW and
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # converting to a compressed image.  It ought to be possible to
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # create a compressed image directly, but those come out far too
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # large (journaling?) and need to be read-write to fix up the
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # volume icon anyway.  Luckily, we can take advantage of a single
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # call back into this function.
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      my($udrwImage);
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $udrwImage = giveExtension($tempDir.'/udrw', '.dmg');
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      diskImageMaker($source, $udrwImage, 'UDRW', $name, $tempDir,
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       $tempMount, $baseName, $setRootIcon);
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The call back into diskImageMaker already removed $source.
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $uncompressedImage = $udrwImage;
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The uncompressed disk image is now in its final form.  Compress it.
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Jaguar doesn't support hdiutil convert -ov, but it always allows
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # overwriting.
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # bzip2-compressed UDBZ images can only be created and mounted on 10.4
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # and later.  The bzip2-level imagekey is only effective when creating
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # images in 10.5.  In 10.4, bzip2-level is harmlessly ignored, and the
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # default value of 1 is always used.
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(command($gConfig{'cmd_hdiutil'}, 'convert', '-format', $format,
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     ($format eq 'UDZO' ? ('-imagekey', 'zlib-level=9') : ()),
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     ($format eq 'UDBZ' ? ('-imagekey', 'bzip2-level=9') : ()),
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     (defined($gDarwinMajor) && $gDarwinMajor <= 6 ? () : ('-ov')),
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     $uncompressedImage, '-o', $destination) != 0) {
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cleanupDie('hdiutil convert failed');
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # $uncompressedImage is going to be unlinked before anything else can
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # fail.  splice in this form is the same as pop/push.
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    splice(@gCleanup, -1, 1,
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     sub {commandInternalVerbosity(0, 'unlink', $destination);});
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(commandInternal('unlink', $uncompressedImage) != 1) {
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cleanupDie('unlink uncompressedImage failed: '.$!);
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # At this point, the only thing that the compressed block has added to
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the cleanup stack is the removal of $destination.  $source has already
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # been removed, and its cleanup entry has been removed as well.
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elsif($format eq 'UDRW' || $format eq 'UDSP') {
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my(@extraArguments);
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!$gConfig{'partition_table'}) {
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      @extraArguments = ('-layout', 'NONE');
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($gConfig{'create_directly'}) {
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Use -fs HFS+ to suppress the journal.
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', $format,
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       @extraArguments, '-fs', 'HFS+', '-volname', $name,
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       '-ov', '-srcfolder', $source, $destination) != 0) {
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('hdiutil create failed');
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # $source is no longer needed and will be removed before anything
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # else can fail.  splice in this form is the same as pop/push.
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      splice(@gCleanup, -1, 1,
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       sub {commandInternalVerbosity(0, 'unlink', $destination);});
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) {
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('rm -rf failed');
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else {
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # hdiutil create does not support -srcfolder or -srcdevice, it only
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # knows how to create blank images.  Figure out how large an image
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # is needed, create it, and fill it.  This is needed for Jaguar.
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Use native block size for hdiutil create -sectors.
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete $ENV{'BLOCKSIZE'};
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      my(@duOutput, $ignore, $sizeBlocks, $sizeOverhead, $sizeTotal, $type);
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(!(@output = commandOutput($gConfig{'cmd_du'}, '-s', $tempRoot)) ||
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       $? != 0) {
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('du failed');
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ($sizeBlocks, $ignore) = split(' ', $output[0], 2);
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The filesystem itself takes up 152 blocks of its own blocks for the
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # filesystem up to 8192 blocks, plus 64 blocks for every additional
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # 4096 blocks or portion thereof.
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $sizeOverhead = 152 + 64 * POSIX::ceil(
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       (($sizeBlocks - 8192) > 0) ? (($sizeBlocks - 8192) / (4096 - 64)) : 0);
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The number of blocks must be divisible by 8.
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      my($mod);
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if($mod = ($sizeOverhead % 8)) {
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $sizeOverhead += 8 - $mod;
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # sectors is taken as the size of a disk, not a filesystem, so the
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # partition table eats into it.
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if($gConfig{'partition_table'}) {
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $sizeOverhead += 80;
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # That was hard.  Leave some breathing room anyway.  Use 1024 sectors
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # (512kB).  These read-write images wouldn't be useful if they didn't
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # have at least a little free space.
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $sizeTotal = $sizeBlocks + $sizeOverhead + 1024;
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Minimum sizes - these numbers are larger on Jaguar than on later
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # systems.  Just use the Jaguar numbers, since it's unlikely to wind
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # up here on any other release.
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if($gConfig{'partition_table'} && $sizeTotal < 8272) {
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $sizeTotal = 8272;
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(!$gConfig{'partition_table'} && $sizeTotal < 8192) {
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $sizeTotal = 8192;
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # hdiutil create without -srcfolder or -srcdevice will not accept
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # -format.  It uses -type.  Fortunately, the two supported formats
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # here map directly to the only two supported types.
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ($format eq 'UDSP') {
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $type = 'SPARSE';
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else {
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $type = 'UDIF';
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_hdiutil'}, 'create', '-type', $type,
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       @extraArguments, '-fs', 'HFS+', '-volname', $name,
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       '-ov', '-sectors', $sizeTotal, $destination) != 0) {
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('hdiutil create failed');
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      push(@gCleanup,
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       sub {commandInternalVerbosity(0, 'unlink', $destination);});
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The rsync will occur shortly.
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my($mounted, $rootDevice, $partitionDevice, $partitionMountPoint);
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    $mounted=0;
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!$gConfig{'create_directly'} || $gConfig{'openfolder_bless'} ||
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     $setRootIcon) {
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The disk image only needs to be mounted if:
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #  create_directly is false, because the content needs to be copied
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #  openfolder_bless is true, because bless -openfolder needs to run
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #  setRootIcon is true, because the root needs its attributes set.
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(!(($rootDevice, $partitionDevice, $partitionMountPoint) =
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       hdidMountImage($tempMount, $destination))) {
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('hdid mount failed');
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $mounted=1;
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      push(@gCleanup, sub {commandVerbosity(0,
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);});
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!$gConfig{'create_directly'}) {
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Couldn't create and copy directly in one fell swoop.  Now that
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # the volume is mounted, copy the files.  --copy-unsafe-links is
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # unnecessary since it was used to copy everything to the staging
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # area.  There can be no more unsafe links.
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_rsync'}, '-aC', '--include', '*.so',
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       $source.'/',$partitionMountPoint) != 0) {
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('rsync to new volume failed');
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # We need to get the rm -rf of $source off the stack, because it's
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # being cleaned up here.  There are two items now on top of it:
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # removing the target image and, above that, ejecting it.  Splice it
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # out.
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      my(@tempCleanup);
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      @tempCleanup = splice(@gCleanup, -2);
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The next splice is the same as popping once and pushing @tempCleanup.
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      splice(@gCleanup, -1, 1, @tempCleanup);
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) {
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('rm -rf failed');
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($gConfig{'openfolder_bless'}) {
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # On Tiger, the bless docs say to use --openfolder, but only
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # --openfolder is accepted on Panther.  Tiger takes it with a single
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # dash too.  Jaguar is out of luck.
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_bless'}, '-openfolder',
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       $partitionMountPoint) != 0) {
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('bless failed');
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    setAttributes($partitionMountPoint, @attributes);
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($setRootIcon) {
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # When "hdiutil create -srcfolder" is used, the root folder's
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # attributes are not copied to the new volume.  Fix up.
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_SetFile'}, '-a', 'C',
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       $partitionMountPoint) != 0) {
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('SetFile failed');
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($mounted) {
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Pop diskutil eject
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pop(@gCleanup);
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) {
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cleanupDie('diskutil eject failed');
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # End of UDRW/UDSP section.  At this point, $source has been removed
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # and its cleanup entry has been removed from the stack.
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else {
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cleanupDie('unrecognized format');
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print STDERR ($0.": unrecognized format\n");
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exit(1);
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# giveExtension($file, $extension)
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If $file does not end in $extension, $extension is added.  The new
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# filename is returned.
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub giveExtension($$) {
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($extension, $file);
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($file, $extension) = @_;
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(substr($file, -length($extension)) ne $extension) {
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return $file.$extension;
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return $file;
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# hdidMountImage($mountPoint, @arguments)
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Runs the hdid command with arguments specified by @arguments.
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# @arguments may be a single-element array containing the name of the
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# disk image to mount.  Returns a three-element array, with elements
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# corresponding to:
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#  - The root device of the mounted image, suitable for ejection
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#  - The device corresponding to the mounted partition
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#  - The mounted partition's mount point
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If running on a system that supports easy mounting at points outside
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# of the default /Volumes with hdiutil attach, it is used instead of hdid,
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# and $mountPoint is used as the mount point.
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The root device will differ from the partition device when the disk
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# image contains a partition table, otherwise, they will be identical.
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If hdid fails, undef is returned.
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub hdidMountImage($@) {
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@arguments, @command, $mountPoint);
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($mountPoint, @arguments) = @_;
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@output);
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if($gConfig{'hdiutil_mountpoint'}) {
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @command=($gConfig{'cmd_hdiutil'}, 'attach', @arguments,
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     '-mountpoint', $mountPoint);
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else {
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @command=($gConfig{'cmd_hdid'}, @arguments);
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(!(@output = commandOutput(@command)) ||
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   $? != 0) {
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return undef;
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if($gDryRun) {
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return('/dev/diskX','/dev/diskXsY','/Volumes/'.$volumeName);
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($line, $restOfLine, $rootDevice);
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  foreach $line (@output) {
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my($device, $mountpoint);
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($line !~ /^\/dev\//) {
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Consider only lines that correspond to /dev entries
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next;
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ($device, $restOfLine) = split(' ', $line, 2);
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!defined($rootDevice) || $rootDevice eq '') {
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # If this is the first device seen, it's the root device to be
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # used for ejection.  Keep it.
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $rootDevice = $device;
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if($restOfLine =~ /(\/.*)/) {
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The first partition with a mount point is the interesting one.  It's
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # usually Apple_HFS and usually the last one in the list, but beware of
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # the possibility of other filesystem types and the Apple_Free partition.
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # If the disk image contains no partition table, the partition will not
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # have a type, so look for the mount point by looking for a slash.
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      $mountpoint = $1;
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return($rootDevice, $device, $mountpoint);
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # No mount point?  This is bad.  If there's a root device, eject it.
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(defined($rootDevice) && $rootDevice ne '') {
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Failing anyway, so don't care about failure
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    commandVerbosity(0, $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return undef;
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# isFormatReadOnly($format)
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Returns true if $format corresponds to a read-only disk image format.
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Returns false otherwise.
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub isFormatReadOnly($) {
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($format);
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($format) = @_;
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return $format eq 'UDZO' || $format eq 'UDBZ' || $format eq 'UDRO';
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# licenseMaker($text, $resource)
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Takes a plain text file at path $text and creates a license agreement
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# resource containing the text at path $license.  English-only, and
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# no special formatting.  This is the bare-bones stuff.  For more
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# intricate license agreements, create your own resource.
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ftp://ftp.apple.com/developer/Development_Kits/SLAs_for_UDIFs_1.0.dmg
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub licenseMaker($$) {
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($resource, $text);
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($text, $resource) = @_;
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(!sysopen(*TEXT, $text, O_RDONLY)) {
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print STDERR ($0.': licenseMaker: sysopen text: '.$!."\n");
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(!sysopen(*RESOURCE, $resource, O_WRONLY|O_CREAT|O_EXCL)) {
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print STDERR ($0.': licenseMaker: sysopen resource: '.$!."\n");
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print RESOURCE << '__EOT__';
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/Script.h for language IDs.
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)data 'LPic' (5000) {
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Default language ID, 0 = English
13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0000"
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of entries in list
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0001"
13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Entry 1
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Language ID, 0 = English
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0000"
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Resource ID, 0 = STR#/TEXT/styl 5000
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0000"
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Multibyte language, 0 = no
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0000"
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)resource 'STR#' (5000, "English") {
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Language (unused?) = English
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "English",
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Agree
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Agree",
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Disagree
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Disagree",
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__EOT__
13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # This stuff needs double-quotes for interpolations to work.
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print RESOURCE ("    // Print, ellipsis is 0xC9\n");
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print RESOURCE ("    \"Print\xc9\",\n");
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print RESOURCE ("    // Save As, ellipsis is 0xC9\n");
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print RESOURCE ("    \"Save As\xc9\",\n");
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print RESOURCE ('    // Descriptive text, curly quotes are 0xD2 and 0xD3'.
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     "\n");
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print RESOURCE ('    "If you agree to the terms of this license '.
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     "agreement, click \xd2Agree\xd3 to access the software.  If you ".
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     "do not agree, press \xd2Disagree.\xd3\"\n");
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)print RESOURCE << '__EOT__';
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Beware of 1024(?) byte (character?) line length limitation.  Split up long
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// lines.
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If straight quotes are used ("), remember to escape them (\").
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Newline is \n, to leave a blank line, use two of them.
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 0xD2 and 0xD3 are curly double-quotes ("), 0xD4 and 0xD5 are curly
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   single quotes ('), 0xD5 is also the apostrophe.
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)data 'TEXT' (5000, "English") {
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__EOT__
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while(!eof(*TEXT)) {
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my($line);
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chop($line = <TEXT>);
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while(defined($line)) {
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      my($chunk);
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Rez doesn't care for lines longer than (1024?) characters.  Split
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # at less than half of that limit, in case everything needs to be
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # backwhacked.
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(length($line)>500) {
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $chunk = substr($line, 0, 500);
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $line = substr($line, 500);
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else {
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $chunk = $line;
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $line = undef;
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if(length($chunk) > 0) {
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Unsafe characters are the double-quote (") and backslash (\), escape
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # them with backslashes.
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        $chunk =~ s/(["\\])/\\$1/g;
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print RESOURCE '  "'.$chunk.'"'."\n";
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print RESOURCE '  "\n"'."\n";
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close(*TEXT);
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print RESOURCE << '__EOT__';
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)data 'styl' (5000, "English") {
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of styles following = 1
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0001"
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Style 1.  This is used to display the first two lines in bold text.
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start character = 0
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0000 0000"
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Height = 16
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0010"
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ascent = 12
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"000C"
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Font family = 1024 (Lucida Grande)
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0400"
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Style bitfield, 0x1=bold 0x2=italic 0x4=underline 0x8=outline
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 0x10=shadow 0x20=condensed 0x40=extended
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"00"
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Style, unused?
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"02"
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Size = 12 point
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"000C"
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Color, RGB
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  $"0000 0000 0000"
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__EOT__
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close(*RESOURCE);
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1;
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# pathSplit($pathname)
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Splits $pathname into an array of path components.
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub pathSplit($) {
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($pathname);
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($pathname) = @_;
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return split(/\//, $pathname);
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# setAttributes($root, @attributeList)
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# @attributeList is an array, each element of which must be in the form
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# <a>:<file>.  <a> is a list of attributes, per SetFile.  <file> is a file
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# which is taken as relative to $root (even if it appears as an absolute
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# path.)  SetFile is called to set the attributes on each file in
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# @attributeList.
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub setAttributes($@) {
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my(@attributes, $root);
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($root, @attributes) = @_;
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($attribute);
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  foreach $attribute (@attributes) {
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my($attrList, $file, @fileList, @fixedFileList);
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ($attrList, @fileList) = split(/:/, $attribute);
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!defined($attrList) || !@fileList) {
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cleanupDie('--attribute requires <attributes>:<file>');
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @fixedFileList=();
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    foreach $file (@fileList) {
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if($file =~ /^\//) {
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        push(@fixedFileList, $root.$file);
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else {
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        push(@fixedFileList, $root.'/'.$file);
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(command($gConfig{'cmd_SetFile'}, '-a', $attrList, @fixedFileList)) {
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cleanupDie('SetFile failed to set attributes');
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return;
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub trapSignal($) {
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  my($signalName);
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ($signalName) = @_;
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cleanupDie('exiting on SIG'.$signalName);
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sub usage() {
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print STDERR (
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"usage: pkg-dmg --source <source-folder>\n".
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"               --target <target-image>\n".
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--format <format>]           (default: UDZO)\n".
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--volname <volume-name>]     (default: same name as source)\n".
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--tempdir <temp-dir>]        (default: same dir as target)\n".
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--mkdir <directory>]         (make directory in image)\n".
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--copy <source>[:<dest>]]    (extra files to add)\n".
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--symlink <source>[:<dest>]] (extra symlinks to add)\n".
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--license <file>]            (plain text license agreement)\n".
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--resource <file>]           (flat .r files to merge)\n".
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--icon <icns-file>]          (volume icon)\n".
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--attribute <a>:<file>]      (set file attributes)\n".
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--idme]                      (make Internet-enabled image)\n".
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--sourcefile]                (treat --source as a file)\n".
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--verbosity <level>]         (0, 1, 2; default=2)\n".
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"              [--dry-run]                   (print what would be done)\n");
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return;
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1524