views:

137

answers:

2

I have two processes - a user process and a root-level LaunchDaemon. I'd like both processes to have shared settings. I've tried getting this to work via a sqlite database, but have run into corruption issues. I've thought about using NSUserDefaults, but the NSGlobalDomain seems to only be global for the user, and I need a cross-user persistent domain, which NSUserDefaults doesn't seem to provide.

I've tried reading and writing an XML file directly, and I can get this to work fine with multiple threads (via a simple NSLock), but when I attempt to apply an O_EXLOCK to the file to prevent one process from writing to the file while the other is, it doesn't seem to work.

CFPreferences seems to have most of the same issues as NSUserDefaults. There is a kCFPreferencesAnyUser constant, but the documentation says that I can only use that if I have admin privileges (which the user process does not have).

So my question is this:

How can I effectively implement cross-process and cross-user shared settings?

+2  A: 

Your best bet is probably the O_EXLOCK approach, wrapped into an NSFileHandle for convenience (-initWithFileDescriptor:). Something like this (untested; uncompiled):

Writing:

int fd = open([path UTF8String], O_TRUNC|O_EXLOCK);
if (fd >= 0)
{
    NSFileHandle *fh = [[NSFileHandle alloc] initWithFileDescriptor:fd closeOnDealloc:YES];
    [fh writeData:xmlData]; // Creating xmlData left as exercise for the reader
    [fh release];
}
else // Error stuff

Reading:

int fd = open([path UTF8String], O_RDONLY|O_SHLOCK);
if (fd >= 0)
{
    NSFileHandle *fh = [[NSFileHandle alloc] initWithFileDescriptor:fd closeOnDealloc:YES];
    NSData *xmlData = [fh readDataToEndOfFile];
    [fh release];
}
else // Error stuff

Of course these will block, so you need to use O_NONBLOCK or put them on a non-UI thread so your GUI app doesn't beachball.

What's the problem you're seeing with O_EXLOCK?

Rob Napier
+1  A: 

Note that using O_EXLOCK and O_SHLOCK with open(2) just lets you avoid a call to flock(2). Mac OS X only supports advisory locking, and, as the manpage for flock() notes:

Advisory locks allow cooperating processes to perform consistent operations on files, but do not guarantee consistency (i.e., processes may still access files without using advisory locks possibly resulting in inconsistencies).

You'll run into problems, then, if both apps are not opting into the advisory locking system every time they open the advisory-locked file.

You could also try having the user process make defaults calls via the daemon using RPC. It would then handle all default writing on behalf of client applications; default reading would already hit the any user, current host/any host defaults.

Jeremy W. Sherman