Re: Determining how the app is run (intel/ppc/rosetta/os version)?
Re: Determining how the app is run (intel/ppc/rosetta/os version)?
- Subject: Re: Determining how the app is run (intel/ppc/rosetta/os version)?
- From: Gerben Wierda <email@hidden>
- Date: Sun, 21 May 2006 16:20:46 +0200
On May 21, 2006, at 15:43, Greg Hurrell wrote:
El 21/05/2006, a las 15:09, Gerben Wierda escribió:
Anyway, I am curious if and how you handle (amongst others):
Well, I suspect we are trying to solve slightly different problems,
but anyway...
- getting the pid of your subprocess where the subprocesses are many,
some slightly equivalent (e.g. checking GPG signatures with gpg or
MD5 hashes on files with openssl).
I don't have *multiple* simultaneous subprocesses but I do run
subprocesses (one at a time) from a separate worker thread so as to
keep the user interface responsive. I also return the output in one
hit at the end of execution rather than incrementally, but if I did
need to return output a line at a time I'd use
performSelectorOnMainThread:withObject:waitUntilDone:
- finding out if your subprocess is still running
I don't use an NSTask subclass to do this, so it's not something I've
ever had to worry about. But elsewhere in the code where I need to
observe the lifetime of another process without polling I use the mach
port dead name notifications described here:
http://developer.apple.com/technotes/tn/tn2050.html
- getting stderr and stdout separately from your subprocess as it
runs and appending it to a view
In my case I log to the console directly, not to a view: but if I did
want to do that I'd use the
performSelectorOnMainThread:withObject:waitUntilDone: method I
mentioned above.
As for getting them separately, I don't know how you'd do that in the
case of AuthorizationExecuteWithPrivileges() because it only provides
a single parameter for setting up a communications pipe, which is
connected to "to the tool’s standard input and output".
- influencing the environment of your subprocess
I'm not sure if getenv(), putenv(), setenv() have influence over a
subprocess that's been launched with root privileges
AuthorizationExecuteWithPrivileges(). I imagine they get propagated by
fork(), which is probably what ultimately underlies
AuthorizationExecuteWithPrivileges(), but I don't know if
AuthorizationExecuteWithPrivileges() "cleans" the environment before
launching.
If it does do such cleaning then I suppose the only way to influence
the environment is to make your own suid helper tool which handles the
setting up of the environment before executing the real subprocess
that you want to run.
In other words, the many of the things that NSTask can do.
Well, like I said, not really trying to solve the same problems as
you, but I agree it would be neat to wrap all this stuff up in an
NSTask subclass.
When I tried to do that it turned out I needed a generic helper program
that can set thing sup so I can get around the
AuthorizationExecuteWithPrivileges() limitations. This helper sets real
uid to effective uid, makes itself process group leader, receives the
environment from the parent on a fifo, returns the pid, sets up a fifo
for stderr, etc, and then execves the actual program to run.
Communication with the main program then happens through the fifos.
G
gluprunner.c (BSD License):
/*
* Copyright (c) 2002-2004, Gerben Wierda, R&A All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
are met:
*
* Redistributions of source code must retain the above copyright
notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
notice,
* this list of conditions and the following disclaimer in the
documentation
* and/or other materials provided with the distribution.
*
* Neither the name of R&A nor the names of its contributors may be
used to
* endorse or promote products derived from this software without
specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This is gluprunner, Gerben's Leader-setting, User-setting, Process-
* reporting runner program
* (c) Gerben Wierda, 2002
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/wait.h>
extern int errno;
#include <syslog.h>
#include <stdarg.h>
char **myenviron = 0;
main( int argc, char *argv[], char *envp[]) {
extern char **environ; /* works, where passing on envp does not
work (envp 0??) */
unsigned int nrofenventries = 0;
const char *progname = argv[0];
char envsizebuf[32];
int i;
int ch;
int quiet = 0;
const char *pfifoname = NULL; /* pid fifo name */
const char *ififoname = NULL; /* stdin fifo name */
const char *ofifoname = NULL; /* stdout fifo name */
const char *efifoname = NULL; /* stderr fifo name */
const char *Efifoname = NULL; /* stderr fifo name */
int ififo=-1, ofifo=-1, efifo=-1, pfifo=-1, Efifo=-1;
pid_t pid = getpid();
setuid( geteuid());
setpgrp( 0, setsid());
openlog( "gluprunner", LOG_CONS|LOG_PID, LOG_USER);
/* syslog( LOG_ERR, "============ testing syslog\n"); */
/*
* getopt handling:
* -d <dir>
* Change working directory to <dir> before execution
* -i <file>
* Use <file> as the fifo to connect stdin to
* -o <file>
* Use <file> as the fifo to connect stdout to
* -e <file>
* Use <file> as the fifo to connect stderr to
* -E <file>
* Read environment settings from fifo <file>
* -q
* Quiet. Do not print PID
* -p <file>
* Print pid (raw) to fifo <file>
*/
while ((ch = getopt( argc, argv, "qd:o:e:p:i:E:")) != -1) {
switch (ch) {
case 'i':
if ((ififo = open( (ififoname = optarg), O_RDONLY, 0)) < 0)
{
syslog( LOG_ERR, "open %s: %s\n", optarg, strerror(
errno));
exit(1);
}
break;
case 'o':
if ((ofifo = open( (ofifoname = optarg), O_WRONLY|O_APPEND,
0)) < 0) {
syslog( LOG_ERR, "open %s: %s\n", optarg, strerror(
errno));
exit(1);
}
break;
case 'e':
if ((efifo = open( (efifoname = optarg), O_WRONLY|O_APPEND,
0)) < 0) {
syslog( LOG_ERR, "open %s: %s\n", optarg, strerror(
errno));
exit(1);
}
break;
case 'p':
if ((pfifo = open( (pfifoname = optarg), O_WRONLY|O_APPEND,
0)) < 0) {
syslog( LOG_ERR, "open %s: %s\n", optarg, strerror(
errno));
exit(1);
}
write( pfifo, &pid, sizeof( pid_t));
close( pfifo);
break;
case 'E':
if ((Efifo = open( (Efifoname = optarg), O_RDONLY, 0)) < 0)
{
syslog( LOG_ERR, "open %s: %s\n", optarg, strerror(
errno));
exit(1);
}
i=0;
while (i<sizeof(envsizebuf)) {
if (read( Efifo, envsizebuf+i, 1) < 0) {
syslog( LOG_ERR, "read %s: %s\n", optarg, strerror(
errno));
exit( 1);
}
if (envsizebuf[i] == '\n') {
break;
}
i++;
}
if (i<sizeof(envsizebuf)) {
unsigned int envsize;
char *envblock, *startpt, *endpt;
if (sscanf( envsizebuf, "%u", &envsize) != 1) {
syslog( LOG_ERR, "sscanf %s: %s\n", optarg,
envsizebuf);
exit( 1);
}
envblock = calloc( envsize, 1);
if (read( Efifo, envblock, envsize) < envsize) {
syslog( LOG_ERR, "read block too small %s: %u\n",
optarg, envsize);
exit( 1);
}
startpt = envblock;
while (startpt < (envblock + envsize)) {
char *entry;
endpt = strchr( startpt, '\n');
*endpt = 0;
/* syslog( LOG_ERR, "READ ENV: %s\n", startpt); */
if (putenv( startpt)) {
syslog( LOG_ERR, "putenv failure %s: %s\n",
startpt, strerror( errno));
}
if (!myenviron) {
myenviron = calloc(2, sizeof( char *));
nrofenventries=1;
}
else {
myenviron = realloc( myenviron,
(++nrofenventries + 1) * sizeof( char *));
if (!myenviron) {
syslog( LOG_ERR, "(re)alloc failure %s:
%s\n", startpt, strerror( errno));
}
}
if (myenviron) {
entry = calloc( strlen( startpt) + 1, sizeof(
char));
strcpy( entry, startpt);
myenviron[nrofenventries-1] = entry;
}
startpt = endpt+1;
}
if (myenviron) {
/* Sentinel! */
myenviron[nrofenventries] = NULL;
}
free( envblock);
}
close( Efifo);
unlink( Efifoname);
break;
case 'd':
if (chdir( optarg) != 0) {
syslog( LOG_ERR, "chdir %s: %s\n", optarg, strerror(
errno));
fflush( stderr);
exit(1);
}
break;
case 'q':
quiet = 1;
break;
default:
syslog( LOG_ERR, "illegal option %c\n", ch);
exit( 1);
}
}
argc -= (optind-1);
argv += (optind-1);
if (ififo != -1) {
if (dup2( ififo, fileno(stdin)) == -1) {
syslog( LOG_ERR, "Cannot dup2 %u: %s\n", fileno( stdin),
strerror( errno));
exit(1);
}
}
if (ofifo != -1) {
if (dup2( ofifo, fileno(stdout)) == -1) {
syslog( LOG_ERR, "Cannot dup2 %u: %s\n", fileno( stdout),
strerror( errno));
exit(1);
}
}
if (efifo != -1) {
if (dup2( efifo, fileno(stderr)) == -1) {
syslog( LOG_ERR, "Cannot dup2 %u: %s\n", fileno( stderr),
strerror( errno));
exit(1);
}
}
if ((pfifo == -1) && !quiet) {
fprintf( stdout, "%s: PID = %u\n", progname, pid); fflush(
stdout);
}
execve( argv[1], &argv[1], (myenviron ? myenviron : environ));
syslog( LOG_ERR, "Execve failed with error: %s\n", strerror(
errno));
}
_______________________________________________
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