// // Perforce_ServerConfig.m // Perforce Server // // Created by Mike Ashmore on 3/3/10. // Copyright 2010 Mike Ashmore. All rights reserved. // #import "Perforce_ServerConfig.h" NSString *plistPath = @"/Library/LaunchDaemons/com.perforce.p4d.plist"; @implementation Perforce_ServerConfig @synthesize p4rootPath, p4logPath, p4port; - (BOOL) authenticatedRunCommand:(NSString *)command { BOOL ret = NO; char *buf = NULL; asprintf(&buf, [command UTF8String]); if(!buf) { return NO; } char* arguments[] = { "-c", buf, NULL }; if(AuthorizationExecuteWithPrivileges(auth, "/bin/sh", kAuthorizationFlagDefaults, arguments, NULL) == errAuthorizationSuccess) { int status; int pid = wait(&status); if(pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0) ret = YES; } free(buf); return ret; } - (BOOL) installPlist { NSDictionary *launchdPlist = [self launchdPrefList]; [launchdPlist writeToFile:@"/tmp/com.perforce.p4d.plist" atomically:YES]; return [self authenticatedRunCommand:[@"cp /tmp/com.perforce.p4d.plist " stringByAppendingString:plistPath]]; } - (BOOL) isRunning { BOOL running; // Run a shell command to check with launchctl if the com.perforce.p4d job is loaded NSArray *args = [NSArray arrayWithObjects:@"-c", @"launchctl list | grep com.perforce.p4d", nil]; NSTask *runCheck = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:args]; [runCheck waitUntilExit]; // if grep doesn't see a line from launchctl indicating the com.perforce.p4d job is loaded, the command's exit status will be nonzero running = ([runCheck terminationStatus] == 0); return running; } - (void) startServer { NSFileManager *fileManager = [NSFileManager defaultManager]; if (![fileManager fileExistsAtPath:plistPath]) { [self installPlist]; } // Make sure we have a directory for p4root BOOL isDir = NO; if ([fileManager fileExistsAtPath:self.p4rootPath isDirectory:&isDir]) { if (!isDir) { NSLog(@"Perforce Server Error: P4ROOT (%@) exists, but is not a directory", self.p4rootPath); } } else { NSError *err = nil; [fileManager createDirectoryAtPath:self.p4rootPath withIntermediateDirectories:YES attributes:nil error:&err]; if (err) { NSLog(@"Perforce Server Error while creating P4ROOT directory: %@", err); } } [self authenticatedRunCommand:[@"launchctl load " stringByAppendingString:plistPath]]; } - (void) stopServer { [self authenticatedRunCommand:[@"launchctl unload " stringByAppendingString:plistPath]]; [self authenticatedRunCommand:[@"rm " stringByAppendingString:plistPath]]; } - (void) awakeFromNib { self.p4rootPath = [@"~/Documents/p4d" stringByStandardizingPath]; self.p4logPath = [@"~/Documents/p4d/log" stringByStandardizingPath]; self.p4port = [NSNumber numberWithInt:1666]; auth = nil; // create an empty authorization reference for later use by commands that need it if (AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagInteractionAllowed, &auth) != errAuthorizationSuccess) { auth = nil; } } - (NSDictionary *) launchdPrefList { NSBundle *mb = [NSBundle bundleWithIdentifier:@"com.perforce.p4d"]; NSString *launchdPlistTemplatePath = [mb pathForResource:@"com.perforce.p4d.plist" ofType:nil]; NSDictionary *launchdTemplate = [NSDictionary dictionaryWithContentsOfFile:launchdPlistTemplatePath]; NSString *p4dPath = [mb pathForResource:@"p4d" ofType:nil]; // Only one program argument, the path to the server. NSArray *programArgs = [NSArray arrayWithObject:p4dPath]; [launchdTemplate setValue:programArgs forKey:@"ProgramArguments"]; // and the environment variables we're setting ... NSDictionary *environment = [NSDictionary dictionaryWithObjectsAndKeys: self.p4rootPath, @"P4ROOT", self.p4logPath, @"P4LOG", [self.p4port stringValue], @"P4PORT", nil]; [launchdTemplate setValue:environment forKey:@"EnvironmentVariables"]; return launchdTemplate; } - (void) dealloc { [defaultsController release]; [super dealloc]; } @end
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#4 | 7597 | Mike Ashmore |
Bit of a bugfix - if p4root didn't exist as a directory (i.e. if this is the first time we're enabling p4d via this prefpane) we now create the p4root directory automatically, rather than failing abysmally. |
||
#3 | 7595 | Mike Ashmore |
Now displays the values we're setting for P4ROOT, P4LOG, and P4PORT. These values are not, as yet, configurable. If I worked for Perforce, I would have a substantial incentive to improve this state of affairs. |
||
#2 | 7594 | Mike Ashmore |
Now correctly reflect status of server: running vs. not running. Note: OS X's authorization services make it really really hard to handle the installation of launchd services in a genuinely secure manner. You have to create a helper app to run with elevated privileges, then send commands to it via IPC and ... well, it's all just a bit much for me to figure out for a tool that was intended to be a quick one-off. Perhaps if I were employed by Perforce I could be troubled to do it the "right" way. Supposedly the ServiceManagement framework makes this all less painful, but it's an API that's brand-new in OS X 10.6 and not terribly well documented yet. And in any case, 10.6 still has not seen widespread enough adoption to justify using a 10.6-only framework. |
||
#1 | 7588 | Mike Ashmore |
This preference pane will make installation of p4d on OS X much simpler. Perhaps after some refinement it'll be worthy of packaging and letting Perforce Inc. distribute directly. |