• 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: Is this program open?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Is this program open?


  • Subject: Re: Is this program open?
  • From: Jerry Krinock <email@hidden>
  • Date: Thu, 13 Apr 2006 13:13:49 -0700
  • Thread-topic: Is this program open?

on 06/04/13 11:07, John Stiles at email@hidden wrote:

> Gah.

Here's some NSTask -ps code for you.  It's not too pretty, but it has been
field tested, 10.3-10.4.  The only trouble occurred when a users's system is
too loaded to launch another process, as I discussed in the "Weirdness in my
powerbook" thread a couple weeks ago.  The NS_DURING now catches that rare
exception and warns the user.  If I had this to do over again I think would
look into the Carbon Process Manager as you are thinkning of.

Replace all my SheepSysLog() with NSLog() and have fun.

SheepSysPIDOfRunningExecutableNamed() returns 0 if named executable is not
found.

Local autorelease pool keeps you from running out of file handles in case
you need to loop and launch lots of these things.

Jerry


/************* HEADERS ****************************/

int SheepSysDoShellTask(NSString* launchPath, NSArray* args,
NSString*inDirectory, NSMutableData* stdInData, NSMutableData* stdOutData,
NSMutableData* stdErrData, BOOL waitUntilExit) ;
// If the command has no arguments, pass args=nil
// inDirectory may be nil.  If nil, the tasks's current directory is
inherited from this process.
// stdInData may be nil.  If nil, the tasks's standard input is inherited
from this process.
// stdOutData may be nil.  If nil, the tasks's standard output is inherited
from this process.
// stdErrData may be nil.  If nil, the tasks's standard error is inherited
from this process.
// All non-nil pointer arguments must be allocated and initialized (at least
temporarily).
// Note that if last argument waitUntilExit is NO, returned result will be
-999.

int unsigned SheepSysPIDOfThisUsersRunningExecutableNamed( NSString*
executableName ) ;
// This function uses unix "ps" instead of [[NSWorkspace sharedWorkspace]
launchedApplications]
// The advantage of this is that it does not use AppKit, therefore does not
invoke
// WindowServer, therefore does not raise an exception if the user is not
the console user.
// It returns the process ID (PID), or 0 if user is not running
executableName

int unsigned SheepSysPIDOfRunningExecutableNamed( NSString* executableName )
;
// Same as previous function, except returns PID of named executable
regardless of
// whether or not the owner of this process is the owner of that process.


/************* IMPLEMENTATIONS ****************************/


int SheepSysDoShellTask(NSString* launchPath, NSArray* args,
NSString*inDirectory, NSMutableData* stdInData, NSMutableData* stdOutData,
NSMutableData* stdErrData, BOOL waitUntilExit)
{
    int taskResult = -999;
    NSTask *task;
    NSPipe *pipeStdIn = nil ;
    NSPipe* pipeStdOut = nil ;
    NSPipe* pipeStdErr = nil ;
    NSFileHandle* hdlStdIn = nil ;
    NSFileHandle* hdlStdOut = nil ;
    NSFileHandle* hdlStdErr = nil ;

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


    task = [[NSTask alloc] init] ;

    [task setLaunchPath:launchPath] ;

    if (inDirectory)
        [task setCurrentDirectoryPath: inDirectory] ;

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

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

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

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

    SheepSysLog(5, "about to launch shell task \"%@\"\n   in directory
\"%@\"\n   with args %@", [task launchPath], [task currentDirectoryPath],
[task arguments]) ;

    NS_DURING

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

    SheepSysLog(5, "Task is working now") ;

    if (waitUntilExit)
    {
            // Note: The following won't execute if no stdIn/ErrData
(hdlStdIn/Err will be nil too)
            [stdOutData setData:[hdlStdOut readDataToEndOfFile]] ;
            [stdErrData setData:[hdlStdErr readDataToEndOfFile]] ;
            [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.
        SheepSysLog(0, "NSTask %@ %@ failed.", launchPath, args);
        NSString* processName = [[NSProcessInfo processInfo] processName] ;
        NSString* caption = [NSString stringWithFormat:@"%@: %@ %@",
            NSLocalizedString(@"failed", nil),
            launchPath,
            args ] ;
        NSString* msg = SheepSysLocalizedString(@"insufficientResources",
@"i@", 3, processName) ;
        NSRunCriticalAlertPanel(caption, msg, NSLocalizedString(@"quit",
nil), nil, nil) ;
        [NSApp terminate:nil] ;
    NS_ENDHANDLER

    SheepSysLog(5, "Releasing task and pipes") ;
    [pipeStdIn release] ;
    [pipeStdOut release] ;
    [pipeStdErr release] ;
    [task release] ;

    if (gLogging >= 5) {
        NSString* stdOutString = [[NSString alloc] initWithData:stdOutData
encoding:NSUTF8StringEncoding] ;
        SheepSysLog(5, "Task returned %i.  stdout (%i bytes):\n%@",
taskResult, [stdOutData length], stdOutString) ;
        [stdOutString release] ;
    }

    [pool release];

    // Be careful that you don't return any autoreleased objects here; due
to the local autorelease
    // pool, the preceding statement may have released it!
    // In this case, we're returning an int, OK!
    return taskResult ;
}

NSArray* RunningExecutablesUsersAndPIDs()
{
    int i ;

    // Run unix task "ps" and get results as an array, with each element
containing process command and user
    // The invocation to be constructed is: ps -xca -o pid -o command -o
user
    NSArray* args = [NSArray arrayWithObjects:@"-xca", @"-o", @"pid", @"-o",
@"command", @"-o", @"user", nil] ;
    NSMutableData* stdOutData = [NSMutableData data] ;
    SheepSysDoShellTask(@"/bin/ps", args, nil, nil, stdOutData, nil, YES) ;
    NSString* sProcessesAndUsers = [[NSString alloc] initWithData:stdOutData
encoding:[NSString defaultCStringEncoding]] ;
    NSArray* aProcessesAndUsers = [sProcessesAndUsers
componentsSeparatedByString:@"\n"] ;
            /* We must now parse sProcessesAndUsers which looks like this:
              PID USER     COMMAND
                1 root     launchd
               86 windowse WindowServer
              238 jk       Archive Assistant Scheduler
            13668 jk       BookdogLicensor
            19523 jk       Safari
            19754 jk       Camino
            19755 jk       firefox-bin
            20575 root     ps                               */

    // Examine first element, which is the column headings, to determine
where "USER" ends and "COMMAND" begins
    NSString* columnHeadings = [aProcessesAndUsers objectAtIndex:0] ;
    int break1 = [columnHeadings rangeOfString:@"USER"].location ;
    int break2 = [columnHeadings rangeOfString:@"COMMAND"].location ;
    NSRange range0 = NSMakeRange(0, break1) ;
    NSRange range1 = NSMakeRange(break1, break2-break1) ;

    NSMutableArray* commandsAndUsers = [NSMutableArray array] ;
    for (i=1; i<([aProcessesAndUsers count] -1); i++)
    // That loop range omits the first element, which is the column
headings, and the last element, which is blank due to the trailing \n.
    {
        NSString* pidString ;
        NSString* user ;
        NSString* command ;

        NSString* sCommandAndUser = [aProcessesAndUsers objectAtIndex:i] ;

        pidString = [[sCommandAndUser substringWithRange:range0]
stringByTrimmingCharactersInSet:[NSCharacterSet
whitespaceAndNewlineCharacterSet]] ;
        user      = [[sCommandAndUser substringWithRange:range1]
stringByTrimmingCharactersInSet:[NSCharacterSet
whitespaceAndNewlineCharacterSet]] ;
        command   =  [sCommandAndUser substringFromIndex:break2] ; // do not
trim since command may have spaces in, and will end with \n with no padding
whitespace
        NSDictionary* commandAndUser = [NSDictionary
dictionaryWithObjectsAndKeys:
            pidString, @"pidString",
            user, @"user",
            command, @"command",
            nil ] ;
        [commandsAndUsers addObject:commandAndUser] ;
    }

    return [[[NSArray arrayWithArray:commandsAndUsers] retain] autorelease]
;
}

int unsigned SheepSysPIDOfThisUsersRunningExecutableNamed( NSString*
executableName )
{
    NSString* shortNameOfThisUser = NSUserName() ;
    NSArray* commandsAndUsers = RunningExecutablesUsersAndPIDs() ;
    NSEnumerator* e = [commandsAndUsers objectEnumerator] ;
    NSDictionary* commandAndUser ;
    while ((commandAndUser = [e nextObject]))
    {
        NSString* command = [commandAndUser objectForKey:@"command"] ;
        NSString* user = [commandAndUser objectForKey:@"user"] ;
        if ([command isEqualToString:executableName] && [user
isEqualToString:shortNameOfThisUser])
        {
            NSString* pidString = [commandAndUser objectForKey:@"pidString"]
;
            if (pidString)
            {
                unsigned int pid = [pidString intValue] ;
                return pid ;
            }
        }
    }

    return 0 ;
}

int unsigned SheepSysPIDOfRunningExecutableNamed( NSString* executableName )
{
    NSArray* commandsAndUsers = RunningExecutablesUsersAndPIDs() ;
    NSEnumerator* e = [commandsAndUsers objectEnumerator] ;
    NSDictionary* commandAndUser ;
    while ((commandAndUser = [e nextObject]))
    {
        NSString* command = [commandAndUser objectForKey:@"command"] ;
        if ([command isEqualToString:executableName])
        {
            NSString* pidString = [commandAndUser objectForKey:@"pidString"]
;
            if (pidString)
            {
                unsigned int pid = [pidString intValue] ;
                return pid ;
            }
        }
    }

    return 0 ;
}


 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

References: 
 >Re: Is this program open? (From: John Stiles <email@hidden>)

  • Prev by Date: Re: Is this program open?
  • Next by Date: Re: Progress bar on front NSPanel is grey not blue??
  • Previous by thread: Re: Is this program open?
  • Next by thread: Re: Is this program open?
  • Index(es):
    • Date
    • Thread