C fork and pipe printing pid in order - c

So I need this program which needs to create argv[1] child using fork() and print what children number are they and what PID do they have in order of its creation.
I have to do that using pipes blocking properties.
Example output:
I am child 1 and my PID is 25853.
I am child 2 and my PID is 25854.
I am child 3 and my PID is 25855.
This is what I have tried so far, but it doesn't respect the order of children creation.
int main(int argc, char* argv[])
{
char buffer[80];
int p[2], i;
int pid = getpid();
for (i = 0; i < atoi(argv[1]); i++) {
pipe(p);
if (fork() == 0) {
read(p[0], &pid, sizeof(pid)); // It should block here until there's
// something in the pipe to read
sprintf(buffer, "I am child %d and my PID is %d\n", i + 1, getpid());
write(1, &buffer, strlen(buffer));
close(p[0]);
close(p[1]);
exit(0);
}
else { // parent
close(p[0]);
write(p[1], &pid, sizeof(pid));
close(p[1]); // The child is able to read the EOF now.
}
}
while ((waitpid(-1, NULL, 0)) > 0)
;
close(p[0]);
close(p[1]);
sprintf(buffer, "I've finished\n");
write(1, &buffer, strlen(buffer));
}
I feel like I am close but I am not using the pipes block poperties correctly.
I need some advice, thanks.

#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc != 2) {
return 1;
}
int const n = atoi(argv[1]);
for (int i = 0; i < n; i++) {
int p[2];
if (pipe(p) != 0)
return 1;
int pid = fork();
if (pid == 0) {
close(p[1]);
if (read(p[0], &pid, sizeof pid) != sizeof pid)
return 1;
close(p[0]);
fprintf(stdout, "I am child %d and my PID is %d\n", i + 1, pid);
return 0;
}
else if (pid > 0) {
close(p[0]);
if (write(p[1], &pid, sizeof pid) != sizeof pid)
return 1;
close(p[1]);
if (waitpid(pid, NULL, 0) == -1)
return 1;
}
else {
return 1;
}
}
fprintf(stdout, "I've finished\n");
}

Related

How do you create n children, connect them through pipes and execute commands

I'm trying to simulate bash pipe like ls | grep ma | wc but for some reason it seems like my third child process that executes wc just hangs. I can't find the culprit, please help.
Here's my code:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define CMD_NUM 3
int main(void)
{
pid_t pids[CMD_NUM];
int *pipeFd;
int pipeFds[CMD_NUM - 1][2];
for (int i = 0; i < CMD_NUM - 1; i++)
if (pipe(pipeFds[i]) == -1)
perror("Error creating pipes");
pids[0] = fork();
if (pids[0] == 0)
{
printf("I'm in 1r if\n");
pipeFd = pipeFds[0];
close(pipeFd[0]);
close(1);
dup2(pipeFd[1], 1);
char* argv[] = {"ls", "-l", NULL};
execvp("ls", argv);
perror("Error ls execvp");
exit(1);
}
for (int i = 1; i < CMD_NUM - 1; i++)
{
printf("I'm in for\n");
pids[i] = fork();
if (pids[i] == 0)
{
close(0);
close(1);
pipeFd = pipeFds[i - 1];
close(pipeFd[1]);
dup2(pipeFd[0], 0);
pipeFd = pipeFds[i];
close(pipeFd[0]);
dup2(pipeFd[1], 1);
char* argv[] = {"grep", "ma", NULL};
execvp("grep", argv);
perror("Error in execvp");
exit(1);
}
}
pids[CMD_NUM - 1] = fork();
if (pids[CMD_NUM - 1] == 0)
{
printf("I'm in 2n if\n");
pipeFd = pipeFds[CMD_NUM - 2];
close(pipeFd[1]);
close(0);
dup2(pipeFd[0], 0);
char* argv[] = {"wc", NULL};
perror("hello");
execvp(argv[0], argv);
perror("Error en execvp");
exit(1);
}
for (int i = 0; i < CMD_NUM - 1; i++)
{
printf("I'm closing pipes\n");
pipeFd = pipeFds[i];
close(pipeFd[0]);
close(pipeFd[1]);
}
printf("I'm waiting for my last child\n");
waitpid(pids[CMD_NUM - 1], NULL, 0);
}
I'm only waiting for the last child because it's a requirement.

Passing data from one pipe to another

I am new to pipes but how do I redirect the output from child_1 to the input for child_2?
I am trying to pass the value from the parent to child_1, adds 1 to the value, print the value, then use that output and pass it into child_2, add 1 again, and finally print the value.
The code below has the right output value for child_1, but not for child_2, how do I redirect the output from child_1 to the input for child_2?
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[]) {
int fd[2];
int PID;
pipe(fd); //fd1[0] = read | fd1[1] = write
PID = fork(); // spawn child_1
if (PID < 0){ // failed to fork
perror("Unable to fork child");
exit(1);
}
if (PID > 0) { // parent
int value = 100;
// since parent is only writing, close the reading end of pipe
close(fd[0]);
// write the data to the write end of the pipe
write(fd[1], &value, sizeof(int));
// then close the writing end of the pipe (parent)
close(fd[1]);
/**********************************************************/
} else { // child 1
int val = 0;
// read from the parent pipe
read(fd[0], &val, sizeof(int));
val += 1;
// is this how to redirect from one pipe to another?
dup2(fd[0], fd[1]);
// this prints the right value for val (val [101] = value [100] + 1)
printf("Child [%d] read value %d\n", getpid(), val);
// close the reading end of the pipe for child_1
close(fd[0]);
int PID2 = fork(); // make child 2
if(PID2 == 0) { // child 2
int val2 = 0;
close(0); // close stdin since we are trying to take the value from child_1
// read input from child_1 pipe (NOT WORKING?)
read(fd[0], &val2, sizeof(int));
val2 += 1;
printf("Child [%d] out %d\n", getpid(), val2);
close(fd[0]);
}
}
return EXIT_SUCCESS;
}
The way you have things set up, there's no need to use dup2() or any other I/O redirection.
Add #include <unistd.h> to the list of include files (and remove #include <string.h> — it seems to be unused)
Delete: dup2(fd[0], fd[1]);
Delete: close(fd[0]);
Delete: close(0);
Before the second fork(), add write(fd[1], &val, sizeof(val));
When you have close(fd[0]) in the first child, you effectively close fd[0] for the second child too.
You should check the status of the read and write operations before using the results.
Those changes lead to:
/* SO 7383-1815 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int fd[2];
int PID;
pipe(fd);
PID = fork();
if (PID < 0)
{
perror("Unable to fork child");
exit(EXIT_FAILURE);
}
if (PID > 0)
{
int value = 100;
close(fd[0]);
write(fd[1], &value, sizeof(int));
close(fd[1]);
}
else
{
int val = 0;
if (read(fd[0], &val, sizeof(val)) != sizeof(val))
{
perror("read() failed in child 1");
exit(EXIT_FAILURE);
}
val += 1;
printf("Child [%d] read value %d\n", getpid(), val);
if (write(fd[1], &val, sizeof(val)) != sizeof(val))
{
perror("write() failed in child 1");
exit(EXIT_FAILURE);
}
int PID2 = fork();
if (PID2 == 0)
{
int val2 = 0;
if (read(fd[0], &val2, sizeof(val2)) != sizeof(val2))
{
perror("read() failed in child 2");
exit(EXIT_FAILURE);
}
val2 += 1;
printf("Child [%d] out %d\n", getpid(), val2);
close(fd[0]);
close(fd[1]);
}
}
return EXIT_SUCCESS;
}
When compiled (cleanly with options set fussy), it produces output such as:
Child [34520] read value 101
Child [34521] out 102
I believe this is what was wanted.

execlp redirect stdin in c

Question is simple
I've searched around but I couldn't find the solution
char *data1;
char *data2;
pid_t pid = fork();
int stat;
if (pid == 0){
execlp("Program B");
} else {
wait(&stat);
if (WIFEXITED(stat))
printf("%d\n", WEXITSTATUS(stat));
}
the thing is I need to send data1 and data2 to Program B as stdin
but I couldn't find the solution
how can I deal with this?
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
char *data1 = "First message.\n";
char *data2 = "What the rest of the world has been waiting for.\n";
pid_t pid;
int p[2];
if (pipe(p) < 0)
perror("pipe() failed");
else if ((pid = fork()) < 0)
perror("fork() failed");
else if (pid == 0)
{
dup2(p[0], STDIN_FILENO);
close(p[0]);
close(p[1]);
execlp("cat", "cat", (char *)0);
perror("execlp() failed");
}
else
{
close(p[0]);
write(p[1], data1, strlen(data1));
write(p[1], data2, strlen(data2));
close(p[1]);
int status;
int corpse = wait(&status);
if (WIFEXITED(status))
printf("%d exited with status %d\n", corpse, WEXITSTATUS(status));
}
return 0;
}
Note how many closes are necessary.
Building a pipe to stdin is the way to go,
Like
char *data1;
char *data2;
int stat;
pid_t pid;
if( pipe(pfd) < 0 ) {
perror("pipe");
return 1;
}
pid = fork();
if (pid == 0)
{
// Close the writing end of the pipe
close(pfd[1]);
execlp("Program B");
}
else if(pid==-1)
{
perror("fork");
}
else
{
// Write to the pipe.
if (write(pfd[1], "This is my data \n", 16) != 16)
perror("write");
close(pfd[1]);
wait(&stat);
if (WIFEXITED(stat))
printf("%d\n", WEXITSTATUS(stat));
}
You can provide data as argument list to the new process.
Syntax:- int execlp(const char *path, const char *arg0, ..., NULL);
So your call can look something like this
// convert the input data into string format i.e data1 and data2 should be strings
execlp("Program B","Program B",data1,data2,NULL);
In program B use appropriately to convert it into whatever type you want to.

Getting return from execlp()

I have a program which I would like to sort the first column in a file, from a child process, and return the output to the parent process. How can I retrieve the response from the execlp and print it? Here is what I have so far:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define WRITE 1
#define READ 0
int main(int argc, char **argv)
{
int i, k;
int p1[2], p2[2];
int p1[2], p2[2];
pid_t childID;
if (pipe(p1) < 0 || pipe(p2) < 0) {
perror("pipe");
exit(0);
}
childID = fork();
if (childID < 0) {
perror("fork");
exit(0);
}
else if (childID == 0){
close(p1[WRITE]);
close(p2[READ]);
dup2(p1[READ], STDIN_FILENO);
close(p1[READ]);
dup2(p2[WRITE], STDOUT_FILENO);
close(p2[WRITE]);
execlp("sort", "-k1", "-n", "temp.txt", (char *)NULL);
perror("exec");
exit(0);
}
else {
//parent process
//Not sure how to get response from exec
}
}
After call execlp(), the memory image of current process will be replaced by the called progame, so you cannot get what you want through return value. What you can do is let the child process write its result to somehere, such as a temporal file or a pipe, and the parent process read the result from this place.
After proper setup a pipe to communite between parent and child processes, you can write the result of child process in its stdout, and read the result in parent processes from its stdin.
Something like this:
else if (childID == 0){
close(p1[READ]);
dup2(p1[WRITE], STDOUT_FILENO);
close(p1[WRITE]);
execlp("sort", "-k1", "-n", "temp.txt", (char *)NULL);
perror("exec");
exit(0);
}
else {
close(p1[WRITE]);
dup2(p1[READ], STDIN_FILENO);
close(p1[READ]);
while (scanf("%ms ", &l) != EOF) {
printf("%s\n", l);
free(l);
}
}
Here is full code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define WRITE 1
#define READ 0
int main(int argc, char **argv)
{
int p1[2];
char *l;
pid_t childID;
if (pipe(p1) < 0) {
perror("pipe");
exit(0);
}
childID = fork();
if (childID < 0) {
perror("fork");
exit(0);
}
else if (childID == 0){
close(p1[READ]);
dup2(p1[WRITE], STDOUT_FILENO);
close(p1[WRITE]);
execlp("sort", "-k1", "-n", "temp.txt", (char *)NULL);
perror("exec");
exit(0);
}
else {
close(p1[WRITE]);
dup2(p1[READ], STDIN_FILENO);
close(p1[READ]);
while (scanf("%ms ", &l) != EOF) {
printf("%s\n", l);
free(l);
}
}
return 0;
}
And test file temp.txt:
$ cat temp.txt
a
e
b
d
f
c
Result of a test run:
$ ./a.out
a
b
c
d
e
f

Run N concurrent processes in C

I am trying to run N concurrent processes in a C program. I've built a simple example that takes commands as arguments, creates a fork for each one, and executes it.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
for(i = 1; i < argc; i++)
{
pid_t pid = fork();
if(pid < 0)
{
fprintf(stderr, "forking error\n");
exit(1);
}
else if(pid > 0)
{
int status;
waitpid(pid, &status, 0);
printf("Command %s has completed successfully by PID=%d\n", argv[i], pid);
}
else
{
char cmd[1024];
sprintf(cmd, "%s", argv[i], i);
system(cmd);
_exit(1);
}
}
printf("Finished\n");
return 0;
}
This seems to run the processes correctly, but not concurrently. Any ideas as to what am I doing wrong?
EDIT: I've edited based on suggestions, but this also does not seem to work.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
pid_t *pids = malloc( sizeof(pid_t) * (argc) );
int *statuses = malloc( sizeof(int) * (argc) );
for(i = 1; i < argc; i++)
{
pid_t pid = fork();
if(pid < 0)
{
fprintf(stderr, "forking error\n");
exit(1);
}
else if(pid > 0)
{
//int status;
//waitpid(pid, &status, 0);
//printf("Command %s has completed successfully by PID=%d\n", argv[i], pid);
pids[i] = pid;
}
else
{
char cmd[1024];
sprintf(cmd, "%s > out.%d", argv[i], i);
system(cmd);
_exit(1);
}
}
int needtowait = 0;
do
{
needtowait = 0;
for(i = 1; i < argc; i++)
{
if(pids[i] > 0)
{
if(waitpid(pids[i], &statuses[i], 0) != 0)
{
pids[i] = 0;
char *successstr = "successfully";
if(statuses[i])
{
successstr = "unsuccessfully";
}
printf("Command %s has completed %s by PID=%d\n", argv[i], successstr, pids[i]);
}
}
else
{
needtowait = 1;
}
sleep(0);
}
} while(needtowait);
printf("Finished!\n");
return 0;
}
The reason you are not running these processes concurrently is in this line:
waitpid(pid, &status, 0);
The main process that forks out the child process waits for the child process to exit before continuing with the loop, and starting the next process.
Since you want to run your processes concurrently, you can do this: allocate an array of pid_t for process IDs, and fill it in inside the loop. Once you are out of the loop, you can wait for the individual processes to complete by executing waitpid calls in a loop.
pid_t *pids = malloc(argc * sizeof(pid_t));
for (int i = 0 ; i < argc ; i++) { // Start i at 0, not at 1
pid_t pid = fork();
if (pid < 0) {
...
} else if (pid > 0) {
pids[i] = pid;
} else {
char cmd[1024];
sprintf(cmd, "%s", argv[i+1], i+1);
system(cmd);
_exit(1);
}
}
for (int i = 0 ; i < argc ; i++) {
int status;
waitpid(pids[i], &status, 0);
printf("Command %s has completed successfully by PID=%d\n", argv[i+1], pids[i]);
}
Sure. Your parent process is waiting for the child process to finish executing before forking again. You're just running cmd sequentially N times.

Resources