writing stdout to a file from execvp - c

Why is it that execvp isnt writing to the redirected STDOUT?
I tried using printf() as a test within this block, and that writes exactly where it should, which is in the file that I redirected STDOUT to.
edit: I changed the code, and added my implementation of makesubcommand, and added some debugging messages.
pid = fork();
wait(0);
if(pid == 0)
{
fd = open(subargs[next_redirect + 1], O_CREAT|O_TRUNC|O_WRONLY, 0644);
dup2(fd, STDOUT_FILENO);
close(fd);
//create sub-command
int val = (next_redirect - (last_redirect + 1));
fprintf(stderr,"subcommand will have %i indexes\n", val);
char* subcommand[val];
makesubcommand(subcommand, subargs, last_redirect + 1, next_redirect);
execvp(subcommand[0], subcommand);
fprintf(stderr,"execvp failed\n");
}
last_redirect = next_redirect;
next_redirect = getnextredirect(subargs, last_redirect+2, subargc);
heres makesubcommand(4):
void makesubcommand(char** newcommand, char** oldcommand, int lowerbound, int upperbound)
{
int i;
fprintf(stderr, "lowerbound: %i upperbound: %i\n",lowerbound, upperbound);
for(i = lowerbound; i < upperbound; i++)
{
fprintf(stderr,"subarg[%i]: %s\n", (i-lowerbound), oldcommand[i]);
newcommand[i - lowerbound] = oldcommand[i];
}
for(i = lowerbound; i < upperbound; i++)
{
fprintf(stderr, "newcommand[%i] = %s\n",(i - lowerbound), newcommand[i]);
}
fprintf(stderr, "it worked\n");
}
heres a testrun:
{12425}/home/chris/2240New/WMU-CS2240/A3_Shell$ ls > a
subcommand will have 1 indexes
lowerbound: 0 upperbound: 1
subarg[0]: ls
newcommand[0] = ls
it worked
execvp failed

My problem ended up being that I needed to allocate memory for the subcommand. malloc did the trick!

Related

C: How do I pass a value from child process to parent process via pipes before execv?

Before I start, I just want to say that this is for a school assignment of mine. I'm really close to finishing, except well, since I'm here, obvious to say, I'm stuck on a problem :(.
First of I'll explain what my assignment wants:
The assignment wants me to create a command-line program in C that allows the user to type in N number of /bin/ commands (E.g. > /bin/ps /bin/ls "/bin/which gcc"). Once the user enters the command and hits the enter key, the parent process (the parent process is the program) will create N child processes (i.e. no. of /bin/ commands entered = no. of child processes parent process will create). Each child will run one of the N commands. All the children will be running concurrently, with the parent waiting for each child to terminate.
Once a child terminates, the parent will print whether the command executed successfully or not (E.g. "Command /bin/ps has completed successfully" or "Command /bin/ps has not completed successfully") and once all children have been terminated, the parent will print "All done, bye!"
The issue:
So I've managed to get my child processes to run concurrently, the only issue is that I'm not sure how to pipe the value of the command (like /bin/ps or /bin/which gcc) from the child process to the parent process to print out the success or not message. I've tried putting the write pipe above my execv which allows me to pipe what I want but the execv won't output anything and I can't put my pipe code below my execv because in that case, then while my execv output will show, my pipe won't. I did think that it might be due to close(1) but commenting that out didn't change the result.
So what I am trying to achieve is something like this:
> /bin/ls "/bin/which gcc" /bin/domainname /bin/fake_command
Output:
/usr/bin/gcc
localdomain
Command /bin/which gcc has completed successfully
Command /bin/domainname has completed successfully
a.txt b.c
Command /bin/ls has completed successfully
Command /bin/fake_command has not completed successfully
All done, bye!
>
But right now, I'm getting:
> /bin/ls "/bin/which gcc" /bin/domainname /bin/fake_command
Output:
Command /bin/which gcc has completed successfully
Command /bin/domainname has completed successfully
Command /bin/ls has completed successfully
Command /bin/fake_command has not completed successfully
>
As you can see, my execv output for the /bin/ commands aren't shown in the output.
I've tried searching SO for people who faced this similar issue as me but none of their solutions managed to work for me which is why I'm asking here. If there's anything you're not clear about, please let me know and I will try my best to explain.
The code:
q1.c
#include "q1.h"
int main(int argc, char *argv[])
{
int
child_status,
pipe_array[2];
pid_t child;
char *success_or_fail;
char *msg_buffer = malloc(CHAR_MAX);
if (msg_buffer == NULL)
{
return -1;
}
struct timespec tw = {.tv_sec = 0, .tv_nsec = 10000000L};
Tuple *process_tuple;
size_t tuple_size = sizeof(*process_tuple) + sizeof(pid_t) + sizeof(char *);
process_tuple = calloc(argc, tuple_size);
if (process_tuple == NULL)
{
return -1;
}
// if (pipe(pipe_array) == -1)
// {
// perror("pipe: ");
// return -1;
// }
for (int j = 1; j < argc; j++)
{
child = fork();
if (child == 0)
{
int
executed,
num_of_words,
num_of_chars;
char
string[strlen(argv[j]) + 1],
*backup = argv[j];
snprintf(string, sizeof(string), "%s", argv[j]);
num_of_chars = get_num_of_chars(string);
num_of_words = get_num_of_words(string);
char *command[num_of_chars + 1];
preparing_the_command(num_of_words, string, command);
// close(pipe_array[0]);
// close(1);
// dup2(pipe_array[1], STDOUT_FILENO);
// write(pipe_array[1], backup, sizeof(backup));
process_tuple[j - 1].pid = getpid();
process_tuple[j - 1].command = backup;
printf(" %i-PID -> %i\n %i-Command -> %s\n\n", process_tuple[j - 1].pid, process_tuple[j - 1].pid, process_tuple[j - 1].pid, process_tuple[j - 1].command);
executed = execv(command[0], command);
nanosleep(&tw, 0);
if (executed == -1)
{
exit(EXIT_FAILURE);
}
else
{
exit(EXIT_SUCCESS);
}
}
else if (child == -1)
{
perror("fork() failed: ");
exit(EXIT_FAILURE);
}
}
printf(" PID -> %i\n Command -> %s\n\n", process_tuple[0].pid, process_tuple[0].command);
// while ((child = waitpid(-1, &child_status, 0)) != -1)
// {
// for (int o = 0; o < argc; o++)
// {
// printf(" PID -> %i\n Command -> %s\n\n", process_tuple[o].pid, process_tuple[o].command);
// }
// close(0);
// close(pipe_array[1]);
//
// dup2(pipe_array[0], STDIN_FILENO);
// char *recipient;
//
// read(pipe_array[0], recipient, sizeof(recipient));
// if (!(WIFEXITED(child_status) && (WEXITSTATUS(child_status) == 0)))
// {
// success_or_fail = "not completed successfully";
// }
// else
// {
// success_or_fail = "completed successfully";
// }
// snprintf(msg_buffer, CHAR_MAX, "Command %s has %s\n", recipient, success_or_fail);
// fputs(msg_buffer, stdout);
// }
fputs("All done, bye!\n", stdout);
free(msg_buffer);
return 0;
}
int get_num_of_chars(const char string[])
{
int
i = 0,
num_of_chars = 0;
while (string[i++] != '\0')
{
if (string[i] != ' ' && string[i] != '\t')
{
num_of_chars++;
}
}
return num_of_chars;
}
int get_num_of_words(const char string[])
{
int
i = 0,
num_of_words = 0;
bool is_not_separator = false;
while (string[i++] != '\0')
{
if (string[i] == ' ' || string[i] == '\t')
{
is_not_separator = false;
}
else if (!is_not_separator)
{
is_not_separator = true;
num_of_words++;
}
}
return num_of_words;
}
void preparing_the_command(int num_of_words, char string[], char *command[])
{
char *token;
for (int j = 0; j < num_of_words && (token = strtok_r(string, " ", &string)); j++)
{
command[j] = token;
}
command[num_of_words] = (void *) NULL;
}
q1.h
#ifndef ASSIGNMENT2Q1_Q1_H
#define ASSIGNMENT2Q1_Q1_H
/***************
** LIBRARIES **
***************/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>
/*************
** STRUCTS **
*************/
typedef struct
{
pid_t pid;
char *command;
} Tuple;
/*************************
** FUNCTION PROTOTYPES **
*************************/
int get_num_of_chars(const char string[]);
int get_num_of_words(const char string[]);
void preparing_the_command(int num_of_words, char string[], char *command[]);
#endif //ASSIGNMENT2Q1_Q1_H

Can i write array[x][x] to a pipe?

im trying to run this on Linux, this program supposed to pass arrays of numbers with pipes, to the children, and each children calculate the gcd of the pairs. But I get "Segmentation fault(core dumped)" ERROR. I've checked the child's process, and right after the read() i tried to print string just for check and it doesn't work. The weird thing that the read not returns -1, which means it worked. is it possible to write char **arr; into a pipe? or is it to big for a pipe and this is why it crashes.
Thank you for any help.
BTW, the ./v2_child1 is fine, the problem comes before the execvp()
#include <stdarg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 100
#define FILE_NAME "numbers.txt"
char** readFromTextFile(char *fileName) {
FILE *f = fopen(fileName, "r");
if (f == NULL) {
printf("Error while opening file!");
return NULL;
}
char *line = (char*) malloc(MAX_LINE_LENGTH * sizeof(char));
char **pairs = (char**) malloc(50 * sizeof(char*));
int counter = 0;
while (!feof(f)) {
char *num1 = (char*) malloc(sizeof(char) * 2);
char *num2 = (char*) malloc(sizeof(char) * 2);
fgets(line, MAX_LINE_LENGTH, f);
sscanf(line, "%s %s", num1, num2);
pairs[counter] = num1;
pairs[counter + 1] = num2;
counter += 2;
}
pairs[counter] = NULL;
fclose(f);
return pairs;
}
int numOfPairs(char **arr) {
int count = 0;
while (arr[count] != NULL) {
count += 1;
}
if ((count % 2) != 0) {
printf("odd amount off numbers");
return -1;
} else {
return count / 2;
}
}
int main(int argc, char *argv[]) {
//read the pairs of numbers into array
char **numbers = readFromTextFile(FILE_NAME);
//returns the num of pairs to check
int num_pairs = numOfPairs(numbers);
//initialize the pipes
int write_pipe[2], read_pipe[2];
if (pipe(write_pipe) == -1 || pipe(read_pipe) == -1) {
fprintf(stderr, "Pipe operation failed!");
exit(0);
}
//child --> parent
int PARENT_READ = read_pipe[0]; // IN
int CHILD_WRITE = read_pipe[1]; // OUT
//parent --> child
int CHILD_READ = write_pipe[0];
int PARENT_WRITE = write_pipe[1];
pid_t status = fork(); // create child number 1
if (status < 0) { // error ocurred
fprintf(stderr, "Error with fork");
exit(0);
} else if (status > 0) { // parent go here
char **to_child1 = (char**) malloc(sizeof(char*) * (num_pairs / 2) * 2);
for (int i = 0; i < num_pairs / 2; ++i) {
to_child1[2 * i] = numbers[2 * i];
to_child1[2 * i + 1] = numbers[2 * i + 1];
}
if (close(CHILD_READ) == -1)
perror("problem while close CHILD_READ");
if (write(PARENT_WRITE, to_child1, sizeof(char*) * (num_pairs / 2) * 2)
== -1)
perror("problem while write to PARENT_WRITE");
if (close(PARENT_WRITE))
perror("problem while close PARENT_WRITE");
printf("wrote from parent to pipe\n\n");
} else { // child process
char **first_half = (char**) malloc(
sizeof(char*) * (num_pairs / 2) * 2);
printf("Hello form son 1\n");
if (close(PARENT_WRITE) == -1)
perror("Error while close");
read(CHILD_READ, first_half, sizeof(char*) * (num_pairs / 2) * 2);
printf("child got here"); // not printing this*
if (close(PARENT_READ) == -1) //read is unused
perror("Error while close");
if (dup2(CHILD_WRITE, STDOUT_FILENO) == -1) { //redirecting Stdout to pipe.
perror("dup2 error");
}
char *args[num_pairs / 2 + 1];
args[0] = "./v2_child1";
for (int i = 1; i < num_pairs / 2 + 1; ++i) {
args[i] = first_half[i];
}
execvp(args[0], args);
}
wait(NULL);
char **gcds = (char**) malloc(sizeof(char*) * (num_pairs / 2));
close(CHILD_WRITE);
read(PARENT_READ, gcds, sizeof(int));
for (int i = 0; i < num_pairs / 2; ++i) {
printf("The gcd of %d and %d is: %d - calculated from child 1\n",
atoi(numbers[i * 2]), atoi(numbers[i * 2 + 1]), atoi(gcds[i]));
}
/// another child to be created
}
to_child1 is an array of pointers. Pointer values are only meaningful within the process that created them. Writing a pointer into the pipe does not copy the data that it points to. So when the child process reads the pointers, it doesn't have the strings they point to.
Since all the strings are just 1 character, there's no need to use an array of pointers, just make an array of char, and write that to the pipe.

Bad file number in simple main function with pipes

I am still a baby in C world and I was doing some "system" programming in order to do some exercises when I stumbled upon some error which is obvious, but I can't find the problem within my application
This is the code
const int __WRITE_ERROR = 44;
const int __READ_ERROR = 43;
const int READ = 0;
const int WRITE = 1;
const int MAX = 1024;
int main(int argc, char *argv[]) {
int fd[2], n;
char buff[MAX];
if(pipe(&fd[2]) < 0)
exit(__PIPE_ERROR);
printf("Hello, from pipe: write: %d and read: %d\n", fd[WRITE], fd[READ]);
if(write(fd[WRITE], "Hello World\n", 12) != 12) {
printf("Explanation: %i", errno); // <- constantly comes here with errno 9 for some reason.
exit(__WRITE_ERROR);
}
if((n = read(fd[READ], buff, MAX)) != 0)
exit(__READ_ERROR);
write(1, buff, n);
exit(0);
}
Could you help me out, cause I ran out of options, thanks.
There is a problem with:
if (pipe(&fd[2]) < 0)
It should be instead:
if (pipe(fd) < 0)
The former is passing to pipe() the address of one element past of the bounds of the array fd (i.e.: the &fd[2]).
Also, read() and write() return the number of bytes read or written, respectively. However, if an error occurs -1 is returned for both functions.
As someone already pointed out first mistake was
if (pipe(&fd[2]) < 0)
had to be
if (pipe(fd) < 0)
then read was failing because of wrong conition
if((n = read(fd[READ], buff, MAX)) != 0)
should have been
if((n = read(fd[READ], buff, MAX)) <= 0)

Issue with multiple dup2s, forks, pipes and execs

I am working on a shell(yes, it's an assignment, so I am not looking for a solution, more of a guide and clues to what I am doing wrong), and I'm stuck with pipes. I have read numerous tutorials, mans and what not, even copy-pasted some codes that "work", nothing seems to do the trick.
This is what I have so far:
void ft_run_pipe(char **cmd, int num)
{
int i;
int j;
int piped[num][2];
pid_t pid;
i = 0;
j = 0;
while (i < num)
{
ft_putstr("Creating pipe");
ft_putnbr(i);
ft_putchar('\n');
if (pipe(piped[i]) < 0)
ft_putstrn("piped failed");
i++;
}
while (cmd[j] != '\0')
{
pid = fork();
if (pid == 0)
{
ft_putchar('a');
if (j != 0)
{
ft_putstrn("If not first");
ft_putnbr(j - 1);
if (dup2(piped[j - 1][0], 0) < 0)
{
ft_putstrn("dup1 failed");
ft_putstrn(strerror(errno));
}
close(piped[j - 1][1]);
close(piped[j - 1][0]);
}
if (j != num)
{
ft_putstrn("If not last");
ft_putnbr(j);
if (dup2(piped[j][1], 1) < 0)
{
ft_putstrn("dup2i failed");
ft_putstrn(strerror(errno));
}
close (piped[j][0]);
close (piped[j][0]);
}
i = 0;
while (i < num)
{
close(piped[i][0]);
close(piped[i][1]);
i++;
}
// ft_run_special(cmd[j], environ);
}
else
{
i = 0;
while (i < num)
{
close(piped[i][0]);
close(piped[i][1]);
i++;
}
}
j++;
}
wait (NULL);
}
The various ft_something functions are coded by me alternatives to some libc functions(ft_putstr writes a string, with n in the end it adds a \n, etc.). ft_exec_special is a function that executes an executable with execve, searching in the PATH variable.
When ran with two commands and a single pipe, it returns
Creating pipe0
aIf not last
0aIf not first
0dup1 failed
Bad file descriptor
While, normally, it seems to me, it should work - piped[0][0] exists, is properly piped, and something was written to piped[0][1] - why would it say piped[0][0] is a bad file descriptor?

Pipe communication in C problems

I'm trying to write some code which uses pipes to communicate between a parent process and it's children. However, my pipe seems to give up after the first time I use it (that is, it stops working after the first use of the pipe). I'm not really sure how to fix this problem, and any help will be greatly appreciated. I also know that some of the coding practice I am using in this are not really ideal (mainly use of sleep).
const int READ = 0;
const int WRITE = 1;
char* COOP = "Criminal cooperates\n";
char* SIL = "Criminal doesn't talk\n";
char* reader(int);
void writer(int, char *c);
int main()
{
int c1pipe1[2];
int c1pipe2[2];
int c2pipe1[2];
int c2pipe2[2];
int c1sentence = 0;
int c2sentence = 0;
int r;
int c;
pipe(c1pipe1);
pipe(c1pipe2);
pipe(c2pipe1);
pipe(c2pipe2);
int C2;
int C1 = fork();
if(C1 > 0)
C2 = fork();
if(C1 < 0 || C2 < 0) //error
{
perror("fork() failed");
exit(1);
}
else if(C1 == 0)
{
close(c1pipe1[WRITE]);
close(c1pipe2[READ]);
for(c = 0; c < 10; c++)
{
r = rand();
//printf("C1 rand = %d\n", r%2);
if(r % 2 == 1)
writer(c1pipe2[WRITE], "1");
else
writer(c1pipe2[WRITE], "0");
sleep(1);
}
exit(0);
}
else if(C2 == 0)
{
close(c2pipe1[WRITE]);
close(c2pipe2[READ]);
for(c = 0; c < 10; c++)
{
r = rand();
//printf("C2 rand = %d\n", r%2);
if(r % 2 == 1)
writer(c2pipe2[WRITE], "1");
else
writer(c2pipe2[WRITE], "0");
sleep(1);
}
exit(0);
}
else //parent
{
int buff1; //stores choice of c1
int buff2; //stores choice of c2
close(c1pipe1[READ]);
close(c1pipe2[WRITE]);
close(c2pipe1[READ]);
close(c2pipe2[WRITE]);
for(c = 0; c< 10; c++)
{
buff1 = atoi(reader(c1pipe2[READ]));
buff2 = atoi(reader(c2pipe2[READ]));
printf("C1's \(%d)\ choice trial %d : %d\n", C1, c+1, buff1);
printf("C2's \(%d)\ choice trial %d : %d\n", C2, c+1, buff2);
if(buff1 && buff2) //c1 and c2 cooperate with police
{
c1sentence = c1sentence + 6;
c2sentence = c2sentence + 6;
}
else if(buff1 || buff2) // one cooperates, one is silent
{
if(buff1) // if c1 cooperates and c2 is silent
{
c1sentence = c1sentence + 0;
c2sentence = c2sentence + 10;
}
else // if c2 cooperates and c1 is silent
{
c1sentence = c1sentence + 10;
c2sentence = c2sentence + 0;
}
}
else if(!(buff1 && buff2)) //both c1 and c2 are silent
{
c1sentence = c1sentence + 1;
c2sentence = c2sentence + 1;
}
sleep(1);
}
printf("C1 is in jail for %d years total\n", c1sentence);
printf("C2 is in jail for %d years total\n", c2sentence);
exit(0);
}
exit(0);
}
void writer(int pipe_write_fd, char *c)
{
open(pipe_write_fd);
char* choice = c;
// Write to the pipe
write(pipe_write_fd, choice, strlen(choice));
// Close the pipe
// (Sends 'end of file' to reader)
close(pipe_write_fd);
}
char* reader(int pipe_read_fd)
{
open(pipe_read_fd);
// Allocate buffer to store
// result of read
int buffer_size = 1024;
char buffer[buffer_size];
// Keep reading until we exhaust
// buffer or reach end of file
int i = 0;
while (i < buffer_size
&& read(pipe_read_fd, &buffer[i], 1) > 0)
{ i++; }
if (i < buffer_size) {
// Add null termination
buffer[i] = '\0';
} else {
// We exhausted buffer
fprintf(stderr, "Warning: buffer full.\n");
buffer[buffer_size-1] = '\0';
}
//printf("%s", buffer);
// Close the pipe
close(pipe_read_fd);
return buffer;
}
You need to close more of the pipes. The child processes must close every pipe file descriptor that they are not using. You have 8 pipe file descriptors; each child process has to close 6 of those - at least! You would be very well advised not to create all the pipes up front as you have done - it is complicated to control things and get all the right descriptors closed.
Looking at the code more closely, the parent does not write messages to the child processes, so you have twice as many pipes as you need - you only need one pipe for each child process to write back to the parent with.
You also do not open() already open file descriptors to the pipes...but how did you get the code to compile? You must be missing the correct header (#include <fcntl.h>) for open() and compiling without enough warning options enabled.
Your variables COOP and SIL are unused in the code presented.
Your writer() function not only mistakenly tries to open an already closed file descriptor, it also closes it, which means that there is no way to send back the extra messages after the first. You should only close the file descriptor once finished - after the loop in the main program for each child. This is why you only see one message.
It is also worth getting into the habit of error-checking the return from every system call that can fail. There are a few that can't fail - getpid() is one such. But I/O operations are notorious for failing for reasons outside the direct control of the program (or, in this case, within the control of the program), so you should check that writes succeed. When you get back an EBADF - bad file descriptor - error, you know something is up.
You have similar problems with close() (and open()) in reader(), plus the additional problem that you attempt to return a pointer to a local automatic variable - which is not a good idea, ever. Again, a decent compiler (like GCC) with warnings enabled will tell you about such things. I used this command to compile your program:
gcc -O -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
pipe.c -o pipe
Your child processes are always going to generate the same sequence of (pseudo-)random numbers, which isn't very exciting. You should probably use something like:
srand(getpid());
to ensure they get different sequences.
Your reader() function is both not enthusiastic enough and too enthusiastic about reading the data. You read a single byte at a time, but you then loop to accumulate single bytes, so the code waits around for all 10 results to be known, and then spits everything out at once. Since a 32-bit integer can store a number up to 1,111,111,111 without problem, you would get just one number back from your call to atoi() on the first iteration, which isn't quite what you wanted.
Reads and writes on pipes are atomic - in the sense that if the writing process writes 6 bytes and the reading process attempts to read more than 6 bytes, then the packet of 6 bytes will be returned by a single read, even if there are other bytes in the pipe waiting to be read; those extra bytes will be returned on subsequent calls to read().
So, your reader() function should be passed in a buffer to use, along with its size; the code should attempt to read that buffer size; it should null terminate what it does receive; it can return the pointer to the buffer it was passed; it should error check the returned value from read().
The code for the two child processes is essentially the same - you should use an appropriately parameterized function rather than writing out the code twice.
Putting it all together, you end up with something like this (which works fine for me on MacOS X 10.6.6 with GCC 4.5.2):
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
const int READ = 0;
const int WRITE = 1;
static char* reader(int fd, char *buffer, size_t bufsiz);
static void writer(int fd, const char *c);
static void child_process(int *my_pipe, int *his_pipe);
static void err_exit(const char *fmt, ...)
{
va_list args;
int errnum = errno;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
exit(1);
}
int main(void)
{
int c1pipe[2];
int c2pipe[2];
int c1sentence = 0;
int c2sentence = 0;
int c;
if (pipe(c1pipe) != 0 || pipe(c2pipe) != 0)
err_exit("Failed to open a pipe\n");
int C2 = 0;
int C1 = fork();
if (C1 > 0)
C2 = fork();
if (C1 < 0 || C2 < 0) //error
err_exit("fork() failed\n");
else if (C1 == 0)
child_process(c1pipe, c2pipe);
else if (C2 == 0)
child_process(c2pipe, c1pipe);
else //parent
{
int choice1; //stores choice of c1
int choice2; //stores choice of c2
char buffer1[BUFSIZ];
char buffer2[BUFSIZ];
close(c1pipe[WRITE]);
close(c2pipe[WRITE]);
for (c = 0; c< 10; c++)
{
choice1 = atoi(reader(c1pipe[READ], buffer1, sizeof(buffer1)));
choice2 = atoi(reader(c2pipe[READ], buffer2, sizeof(buffer1)));
printf("C1's (%d) choice trial %d : %d\n", C1, c+1, choice1);
printf("C2's (%d) choice trial %d : %d\n", C2, c+1, choice2);
if (choice1 && choice2) //c1 and c2 cooperate with police
{
c1sentence = c1sentence + 6;
c2sentence = c2sentence + 6;
}
else if (!(choice1 && choice2)) //both c1 and c2 are silent
{
c1sentence = c1sentence + 1;
c2sentence = c2sentence + 1;
}
else if (choice1) // if c1 cooperates and c2 is silent
{
c1sentence = c1sentence + 0;
c2sentence = c2sentence + 10;
}
else // if c2 cooperates and c1 is silent
{
c1sentence = c1sentence + 10;
c2sentence = c2sentence + 0;
}
}
printf("C1 is in jail for %d years total\n", c1sentence);
printf("C2 is in jail for %d years total\n", c2sentence);
}
return(0);
}
static void writer(int pipe_write_fd, const char *c)
{
int len = strlen(c);
if (write(pipe_write_fd, c, len) != len)
err_exit("Write failed\n");
}
static char* reader(int pipe_read_fd, char *buffer, size_t bufsiz)
{
int i = read(pipe_read_fd, buffer, bufsiz-1);
if (i < 0)
err_exit("Read failed\n");
buffer[i] = '\0';
return buffer;
}
static void child_process(int *my_pipe, int *his_pipe)
{
int c;
srand(getpid());
close(my_pipe[READ]);
close(his_pipe[READ]);
close(his_pipe[WRITE]);
for (c = 0; c < 10; c++)
{
writer(my_pipe[WRITE], ((rand() % 2) == 1) ? "1" : "0");
sleep(1);
}
close(my_pipe[WRITE]);
}
Note how the error routine captures errno early - to avoid damaging it. It is one of the perils of using global variables; they may change when you call a function. Don't use them when you can avoid them (but note that you can't avoid using errno completely, in general).
void writer(int pipe_write_fd, char *c)
{
open(pipe_write_fd);
char* choice = c;
// Write to the pipe
write(pipe_write_fd, choice, strlen(choice));
// Close the pipe
// (Sends 'end of file' to reader)
close(pipe_write_fd);
}
I'm not sure which function open you are trying yo use but the usual one takes a filename and returns a file descriptor. In any case you are discarding the return value so I suppose that this doesn't matter.
What is clear is that you close the pipe immediately after the first write so it is "correct" that the next write will fail; the pipe has been closed.
If you fix this problem then the next problem is that reader will, one byte at a time, all of the available input - up to 1024 bytes - before closing the read pipe. As reader is called in a loop, the read attempt in the second iteration will fail.

Resources