[comp.sys.sgi] Starting up another process from within a C program

corkum@csri.toronto.edu (Brent Thomas Corkum) (11/06/90)

What I want to do is start up and run another program in the background from
within a C program. I want to continue to run the program that invokes the 
other program. To make things a little more clear what I'm doing is 
interacting with a user interface and at some point wish to run some
analysis program. The analysis program is a standalone program that accepts
command line arguments to run. But after I start the analysis I want to
continue within the interface. Now, I can successfully do this using
the system function with the following syntax:

system("analysis test.dat &");  /* test.dat is the data file */

What I want to know is whether this is the best way of doing it and what
other options are there. I looked at exec but this seems to kill the parent
process.


Also, I want to have the analysis program ring a bell when it's done. I
looked at the man pages for setbell and ringbell but I can't seem to get
the program to compile, I get the old Undefined function error. So how
do I use these? Or is there another way to ring the keyboard bell from
within a C program.

Brent
corkum@boulder.civ.toronto.edu

jmb@patton.wpd.sgi.com (Doctor Software) (11/07/90)

In article <1990Nov5.124751.14923@jarvis.csri.toronto.edu>,
corkum@csri.toronto.edu (Brent Thomas Corkum) writes:
> What I want to do is start up and run another program in the background from
> within a C program. I want to continue to run the program that invokes the 
> other program ... Now, I can successfully do this using
> the system function with the following syntax:
> 
> system("analysis test.dat &");  /* test.dat is the data file */
> 
> What I want to know is whether this is the best way of doing it and what
> other options are there. I looked at exec but this seems to kill the parent
> process.
>

Exec in all it's forms does NOT kill the parent process - the only way
to do that is to signal(2) the parent or for it to call exit(2). Your
mistake is probably in not calling fork(2) before calling exec(2) - as
it says in the man page, exec(2) "overlays the current process image
with a new image taken from the named file". Thus, it probably seemed
like your parent exited - but you never had one!

Rather than go into the arcane incantation needed to do the fork/exec
sequence, I prefer to use the popen()/pclose() library routines. popen()
does what system() does, except it returns a FILE * (a standard IO file
descriptor) which is attached to the process. Thus allows you to send
data to the program, or to get data back. pclose() can be used to pick
up the exit status of the process, and to kill it if you want.

However, if you need to both write to the child and read from it,
popen() won't do it. In that case, you need to do the classic fork/exec
sequence:

int	readpipe[2];
int	writepipe[2];

pipe(readpipe);
pipe(writepipe);
if (fork() == 0) {
	close(readpipe[1]);
	close(0);
	dup(readpipe[0]);
	close(writepipe[0]);
	close(1);
	dup(writepipe[1]);
	close(2);
	dup(writepipe[1]);
	execl("/bin/myprog", "myprog", arg1, arg2, 0);
}
close(readpipe[0]);
close(writepipe[1]);

Now in this sequence I left out all the error checking a good programmer
would do, but this is the core of what needs to be done. Essentially,
after this sequence, data written to readpipe[1] will appear as standard
input to the child, and standard output and standard error in the child
will appear on the writepipe[0] descriptor. Examination of the man pages
for pipe(2) and dup(2) is left as an excersize for the reader.

Of course, you probably want to save the process ID returned by fork()
so you can manipulate the process at some later time (e.g., kill(2) it
or wait(2) for it). If you get really creative, you can catch SIGCHLD
(signal(2)) so you get an interrupt if the child terminates unexpectedly.

Now you understand why I like to use popen()/pclose().

> 
> Also, I want to have the analysis program ring a bell when it's done. I
> looked at the man pages for setbell and ringbell but I can't seem to get
> the program to compile, I get the old Undefined function error. So how
> do I use these? Or is there another way to ring the keyboard bell from
> within a C program.
> 

Basically, your parent program should ring the bell when the child
terminates. It can find out when the child is done as I described above
(i.e., wait(2) or SIGCHLD) and when that happens, ring the bell.

> Brent
> corkum@boulder.civ.toronto.edu


-- Jim Barton
   Silicon Graphics Computer Systems
   jmb@sgi.com

sgf@cs.brown.edu (Sam Fulcomer) (11/09/90)

In article <1990Nov7.155855.16316@odin.corp.sgi.com> jmb@patton.wpd.sgi.com (Doctor Software) writes:
>...
>Now you understand why I like to use popen()/pclose().
>...

Bear in mind that one of the things that makes popen more convenient is 
its use of /bin/sh to exec the command. It's not always the most secure
method.

vjs@rhyolite.wpd.sgi.com (Vernon Schryver) (11/10/90)

In article <55759@brunix.UUCP>, sgf@cs.brown.edu (Sam Fulcomer) writes:
> In article <1990Nov7.155855.16316@odin.corp.sgi.com> jmb@patton.wpd.sgi.com (Doctor Software) writes:
> >...
> >Now you understand why I like to use popen()/pclose().
> >...
> 
> Bear in mind that one of the things that makes popen more convenient is 
> its use of /bin/sh to exec the command. It's not always the most secure
> method.


Elaboration:  Never use popen() in a set-uid program for any UNIX system,
unless you understand the hole, and have done something about it.

(If you just want to open a hole, create a suid copy of your favorite
shell--it's easier to use.)


vjs