How to execute a program by fork and exec - c

I have a binary file that contains a program with function written in C inside that looks like:
int main()
{
int a, b;
foo(a,b);
return 0;
}
And now I want to execute that program by using fork() and execve() in another program called "solver".
int main(int argc, char* argv[])
{
pid_t process;
process = fork();
if(process==0)
{
if(execve(argv[0], (char**)argv, NULL) == -1)
printf("The process could not be started\n");
}
return 0;
}
Is that a good way? Because it compiles, but I'm not sure whether the arguments of function inside "worker" program receive variables passed by command line to "solver" program

I believe you are trying to achieve something like that:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
static char *sub_process_name = "./work";
int main(int argc, char *argv[])
{
pid_t process;
process = fork();
if (process < 0)
{
// fork() failed.
perror("fork");
return 2;
}
if (process == 0)
{
// sub-process
argv[0] = sub_process_name; // Just need to change where argv[0] points to.
execv(argv[0], argv);
perror("execv"); // Ne need to check execv() return value. If it returns, you know it failed.
return 2;
}
int status;
pid_t wait_result;
while ((wait_result = wait(&status)) != -1)
{
printf("Process %lu returned result: %d\n", (unsigned long) wait_result, status);
}
printf("All children have finished.\n");
return 0;
}
./work will be launched with the same arguments as your original program.

Related

Why is argv[0] not consistent?

From what I understand, argv[0] is the program's path. However, we are doing an assignment and one of my friends gets the name of the first argument when invoking argv[0].
Why does this happen and how can I change this behaviour?
Edit: This is the parent process
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define SIZE 200
int main(int argc, char const *argv[])
{
char fileName[SIZE];
int bytesToRead;
int status;
bytesToRead = read(0, fileName, SIZE);
int p[2];
pipe(p);
pid_t pid;
if((pid = fork()) == -1) {
perror("error en el fork");
} else
if(pid == 0) {
close(p[0]);
dup2(STDOUT_FILENO, p[1]);
execl("./printTest", fileName, NULL);
close(p[1]);
exit(0);
}
waitpid(pid, &status, 0);
return 0;
}
And next is a child process:
#include <stdio.h>
#include <unistd.h>
#define SIZE 512
int main(int argc, char const *argv[])
{
printf("%s\n",argv[0]);
printf("Exec executed\n");
return 0;
}
From what we understand, argv[0] should hold the program's name, yet it's printing the first argument (whatever was input from stdin in the parent process)
argv[0] isn't necessarily the program's path. It is simply the first argument.
It just so happens that by convention, we use it for the program's name.
For your specific case, you need:
execl("./printTest", "./printTest", fileName, NULL);
Note that this means you always should check if argv[0] is defined before using it.
As per C standard argv[0] should contain the program name.

C program that tells the user which child process finished first

I am working on an assignment that involves using fork. The program runs two separate programs simultaneously and tells the user which one finished first. If a child finishes, the other child still running should be killed immediately.
My code so far is this...
int main(int argc, char **argv) {
if (argc != 2) {
perror("Invalid number of arguments!");
exit(1);
}
pid_t pid;
pid_t wpid;
int status = 0;
for (int i = 0; i < 2; i++) {
if ((pid = fork()) == 0) {
execv("/bin/sh", argv[i+1]);
}
}
while ((wpid = wait(&status)) > 0);
printf("%s finished first!", <Insert winning program here>);
return 0;
}
From my understanding, this runs the programs and will not let the parent process continue until the child processes have finished. Now I'm wondering how I can terminate another child and return the winning process.
But how can I immediately get the pid of the losing process so that I can kill it?
Just as TonyB told: the "parent" saves the pid of the new child. 2) wait will tell you the pid of the winning process. More verbose: Save the PID of both children, wait for any one, compare the return value to (one of) the saved PIDs; the matching one is the winner, the non-matching one is the loser. E. g.:
#define _POSIX_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
int main(int argc, char **argv)
{
if (argc != 3) // with two program arguments, argc is 3
fputs("Invalid number of arguments!\n", stderr), exit(EXIT_FAILURE);
pid_t pid[2]; // to store both child pids
pid_t wpid;
for (int i = 0; i < 2; i++)
if ((pid[i] = fork()) == 0)
execl("/bin/sh", "sh", "-c", argv[i+1], NULL),
perror(argv[i+1]), exit(EXIT_FAILURE);
wpid = wait(NULL); // wait for first
int wi = wpid==pid[0] ? 0 : 1; // get index of winner
kill(pid[!wi], SIGKILL), wait(NULL); // kill and reap loser
printf("%s finished first!\n", argv[wi+1]);
return 0;
}

Can't get execvp to execute file

I am trying to write a program that will fork, then open a file and execute it. The file it should execute is called child and it has been compiled. When I type ./child, it runs. However, when I run this program it does not execute the child program and I am prompted with the error message I put in "Execution failed". What I am doing wrong?
This is my parent class
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main (int argc, char **argv)
{
pid_t parent = getpid();
pid_t pid = fork();
if (pid == -1)
{
// error, failed to fork()
}
else if (pid > 0)
{
int status;
waitpid(pid, &status, 0);
}
else
{
int var = execvp("./child", NULL);
if(var < 0)
{
printf("Execution failed");
}
}
exit(0); // exec never returns
}
This is the child
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
printf ("Im the child");
exit (0);
}
I actually don't know what you are doing wrong. After a copy and a compilation (and several warning complains) your code runs fine (GCC 7.2).
Obviously, child must be in the same working directory in which you run your main executable (the one that forks).
But probably I would write that code in this way, but I'm not an expert in forking:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
extern int errno;
int main () {
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
if (pid == 0) {
int ret = execl("./child", "", (char *)NULL);
if(ret < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
} else {
wait(NULL);
}
return 0;
}
At least it tells you which error execl has encountered.

fork() and exec() run in parallel in C

I am trying to run three execv("./test",execv_str) in parallel. And I need to print out success message when each of execv() completes successfully.
But now I get result as following:
username#username:~/Desktop/$./test -p
SUCCESS
SUCCESS
SUCCESS
username#username:~/Desktop/$ TESTING
TESTING
TESTING
The expected result will be:
username#username:~/Desktop/$./test -p
TESTING
SUCCESS
TESTING
SUCCESS
TESTING
SUCCESS
username#username:~/Desktop/$
Here is the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int fork_execv()
{
int status;
pid_t pid;
pid = fork();
/* Handling Child Process */
if(pid == 0){
char* execv_str[] = {"./test", NULL};
if (execv("./test",execv_str) < 0){
status = -1;
perror("ERROR\n");
}
}
/* Handling Child Process Failure */
else if(pid < 0){
status = -1;
perror("ERROR\n");
}
return status;
}
int main(int argc, char *argv[]){
if (argc == 1){
sleep(5);
printf("TESTING\n");
}
else{
int i;
for(i = 0; i < 3; ++i){
if (fork_execv() != -1){
printf("SUCCESS\n");
}
}
}
}
How to modify my code to make it work?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int fork_execv()
{
int status;
pid_t pid;
pid = fork();
/* Handeling Chile Process */
if(pid == 0){
char* execv_str[] = {"./test", NULL};
if (execv("./test",execv_str) < 0){
status = -1;
perror("ERROR\n");
}
}
/* Handeling Chile Process Failure */
else if(pid < 0){
status = -1;
perror("ERROR\n");
}
return pid;
}
void handler(int sig){
printf("SUCCESS\n");
}
int main(int argc, char *argv[]){
if (argc == 1){
sleep(5);
printf("TESTING\n");
}
else{
int i;
pid_t process_id;
for(i = 0; i < 3; ++i){
if ((process_id = fork_execv()) != -1){
if(process_id != 0){
signal(SIGCHLD, handler);
waitpid(process_id, NULL, 0);
}
}
}
}
}
Here what I would do. After the fork, I return the pid, check if it isn't 0 (so we are in the father process) and make the father wait for the son. To print "success", I bind the SIGCHLD signal that is triggered when a child process ends. Note that this is a little overkill and put print after the waitpid would have done the job. (But I like to bind signal.)

Grabbing the return value from execv()

//code for foo (run executable as ./a.out)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/wait.h>
int main (int argc, char **argv) {
pid_t pid;
pid = fork();
int i = 1;
char *parms[] = {"test2", "5", NULL}; //test executable named test2
if(pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
else if(pid == 0) {
printf("Child pid is %d\n", pid);
i = execv("test2", parms); //exec call to test with a param of 5
}
else {
wait(NULL);
}
printf("I is now %d\n", i); //i is still 1 here, why?
return 0;
}
Hey everybody, I am trying to learn a little bit about fork and execv() calls. I make my foo.c program above make a call to a file I have named test.c. I fork a child and have the child make a call to execv, which will just add 10 to the parameter read in. I am unsure of why the variable does not change, at the bottom of my foo.c function. Does the call need to be a pointer or return an address? Any help would be greatly appreciated. Thanks
Code for test.c (executable named test2)
#include <stdio.h>
int main(int argc, char ** argv[]) {
int i = atoi(argv[1]);
i = i +10;
printf("I in test is %d\n", i);
return i;
}
You only call execv() in the child process. The exec() family functions never return if it runs successfully. See evec(3):
The exec() functions only return if an error has occurred. The return value is -1, and errno is set to indicate the error.
You printed the value of i in the parent process, it never changed in the parent process.
To get the exit status from the child process, you can make use of wait() or waitpid():
else {
int waitstatus;
wait(&waitstatus);
i = WEXITSTATUS(waitstatus);
}

Resources