cannot execute execl after fork - c

My goal is to create N process child with one process father.
I am using two files.The first is named forkn.c which contains this code:
#include <sys/types.h>
#include <wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[] )
{
int status =4;
int i=1;
int wpid;
for (int cpt=0;cpt<atoi(argv[1]);cpt++)
{
if (i>0)
{
i=fork();
if(i>0)
printf("I create process number %d \n",cpt+1);
}
}
//The father process created argv [1] son ​​process. This ensures a single father and argv [1] son ​​process
if(i==0)
{
execl("~/tpBash/tp2/argv[2]","argv[2]",(char*) NULL);
}
if (i>0)
{
for(int cpt=0;cpt<atoi(argv[1]);cpt++)
{
wait(&status) ;
}
printf("I am the father, I waited all my son processes, I finished \n");
}
}
And there is the code of trait2.c:
#include <sys/types.h>
#include <wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int status =4;
printf("I am the child process,my PID is : %d \n",getpid());
exit(status);
}
After i compile :
gcc -std=c99 forkn.c -o forkn
gcc -std=c99 trait2.c -o trait2
And then run the executable file :
./forkn 3 trait2
the first arguments is N (the number of child process to create ) and the second argument is the name of file to execute.
My problem is that the child process does not work.
Any idea please

The problem you are seeing is related to the way you're trying to do string interpolation:
execl("~/tpBash/tp2/argv[2]","argv[2]",(char*) NULL);
I suggest you try snprintf:
char buffer[ENOUGH];
snprintf(buffer, sizeof buffer, "%s/tpBash/.../...%s", home, argv[2]);
execl(buffer, argv[2]...);
Also, the second argument to execl should be argv[2] and not "argv[2]".

Related

For loop is executing in wrong order

I am doing a for loop to create children with fork and print their pids, but instead of printing them in order it mixes them up.! what it prints :
[PARENT/PID=953] Created child 0 [PID=954] and initial state f
[PARENT/PID=953] Created child 3 [PID=957] and initial state f
[PARENT/PID=953] Created child 2 [PID=956] and initial state t
[PARENT/PID=953] Created child 1 [PID=955] and initial state f
also prints in other orders
tried to put wait(&status) in different places but it didnt help.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#define PERMS 0644
int main(int argc, char **argv) {
int n = strlen (argv[1]);
int status;
for(int i=0;i<n;i++) // loop will run n times
{
if(fork() == 0)
{
char s[5];
sprintf(s, "%c", argv[1][i]);
char *const argv2[] = {"./child.c",s,NULL};
wait(&status);
status = execv("./child", argv2);
printf("[PARENT/PID=%d] Created child %d [PID=%d] and initial state %s \n",getppid(),i,getpid(),s);
exit(0);
}
}
for(int i=0;i<n;i++) // loop will run n times
wait(NULL);
}

Why does this function produce so many child processes?

I wrote this code in order to calculate the factorial of a number using processes and pipe(). I wanted to pass on the result from the child process to the child process. For example, to create calculate 5! the main which is the father sends the number 1 in the pipe. Then the first child is created and does 1*2, then it pushes in the pipe the number 2, the second child does 2*3 pushes the result in the pipe etc... Also, I use argv[1][0] thinking that we run the program like this (./ex3 5) where 5 is the number of which the factorial we would like to find. After running the program though, I noticed that a lot of child process was created (I only wanted 4). Why is that?
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int fd[2];
int w,count=2;
void child_creator(){
pid_t child;
child=fork();
if (child==0) {
close(fd[1]);
read(fd[0],&w,sizeof(w));
close(fd[0]);
w=w*count;
count++;
printf("I am child %d , my father is %d , the prod is %d\n",getpid(),getppid(),w);
sleep(1);
close(fd[0]);
write(fd[1],&w,sizeof(w));
close(fd[1]);
}
}
int main(int argc , char **argv){
int fact=argv[1][0]-'0';
pipe(fd);
w=1;
for (int i=0; i<fact-1; i++){
printf("this is i %d\n", i);
child_creator();
}
return 0;
}
After a suggested answer I tried this code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int fd[1000][2];
int w,count=1,j=0;
void child_creator(){
pid_t child;
j++;
pipe(fd[j]);
child=fork();
if (child==0) {
close(fd[j-1][1]);
read(fd[j-1][0],&w,sizeof(w));
close(fd[j-1][0]);
w=w*count;
printf("I am child %d , my father is %d , the prod is %d\n",getpid(),getppid(),w);
sleep(1);
close(fd[j-1][0]);
write(fd[j][1],&w,sizeof(w));
close(fd[j][1]);
exit(0);
}
}
int main(int argc , char **argv){
int fact=argv[1][0]-'0';
w=1;
for (int i=0; i<fact-1; i++){
count++;
child_creator();
sleep(2);
}
return 0;
}
Both the parent and child are returning to the for loop in main(). Since the child doesn't need to do anything after it writes its result, it should just exit rather than returning.
You also have problems with your handling of the pipe file descriptors. You do close(fd[1]) at the beginning of the child, but later try to write(fd[1],&w,sizeof(w)). You can't write to a closed FD. You don't need to close anything until the child is exiting, and exiting a process automatically closes all its files.
void child_creator(){
pid_t child;
child=fork();
if (child==0) {
read(fd[0],&w,sizeof(w));
w=w*count;
count++;
printf("I am child %d , my father is %d , the prod is %d\n",getpid(),getppid(),w);
sleep(1);
write(fd[1],&w,sizeof(w));
exit(0);
}
}

execve on linux, execute from arguments

I need to create a program that allows the user to execute a command passed as argument using execve in linux. I'm not sure about the syntax of the execve command. I wrote the program but it doesn't work with multiple arguments and I can't figure out why.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char **argv)
{
int status;
pid_t pid;
if((pid = fork())>0)
{
///Father process
wait(&status);
printf("Process terminated with status = %d\n",status);
}
else
{
///son process
int i;
char param[100];
printf("I'm the son woth PID= %d\n",getpid());
printf("%s\n",argv[0]);
printf("%s\n",argv[1]);
printf("%s\n",argv[2]);
strcpy(param,"/bin/");
strcat(param,argv[1]);
execve(param,argv,NULL);
exit(-1);
}
return 0;
}
A command that doesn't work using this code is
cp file1.txt file2.txt
Can someone help me?
This version is corrected:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char **argv)
{
int status;
pid_t pid;
if((pid = fork())>0)
{
///Father process
wait(&status);
printf("Process terminated with status = %d\n",status);
}
else
{
///son process
int i;
char program[100];
printf("I'm the son woth PID= %d\n",getpid());
strcpy(program,argv[1]);
printf("Program: %s\n", program);
execve(program, argv+1, NULL);
exit(0);
}
return 0;
}
Example:
$ ./a.out /bin/cp a.txt b.txt
I'm the son woth PID= 1590
Program: /bin/cp
/bin/cp
a.txt
b.txt
Process terminated with status = 0
Example 2:
./a.out /bin/ls
I'm the son woth PID= 3021
Program: /bin/ls
/bin/ls
a.c a.out
Process terminated with status = 0
I've added #include <unistd.h> because I needed it.
I recommend you to do more printf in order to understand and troubleshoot.
Edit As #jonathan-leffler say, you can use execvp to be able to exec programs using PATH:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char **argv)
{
int status;
pid_t pid;
if((pid = fork())>0)
{
///Father process
wait(&status);
printf("Process terminated with status = %d\n",status);
}
else
{
///son process
int i;
char program[100];
printf("I'm the son woth PID= %d\n",getpid());
strcpy(program,argv[1]);
printf("Program: %s\n", program);
execvp(program, argv+1);
exit(0);
}
return 0;
}
Example:
▶ ./a.out ls
I'm the son woth PID= 5056
Program: ls
a.c a.out
Process terminated with status = 0

Logging results of fork() in C to file to see results

I'm trying to get the results of each run of the program (both the parent and child). The results print once on the screen and only once in a file. I can't seem to get two unique files created (one representing parent and one representing child). I'm not sure if getpid() is the effective way to separate parent and child identification. What could I be doing wrong?
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static char *app1="/path/to/app1";
static char *app;
static pid_t forky=-1;
void otherfunction(){
int aflag=1;
//do something
if (aflag==1){
//run app 1
app=app1;
printf("Starting fork\n");
forky=fork();
}
}
int main(){
char dat[40000],test[10000];
sprintf(dat,"Exec start\nFORKY = %d\nPID = %d\nPPID = %d\n",forky,getpid(),getppid());
sprintf(test,"/TEST%d",getpid());
int h=open(test,O_WRONLY|O_CREAT);
write(1,dat,strlen(dat));
write(h,dat,strlen(dat));
close(h);
otherfunction();
return 0;
}
You're creating the file before you call fork. The fork is the last thing you do and then both processes just return 0.
As specified in fork's man page, the process created by calling fork is a copy of the parent process except for some specific differences, and this child process starts execution as if resuming from after the call to fork. So, it's kind of like you get two returns from fork, one for the parent and one for the child. So, it looks like you ask two questions here:
How to differentiate parent and child
Again, the man page mentions that fork will return the child's pid in the parent process and 0 for the child process so the following code sample will get you distinguished output from both:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
pid_t pid = fork();
if (pid == 0)
printf("Hello from child!!!\n");
else if(pid > 0)
printf("Hello from parent!!!\n");
else
printf("Wow, fork failed!!!");
return 0;
}
Obtaining separate files for each process
As mentioned above, both processes resume from after the call to fork, so the files must be created after calling to fork. In your example you are calling otherfunction last in main, so fork is pretty much the last call in both processes.
The following is an example that will give you different files with different content for each process, as well as print in stdout for each process. The usage of getpid here is just so you can actually check what the man page says.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv)
{
pid_t pid = fork();
int h;
char *test;
char dat[100];
if (pid == 0)
test = "child";
else if(pid > 0)
test = "parent";
else
test = "failed";
h = open(test,O_WRONLY|O_CREAT);
sprintf(dat, "%s | fork returned = %d | my_pid = %d\n", test, pid, getpid());
write(1,dat,strlen(dat));
write(h,dat,strlen(dat));
close(h);
}

Use of function execlp() in C

I'm trying to use the function execlp() to make a child processes run a specific code that I wrote, but I don't understand how the path works.
NOTE: I use export PATH=$PATH:. in the terminal so I don't need to type /.ProgName every time.
The first program is:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
main() {
pid_t childpid;
int i;
int nprocess = 3;
for (i = 0; i < nprocess; ++i) {
if ((childpid = fork()) < 0) {
perror("fork:");
exit(1);
}
if (childpid==0){
printf("I'm the son with ID= %ld\n",(long)getpid());
char *path = "exectest";
if ((execl(path,"0",NULL))<0) printf("\n error exec \n");
}
else
printf("I'm the father with ID= %ld",(long)getpid());
}
}
The second program to be called by the execlp is :
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
void main(){
printf("\n I'm using exec \n");
}
Both programs are in the same directory. The second program is named "exectest" but when I launch the first, I get the error message.
You should compile your second file exectest.c and get executable file which called exectest, because of your first program launch executable file exectest.

Resources