Iam trying to create a code with 1 parent and 2 childrens. The method recive 3 parameters:
original_file word1 word2
The parent read a file line by line:
If the line is pair, send the line to method proccess_pair and the word1.
If the line contains the word1, save the lines in the file_1.txt
If the line is odd, send the line to method proccess_odd and the word2.
If the line contains the word1, save the lines in the file_2.txt
Im beginner in c, and i trying with this:
int p_h1[2] // pipe from parent to child1
int p_h2[2];// pipe from parent to child2
int main(int argc, char **argv){
pid_t pdi1, pdi2;
FILE *fd; // for original file
FILE *p_h1f, *p_h2f; //file create for child1 and child2 respectively
char buffer[1024];//buffer
if (pid1<0){
fprintf(stderr,"Error fork \n %s \n",strerror(errno));
exit(EXIT_FAILURE);
}
else if (pid1==0){//Im the child1
//proccess for child 1
proccess_pair(arg[2]);
exit(EXIT_SUCCESS);
}
pid2 = fork();
if (pid2<0){
fprintf(stderr,"Error fork \n %s \n",strerror(errno));
exit(EXIT_FAILURE);
}
else if (pid2==0){//Im the child2
//proccess for child 2
proccess_odd(arg[2]);
exit(EXIT_SUCCESS);
}
//Parent dont read from pipe
close(p_h1[0]);
close(p_h2[0]);
fd = fopen(argv[1],"r"); //I openthe file for read it;
p_h1f = fdopen(p_h1[1],"w")
p_h2f = fdopen(p_h2[1],"w")
int i = 1;
while(fgets(buffer,1024,fd) != NULL){
if (i % 2 ==0){ //check if the lines is pairs
fputs(buffer,p_h1f);
fflush(p_h1f);
}else{
fputs(buffer,p_h2f);
fflush(p_h2f);
}
i++;
}
close(p_h1[1]);
close(p_h2[1]);
fclose(fd);
wait(NULL);
wait(NULL);
}
Both methods(for chil1 and chil2) will be the same(but closing the correct sides of pipes), for this reason i only implement one of them:
void proccess_pair(char *word1){
FILE *fd;
fd = fopen("file_1.txt","w");
//closing the not used
close(p_h1[1]);
close(p_h2[1]);
close(p_h2[0]);
int nsto = dup(1)//duplicate the stdout
dup2(fd,1);//changing stdout->file_1.txt
execlp("grep","grep",word1,NULL);//execution of grep
exit(EXIT_SUCCESS);
}
Im learning and i know that i have many many error, for this reason i need help.
Regards
How i can create many pipes in an array in c?
On a POSIX-conformant system, you can do that by calling pipe() many times on elements of a 2D array of int, as you presented.
¿I can use two different pipes(parent-child1,parent-child2)? I can use an array of pipes?
A pipe itself lives only in the kernel. There is no userspace data
structure representing a pipe, so you cannot have an array of pipes.
The file descriptors for the pipe ends, however, are just ints. The pipe() function takes as its argument a pointer to the first element of an array of at least two int, and (on success) it writes the appropriate file descriptors into the array.
From a C perspective, there is nothing special about the array in which the pipe ends are to be returned. In particular, it can be an element of a multi-dimensional array if you so desire. Or it can be a local variable. Or it can be a member of a struct or a union. Or it can be a large enough block of dynamically-allocated space. It's not special.
Something like this should work:
int new_process(char *word){ // return the writing part of a pipe to a newly created child
int p[2];
pipe( p ); // get a new pipe
if (fork()==0) { // create a new child
dup2(p[0],0); // child's in is pipe's entry
close(p[1]); // close writing part
execlp("grep","grep",word,NULL); // exec
}
close(p[0]); // parent don't need the reading part
return p[1]; // send back the writing part to caller
}
int main(int argc, char **argv) {
int f1 = new_process(argv[1]); // get the pipe to first child
int f2 = new_process(argv[1]); // ...second...
char buffer[1024];//buffer
FILE *fd = fopen(argv[1],"r"); // open the file for reading;
while(fgets(buffer,1024,fd) != NULL) { // read aline
if (i % 2 ==0) { //check if the line no is pair
fputs(buffer,f1); // send it to first child
fflush(f1);
} else{
fputs(buffer,f2); // send it to second child
fflush(f2);
}
i++;
}
close(f1);
close(f2);
fclose(fd);
wait(NULL);
wait(NULL);
}
Don't forget to add necessary controls on failures.
Related
To learn how Pipe IPC mechanism works, I wrote a simple program that creates two child processes which share data using a pipe. The first child process has to read data from a file and pass it to the pipe.
Afterwards, the second child process has to read it, convert it to uppercase and write it to another file. The read system call in the second child process returns -1 when reading from the pipe. Also when I execute the program, in some cases printf in the first child does not print anything and in other cases printf in the second child does not print, too. Could you please point the mistakes in the program which are causing the problems?
int main(int args[], char * argv[]) {
int fd[2];
long length;
char buff1[250];
char buff2[250];
FILE * fptr1;
FILE * fptr2;
pid_t A, B;
pipe(fd);
A = fork();
if (A == -1) {
printf("error in fork of A\n");
exit(1);
}
if (A == 0) {
fptr1 = fopen(argv[1], "r"); // program receives file names as argument
if (fptr1 == NULL) {
printf("Erro in file open1\n");
exit(1);
}
fseek(fptr1, 0 L, SEEK_END);
length = ftell(fptr1);
fseek(fptr1, 0 L, SEEK_SET);
close(fd[0]);
fread(buff1, length, 1, fptr1);
buff1[length] = '\0';
printf("buff1 = %s", buff1);
write(fd[1], buff1, length);
fclose(fptr1);
exit(0);
} else {
B = fork();
if (B == -1) {
printf("Error in forking child B");
exit(1);
}
if (B == 0) {
fptr2 = fopen(argv[2], "w");
if (fptr2 == NULL) {
printf("Error in file open2\n");
exit(1);
}
close(fd[1]);
int n = read(fd[0], buff2, length);
printf("n = %d\n", n);
upper_string(buff2); // converts characters to uppecase
fwrite(buff2, 1, length, fptr2);
fclose(fptr2);
}
}
return 0;
}
There are few things to take into account here. First thing i would like to point is that you do not need to use two fork() calls. In that case you have three processes working in parallel (parent process and two child process, one per each fork() call).
One important point to take into account when you work with processes working in parallel is synchronism. In your code you are creating two processes. Parent process does not wait for any of its child, so it finishes its execution, and if child processes have not finished, they will become child of init process. But appart from that, you have the typical producer consumer problem. One of your child produce something and the other consume it, but how they work in parallel, consumer need to know that the product is ready to be consumed. So, in this case, i think the easiest way to do this job is to use just one fork(), so child become the producer and the parent process (the consumer) wait until its child finish the job.
I have 2 simple programs that I use to modify text files.
The first one receives a commands file and a list of files to modify. The second program is made to be run by the first one, receives as a parameter a file to be read then reads commands from the stdin, execute them on the file and display to the stdout when it's done. Repeat.
My problem is that each fork seems to be waiting for the others to finish all it's commands rather than starting its own.
Main program
int main(int argc, char const *argv[]){
...
// Multiple forks
for(i=2; i < argc; i++){
...
pipe(pipes[forks]);
forks++;
pid = fork();
if(pid == 0) break;
...
}
if(pid == 0){
dup2(pipes[forks-1][0], STDIN_FILENO);
// Execute the second program in the fork,
// pass a file to be read as a single argument
execl("second_program", "second_program" , argv[i], NULL);
fprintf(stderr, "execl() failed\n");
return EXIT_FAILURE;
} else {
...
// Reads a file containing commands, normalize it and output a string
char *cmds = getcmds(argv[1]);
int f;
for(f=0; f < forks; f++){
// Send the list of commands to the second program
write(pipes[f][1], cmds, strlen(cmds));
}
wait(NULL);
}
return 0;
}
Child program
int main(int argc, char const *argv[]){
...
char buffer[READ_SIZE];
do {
scanf("%s",buffer);
if(strcmp(buffer,"COMMAND_A") == 0){
...
printf("`COMMAND_A on %s\n", filename);
} if(strcmp(buffer,"COMMAND_b") == 0){
...
printf("`COMMAND_b on %s\n", filename);
} else {
break;
}
...
} while(1);
return 0;
}
Example output I'm getting
COMMAND_A on file1
COMMAND_B on file1
...
COMMAND_Z on file1
COMMAND_A on file2
COMMAND_B on file2
...
COMMAND_Z on file2
COMMAND_A on file3
COMMAND_B on file3
...
COMMAND_Z on file3
The forks blocks and complete all theirs tasks rather than running in parallel. Is there something I'm doing wrong?
The forks start running concurrently, but they are all waiting for input through the pipe at the point of calling scanf. Try changing the order in which you write, and the order of the reads will change, too. Also, whenever strlen(cmds) exceeds PIPE_BUF, you may observe different results.
Writing something shorter than PIPE_BUF on a pipe is guaranteed to be delivered in one chunk at the other end. It's not that each command in your cmds wakes up the child processes.
I'm trying to elevate my program's privileges, to write a file to a system location. I am doing this in C on OSX, by forking a child process that uses authopen to create and write to a file.
I can create the file, however I'm having difficulty writing a string to it. From the man pages of authopen, I can use -w to direct stdin to the file if -stdoutpipe is not declared. I don't want to read from stdin, but I want to write a constant str to the file.
I find the description of -stdoutpipe confusing on the man pages, and there are no examples online on how to use this flag. Can anyone offer any advice how to accomplish this?
My code:
pid_t processId = fork();
if (processId == 0) {
//in child process
const char * authopenPath = "/usr/libexec/authopen";
//Create the file fromProg if it does not exist. This works OK.
execl(authopenPath,
authopenPath,
"-c",
"/etc/fromProg",
NULL);
//This is where I need help.
execl(authopenPath,
authopenPath,
"-stdoutpipe", //<- Not sure how to write a string to file using this
//-w -a", //<- Or this
"/etc/fromProg",
NULL);
exit(0);
}
Ok I got this to work so I'll answer my own question for others.
In a nutshell, the string should be sent by the parent process through a pipe, and the dup function conveniently duplicates the read end of the pipe to stdin.
Also, I found this reference on creating pipes very helpful.
int pip[2];
if (pipe(pip) != 0){
//error creating pipe
exit(1);
}
pid_t processId;
processId = fork();
if (processId == -1) {
//error creating fork
exit(1);
}
if (processId == 0) {
//in child process
//close write end of pipe
close(pip[1]);
//close stdin and duplicate the read end of pipe to stdin
close(0);
dup(pip[0]);
//test reading from stdin
//char buffer[35];
//read(STDIN_FILENO, buffer, 35);
//printf("Received string: %s", buffer);
const char * authopenPath = "/usr/libexec/authopen";
execl(authopenPath,
authopenPath,
"-c","-w","-a",
"/etc/fromProg",
NULL);
exit(0);
}
else {
//in parent process
//close read end of pipe
close(pip[0]);
//write to write end of pipe
char string[] = "Helloooo Pipe!\n";
write(pip[1], string, (strlen(string)+1));
}
I want to preface this with the fact that I have no formal education in the use of pipes, so this is my first venture. Not to mention that I couldn't find any similar questions to my situation.
Note: This IS part of a larger project for a school assignment, so I am NOT asking for anyone to do this for me. I would just like some direction/helpful code segments. (I have tried to make this as generic as possible to avoid "cheater" remarks.)
I am trying to run a for-loop over int k elements in which a parent process spawns off k children with fork() and execl(), and then use a pipe() to send the output back to the parent. Here is some generic code that I am trying to use and the error/problem in which I encounter:
Note: helloworld= an executable compiled with GCC that produces printf("hello world\n");
int k = 10; //The number of children to make
int fd[2]; //Used for each pipe
int readFromMe[k]; //Holds the file IDs of each pipe fd[0]
int writeToMe[k]; //Holds the file IDs of each pipe fd[1]
int processID[k]; //Holds the list of child process IDs
//Create children
int i;
for(i = 0; i < k; i++)
{
if(pipe(fd) == -1)
{
printf("Error - Pipe error.\n");
exit(EXIT_FAILURE);
}
//Store the pipe ID
readFromMe[i] = fd[0];
writeToMe[i] = fd[1];
if((processID[i] = fork()) == -1)
{
fprintf(stderr, "fork failure");
exit(EXIT_FAILURE);
}
//If it is a child, change the STDOUT to the pipe-write file descriptor, and exec
if(processID[i] == 0)
{
dup2 (writeToMe[i], STDOUT_FILENO);
close(readFromMe[i]);
execl("./helloworld", (char *)0);
}
//If it is the parent, just close the unnecessary pipe-write descriptor and continue itterating
else
{
close(writeToMe[i]);
}
}
//Buffer for output
char output[100000];
//Read from each pipe and print out the result
for(i = 0; i < k; i++)
{
int r = read(readFromMe[i], &output, (sizeof(char) * 100000));
if(r > 0)
{
printf("result = %s\n", output);
}
close(readFromMe[i]);
}
I get no output from my program at all, so I am trying to figure out why this issue is occurring.
Probably unrelated, but you call execl wrong. The extra arguments after the program is what will the the argv array to the other programs main function. And as you know it always have one entry, the program name. So you need to call it like this:
execl("./helloworld", "helloworld", NULL);
More related to your problem, you should also check for errors, it might actually fail.
Try printing the value of 'r' in your printout function. I suspect the read is returning an error (perhaps EPIPE) that you're not seeing. Also, you example code is trying to printf 'c', not output like it looks like you meant.
I have a task in Linux and I can't get it work.
I have a program that receives a text file as parameter. It then creates a child process using fork() and sends to the child process, line by line the content of the text file received as parameter. The child process needs to count the lines and return to the parent process the number of lines received.
This is what I have until now, but somewhat the child process does not receive all the lines. For my test I used a text file with 9 lines. The parent sent 9 lines as strings but the child process received only 2 or 3 of them.
What am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char string[80];
char readbuffer[80];
int pid, p[2];
FILE *fp;
int i=0;
if(argc != 2)
{
printf("Syntax: %s [file_name]\n", argv[0]);
return 0;
}
fp = fopen(argv[1], "r");
if(!fp)
{
printf("Error: File '%s' does not exist.\n", argv[1]);
return 0;
}
if(pipe(p) == -1)
{
printf("Error: Creating pipe failed.\n");
exit(0);
}
// creates the child process
if((pid=fork()) == -1)
{
printf("Error: Child process could not be created.\n");
exit(0);
}
/* Main process */
if (pid)
{
// close the read
close(p[0]);
while(fgets(string,sizeof(string),fp) != NULL)
{
write(p[1], string, (strlen(string)+1));
printf("%s\n",string);
}
// close the write
close(p[1]);
wait(0);
}
// child process
else
{
// close the write
close(p[1]);
while(read(p[0],readbuffer, sizeof(readbuffer)) != 0)
{
printf("Received string: %s\n", readbuffer);
}
// close the read
close(p[0]);
}
fclose(fp);
}
A pipe is a unidirectional interprocess communication channel. You have to create 2 pipes, one to speak to the child process, the other to read data back.
Remember to close the unused side of the pipe on both processes.
You are sending the null terminator to the other process:
write(p[1], string, (strlen(string)+1));
That makes the result confusing because when you print what you've received, you only see up to the null terminator.
If you do this instead:
write(p[1], string, strlen(string));
you should get what you expect.
You're not counting the number of lines, you're counting the number of times read(2) returns.
When using pipes, read(2) will pull as much data as possible from the pipe: min(pipe_available, space_available). It doesn't care for newlines, 0 bytes etc. Simple tricks to make it work:
Use a loop to walk readbuffer and look for \n
Use fdopen + fgets (I have a feeling this is probably flawed)
look into manpage of pipe ( man 2 pipe ), the program you're trying to write is as an example there, compare it with yours :)