Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Starting an external program and get pid. 2

Status
Not open for further replies.

SmileeTiger

Programmer
Mar 13, 2000
200
US
I am running under unix and I want my program to start another program and print out the PID of the process that is started.


ie.

Prog1:

int main(..)
{
int pid;
pid=start(prog2, arg);
printf("Prog 2 has been started and has a PID of: %d\n", pid);
}


Normally I would use system() for this but it doesn't return the pid.

Suggestions?

Smilee
 
A fork isn't quite what I want in this case because I want to start another seperate program not fork off a copy of the current one.
 
You do a [tt]fork()[/tt], then test the return code to see which is the child. The child then does an [tt]exec()[/tt] to run the program you want. The return codes from the fork will let you know the child's PID.

See the man pages for fork and exec. There are also a lot of good books that cover this. I think there's a FAQ or two on Tek-Tips showing how this is done too.

Hope this helps.

 
Forking to get a child process to start another program is fine and all but the external program (program2) that needs to be started would still have a different PID then the thread that starts it. The problem remains that I need the pid of program2.
 
Since fork creates a new process with the same context (right in the middle of a fork call), it returns twice: once in the parent, and once in the child. In the child, it returns 0. In the parent, as SamBones already pointed out, it returns the PID of the child it just created.

In the parent process, fork returns the PID of the child process it just created.

Trust me: fork.

If you don't believe me, read a man page or tutorial.

It's fork.

Also, reread SamBones's post. Aside from the fact that, in the parent process, fork returns the PID of the child it just created (which you apparently overlooked the first time), it also mentions the use of exec, which should be of use to you if your child process is complex.

fork.
 
Well, here's an untested shot at a code sample off the top of my head. This would give you your [tt]start()[/tt] function from your question above...
[tt]
#include <sys/types.h>
#include <unistd.h>

pid_t start(char * prog, char * args[]))
{
int rv;
pid_t child_pid;

if(child_pid = fork())
{
/* This is the parent. */
/* The non-zero value we got back is the PID */
/* of the child we created. */
}
else
{
/* We got a zero. This is the child. */
rv = execvp(prog, args);
/* The exec doesn't return if successful */
}

return(child_pid);
}
[/tt]
You need to look at the different flavors of [tt]exec()[/tt]. There are several depending on how you want to pass args to the program being started. Also keep in mind I've put NO error handling here. This should give you an idea how it works though.

Like chipperMDW says, [tt]fork()[/tt] returns twice. That is, [tt]fork()[/tt] basically clones your process. They are identical. So the code that's being executed is that same in both the parent that called [tt]fork()[/tt], and the child that was just created. Think Perfect Parallel Universe. The only difference is the return code that each gets. The parent gets a non-zero number back from the [tt]exec()[/tt]. This is the child's PID. The child gets a zero back. If you don't test the return code and have the child [tt]exec()[/tt] something else, then you just have two programs doing the same exact thing. [tt]fork()[/tt] and [tt]exec()[/tt] are almost always called in an [tt]if[/tt] statement like this so the child goes off to do something else.

Hope this helps.

 
Fork does not create the 'same' program whatever that means.
It simply creates a child process with the same attributes as the parent.

The fork call as shown in the last post allows you to
do different things in the parent and child..

Here is a simple example without any signal handling.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define INTERVAL 20

int main(int argc, char **argv) {
int y, status;
pid_t pid;


        if (argc != 2) {
           printf(&quot;Error: One arg == name of program to exec\n&quot;);
           return 1;
        } 

          pid = fork();

              if (pid < 0) {
                 perror(&quot;fork()&quot;);
                 return 1;
              } else if (pid == 0) {
                 system(argv[1]);
                 printf(&quot;Child %u, parent %u\n&quot;,getpid(), getppid());
                 exit(0);
              } else {
                         
                   while ( (pid = waitpid(-1,&status,WNOHANG)) == 0) {
                           system(&quot;ps -a&quot;);
                           printf(&quot;Still waiting!\n&quot;);
                           sleep(INTERVAL);
                   }
                   printf(&quot;Exit Status %d\n&quot;,WEXITSTATUS(status));
               }
return 0;
}
 
Hi marsd,

I don't think your code is answering the original question of this thread. Yes, your example does fork a child process, but when you make the call
Code:
system(argv[1]);
, this actually spawns a third and fourth process. The fourth process is the PID that SmileeTiger wanted to capture and you code doesn't capture this. You're code is only capturing the PID of the child that makes that
Code:
system(argv[1]);
call.

For example, I've changed your code to have a
Code:
INTERVAL
of 2, and I've changed the
Code:
system(&quot;ps -a&quot;);
call to a
Code:
system(&quot;ps -f&quot;);
so it will only report my processes. Running it with the command line parameter
Code:
'sleep 2'
, I get the following...
[tt]
$ ./marsd 'sleep 2'
UID PID PPID C STIME TTY TIME CMD
sambones 20312 20310 0 10:42:34 pts/0 0:00 sh -c sleep 2

sambones 20311 20309 0 10:42:34 pts/0 0:00 sh -c ps -f
sambones 20310 20309 0 10:42:34 pts/0 0:00 ./marsd sleep 2

sambones 20278 16752 0 10:42:17 pts/0 0:00 ksh
sambones 16752 16750 0 09:45:53 pts/0 0:00 -ksh
sambones 20313 20312 0 10:42:34 pts/0 0:00 sleep 2

sambones 20309 20278 0 10:42:34 pts/0 0:00 ./marsd sleep 2

Still waiting!
Child 20310, parent 20309
Exit Status 0
$
[/tt]
Your parent and child are PID 20309 and 20310 and are running the identical command, which is what a fork does. The process created by the
Code:
system(argv[1]);
call is a bourne shell with PID 20312 which then creates a process that actually does the command of
Code:
'sleep 2'
with a PID of 20313. You're code isn't capturing the PID of 20313, which is what SmileeTiger was looking for. This is four processes and it still isn't giving the parent the PID of the process he wants the PID for. My example is only two processes, and does give the parent the correct PID of the child process he wants to track.

Also, the redundant process from your fork isn't buying you anything in this case. In any real world application where the processes are more complicated, the redundant processes cause problems. Also fork() and exec() are the cleanest way to create a daemon.

Hope this helps.

 
Yes, I was DELIBERATELY not using the exec() family
of calls, which replace the current process with the
exec() program and fulfill the original requirement.

Why?
You had already given an example of this: however
your example was badly flawed. It was not a
standalone program, the exec call(when fixed)does not
terminate cleanly, the child pid and parent pid
are not available, the return value is not the child pid
contrary to what you said, the execve() call would
never work as execve() needs a NULL terminator, there
was no example of wait() being used which is just
sloppy,etc..

In other words, it was a bare bones example, and I gave an example that displayed all processes and id's in a way that
allowed:
1) Clean termination
2) Easy identification of processes and id's.
3) Standalone execution.
4) Printing of the child and parent id's
as designed, not the system() calls pid directly.
(Though through the ps -a in the parent, as you show,
this information is available.) Though a custom system
call that identifies itself and it's id's is trivial.

So what was the point of your analysis: to nitpick,
or to lecture someone who is at least as experienced
as yourself in an irritating manner?




 
I'm Sorry, I wasn't meaning to be irritating or lecturing. I was just trying to address the original question. I apologize if it came off that way. Also, my example was to give the gist of how fork() and exec() are used, not to give actual compileable code. Like I said in my post, it was an untested shot off the top of my head just as an example of how it would be used.

To give a real example that can be compiled, here's your example using an exec() instead of a system() call.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define INTERVAL 2

int main(int argc, char **argv) {
int y, status;
pid_t pid;

   pid = fork();

   if (pid < 0) {

       /* This is an error */
       perror(&quot;fork()&quot;);
       return 1;

    } else if (pid == 0) {

       /* This is the CHILD */

       execlp(&quot;sleep&quot;, &quot;sleep&quot;, &quot;2&quot;, (char*)0);

       perror(&quot;execlp()&quot;);

       /* An exec does NOT return. */
       /* The next lines won't execute unless there's an error with exec. */

       printf(&quot;Child %u, parent %u\n&quot;,getpid(), getppid());
       exit(0);

    } else {
       /* This is the PARENT */
       printf(&quot;Parent %u says child PID is %u\n&quot;, getpid(), pid);

       while ( (pid = waitpid(pid,&status,WNOHANG)) == 0) {
             system(&quot;ps -f&quot;);
             printf(&quot;Still waiting!\n&quot;);
             sleep(INTERVAL);
             }
       printf(&quot;Exit Status %d\n&quot;,WEXITSTATUS(status));
    }

   return 0;
}
when run this gives...
[tt]
$ ./marsd2
Parent 27383 says child PID is 27384
UID PID PPID C STIME TTY TIME CMD
pawleys 27384 27383 0 12:23:54 pts/0 0:00 sleep 2
pawleys 16752 16750 0 09:45:53 pts/0 0:01 -ksh
pawleys 27383 16752 0 12:23:54 pts/0 0:00 ./marsd2
pawleys 27385 27383 0 12:23:54 pts/0 0:00 sh -c ps -f
Still waiting!
Exit Status 0
$
[/tt]
Again, I apologize if any offense was taken.

 
Perhaps I was a bit sensitive, I too apologize.

The reason I did not use the exec() family was
precisely the reason I chose to use system() of
course.

For the OP:
Using Sam's code provided, you can still get the child
and parent processes by inverting the order of the
exec() and printf().
 
Guys,

Thanks for your help. The one thing I was confused with in the beginning was that an exec() call gets the PID of the caller. You guys managed to more then clear that up!


Thanks
Smilee
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top