using execv instead of execl in linux - c

I wrote a program to use execl and I want to have the same functionality but instead use execv.
here is my program from execl:
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
int pid, status,waitPid, childPid;
pid = fork (); / Duplicate /
if (pid == 0 && pid != -1) / Branch based on return value from fork () /
{
childPid = getpid();
printf ("(The Child)\nProcess ID: %d, Parent process ID: %d, Process Group ID: %d\n",childPid,getppid (),getgid ());
execl("/bin/cat","cat","-b","-t","-v",argv[1],(char*)NULL);
}
else
{
printf ("(The Parent)\nProcess ID: %d, The Parent Process ID: %d, Process Group ID: %d\n",getpid (),getppid (),getgid ());
waitPid = wait(childPid,&status,0); / Wait for PID 0 (child) to finish . /
}
return 1;
}
I then tried modifying it as such in order to use execv instead, but I could not get it to work (as in it would say no such file or directory found)
You call the program with ./ProgramName testfile.txt
Here is my attempting at execv:
#include <stdio.h>
#include <unistd.h>
int main ()
{
int pid, status,waitPid, childPid;
char *cmd_str = "cat/bin";
char *argv[] = {cmd_str, "cat","-b","-t","-v", NULL };
pid = fork (); / Duplicate /
if (pid == 0 && pid != -1) / Branch based on return value from fork () /
{
childPid = getpid();
printf ("(The Child)\nProcess ID: %d, Parent process ID: %d, Process Group ID: %d\n",childPid,getppid (),getgid ());
execv(cmd_str,argv);
}
else
{
printf ("(The Parent)\nProcess ID: %d, The Parent Process ID: %d, Process Group ID: %d\n",getpid (),getppid (),getgid ());
waitPid = wait(childPid,&status,0); / Wait for PID 0 (child) to finish . /
}
return 1;
}
Any help would be huge, have been stuck on this for quite a while now. Thanks!

You have a few errors in the code, which I marked down:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) // <-- missing argc/argv
{
int pid, status,waitPid, childPid;
char *cmd_str = "/bin/cat"; // <-- copy/pasta error
char *args[] = { "cat", "-b", "-t", "-v", argv[1], NULL }; // <-- renamed to args and added argv[1]
pid = fork (); // Duplicate /
if (pid == 0) // Branch based on return value from fork () /
{
childPid = getpid();
printf ("(The Child)\nProcess ID: %d, Parent process ID: %d, Process Group ID: %d\n",childPid,getppid (),getgid ());
execv(cmd_str,args); // <-- renamed to args
}
else
{
printf ("(The Parent)\nProcess ID: %d, The Parent Process ID: %d, Process Group ID: %d\n",getpid (),getppid (),getgid ());
waitPid = wait(childPid,&status,0); // Wait for PID 0 (child) to finish . /
}
return 1;
}

Related

How would you change the code so that the child and parent run concurrently?

I am struggling to understand this question. Aren't the child and parent already running concurrently? Would the answer be to remove wait(NULL)? Please help.
Here the Code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main (int args, char *argv[])
{
pid_t fork_return;
pid_t pid;
pid=getpid();
fork_return = fork();
if (fork_return==-1) {
// When fork() returns -1, an error has happened.
printf("\nError creating process " );
return 0;
}
if (fork_return==0) {
// When fork() returns 0, we are in the child process.
printf("\n\nThe values are Child ID = %d, Parent ID=%d\n", getpid(), getppid());
execl("/bin/cat", "cat", "-b", "-v", "-t", argv[1], NULL);
}
else {
// When fork() returns a positive number, we are in the parent process
// and the return value is the PID of the newly created child process.
wait(NULL);
printf("\nChild Completes " );
printf("\nIn the Parent Process\n");
printf("Child Id = %d, Parent ID = %d\n", getpid(), getppid());
}
return 0;
}

Finding the level of a child process in a process tree

I've been trying to create a process tree using fork() and print each child's level (0 for base process, 1 for its child, 2 for its grandchild etc.) in the tree. The code below only works for depth 0 and 1. Any idea how I can improve it?
Thanks.
#include <stdio.h>
#include <unistd.h>
int i;
int main()
{
pid_t baseID = getpid();
printf("Base Process ID: %d, level: 0 \n", baseID);
for (i = 0; i < 3; i++) {
int level = 1;
pid_t pid;
pid = fork();
if (pid == 0) {
pid_t childID = getpid();
pid_t parentID = getppid();
if (parentID == baseID) {
level = 1;
}
else {
// do something for grandchildren here
level++;
}
printf("Process ID: %d, Parent ID: %d, level: %d \n", getpid(), getppid(), level);
}
else {
wait(NULL);
}
}
return 0;
}
The intended process tree is the following:
0
|->1
| |->2
| | |->3
| |
| |->2
|
|->1
| |->2
|
|->1
So to be able to print the level of each process, we should just initialize the level variable to 0 outside the main for loop and just increment its value each time a child process is created.
The following code will print the level of each child process as expected:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t baseID = getpid();
printf("Base Process ID: %d, level: 0 \n", baseID);
int level = 0;
for (int i = 0; i < 3; i++) {
pid_t pid = fork();
if (pid == 0) { // Child
pid_t childID = getpid();
pid_t parentID = getppid();
level++;
printf("Process ID: %d, Parent ID: %d, level: %d \n", getpid(), getppid(), level);
} else { // Parent
wait(NULL);
}
}
return 0;
}

C child process runs its code twice

Total C noob here, looking for some help with fork(). I'm not sure why its print the child process 2 code twice. I believe it has to do with the sleep call because it was working fine before.
Output
Child Process 2
Process ID: 31973
Parent Process ID: 1
Child Process 1
Process ID: 31972
Parent Process ID: 1
Child Process 2
Process ID: 31974
Parent Process ID: 1
C Code
#define _XOPEN_SOURCE // required for cuserid to work
// includes
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <time.h>
int main(void) {
getP0Info();
putenv("WHALE=7");
forkProcesses();
return 0;
}
// Prints an error message and exits if one occurs. Else, returns the system call value.
int print_if_err(int syscall_val, const char* syscall_name) {
if (syscall_val < 0) {
perror(syscall_name);
exit(errno);
} else {
//No syscall error; we can return
return syscall_val;
}
}
void forkProcesses() {
pid_t child1_pid = print_if_err(fork(), "fork");
if (child1_pid == 0) {
printf("\nChild Process 1\n");
printf("Process ID: %d\n", getpid());
printf("Parent Process ID: %d\n", getppid());
sleep(1);
int whale = atoi(getenv("WHALE"));
printf("C1: %d\n", whale);
}
pid_t child2_pid = print_if_err(fork(), "fork");
if (child2_pid == 0) {
printf("\nChild Process 2\n");
printf("Process ID: %d\n", getpid());
printf("Parent Process ID: %d\n", getppid());
}
}
That's because child process 1's execution continues even after the if-statement is over. You need to explicitly do a return or call _exit() or such to prevent this:
void forkProcesses() {
pid_t child1_pid = print_if_err(fork(), "fork");
if (child1_pid == 0) {
printf("\nChild Process 1\n");
printf("Process ID: %d\n", getpid());
printf("Parent Process ID: %d\n", getppid());
sleep(1);
int whale = atoi(getenv("WHALE"));
printf("C1: %d\n", whale);
_exit(0);
}
pid_t child2_pid = print_if_err(fork(), "fork");
if (child2_pid == 0) {
printf("\nChild Process 2\n");
printf("Process ID: %d\n", getpid());
printf("Parent Process ID: %d\n", getppid());
}
}

Wait() runs twice?

In my code below, I'm running a parent process which forks off into two child processes. After child(getpid());, both children exit with a status.
However, when I run the parent process, it somehow always decides to run the parent section twice (sets two different pid values), and I just can't get it to run just once. Is there a way to make wait stop after getting one value?
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
void child(int n) { //n: child pid
printf("\nPID of child: %i \n", n);
//random number rand
int randFile = open("/dev/random", O_RDONLY);
int r;
if(rand < 0)
printf("ERROR: %s\n", strerror(errno));
else {
unsigned int seed;
read(randFile, &seed, 4); //&rand is a pointer, 4 bytes
int randClose = close(randFile);
srand(seed); //seeds rand() with random from /dev/random
r = rand();
if(randClose < 0)
printf("ERROR: %s\n", strerror(errno));
//range between 5 and 20 seconds
r = r % 20;
if( r < 5)
r = 5;
}
// printf("\n%i\n", r);
sleep(r);
// sleep(1);
printf("\n child with pid %i FINISHED\n", n);
exit( r );
}
int main() {
printf("\nPREFORK\n");
int parentPID = getpid();
int child0 = fork();
if(child0 < 0)
printf("ERROR: %s\n", strerror(errno));
int child1 = fork();
if(child1 < 0)
printf("\nERROR: %s\n", strerror(errno));
if(getpid() == parentPID)
printf("\nPOSTFORK\n");
//if children
if(child1 == 0) //using child1 as child-testing value b/c when child1 is set, both children are already forked
child(getpid());
int status;
int pid = wait(&status);
//parent
if(getpid() != 0) {
if( pid < 0)
printf("\nERROR: %s\n", strerror(errno));
if ( pid > 0 && pid != parentPID) {
printf("\nPID of FINISHED CHILD: %i\n Asleep for %i seconds\n", pid, WEXITSTATUS(status));
printf("PARENT ENDED. PROGRAM TERMINATING");
}
}
return 0;
}
The parent is doing:
int child0 = fork(); // + test if fork failed
int child1 = fork(); // + test if fork failed
First you only have the parent.
After 1st fork you have the parent and the 1st child, both at the same execution point, so just before the next fork.
So just after that the parent re-creates a child, and the 1st child creates its own child (and will act like the parent).
You have to use if/else so that you are sure that the child don't fork. i.e.:
child0 = fork(); // add check for errors
if (child0 == 0) {
// the 1st child just have to call that
child(getpid());
exit(0);
}
// here we are the parent
child1 = fork();
if (child1 == 0) {
// the 2nd child just have to call that
child(getpid());
exit(0);
}
You can do that differently, of course, this is just an example. The main point is to not call fork() within the child.

how to not block parent with waitpid

I need to create a program that creates n number of processes and displays information. When each process ends, I am to print it's PID and the exit status. The way I am doing it, the parent program waits to create the next process until the current one ends. I need it so that it keeps creating the child processes and just displays the exit information when ever one process ends without blocking the parent from continuing. I can;t figure out where to put my wait to ensure this. Below is my code:
int main (int argc, char *argv[])
{
if (argc < 2)
{
printf("\n\nUsage: %s <enter a number (12 or less)>\n\n", argv[0]);
exit (-1);
}
else
{
int *processNum = (int *)malloc(sizeof(12));
int processNumTemp;
processNumTemp = atoi(argv[1]);
processNum = &processNumTemp;
if(*processNum > 12 || *processNum < 1)
{
printf("\n\nUsage: %s <enter a number (12 or lrss)>\n\n", argv[0]);
}
else
{
parentInfo(processNum);
createChildProcess(processNum);
}
}
return 0;
}
//Name: parentInfo
//Description: Displays information about the parent process
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void parentInfo(int *processNum)
{
printf("Parent process ID: %d\n", getppid());
printf("Number of processes to create: %d\n", *processNum);
}
//Name: createChildProcess
//Description: Creates n number of child processes.
// For each child process, it says its a child process and it
// displays its PID.
// After each child process closes, the parent displays info.
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void createChildProcess(int *processNum)
{
int i;
int childStatus;
pid_t childpid;
/*The for loop will create n number of processes based on the value of processNum.*/
for(i = 1; i <= *processNum; i++)
childpid = fork();
//Executes if fork didn't work
if(childpid < 0)
{
perror("fork");
exit(1);
}
//Executes if the fork worked
else if( childpid == 0)
{
int pid = getpid();
//Prints a message and the child processe's PID
printf("\nHello I am a child process.\n");
printf("My PID is %d. \n", getpid());
for(int x = 1; x <= pid; x ++);
exit(15);
}
}
//Executes after the child process has ended
//Checks the child process's exit status
waitpid(childpid, &childStatus, WUNTRACED);
printf("\nPID of the child process that was just created: %d.\n", childpid);
if(WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else if(WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else if(WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
Before fork code
signal(SIGCHLD, childHandler);
In childHandler put your waitpid code.
void childHandler(int signum)
{
pid_t childpid;
int childstatus;
while ((childpid = waitpid( -1, &childstatus, WNOHANG)) > 0)
{
if (WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else
if (WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else
if (WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
}
}
You should not use async-unsafe calls like printf inside a signal handler so alter your code to save the status in a global or heap allocated array - you know the size to create from processNum - and print the status info outside the handler.
Also, as currently structured, your parent could end before reaping all the children. Add a counter for the children so that you wait on all of them before the parent exits.
Look into signal SIGCHLD. If you have it blocked, you must unblock it or might instead explicitly check for it.
The purpose of wait is to, well, wait, so the way to solve your problem is to first create all the children, then start waiting for them to terminate.
Here is a program which does that:
// fork
#include <unistd.h>
// wait
#include <sys/types.h>
#include <sys/wait.h>
// exit
#include <stdlib.h>
//printf
#include <stdio.h>
void child( int id)
{
int seed= id;
int x= rand_r( &seed) % 10;
sleep( x);
exit( x);
}
int main( int argc, char *argv[])
{
const int n= 5;
int i;
printf( "creating %d children.\n", n);
for ( i= 0; i < n; ++i) {
pid_t pid= fork();
if ( !pid)
child( i); // does not return
else
printf( "child [0x%x] created.\n", pid);
}
// all the children are created now
// now we wait for them to terminate
printf( "waiting for children to terminate.\n", n);
for ( i= 0; i < n; ++i) {
int result;
pid_t pid= wait( &result);
printf( "child [0x%x] terminated with result [%u].\n", pid, WEXITSTATUS( result));
}
puts( "all children terminated.");
}

Resources