[launchd-dev] launchctl unload not working

James Bucanek subscriber at gloaming.com
Thu Nov 29 21:37:21 PST 2007


Kevin Van Vechten <mailto:kvv at apple.com> wrote (Thursday, 
November 29, 2007 6:28 PM -0800):

>On Nov 29, 2007, at 5:12 PM, James Bucanek wrote:
>
>>A helper is given a name that includes its user and a job 
>>number. So it would register a port with a name like "QRecallHelper.501.6f3b21e0".
>
>So then let me ask why you think that name has been registered in the
>root bootstrap when it doesn't appear in the following output?

I guess I wasn't clear. Since the registration isn't throwing 
any errors, I'm assuming that the helper is registering its name 
in *some* bootstrap. I expected that to be the same bootstrap as 
the parent process that launched it, but it's clearly not.

Would it help to know the parent of the scheduler daemon? I 
could add debug code to log the PPID of each process as it 
starts up.

>>>   echo 'per-user namespace'; launchctl bslist | fgrep -i qre
>>>   echo 'root namespace'; sudo launchctl bslist | fgrep -i qre
>
>>>per-user namespace
>>>A  QRecallMonitor
>>
>
>>>root namespace
>>>A  QRecallScheduler.501
>
>As you've indicated NSConnection's registerName is succeeding, we can
>probably assume that the name is being registered in _some_ bootstrap,
>but some subtlety of your NSTask approach may be landing it in a
>bootstrap that you don't expect.

The helper is either a normal executable or a SUID root 
executable (a la MoreAuthSample) that gets launched with:

+ (NSTask*)launchHelper:(NSString*)helperPath 
withCommand:(NSString*)commandName 
passingAuthorization:(AuthorizationRef)authorizationRef returningPortName:(NSString**)portNamePtr
{
     NSTask*     helperTask = [[NSTask new] autorelease];
     NSString*   portName = nil;

     NS_DURING
         // If a helper wasn't specified, use the bundled helper
         if (helperPath==nil)
             helperPath = [[NSBundle mainBundle] 
pathForResource:kHelperName ofType:nil];

         // Prepare the helper to execute
         [helperTask setLaunchPath:helperPath];
         // Redirect the task's stdin and stdout to these NSPipe 
objects, so we can talk to the task
         NSPipe*         inPipe = [NSPipe pipe];
         NSPipe*         outPipe = [NSPipe pipe];
         [helperTask setStandardInput:inPipe];
         [helperTask setStandardOutput:outPipe];
         NSFileHandle*   stdInHandle = [inPipe fileHandleForWriting];
         NSFileHandle*   stdOutHandle = [outPipe fileHandleForReading];

         // Start the task running
         [helperTask launch];

         ...

Followed by a bunch of convoluted code to passes all of the 
startup parameters to the helper via stdin (which the helper 
does get, because those get logged as the helper starts up).

My assumption was that [NSTask launch] would start the process 
in the same environment/session/bootstrap as the parent process 
but something seems to be interfering with that.

I can see a couple of possible workarounds:

- Figure out why the helper's ports aren't getting registered in 
a namespace that's accessible by its parent. Maybe I need to use 
something other than NSTask to start the child process.

- Return (once again!) to using UNIX domain sockets for 
communications, which don't have these kinds of scoping issues.
-- 
James Bucanek



More information about the launchd-dev mailing list