Re: Is this program open?
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