Posts Tagged ‘osx’

logrotate Mac OS Launch Daemon with Legacy MacPort

Tuesday, January 20th, 2009

Everbody loves cron. The classic basic scheduler, 80/20 flexibility, gets the job done. So, when I started with OS X, I went looking for cron.

Yes, you can cron if you want to. Or maybe, as the Mac children recommend, you can create Launch Daemons. It’s simply a custom launchd.plist, an XML file to define tasks in Apple’s terms. Sweet, I can do that…

The logrotated.plist Daemon

From what I could tell, out of the box, Leopard doesn’t give you logrotate. So, here it is as a Launch Daemon:

Great. So what do I do with it? Name it anything ‘*.plist’ — logrotated.plist perhaps — and put it here:

  • /System/Library/LaunchDaemons or
  • /Library/LaunchDaemons

I tend to use System for any services I wan to launch on boot (chkconfig-ish), and anything that’s just a scheduled task is more pedestrian.

You register daemons through launchctl. When you change it, just:

$ launchctl unload FILE.plist
$ launchctl load FILE.plist

Sure, not a hard thing. What I did want to point out were some of the things that I learned:

  • Provide each space-separated component of the command line as <string /> element in the ProgramArgument <array />. It’s the easiest way to go.
  • I tend to keep the KeepAlive, LaunchOnlyOnce and RunAtLoad all in sync for each daemon. It seems to guarantee compatability.
  • I still haven’t gotten quite the hand of OnDemand (c’mon, I’m new to this). When you are developing your daemons, keep a watch on /var/log/system.log — if you screw up, you’ll probably see it there in one fashion or another.
  • StartCalendarInterval is the equivalent of the cron schedule mask. See the Nabble post i commented above. You can’t do ranges, but wildcards are do-able sorta by omission. If you want mulltiple disparate schedules, as you see above, you need to pass in an <array /> of <dict />s, not just a single <dict /> when you only need one mask.
  • Yes, datatypes matter! I couldn’t figure out for the life of me why my daemon wouldn’t start, until I realized that my Hour and Minute values were configured as <string />s — vs <integer />s — because I’d been, well, you know, trying to do ranges and wildcards the cron-style way. launchctl didn’t complain, it just didn’t … work. So don’t do that.
  • Any daemon which has a schedule that fires off when the system is down will be automatically executed shortly after the system re-awakens. I don’t know exactly how quickly, but I’ve seen it in action (though I’ve read some dispute about its efficacy in my searches).

The Trials and Tribulations of MacPorts

But of course this Epistle wouldn’t be any fun without a twist, right? Well, lucky us, because it wasn’t that easy.

I’m using MacPorts as my yum-my package manager. It’s great, and easy to set up, but it’s quite as stable as I’ve seen under Linux. Or rather, I’ve seen a disproportionate number of issues in the times I’ve used it. However, I’m eternally grateful because it saves me so much time … the successes far outweigh the problems.

When things do go bad, as they did when I built logrotate 3.7.7, you have to set up a custom Portfile and source repository so that you can effectively drive MacPorts to fetch and build your specific version. logrotate 3.7.1_1 turned out to be much more stable.

Techonova and Joe Homs go into very excellent and welcome detail in their posts on how to pull this off. A summary of what you need to do is:

  • watch the build failure — debug with port -d — to identify where the dying source is located. That’ll be PATH/TO/PROJECT
  • visit http://trac.macosforge.org/projects/macports/log/trunk/dports/PATH/TO/PROJECT and snag the Portfile. That’s a MacPorts spec file, and you can tweak it to do your bidding.
  • create a source directory that you’ll keep around for a while (mine is /Users/Shared/macports).
  • register that directory — your local Portfile repository — with /opt/local/etc/macports/sources.conf (using file:// protocol)
  • copy the Portfile into a PATH/TO/PROJECT sub-directory structure (eg. sysutils/logrotate). Basically, the same path you’ll have snagged it from.
  • pull down a previous source revision and snapshot it locally. That could come from SVN or git, tarball, whatever. Start search from the homepage setting of the Portfile.
  • tweak the Portfile to ‘make sense’ for the source you’ve pulled down. If you based upon a close-enough version, it should be as easy as tweaking the version, etc. — no custom build tasks. I’m glossing over when I say that it’s usually a matter of version-based naming conventions and MD5 checksums.
  • re-build the repository’s PortIndex (which you’ll need to do every time you make an addition / change)

Please feel free to consult the other two posts to fill in the details that I was so cavalier about.

In Summary

This was another one of those occasions when I was glad I kept track of what I was doing while I was in the moment. Pack your config files with comments, because they’re invaluable. And drop READMEs around where you’re likely to find them … I filled in a lot of the extra details for this post from those breadcrumbs I left for myself, things I could have easily wasted 15-20m on re-discovering by braille :)

Peace.

Getting Java SE 6 and Eclipse to play nicely on Mac OS X

Tuesday, January 20th, 2009

Specifically, this post is about getting the standard pre-packaged install of Java SE 6 for OS X Leopard to play nicely with Eclipse 3.4 Ganymede. If you wish to move to Java SE 6 for Tiger or a pre-10.5 release of OS X, you may want to consider using SoyLatte, as recommended by the 2 tablespoons blog. I don’t imagine that any 3.x version of Eclipse would raise additional issues.

When you unpack the installer .dmg, it’s simply going to install the package. It will not automatically assume that you want to use it (not such a bad assumption, as it turns out). So there are a few caveats you need to deal with. I’m taking the approach of addressing all the details I know of, regardless of how obvious this may all seem :)

Post-install, Java 5 will still be in active use:

$ ls -l /usr/bin/java
/usr/bin/java -> /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java
$ Lunditer:~ root# java -version
java version "1.5.0_16"

You’ll see something much like this under /System/Library/Frameworks/JavaVM.framework/Versions :

1.3 -> 1.3.1
1.3.1
1.4 -> 1.4.2
1.4.1 -> 1.4
1.4.2
1.5 -> 1.5.0
1.5.0
1.6.0
A
Current -> A
CurrentJDK -> 1.5

Initially, I went and modified the symlink for CurrentJDK. Modifying the symlink for Current brought me nothing but pain. You can get the results you want by making the following change:

CurrentJDK -> 1.6.0

I’d had it set up that way until I wrote this post. But Apple highly discourages this practice. Instead, they recommend that you use the Java Preferences pane. Get rid of all your symlink shenanigans, and simply drag the ‘Java SE 6’ option to the top of the applet and application listings. It works like a charm. Start a new Terminal shell and you can confirm:

$ /usr/bin/java -version
java version "1.6.0_07"
$ /usr/bin/javac -version
javac 1.6.0_07

However … from my experience, this is a user-specific setting. Which means if you run Java as root, you’ll still get Java SE 1.5. Not a problem. We’ll stick with the Apple-sanctioned solution here.

Hooray, Java SE 6! Now let’s start Eclipse 3.4! Hooray … oops? Startup failure dialog:

JVM terminated.
Exit code=-1
...
-vm /System/Library/Frameworks/JavaVM.framework
...

This is a well documented issue. Both the Rob Kischuk and Stack Overflow blogs are very helpful in explaining that; Eclipse uses 32-bit SWT-Cocoa / Carbon, and Mac OS Java SE 6 only comes in a 64-bit flavor. I have not looked into the SoyLatte option, as suggested above, though that may prove to be an alternative approach.

I had some struggles getting their approach to work (until now, that is). Easiest way to start config testing is to run Eclipse from the command line:

$ cd /Applications/eclipse/Eclipse.app/Contents/MacOS/
$ ./eclipse -vm /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Commands/java

You can also provide /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0, which I extrapolated from the -vm setting in the failure message. If you still get an error dialog, you may see multiple instances of -vm, but that’s a red herring; it will work once properly configured.

Great. Once that’s working for you, let’s apply it to the App shortcut. There’s two ways you can go about this:

The blogs above recommend that you modify the Info.plist:

  • edit /Applications/eclipse/Eclipse.app/Contents/Info.plist
  • uncomment the following line:
    <string>-vm</string><string>/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Commands/java</string>

Alternately, you can modify eclipse.ini, where you might also configure your JVM memory configuration:

  • edit /Applications/eclipse/Eclipse.app/Contents/MacOS/eclipse.ini
  • add the following line:
    -vm /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Commands/java

Either dab will do ya. But if you didn’t know before, now you know where eclipse.ini lives :)

Things should be grand now. If they aren’t, I suggest trying some variations while running Eclipse from the command line. It took me a while to get the right combination, even though this post and (the ones it references) may seem very cookie-cutter. It will eventually work for you!

Now, I mentioned that the Apple-sanctioned approach seems to be user-specific. And I run Tomcat as root. So you will probably still want to add the traditional environment settings.

You can either make these changes to /etc/profile, or to the ~/.bashrc of each relevant account. No surprises here:

export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home
PATH="$JAVA_HOME/bin:$PATH"

My experiments to get /etc/paths to inject something into the path before ‘/usr/bin’ weren’t so useful, so I chose the brute force method.

If you’re going to use sudo to run Tomcat, you’ll want to make sure to load the bash environment.

sudo su -

to guarantee that root’s environment includes the custom /etc/profile overrides. No dash, and it no work. Tomcat Java 5 + App Java 6 =

SEVERE: Error deploying web application directory ...
java.lang.UnsupportedClassVersionError: Bad version number in .class file

With the environment in place, you should be good to go.

The writing of this post drove me to (a) drop the symlinks, (b) use Java Preferences pane and (c) get the right -vm config set up (since I’d been leaning entirely on the environment settings up to this point). So there are definitely a few ways to skin this cat.