(Executing a built in program in UNIX (C) - c

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[],char *envp[])
{
int pid;
int id;
pid=fork();
if(pid<0)
{
printf("\n Error ");
exit(1);
}
else if(pid==0) //Child process
{
execve("a",argv,envp); //Problem is in here
printf("\n Pid of child process is %d ",getpid()); //Finds the id of the child process
exit(0);
}
else //Parent process
{
wait(3);
printf("\n Pid of parent process is %d ",getpid());
exit(1);
}
}
I am trying to execute a program named a in UNIX but it does not work probably because I use the wrong exec command or the program a is in a different directory but I am not sure.When I execute this from terminal it gives me the id of child and parent process but does not notify me about the program a.

It works for me. I had to change the call to wait to:
int retStat;
wait(&retStat);
because wait really wants to return a value and the program crashed without it. Did you check that your a program is in your path or are you including the path in the exec call?

Related

C, Fork(), take CL argument and execute CHDIR

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
char *getcwd(char *buf, size_t size); //define getcwd
char PATH_MAX[1024]; //define max size of path
int chdir(const char *path);
int main(int argc, char *argv[]) { // gets arguments when program ran, no arguments means argv=1
pid_t pid; //process ID = pid
pid=fork();
char cwd[1024]; //compare directory to max character size
if(pid==0){ //child has been forked! //child process created
int ret;
printf("Child PID=%d\n", getpid());
getcwd(PATH_MAX, sizeof(PATH_MAX));
printf(" My current working directory is: %s\n", PATH_MAX);
ret= execl("/bin/ls", "ls", "-a", "-l", "-h", NULL);
printf("%d\n", ret); //why isn't this printed out?
}
//}
else {
int status;
//parent process
//wait for child to complete
printf("Parent PID=%d\n", getpid());
if (waitpid(pid, &status, 0) == -1) {
printf("ERROR");
}
else {
printf("Child done.\n");
getcwd(PATH_MAX, sizeof(PATH_MAX));
printf("0");
exit(0);
}
}
}
I left my commented out code so you can see my thought process. If my understanding is correct the shell(terminal) is its own process so when you call fork, it creates a new child process and its parent becomes the shell. So trying to chdir in the child process will not translate over to the shell and you will remain in the same Directory so you would need to execute the chdir function in the parent PID, which is now the shell, yes?
I am having a hard time trying to figure out where exactly I should be putting this chdir() command and what flavor of exec I need to use to execute the terminal commands.
I am testing 3 different commands as command line arguments when running in terminal. This is after making the file with gcc -o script script.c
$ ./script
result - print out current directory
print out "Usage: "<dir>" string. no command executed
$ ./script .
result -"Executing ls . --all -l --human-readable" string
executes above commands
$./script /
result - should execute above commands but change directory before
executing
$./script /blah/blah
result - can't execute chdir
exit status: 1
I believe this code should cause the child process to return a -1 which would terminate it, or if my if statement is correct it would print out the error message.
Any help would be appreciated, I believe I got the logic down, or at least somewhat. Just having a hard time implementing chdir.
I cooked your program a little and got the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
int main(int argc, char *argv[]) // gets arguments when program ran, no arguments means argv=1
{
int ret;
pid_t pid; //process ID = pid
pid=fork();
char cwd[1024]; //compare directory to max character size
char newPath[200]=".";
if( argc > 1 )
{
strcpy(newPath,argv[1]);
}
ret=chdir(newPath);
if( ret < 0 )
{
printf("Problem switching to :%s\n", newPath);
perror("chdir");
exit(ret);
}
if(pid==0){ //child has been forked! //child process created
int ret;
printf("Child PID=%d\n", getpid());
getcwd(cwd, sizeof(cwd));
printf(" My current working directory is: %s\n", cwd);
ret= execl("/bin/ls", "ls", "-a", "-l", "-h", NULL);
printf("%d\n", ret); //why isn't this printed out?
}
else {
int status;
//parent process
//wait for child to complete
printf("Parent PID=%d\n", getpid());
if (waitpid(pid, &status, 0) == -1) {
printf("ERROR");
} else
{
printf("Child done. stat=%d\n", status);
getcwd(cwd, sizeof(cwd));
printf("Parent cwd:%s\n", cwd);
printf("0");
exit(0);
}
}
}
Your understanding is not quite correct. When you execute a program from the command line on a terminal, the shell forks and does an execute of the process you are running. Normally, the parent shell process waits until the child process is done. You created a child process and did another exec and another wait. The parent shell patiently waits for you to finish, forked processes and all.
Let's see:
I put the chdir in your main program to show the child follows the parent.
A child process is not going to change the working directory of the parent. Unix and Linux don't work that way.
When you run execl, that is it. There is no return unless it can't do the execute. The point of exec* is you are blowing away your currently running program with a new executable. There is nothing to return to.
If you want to see the return code of the child, look at the status returned by the wait. In this case, the ls ran fine so the return code is zero. If you added a last argument of "baddir" (that is not there) you would see the ls non-zero return code, in this case, 512.

Exec won't call my second program

I created a test file to see if I could run a second program, but the code doesn't run the actual file even though it seems to compile. Is my syntax for exec incorrect?
coordinator.c
int main(int argc, char *argv[])
{
// Creates 2^n processes for n amount of values.
pid_t child = fork();
if(child < 0) //parent process
{
perror("fork() system call failed.");
exit(-1);
}
else if(child == 0) //Child Process, worker will be called here.
{
execl("/worker", "worker", "Hello", NULL);
printf("I'm the child %d, my parent is %d\n", getpid(), getpid());
}
else
{
printf("I'm the parent %d, my child is %d\n", getpid(), child);
wait(NULL); // wait for child process to catch up
}
}
worker.c
int main(int argc, char *argv[])
{
printf("Hi, I'm the worker file!");
return 0;
}
The problem is in the PATH argument you're passing to execl().
In fact, if you do insert a / at the beginning of the string passed as the first argument, the function is going to seek the program at the root of your file system.
To let it look for the worker executable in your current directory, just specify the name of it, thus execl("worker", ... ), or execl("./worker", ... )
Take a look here to understand how the function works https://www.systutorials.com/docs/linux/man/3-execl/
Let's say worker executable is in the same directory where you are running the main(coordinator) process then in child process while doing exec you should do ./worker instead of /worker, that shows current working directory.
see then man pages of exec() for other argument, it says
int execl(const char *path, const char *arg, ...);
child process should be like below
else if(child == 0) //Child Process, worker will be called here.
{
printf("I'm the child %d, my parent is %d\n", getpid(), getpid());
//execl("/worker", "worker", "Hello", NULL);/** It's wrong, check the below one **/
execl("./worker", "./worker", NULL);
}
IF worker is in different directory then set the PATH variable, it seems it's in same directory because you are trying to do /worker instead of ./worker.
EDIT :
How to compile & execute :
coordinator.c
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
pid_t child = fork();
if(child < 0){
perror("fork() system call failed.");
exit(-1);
}
else if(child == 0) {
printf("I'm the child %d, my parent is %d\n", getpid(), getpid());
execl("./worker", "./worker", NULL);
}
else {
printf("I'm the parent %d, my child is %d\n", getpid(), child);
wait(NULL); // wait for child process to catch up
}
}
worker.c
int main(int argc, char *argv[])
{
printf("Hi, I'm the worker file!");
return 0;
}
First create the worker executable/binary as
gcc -Wall worker.c -o worker
Next, create the main executable and run it
gcc -Wall coordinator.c
./a.out

Why execution stops after printing "This is the child process!"?

//Why not execute all the conditions(parent and child)?
#include<stdio.h>
#include<unistd.h>
int main(){
pid_t pid; //process-id
printf("This is where we start...\n");
pid = fork();
//For the child process
if(pid==0){
printf("This is the child process!\n");
return 1;
}
//This should have been printed
if(pid>0){
printf("This is the parent!\n");
}
//THis may/may not be printed - its ok
if(pid < 0){
printf("Fork failed!");
}
return 0;
}
It was excepted that after returning from the child, the parent should have been executed but this is what i get:
$ This is the child process!
What am i missing? why not child as well as the parent block printed?
The program is completely fine. When a fork is performed, a new child process is created. The child process created is independent of the parent and it is completely possible that the parent does not wait for the child to complete its execution.
If you want that the parent execution resumes once the child is complete, you should use the wait() function, that makes sure that a forked child is executed before parent continues.
Try updating your code as follows:
#include<stdio.h>
#include<unistd.h>
#include <sys/wait.h> //Add this header
int main()
{
pid_t pid; //process-id
int status; //A variable to get the status of the child, i.e. if error or success
printf("This is where we start...\n");
pid = fork();
if(pid==0){
printf("This is the child process!\n");
return 1;
}
if(pid>0){
wait(&status); //Function to wait for child
printf("This is the parent!\n");
}
if(pid < 0){
printf("Fork failed!");
}
return 0;
}
For more information check out this link: Forking a Process and Parent-Child execution - Linux : C Programming

Why I use the waitpid in parent process, but the child process is still running after the parent process?

The program is below
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
int main(int argc,char **argv)
{
int fds[2];
int error=pipe(fds);
if(error==-1)
{
perror("pipe");
return 1;
}
int ret=fork();
if(ret<0)
{perror("fork failed");
return 1;
}
else if(ret==0)
{
close(fds[0]);
close(1);
dup(fds[1]); char *argv[3];
argv[0]="ls";
argv[1]="-l";
argv[2]=NULL;
execvp(argv[0],argv);
}
else
{
int rett=fork();
if(rett<0)
{
perror("fork failed");
return 1;
}
else if(rett==0)
{
close(fds[1]);///
close(0);
dup(fds[0]);
char *argv[2];
argv[0]="wc";
argv[1]=NULL;
execvp(argv[0],argv);
}
else
{
waitpid(ret,NULL,7); /// wait for child process
waitpid(rett,NULL,7); //// wait for another child process
printf("Process %d finished\n",ret);
printf("Process %d finished\n",rett);
}
}
return 0;
}
There is the outcome below; why is printf is executing before the "wc"?
Process 7189 finished
Process 7190 finished
zyy#ubuntu:~$ 24 209 1125
Check your return values functions that can return errors. And don't use magic numbers instead of correct flags.
Your waitpid calls don't actually wait for any process to finish and just return errors. What does your magic number "7" mean? That's not what the documentation tells you to do. One of the bits in the number 7 is WNOHANG, which tells waitpid to not actually wait for the children to finish. Another bit in those flags is valid, but quite useless since you're not doing any ptrace on your processes. The third bit is invalid and will make waitpid error our immediately. I'm not going to tell you which is which because you're not supposed to do it this way at all. Read the manual page.
Another problem that you have is that you need to close the pipe in the parent process as well. wc will try to read data from the pipe (on its stdin) until the pipe is closed and it still remains open in the parent. The reason wc always prints after the parent has exited is that it's the parent exit that closes the pipe and that makes wc finish reading.

child and parent process id

Just got confused with parent pid value in child process block. My program is given below:
int main(int argc, char *argv[])
{
pid_t pid;
pid=fork();
if(pid==-1){
perror("fork failure");
exit(EXIT_FAILURE);
}
else if(pid==0){
printf("pid in child=%d and parent=%d\n",getpid(),getppid());
}
else{
printf("pid in parent=%d and childid=%d\n",getpid(),pid);
}
exit(EXIT_SUCCESS);
}
Output:
pid in parent=2642 and childid=2643
pid in child=2643 and parent=1
In "Advanced Unix programming" it says that child process can get parent process id using getppid() function. But here I am getting "1" which is "init" process id.
How can I get the parent pid value in the child process block.. Please help me in getting output.
I executed in "Linux Mint OS" but in "WindRiver" OS I am not getting this problem. Does this program change behaviour according to OS?
That's because the father can / will exit before the son. If a father exists without having requested the return value of it's child, the child will get owned by the process with pid=1. What is on classic UNIX or GNU systems SystemV init.
The solution is to use waitpid() in father:
int main(int argc, char *argv[])
{
pid_t pid;
pid=fork();
if(pid==-1){
perror("fork failure");
exit(EXIT_FAILURE);
}
else if(pid==0){
printf("pid in child=%d and parent=%d\n",getpid(),getppid());
}
else{
printf("pid in parent=%d and childid=%d\n",getpid(),pid);
}
int status = -1;
waitpid(pid, &status, WEXITED);
printf("The child exited with return code %d\n", status);
exit(EXIT_SUCCESS);
}
After the fork you have two new processes and you can know the child id in the parent but not the other way round. If you really need this you would have to open a pipe (popen) before the fork and then the parent could write this into the pipe and the child could read it.
Once the parent completes it execution and child is still running. Then child is known as orphan (as it's parent died) and it is adopted by init process if you are login by root ( whose pid =1 ).
If you want child to exit first before parent then use wait() system call and its variants.
#include <stdio.h>
#include <unistd.h>
int main()
{
int pid,pid2;
pid=fork();
if (pid<0) {
printf("fork failed");
exit(-1);
} else if (pid==0) {
printf("child id is%d",getpid());
execlp("/bin/ls","is",NULL);
printf("\nsleeping for 2 seconds using pid of child class");
sleep(2);
printf("killing the child process");
kill(getpid());
} else {
wait(NULL);
printf("The parent id is %d\n",getpid());
printf("The child id is %d\n",getpid());
printf("\nsleeping for 3 seconds without pid");
sleep(3);
printf("\nchild completed\n");
exit(0);
}
}
It is simply, because the parent process no longer exists. If you call the wait() system function, then it will exist until the child finishes its work and you will get the parent PID.

Resources