• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Load launchd job immediately, without restart - how?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Load launchd job immediately, without restart - how?


  • Subject: Re: Load launchd job immediately, without restart - how?
  • From: Dimitris Roilidis <email@hidden>
  • Date: Mon, 29 Sep 2008 16:23:13 +0300

(Oops, hit reply and forgot to change the address to cocoa-dev)

Thanks for the tip! This looks like what I had in mind, I'll give it a spin.

Regarding the "original" route I mentioned, there is a programmatic way to interface directly with launchd. Look in /usr/include/launch.h; there's also some Apple sample code (http://developer.apple.com/samplecode/SampleD/ ). However, after looking through the header and the sample, it seems like an awful lot of trouble - and code - for such a minor task (loading/unloading a job).

I find it very strange that it is so easy to register a launchd job, yet so difficult to actually load it.

As an aside, I found Lingon (http://lingon.sourceforge.net/) to be extremely useful when working with launchd plists.

D. Roilidis

On Sep 29, 2008, at 2:58 PM, Jerry Krinock wrote:


On 2008 Sep, 28, at 7:49, Dimitris Roilidis wrote:

I have a PrefPane that acts as a ui for a command line utility (helper). According to the launchd docs, ...To load the helper immediately ... the alternative possibly involves a script to call launchctl


Well, I wouldn't call it an "alternative". I believe it is the only way to do it. If anyone knows a better way, please let us know.

but how would this work

Unfortunately, it looks like a job for NSTask. Try the function SSYLoadLaunchdJob given below and let me know if it works. I'll need to do the same thing soon.


and more importantly, how would it be integrated into the PrefPane code?

Insert the call to SSYLoadLaunchctlJob() any time after you have written your plist file.


the sporadic comments google turned up on the subject say it's not worth the trouble.

I'd like to read those comments if you could find the links in your browser history.




// *** Declarations with HeaderDoc comments

/*!
@function SSYLoadLaunchdJob
@abstract Invokes the system's launchctl command to "load" a launchd job
@discussion This function blocks until the task completes.
@param plistPath The full path to the .plist file defining the job,
in one of the LaunchAgents directories.
@result The result of the launchctl command which was returned by the system
*/
int SSYLoadLaunchdJob(NSString* plistPath) ;



/*!
@function SSYDoShellTask()
@abstract A wrapper around NSTask to launch a command-line process
@discussion Only use this function after you have searched far and wide for a Cocoa, CoreFoundation,
Carbon, or any built-in API to do what you want to do. That is because this function will spawn
another process which often leads to trouble. Use it sparingly. Examine the return value,
stdOut_p and stdErr_p and write code to recover from errors.
@param command The command, not including its arguments. A full path to the desired tool
is recommended. Example: @"/bin/launchctl"
@param arguments The array of arguments which should be passed with the command. Each element
of the array should be an NSString, one of the space-separated "words" that you would type on the
command line if you were performing this task via Terminal.app. For example, to perform the task
/bin/launchctl -load /Users/me/LaunchAgents/MyTask.plist
The 'command' would be @"/bin/launchctl/" and the 'arguments' would be an array of two strings,
@"-load" and @"/Users/me/LaunchAgents/MyTask.plist" in that order. If the command does not use
a space between its argument "letter" and its text, for example "- oPath/To/Output", this would
be entered as a single string element in 'arguments'.
If the command has no arguments, pass nil. Arguments can be very tricky. For example, I have
never found a way to pass in pipe redirects. I tried this suggestion once:
http://www.cocoabuilder.com/archive/message/cocoa/2005/2/24/129019
but could not get it to work.
@param inDirectory The working directory in which the command will be launched. You
may pass nil. In that case, the tasks's current directory is inherited from this process, which,
for applications, appears to be the root level of the startup drive. Run command "pwd" if you
need to be sure. To avoid problems, I'd say never pass inDirectory = nil unless you're giving
a full path in 'command'.
@param stdInData The stdin data to be passed to the command. If nil, the tasks's standard
input is inherited from this process. I suppose that could be interesting.
@param stdOutData_p If you want the stdout from the task, pass an NSData*. On output it
will point to an NSData object containing the stdout. Otherwise, pass NULL. In that case
the stdout location is inherited from the calling process and will not be returned.
@param stdErrData_p If you want the stderr from the task, pass an NSData*. On output it
will point to an NSData object containing the stderr. Otherwise, pass NULL. In that case
the stderr location is inherited from the calling process and will not be returned.
@param waitUntilExit If YES, this function blocks until the task completes or aborts
and exits. If NO, this function will return immediately.
@result If waitUntilExit is YES, returns whatever the task returns. If waitUntilExit is NO,
returns -999.
*/
int SSYDoShellTask(NSString* command,
NSArray* arguments,
NSString* inDirectory,
NSData* stdInData,
NSData** stdOutData_p,
NSData** stdErrData_p,
BOOL waitUntilExit) ;


// *** Implementations

int SSYLoadLaunchdJob(NSString* plistPath) {
NSArray* arguments = [NSArray arrayWithObjects:@"load", plistPath, nil] ;
return SSYDoShellTask(@"/bin/launchctl/",
arguments,
nil,
nil,
NULL,
NULL,
YES) ;
}


int SSYDoShellTask(NSString* command,
                 NSArray* arguments,
                 NSString*inDirectory,
                 NSData* stdInData,
                 NSData** stdOutData_p,
                 NSData** stdErrData_p,
                 BOOL waitUntilExit) {
   int taskResult = -999 ;
   NSData* stdOutData = nil ;
   NSData* stdErrData = nil ;
   NSTask* task;
   NSPipe* pipeStdIn = nil ;
   NSPipe* pipeStdOut = nil ;
   NSPipe* pipeStdErr = nil ;
   NSFileHandle* fileStdIn = nil ;
   NSFileHandle* fileStdOut = nil ;
   NSFileHandle* fileStdErr = nil ;

// Each of the three NSFileHandles we are going to create requires creation of an NSPipe,
// which according to documentation -fileHandleForReading is released "automatically"
// when the NSPipe is released. Actually, I find that it is autoreleased when the
// current autorelease pool is released, which is a little different.
// To conserve system resources, therefore, we use a local pool here.
// For more info,
// http://www.cocoabuilder.com/archive/message/cocoa/2002/11/30/51122
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init] ;


   task = [[NSTask alloc] init] ;

   [task setLaunchPath:command] ;

   if (inDirectory)
       [task setCurrentDirectoryPath: inDirectory] ;

   if (arguments != nil)
       [task setArguments: arguments] ;

   if (stdInData)
   {
       pipeStdIn = [[NSPipe alloc] init] ;
       fileStdIn = [pipeStdIn fileHandleForWriting] ;
       [task setStandardInput:pipeStdIn] ;
   }

   if (stdOutData_p)
   {
       pipeStdOut = [[NSPipe alloc] init] ;
       fileStdOut = [pipeStdOut fileHandleForReading] ;
       [task setStandardOutput:pipeStdOut ] ;
   }

   if (stdErrData_p)
   {
       pipeStdErr = [[NSPipe alloc] init] ;
       fileStdErr = [pipeStdErr fileHandleForReading] ;
       [task setStandardError:pipeStdErr ] ;
   }

   NS_DURING

[task launch] ;
if ( [task isRunning] )
{
// Note: The following won't execute if no stdInData, since fileStdIn will be nil
[fileStdIn writeData:stdInData] ;
[fileStdIn closeFile] ;
}


   if (waitUntilExit)
   {
       if (stdOutData_p) {
           stdOutData = [fileStdOut readDataToEndOfFile] ;
           *stdOutData_p = stdOutData ;
       }

if (stdErrData_p) {
stdErrData = [fileStdErr readDataToEndOfFile] ;
[stdErrData retain] ; // We retain this here so it doesn't go away with local autorelease
*stdErrData_p = stdErrData ;
}


       [task waitUntilExit] ;
       taskResult = [task terminationStatus] ;
   }

NS_HANDLER
// It would be nice to log [task terminationStatus] here, but that launches another
// task, which will also fail if too many processes are running, so don't do that.
NSLog(@"SSYDoShellTask: NSTask %@ %@ failed.", command, arguments);
NSString* caption = [NSString stringWithFormat:@"%@: %@ %@",
[NSString localize:@"failed"],
command,
arguments ] ;
NSString* msg = [NSString localizeFormat:@"insufficient_", [NSString localize:@"resources"]] ;
NSRunCriticalAlertPanel(caption, msg, [NSString localize:@"quit"], nil, nil) ;
[NSApp terminate:nil] ;
NS_ENDHANDLER


   [pipeStdIn release] ;
   [pipeStdOut release] ;
   [pipeStdErr release] ;
   [task release] ;

if (gLogging >= 0) {
NSString* stdOutString = [[NSString alloc] initWithData:stdOutData encoding:NSUTF8StringEncoding] ;
[stdOutString release] ;
}


// Retain autoreleased objects which we're going to need after releasing the local pool
[stdOutData retain] ;
[stdErrData retain] ;


   [pool release] ;

// After thus autoreleasing the locals, we autorelease the things which will be needed by the caller
// By Obj-C convention, objects returned by reference are not "alloced or copied", so we return them autoreleased.
[stdOutData autorelease] ;
[stdErrData autorelease] ;


   return taskResult ;
}


_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


  • Follow-Ups:
    • Re: Load launchd job immediately, without restart - how?
      • From: Dimitris Roilidis <email@hidden>
References: 
 >Load launchd job immediately, without restart - how? (From: Dimitris Roilidis <email@hidden>)
 >Re: Load launchd job immediately, without restart - how? (From: Jerry Krinock <email@hidden>)

  • Prev by Date: Passing focus to a control
  • Next by Date: Window Shadow
  • Previous by thread: Re: Load launchd job immediately, without restart - how?
  • Next by thread: Re: Load launchd job immediately, without restart - how?
  • Index(es):
    • Date
    • Thread