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
Related
I'm trying to better understand exec() - so I have the following script in testing.c
#include <stdio.h>
#include <sys/types.h>
#include <wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
if(argc < 2) {
fprintf(stderr,"Error:: Expecting an Argument!\n");
exit(-1);
}
pid_t pid;
pid = fork();
if (pid==0) {
execlp("./testing","testing",NULL);
fprintf(stderr, "I want to get to here...\n");
exit(-1);
}
wait(NULL);
printf("Parent and child done\n");
return 0;
}
The block below is the output after I execute with ./testing one:
Error:: Expecting an Argument!
Parent and child done
In reading how exec() works, I was expecting to be able to fprintf after my execlp call since it should be returning -1, I'm wondering if I need to be setting an errno or something or being more explicity about throwing something so that execlp recoginize the error?
If the execlp function successfully starts the given program, it does not return. The current program image gets replaced with the program image of the new program. So even if the new program exits with status -1, it still doesn't go back to the program that called execlp.
If you want to get the exit status of the child process, pass the address of an int to wait and read that:
int main(int argc, char ** argv)
{
if(argc < 2) {
fprintf(stderr,"Error:: Expecting an Argument!\n");
exit(-1);
}
pid_t pid;
pid = fork();
if (pid == -1 {
perror("fork failed");
exit(-1);
} else if (pid == 0) {
execlp("./testing","testing",NULL);
perror("execlp failed");
exit(-1);
}
int status;
wait(&status);
printf("child exit status: %d\n", WEXITSTATUS(status));
printf("Parent and child done\n");
return 0;
}
The output:
Error:: Expecting an Argument!
Parent and child done
is from
(first line) child process tries to run but no command line parameter.
(second line) parent process finishes
The problem here is that the child process does not wait for the message to arrive from the function startWorking(), and because of that I am getting a random char as output or sometimes nothing.
I am sending a char array from startWorking() to the pipe and I am making sure only the parent does this job.
One solution would be, sending a signal from startWorking() to the child processor, after writing into the pipe.
But the read() function behavior is waiting for the pipe to receive the message and only then read the message, but somehow it's not doing that, or maybe there is a problem in writing the message.
int main(int argc, char const *argv[])
{
pid_t pid;
pid = fork();
int mypipefd[2];
if (pid > 0)
{
if (pipe(mypipefd) == -1)
{
perror("Pipe failed\n");
exit(EXIT_FAILURE);
}
storeEngine(mypipefd);
}
else if(pid < 0)
{
perror("fork call failed \n");
exit(EXIT_FAILURE);
}
else
{
printf("I am the child \n");
printf("child: %d \n", getpid());
char message[6];
close(mypipefd[1]);
read(mypipefd[0], &message, 6);
close(mypipefd[0]);
printf("child read value:\n ");
printf("%s \n", message);
}
return 0;
}
void startWorking(int *mypipefd)
{
printf("%d \n" ,getpid());
//close(*mypipefd);
write(*(mypipefd+1), "hello", 6);
close(*(mypipefd+1));
}
Notice that if I remove the two slash behind close(*mypipefd) the program will never finish, and it will get stuck there.
Without examining the rest of your code, you need to call pipe() before you call fork() so the pipe can be used by both the parent and the child process. If you call pipe() after you call fork(), the pipe is only usable by that one process.
More like this:
int main(int argc, char const *argv[])
{
int mypipefd[2];
if ( pipe( mypipefd ) == -1 )
{
perror("Pipe failed\n");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid > 0)
{
storeEngine(mypipefd);
}
.
.
.
No, pipes used to communicate between processes should be created before the fork() (otherwise, you have no easy way to send thru them, since the reading and the writing ends should be used by different processes).
#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.
I have the following code:
int main(int argc, char **argv)
{
char *program;
char stringa[1000] = "";
int num = 123;
char snum[5];
program = argv[1];
sprintf(stringa, "./%s", program);
pid_t pid = fork();
if (pid < 0 ) {
perror("fork failed.");
exit(1); }
else if (pid == 0) {
char* args[] = {stringa, NULL};
execv(args[0], args);
}
else {
char procmon_str[] = "./procmon ";
num = pid;
sprintf(snum, "%d",num);
printf("PID of child is %s", snum);
char* args2[] = {procmon_str, snum, NULL};
execv(args2[0], args2);
sleep(20);
kill(num, SIGTERM);
sleep(2);
int parent_pid = getpid();
printf("PID of parent is %d", parent_pid);
kill(parent_pid, SIGTERM);
}
wait(NULL);
return 0;
}
The idea is to call with program with 1 command line argument which is a name of another compiled C program in the same folder.
I want to execute that program from within the C code (hence the use of fork()), and at the same time i want to launch another program from within the parent part of the fork().
The part that is in the child part of fork() works perfectly, but when i run it through the shell it says Terminated right after and does not execute the code in the parent part of the fork().
Why is that?
Your program call fork(). Now the execution of the parent process and the child process proceeds in parallel.
The child:
Builds the argument array args[].
Calls execv() and is replaced by the program supplied as argument.
The parent, in parallel with the child:
Builds the argument array args2[].
Calls execv() and is replaced by ./procmon.
The code from sleep(20) onwards in not reached unless the execv() fails (which you did not check for).
Read the manual page for fork() again, and redo the logic of the program.
#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?