Saturday, June 07, 2008

Installer.app and chmod/chown

How is it that I would go about chmodding the directories created by CopyPath?

It seems that if the .zip contains the permissions already, they are maintained when used by CopyPath.

In other words, if you have:

foo/bar

in your .zip, and do a CopyPath("foo", "~/foo") in the XML document, the permissions are set up correctly. At least I haven't had any problems if my installer looks like that.

However, if you create implicitly create directories by using CopyPath on the individual files, they are created without permissions, and a chmod/chown is needed. For example, CopyPath("foo/bar", "nuts/baz/bar") will create "nuts/baz", with no permissions.

I have to do this with the Gutenberg SciFi and Baen Books libraries, since I don't host the .zips themselves.

To manage the chmod/chown problem, the packages ensure that the BSD subsystem is installed (or Cydia), and then runs them as part of the install steps.

Here is an example:

      <key>preflight</key>
      <array>
        <array>
          <string>IfNot</string>
          <array>
              <array>
                <string>InstalledPackage</string>
                <string>com.natetrue.iphone.iphone_binkit</string>
              </array>
          </array>
          <array>
              <array>
                <string>AbortOperation</string>
                <string>You must install the "BSD Subsystem" package from Installer first!  It's in the System Category.</string>
              </array>
          </array>
        </array>
      </array>

Which checks for the BSD subsystem as part of the pre-install. If the BSD subsystem is not installed, the user gets a pop-up error message and the package will not install.

And then the install

      <key>install</key>
      <array>
        <array>
          <string>CopyPath</string>
          <string>1013.txt</string>
          <string>~/Media/EBooks/The_First_Men_in_the_Moon/1013.txt</string>
        </array>
        <array>
          <string>If</string>
          <array>
              <array>
                <string>FirmwareVersionIs</string>
                <array>
                  <string>1.1.3</string>
                  <string>1.1.4</string>
                </array>
              </array>
          </array>
          <array>
              <array>
                <string>SetStatus</string>
                <string>Changing Permissions</string>
              </array>                              
              <array>
                <string>Exec</string>
                <string>/bin/chmod -R 755 /var/mobile/Media/EBooks</string>
              </array>
              <array>
                <string>Exec</string>
                <string>/usr/bin/chown -R mobile /var/mobile/Media/EBooks/.</string>
              </array>
              <array>                 
                <string>SetStatus</string>
                <string>Running GutenMark</string>
              </array>
              <array>
                <string>Exec</string>
                <string>/usr/bin/GutenMark --profile=en --no-toc --config=/etc/GutenMark.cfg /var/mobile/Media/EBooks/The_First_Men_in_the_Moon/1013.txt /var/mobile/Media/EBooks/The_First_Men_in_the_Moon/1013-h.htm</string>
              </array>
              <array>
                <string>SetStatus</string>
                <string>Running GutenSplit</string>
              </array>
              <array>
                <string>Exec</string>
                <string>/usr/bin/GutenSplit --no-toc /var/mobile/Media/EBooks/The_First_Men_in_the_Moon/1013-h.htm /var/mobile/Media/EBooks/The_First_Men_in_the_Moon/Chapter_</string>
              </array>
          </array>
        </array>

That's not the full install segment, but it should give you an idea. I have to separate 1.1.3/4 from earlier firmwares because they use different users and store files differently.

To help, I've created a little perl library that allows me to write packages without having to mess with the nasty XML. It's part of the iphoneebookrepo project over at google code. Specifically PlistMaker.pm.

In terms of the perl library, it ends up looking like this:

my $gutenberg_html_install =
 p_if(IsFirmwareVersion("1.1.3", "1.1.4"),
      SetStatus("Changing Permissions").
      Exec("/bin/chmod -R 755 /var/mobile/Media/EBooks").
      Exec("/usr/bin/chown -R mobile /var/mobile/Media/EBooks/.").
      SetStatus("Running GutenSplit").
      Exec("/usr/bin/GutenSplit -1 -2 -3 -4 --no-toc --no-skip /var/mobile/Media/EBooks/$BookDir/${BookNumber}-h.htm /var/mobile/Media/EBooks/$BookDir/Chapter_")
 ).
 p_if(IsFirmwareVersion("1.0.0", "1.0.1", "1.0.2", "1.1.1", "1.1.2" ),
      SetStatus("Changing Permissions").
      Exec("/bin/chmod -R 755 /var/root/Media/EBooks") .
      SetStatus("Running GutenSplit").
      Exec("/usr/bin/GutenSplit -1 -2 -3 -4 --no-toc --no-skip /var/root/Media/EBooks/$BookDir/${BookNumber}-h.htm /var/root/Media/EBooks/$BookDir/Chapter_")
 );

my %BookDescriptor = (
 bundleIdentifier => "ca.pollock.gutenberg.$BookNumber",
 name => $BookTitle,
 version => "1.0",
 location => $BookURL,
 category => "Gutenberg SciFi (" .$BookLang . ")",
 size => $BookSize,
 hash => $BookMD5,
 url => "http://jason-pollock.blogspot.com/",
 maintainer => "Jason Pollock",
 contact => 'jason@pollock.ca',
 description => "by $BookAuthor",
 install => $Book_install,
 preflight => $Book_preflight,
 postflight => "" ,
 uninstall => $Book_uninstall,
 update => ""
 );

my $BookPLIST = CreatePackage(%BookDescriptor);

One "Gotcha" to be aware of... The Exec command is actually performing it's own parameter splitting prior to calling "Exec". It does not do any sort of "~" expansion, nor does it understand spaces. So, if you are doing a chmod on a directory with spaces in the name, it won't work, regardless of escapes or quotes.

No comments: