Creating a pipe in c between two programs - c

I have been working on creating a pipe in c between two programs, reader.c and writer.c. I haven't been able to get the input for the pipe program to work. The pipe program is supposed to take in a int, send it to the writer program, which then pipes its output into the reader program for the final output. Below is the code for the three classes. I think I am close but can anyone help me get the initial int input argv[2] into the writer class then into the reader class?
pipe program (communicat.c)
int main(int argc, char *argv[])
{
int fd[2];
pid_t childpid;
int result;
if (argc != 2)
{
printf("usage: communicate count\n");
return -1;
}
pipe(fd);
childpid = fork();
if (childpid == -1)
{
printf("Error in fork; program terminated\n");
return -1;
}
if(childpid == 0)
{
close(1);
dup(fd[1]);
execlp("writer", "writer", fd[1],(char *) NULL);
}
else
{
childpid = fork();
}
if( childpid == 0)
{
close(0);
dup(fd[0]);
close(fd[0]);
close(fd[1]);
execlp("reader", "reader", (char *) NULL);
}
else
{
close(fd[0]);
close(fd[1]);
int status;
wait(&status);
}
return(0);
}
Reader.c
int main()
{
int count; /* number of characters in the line */
int c; /* input read */
count = 0;
while ((c = getchar())!= EOF)
{
putchar(c); count++;
if (count == LINELENGTH)
{
putchar('\n'); count = 0;
}
}
if (count > 0)
putchar('\n');
return 0;
}
Writer.c
int main(int argc, char *argv[])
{
int count; /* number of repetitions */
int i; /* loop control variable */
if (argc != 2)
{
printf("usage: writer count\n");
return -1;
}
else count = atoi(argv[1]);
for (i = 0; i < count; i++)
{
printf("Hello");
printf("hello");
}
return 0;
}

Correct the code to exec writer this way:
if(childpid == 0)
{
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
execlp("writer", "writer", argv[1], (char *) NULL);
}

Related

Error for pipe: int not a function

I'm using this code to try to implement my own pipe in a simple shell. However, it won't compile because it's telling me fd is not a function. Every other place I've seen this implemented has fd as the parameter for pipe() in the exact same way. I'm not sure why I'm getting this error.
int startProcess (StringArray sa)
{
int pid;
int status;
int fd1;
int fd2;
int current_in;
int current_out;
int fd0;
int fd00;
int in = 0;
int out = 0;
char input[64]="";
char output[64]="";
char cmd1[64] ="";
char cmd2[64] ="";
int pipe = 0;
int fd[2];
switch( pid = fork()){
case -1://This is an error
perror("Failure of child.");
return 1;
case 0: // This is the child
// Redirection
/* finds where '<' or '>' or '|' occurs and make that sa[i] = NULL ,
to ensure that command wont' read that*/
for(int i=0;sa[i]!='\0';i++)
{
if(strcmp(sa[i],"<")==0)
{
sa[i]=NULL;
strcpy(input,sa[i+1]);
in=2;
}
if(strcmp(sa[i],">")==0)
{
sa[i]=NULL;
strcpy(output,sa[i+1]);
out=2;
}
if(strcmp(sa[i],"|")==0)
{
sa[i]=NULL;
strcpy(cmd1,sa[i-1]);
strcpy(cmd2,sa[i+1]);
pipe=2;
}
}
//if '<' char was found in string inputted by user
(erased for brevity)
//if '>' char was found in string inputted by user
(erased for brevity)
//if '|' char was found in string inputted by user
if(pipe)
{
pipe(fd);
if (!fork)
{
close(1);
dup(fd[1]);
close(fd[0]);
int error;
error = 0;
if (fork() == 0){
error = execvp(cmd1, sa);
} if (error == -1) {
printf("ERROR: unknown command (%s)\n)", cmd1);
exit(0);
} else {
waitpid(0,NULL,0);
}
}
} else {
close(0);
dup(fd[0]);
close(fd[1]);
execvp(cmd2, sa);
}
execvp(sa[0], sa);
perror("execvp");
_exit(1);
printf("Could not execute '%s'\n", sa[0]);
default:// This is the parent
wait(&status);
return (status == 0) ? 0: 1;
}
}
First you have
int pipe = 0;
Then you also have
pipe(fd);
Both can't be correct.
I suggest you rename the variable.

Shell program with pipes in C

I have a problem with pipes. My program is a Shell program in C. I want to execute for example ls | wc, but what I get after running is:
ls: cannot access |: no such file or directory ls: cannot access wc: no such file or directory.
What am I doing wrong?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#define MAX_CMD_LENGTH 100
#define MAX_NUM_PARAMS 10
int parsecmd(char* cmd, char** params) { //split cmd into array of params
int i,n=-1;
for(i=0; i<MAX_NUM_PARAMS; i++) {
params[i] = strsep(&cmd, " ");
n++;
if(params[i] == NULL) break;
}
return(n);
};
int executecmd(char** params) {
pid_t pid = fork(); //fork process
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else if (pid == 0) { // child process
execvp(params[0], params); //exec cmd
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
};
int execpipe (char ** argv1, char ** argv2) {
int fds[2];
pipe(fds);
int i;
pid_t pid = fork();
for (i=0; i<2; i++) {
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else
if (pid == 0) {
if(i ==0){
close(fds[1]);
dup2(fds[0], 0);
close(fds[0]);
execvp(argv1[0], argv1);
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else if(i == 1) {
close(fds[0]);
dup2(fds[1], 1);
close(fds[1]);
execvp(argv2[0], argv2);
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
} // end for
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
char * argv1[MAX_NUM_PARAMS+1];
char * argv2[MAX_NUM_PARAMS+1];
int k, y, x;
int f = 1;
while(1) {
printf("$"); //prompt
if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; //read command, ctrl+D exit
if(cmd[strlen(cmd)-1] == '\n') { //remove newline char
cmd[strlen(cmd)-1] = '\0';
}
int j=parsecmd(cmd, params); //split cmd into array of params
if (strcmp(params[0], "exit") == 0) break; //exit
for (k=0; k <j; k++) { //elegxos gia uparksi pipes
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
}
}
if (f==0) {
for (x=0; x<k; x++) {
argv1[x]=params[x];
}
int z = 0;
for (x=k+1; x< j; x++) {
argv2[z]=params[x];
z++;
}
if (execpipe(argv1, argv2) == 0) break;
} else if (f==1) {
if (executecmd(params) == 0) break;
}
} // end while
return 0;
}
Updated your code with following corrections.
Removed for() loop that iterated two times after fork() call.
Removed incorrect close of pipe FDs after dup2 calls for both parent and child processes.
Aligned the command that needed to be run as per the file descriptors that were duplicated in dup2() calls for parent and child. Basically I needed to swap execvp(argv2[0], argv2) and execvp(argv1[0], argv1) calls.
Added a break; statement in the for loop that searched for pipe character.
The updated code is as below.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_CMD_LENGTH 100
#define MAX_NUM_PARAMS 10
int parsecmd(char* cmd, char** params) { //split cmd into array of params
int i,n=-1;
for(i=0; i<MAX_NUM_PARAMS; i++) {
params[i] = strsep(&cmd, " ");
n++;
if(params[i] == NULL) break;
}
return(n);
};
int executecmd(char** params) {
pid_t pid = fork(); //fork process
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else if (pid == 0) { // child process
execvp(params[0], params); //exec cmd
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
};
int execpipe (char ** argv1, char ** argv2) {
int fds[2];
pipe(fds);
int i;
pid_t pid = fork();
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
}
if (pid == 0) { // child process
close(fds[1]);
dup2(fds[0], 0);
//close(fds[0]);
execvp(argv2[0], argv2); // run command AFTER pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
close(fds[0]);
dup2(fds[1], 1);
//close(fds[1]);
execvp(argv1[0], argv1); // run command BEFORE pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
char * argv1[MAX_NUM_PARAMS+1] = {0};
char * argv2[MAX_NUM_PARAMS+1] = {0};
int k, y, x;
int f = 1;
while(1) {
printf("$"); //prompt
if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; //read command, ctrl+D exit
if(cmd[strlen(cmd)-1] == '\n') { //remove newline char
cmd[strlen(cmd)-1] = '\0';
}
int j=parsecmd(cmd, params); //split cmd into array of params
if (strcmp(params[0], "exit") == 0) break; //exit
for (k=0; k <j; k++) { //elegxos gia uparksi pipes
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
break;
}
}
if (f==0) {
for (x=0; x<k; x++) {
argv1[x]=params[x];
}
int z = 0;
for (x=k+1; x< j; x++) {
argv2[z]=params[x];
z++;
}
if (execpipe(argv1, argv2) == 0) break;
} else if (f==1) {
if (executecmd(params) == 0) break;
}
} // end while
return 0;
}
If you are interested only in changes I made, here is the diff between your code and the above updated code:
--- original.c
+++ updated.c
## -4,6 +4,7 ##
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/wait.h>
#define MAX_CMD_LENGTH 100
## -43,44 +44,36 ##
pipe(fds);
int i;
pid_t pid = fork();
- for (i=0; i<2; i++) {
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
- } else
- if (pid == 0) {
- if(i ==0){
+ }
+ if (pid == 0) { // child process
close(fds[1]);
dup2(fds[0], 0);
- close(fds[0]);
- execvp(argv1[0], argv1);
+ //close(fds[0]);
+ execvp(argv2[0], argv2); // run command AFTER pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
- } else if(i == 1) {
+ } else { // parent process
close(fds[0]);
dup2(fds[1], 1);
- close(fds[1]);
- execvp(argv2[0], argv2);
+ //close(fds[1]);
+ execvp(argv1[0], argv1); // run command BEFORE pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
- } else { // parent process
- int childstatus;
- waitpid(pid, &childstatus, 0);
- return 1;
- }
- } // end for
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
- char * argv1[MAX_NUM_PARAMS+1];
- char * argv2[MAX_NUM_PARAMS+1];
+ char * argv1[MAX_NUM_PARAMS+1] = {0};
+ char * argv2[MAX_NUM_PARAMS+1] = {0};
int k, y, x;
int f = 1;
while(1) {
## -95,6 +88,7 ##
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
+ break;
}
}
if (f==0) {
execv* procedure doesn't interpret shell script string. It merely starts an executable file and passes an array of arguments to it. Thus, it cannot organize a pipeline.
If you need "normal" shell command execution, you may want to use system(char*) procedure instead of execvp.
Otherwise, if you need to do the pipes yourself, you may want to parse the string with '|' special characters and use pipe(), fork() and I/O redirection. Like here How to run a command using pipe?

Piping in a while loop C

Im working on a shell that can handle pipes. the problem im runing into now is that when a pipe is found after both are done executing my shell exits. This is some sample code ive been working on to try and figure
int main(int argc, char** argv)
{
int fd[2];
pid_t pid;
pid_t pid2;
int childSt;
int hell;
struct arguments args;
char line[1024];
while (fgets(line, 1024, stdin)) {
line[strlen(line)-1] = '\0';
////////////////////////////////////////////////////////////// /
args = finArgs(line);
pipe(fd);
pid = fork();
if (pid > 0) // PARENT
{
pid2 = fork();
if(pid2 == 0){
close(fd[1]); //close write end
if (fd[0] != STDIN_FILENO)
{
if ((dup2(fd[0], STDIN_FILENO)) != STDIN_FILENO)
{
printf("dup2 error to stdin\n");
close(fd[0]);
}
}
if (execvp(args.pipeArgs[0], args.pipeArgs) < 0)
printf("parent error \n");
}
else {
wait(&childSt);
}
}
else // CHILD
{
close(fd[0]);
if (fd[1] != STDOUT_FILENO)
{
if ((dup2(fd[1], STDOUT_FILENO)) != STDOUT_FILENO)
{
printf("dup2 error to stdout\n");
close(fd[1]);
}
}
if (execvp(args.args[0], args.args) < 0)
printf("child error \n");
}
}
return(0);
}
here is some sample output
ls | wc
14 14 123
this is what i want but then the program exits.

Is there any other way to build pipe in C?

I want to know that is this possible to code this program with using write(), read() functions. It takes 2 initial arguments with argv[] then fork() and after that child process' stdout passes to parents stdin and result will be showed on screen.
when I execute the program like this ---> ./program date wc
It must show a result as same as date | wc does in shell programming.
I coded this program with dup(). it works fine but I want to other way around. Thank you and sorry for my english.
int main(int argc, char* argv[]){
char* argument1[]={argv[1], NULL};
char* argument2[]={argv[2], NULL};
int fd[2];
int d;
pid_t pid;
char buffer[30];
if(argc < 3){
printf("No parameter");
return 1;
}
if(pipe(fd)==-1){
perror("pipe failed");
exit(1);
}
else{
pid=fork();
if(pid==0){
/*child process*/
close(1);
dup(fd[1]);
close(fd[0]);
//close(fd[1]);
execvp(argument1[0], argument1);
}
else if(pid>0){
/*Parent process*/
close(0);
dup(fd[0]);
close(fd[1]);
//close(fd[0]);
execvp(argument2[0], argument2);
}
}
return 0;
}
Same code with dup2: (I let you make your m_exec function)
int m_pipe(char *cmd1, char *cmd2)
{
int fd[2];
if (pipe(fd) == -1)
{
perror("Pipe failed ");
return (-1);
}
if (fork() == 0)
{
/*Child process*/
dup2(fd[0], 0);
close(fd[1]);
m_exec(cmd2);
}
else
{
/*Parent process*/
dup2(fd[1], 1);
close(fd[0]);
m_exec(cmd1);
}
return (0);
}
int main(int argc, char* argv[])
{
if(argc != 3)
{
write(2, "Usage ./a.out cmd1 cmd2\n", strlen("Usage ./a.out cmd1 cmd2\n"));
return EXIT_FAILURE;
}
if (m_pipe(argv[1], argv[2]) == -1)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}

I'm building a small shell. How do I set the standard in- and output of two processes to a pipe, so they can communicate?

I'm trying to implement a very small shell of my own. I have to be able to handle pipes, like
ls -l | wc -l
but only for two programs at a time. Right now, I have this:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFFER_SIZE 256
#define NO_PARAMS 32
void split_string(char **params, char *string){
char *arg;
int i;
arg = strtok(string, " ");
params[0] = arg;
i = 1;
while(arg != NULL){
arg = strtok(NULL, " ");
params[i] = arg;
i++;
}
}
int main(int argc, char **argv){
char string[BUFFER_SIZE];
char *prog1, *prog2;
int i, err;
int fd[2];
pid_t pid1, pid2;
size_t buffer = BUFFER_SIZE;
char *params1[NO_PARAMS], *params2[NO_PARAMS];
int pipe_exists = 0;
memset(string,0,buffer);
while(1){
/*Read command*/
fgets(string, BUFFER_SIZE-1, stdin);
if(string == NULL){
perror("Error reading input:\n");
exit(1);
}
/*replace linefeed character with end of line character*/
for(i=0;i<BUFFER_SIZE;i++){
if(string[i] == 10){
string[i] = 0;
}
}
/*check if command is "exit"*/
if(strcmp(string,"exit") == 0){
return 0;
}
/*split command into different program calls*/
prog1 = strtok(string, "|");
prog2 = strtok(NULL,"\0");
if(prog2 != NULL){
pipe_exists = 1;
printf("PIPE!\n");
err = pipe(fd);
if(err<0){
perror("Error creating pipe:\n");
exit(1);
}
}
/*split string into arguments*/
split_string(params1, prog1);
if(pipe_exists){
split_string(params2, prog2);
}
/*fork child process*/
pid1 = fork();
if(pid1==0){ /*child 1*/
if(pipe_exists){
close(fd[0]); /*close read-end*/
err = dup2(fd[1], 1);
if(err<0){
perror("Error with dup in child 1!\n");
exit(1);
}
}
execvp(params1[0],params1);
perror("Error calling exec()!\n");
exit(1);
}else{ /*parent*/
if(pipe_exists){
pid2 = fork();
if(pid2==0){ /*child 2*/
close(fd[1]); /*close pipe write-end*/
err = dup2(fd[0], 0);
if(err<0){
perror("Error with dup in child 2!\n");
exit(1);
}
execvp(params2[0],params2);
perror("Error calling exec()!\n");
exit(1);
}else{ /*parent with 2 children*/
waitpid(pid1,0,0);
waitpid(pid2,0,0);
}
}else{ /*parent with 1 child*/
waitpid(pid1,0,0);
}
}
}
}
Right now, it'll handle single commands fine, but when I input something like the command above, nothing happens!
Thanks!
Oh! I've already figured it out. I had to close the pipe in the parent program as well :)
To start with, you should loop as long as you find the pipe character. Then you need to create a pipe for each "piping".
Real shells usually forks and exec itself for each command in the pipeline. This is so it should be able to handle internal commands.
There are 3 main parts in a command with pipes.
The begining, that takes stdin and pipes its output something |
The middle, optionnal or repeated at will with two pipes | something |
The end, that outputs to stdout | something
Then use three functions, one for each of those:
#define PIPE_INPUT 0
#define PIPE_OUTPUT 1
execute_pipe_start(t_cmdlist *commands)
{
int pid;
int fd[2];
if (!commands)
return;
if (commands->next)
{
if (pipe(fd) < 0)
{
perror("pipe failed");
exit(1);
}
pid = fork();
if (!pid)
{
close(fd[PIPE_INPUT]);
if (dup2(fd[PIPE_OUTPUT, 1) < 0)
{
perror("dup2 failed");
exit(1);
}
parse_and_exec_cmd(commands->cmd);
}
else
{
waitpid(...); //what you put here is a bit tricky because
//some shells like tcsh will execute all
//commands at the same time (try cat | cat | cat | cat)
}
if (commands->next->next != null) //If you have 2 commands in line there is a middle
execute_pipe_middle(commands->next, fd);
else // no middle
execute_pipe_end(commands->next, fd);
}
else
parse_and_exec_cmd(commands->cmd);
}
execute_pipe_middle(t_cmdlist *commands, int fd_before[2])
{
int pid;
int fd_after[2];
if (pipe(fd_after) < 0)
{
perror("pipe failed");
exit(1);
}
pid = fork();
if (!pid)
{
close(fd_before[PIPE_OUTPUT]);
close(fd_after[PIPE_INPUT]);
if (dup2(fd_after[PIPE_OUTPUT, 1) < 0)
{
perror("dup2 failed");
exit(1);
}
if (dup2(fd_before[PIPE_INPUT, 0) < 0)
{
perror("dup2 failed");
exit(1);
}
parse_and_exec_cmd(commands->cmd);
}
else
waitpid(...);
if (commands->next->next != null) //More than two following commands : a middle again
execute_pipe_middle(commands->next, fd_after);
else // No more repetition
execute_pipe_end(commands->next, fd_after);
}
execute_pipe_end(t_cmdlist *commands, int fd_before[2])
{
int pid;
if (!commands)
return;
if (commands->next)
{
pid = fork();
if (!pid)
{
close(fd_before[PIPE_OUTPUT]);
if (dup2(fd_before[PIPE_INPUT, 0) < 0)
{
perror("dup2 failed");
exit(1);
}
parse_and_exec_cmd(commands->cmd);
}
else
waitpid(...);
}
}

Resources