• 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: Determining how the app is run (intel/ppc/rosetta/os version)?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


  • Follow-Ups:
    • Re: Determining how the app is run (intel/ppc/rosetta/os version)?
      • From: Gerben Wierda <email@hidden>
References: 
 >Re: Determining how the app is run (intel/ppc/rosetta/os version)? (From: Gerben Wierda <email@hidden>)
 >Re: Determining how the app is run (intel/ppc/rosetta/os version)? (From: Greg Hurrell <email@hidden>)
 >Re: Determining how the app is run (intel/ppc/rosetta/os version)? (From: Gerben Wierda <email@hidden>)
 >Re: Determining how the app is run (intel/ppc/rosetta/os version)? (From: Greg Hurrell <email@hidden>)

  • Prev by Date: Re: core data, synchonizing multiple MOC's
  • Next by Date: determine if file is package
  • Previous by thread: Re: Determining how the app is run (intel/ppc/rosetta/os version)?
  • Next by thread: Re: Determining how the app is run (intel/ppc/rosetta/os version)?
  • Index(es):
    • Date
    • Thread