Multiple execlp not working - c

I need some help here. I need to execute all three execlp() once I run the program but what happen is that only case 0 is executed.I changed pid to 1 and case1 gets executed and so on. Tried putting it in a for loop but does not work. I changed break to continue but still the same - only one process is executed. Any suggestions?
main(){
pid_t pid;
pid= fork();
int i;
if(pid==0){
for (i=0; i<3; i++){
switch (i){
case 0:
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
break;
case 1:
execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
break;
case 2:
execlp("/bin/wc", "wctrial.txt", NULL);
break;
}
}
}else{
wait(NULL);
printf("Child process completed!");
exit(0);
}
}

According to man execlp:
The exec() family of functions replaces the current process image with a new process image.
(emphasis is mine)
Therefore, once you called successfully execlp, the process doesn't re-execute the old code.
case 0:
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
/* shouldn't go here */
break;
If you want to execute the three programs, you can create three processes. For instance (loops unrolled):
pid_t son;
son = fork();
if (son == -1) /* report */
else if (son == 0) execlp("/bin/cat", "cat", "wctrial.txt", NULL);
else wait(NULL);
son = fork();
if (son == -1) /* report */
else if (son == 0) execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
else wait(NULL);
/* ... */

See also Kirilenko's answer. The solution is to use system(..) instead of execlp(..).
Man page here.

Related

Wait for an unknown child process

I need to execute n child processes, n being a parameter of the program, those n child process will execute one Linux command each, and when they end the program need to create another child process to substitute it.
The problem is that I don't really know how to wait for an unknown process. As each child can have different commands those commands can last different times, so the main process needs to be available to detect when one of the child process has ended and create another one in it's place.
I tried using a for loop with a pid_t array of n size which contains all the pids but it doesn't work. I also tried using wait but once a child process finishes the program stops. This is what I have:
int main(int argc, char *argv[]){
int opt;
int num_procesos=1;
int status;
pid_t pid;
if(argc > 3){
error(argv[0],EXIT_FAILURE);
}
while((opt = getopt(argc,argv,"p")) != -1){
switch(opt){
case 'p':
if(argv[2]==NULL){
error(argv[0],EXIT_FAILURE);
}
num_procesos = atoi(argv[2]);
if(num_procesos < 1 || num_procesos > 8){
fprintf(stderr,"Error: el número de procesos en ejecución tiene que estar entre 1 y 8.");
error(argv[0],EXIT_FAILURE);
}
break;
default:
num_procesos = 1;
break;
}
}
pid_t pids[num_procesos];
for(int i=0;i<num_procesos;i++){
switch(pid = fork()){
case -1:
perror("fork()");
exit(EXIT_FAILURE);
break;
case 0:
leer_y_ejecutar();
}
}
int j=0;
while(j==0){
for(int i=0;i<num_procesos;i++){
if(wait(&status)==0){
switch(pid = fork()){
case -1:
perror("fork()");
exit(EXIT_FAILURE);
break;
case 0:
leer_y_ejecutar();
}
}else{
perror("wait()");
exit(EXIT_FAILURE);
}
}
}
return EXIT_SUCCESS;
}
Don't mind about the function leer_y_ejecutar() it's just part of the rest of my code. If any test is necessary it can be substituted with a printf or something else.
From the wait(2) manual :
The wait() system call suspends execution of the calling thread until one of its children terminates. The call wait(&wstatus) is equivalent to waitpid(-1, &wstatus, 0);
...
waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) specified by pid exist, but have not yet changed
state, then 0 is returned. On error, -1 is returned.\
The signature for waitpid is pid_t waitpid(pid_t pid, int *wstatus, int options);, so essentially, this piece of code :
while(j==0){
for(int i=0;i<num_procesos;i++){
// from here
if(wait(&status)==0){
switch(pid = fork()){
case -1:
perror("fork()");
exit(EXIT_FAILURE);
break;
case 0:
leer_y_ejecutar();
}
// to here
}else{
perror("wait()");
exit(EXIT_FAILURE);
}
}
}
Is never read, because wait(&status) == 0 cannot happen because WNOHANG has not been specified.
As a potential solution, I'd suggest changing it for wait(&status) > 0.

Not fully understanding fork for switch program output

I have been trying to understand the output of this program, but still I don’t quite get it.
main()
{
int pid, i;
pid = getpid();
for (i = 0; i < 25; i++)
{
switch (fork())
{
case 0:
if (pid % 2 == 0)
{
exit(0);
break;
}
default:
if (pid % 2 != 0)
{
exit(0);
}
}
}
printf("I am the process %d and my father is the process %d\n", getpid(), getppid());
while (wait(NULL) > 0) {}
return 0;
}
When I run this, it returns:
I am the process 11110 and my father is the process 26453
However, if you were to run the above code without both "% 2", it won't return anything.
I am very confused about this. The way I thought it would work (for the code without "% 2") is, for each for iteration:
the child (pid==0) would finish its process (killing the child process) and always break from the switch (not affecting the for loop)
the father/main process will wait until the child dies
next for iteration
Is the above approach correct? If so, how would it be with "% 2"?
Without % 2 you'd get:
switch (fork())
{
case 0:
if (pid == 0)
{
exit(0);
break;
}
default:
if (pid != 0)
{
exit(0);
}
}
Since pid is not 0, the parent would exit(0) immediately after the first fork(), so you won't see a print statement.

Third process "wc" won't work

I'm currently having a problem with the third process because it wont work every time when I run the program. And suggestions with the exit() part because is printing multiple child process! Any suggestions?
I would really APPRECIATE it a lot!
main(){
pid_t son;
int i;
for (i=0; i<3; i++){
switch (i){
case 0:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
}else{
wait(NULL);
printf("Child process completed!");
//exit(0);
}
case 1:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
}else{
wait(NULL);
printf("Child process completed!");
//exit(0);
}
case 2:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/wc","wc","wctrial.txt", NULL);
}else{
wait(NULL);
printf("Child process completed!");
//exit(0);
}
}
}
At least I don't see the break at the end of the each case.
In the case of 0 the program will run through all of your cases.
Actually break is the problem that if case 1 execute then 2,3 also will.(but this is not problem that wc not working)
Why wc is not working ?
Because of path of wc command!
In your system path for wc may not is: "/bin/wc"
Search tha path of wc command in your system like:
:~$ whereis wc
wc: /usr/bin/wc
and change
execlp("/bin/wc","wc","wctrial.txt", NULL);
^
as
execlp("/usr/bin/wc","wc","wctrial.txt", NULL);
^
// actually not exactly this but one that appears in your system.
Give it a try!!
Below are my suggestion ,
1st) suggestion would be the clean-up of child process once it is
done, as below,
}else if (son == 0){
execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
_exit(0);
}
2nd) do break after each switch statement
3rd) and also validate the path of executable by using "whereis"
command before feeding into execlp routine.

WC isn't executing anything

Can anyone tell me what's wrong with this? I'm still a newbie with forking. The computer executes the 1st and 2nd but the 3rd which is wc doesn't work. Need help badly. The terminal returns multiple child process completed but no wc.
pid_t son;
int i;
for (i=0; i<=3; i++){
switch (i){
case 0:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/cat", "cat", "wctrial.txt", NULL);
exit(0);
}else{
wait(NULL);
printf("Child process completed!");
}
case 1:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
execlp("/bin/mkdir", "mkdir", "mydirectory", NULL);
exit(0);
}else{
wait(NULL);
printf("Child process completed!");
}
case 2:
son = fork();
if (son<0){
fprintf(stderr, "Fork failed!");
//exit(-1);
}else if (son == 0){
printf("Work!");
execlp("usr/bin/wc","wc","-w","wctrial.txt", NULL);
exit(0);
}else{
wait(NULL);
printf("Work!");
printf("Child process completed!");
exit(0);
}
}
}
}
Since feature requests to mark a comment as an answer remain declined, I copy the above solution here.
You forgot the leading slash in the path. – Joachim Pileborg
"usr/bin/wc" should be "/usr/bin/wc" – Basile Starynkevitch

Waiting for all child processes to be created - C

Let's suppose I have a code like the following
switch (fork()) {
case -1:
//error checking
break;
case 0:
//child code
break;
default:
int i;
for (i = 0; i < n; i++) {
switch (fork()) {
case -1:
//error checking
break;
case 0:
//exec
break;
default:
//parent that waits for all childs to be created
break;
}
}
}
How do I make the second parent process wait for all the other processes to be created exactly ...
I was told I had to make a loop but I don't know how to implement it exactly. Supposing there are n child processes.
I think you may have misunderstood the requirement slightly. The term 'second parent' doesn't make a lot of sense to me.
What makes most sense as a requirement is:
Parent process launches N children.
Each child does its appropriate stuff.
The parent process must then wait for all N children to complete.
Then it can report its own completion (or get on with other work, or ...).
In outline, you would then have:
int pid;
for (int i = 0; i < N; i++)
{
switch (pid = fork())
{
case 0:
be_childish(i);
/*NOTREACHED*/
break;
case -1:
// Print error report
break;
default:
printf("Started PID %d\n", pid);
break;
}
}
int status;
while ((pid = wait(&status)) > 0)
{
printf("PID %d exited (status 0x%.4X)\n", pid, status);
}
printf("All done!\n");
Note the /*NOTREACHED*/ comment. I assume that the child process exits from within the be_childish() function. The code could ensure no damage by including an exit(1); or perhaps _exit(1); or _Exit(1);. It is rather important that a child process does not continue the loop.

Resources