Is there any other way to build pipe in C? - 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;
}

Related

How to pass STDIN to a program and store its output to a variable? C

I need to execute a file from the bash using and store its output to a variable, there's also the needs to pass to its stdin a string s. Something like this in bash:
usr:~$ s | program args
I know how to call the program and give him args:
execvp(program,args);
So my problem is giving to that his stdin and store output to a variable(string)!
P.S.:can't use system and popen.
Some example code for you to experiement. This excute ls | cat.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv) {
int fd[2];
int pid;
char* cmd1[2] = {"ls", NULL};
char* cmd2[2] = {"cat", NULL};
int status;
pid = fork();
if (pid == 0) {
pipe(fd);
pid = fork();
if (pid == 0) {
printf("cmd1\n");
dup2(fd[1], 1);
close(fd[0]);
close(fd[1]);
execvp(cmd1[0], cmd1);
printf("Error in execvp\n");
}
else {
dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);
printf("cmd2\n");
execvp(cmd2[0], cmd2);
printf("Error in execvp\n");
}
}
else {
close(fd[0]);
close(fd[1]);
wait(&status);
printf("%d\n", status);
wait(&status);
printf("%d\n", status);
}
}

Using sed with the execvp to cut part of stout. C

I'm using a function that echo a string and redirect output to a sed input in c.
If i echo a string like "hello: bye bye", i need to cut everything before the ":". So i buildt a function that fork and pipe for this but sed won't recognize my regex:
void sender (char * str_ ,char * pipe_ ,char **args_) {
int fd[2];
int pid;
char* cmd1[] = {"echo", str_,NULL};
char* sed[] = {"sed","'[^:]*$'",NULL};
int status;
pid = fork();
if (pid == 0) {
if(pipe(fd) < 0){
exit(100);
}
pid = fork();
if (pid == 0) {
close(fd[0]);
dup2(fd[1], 1);
close(fd[1]);
execvp(cmd1[0], cmd1);
printf("Error in execvp1\n");
}else{
close(fd[1]);
wait(&status);
dup2(fd[0],0);
close(fd[0]);
dup2(1,2);
execvp(sed[0],sed);
printf("Error in execvp2\n");
}
}
else{
close(fd[0]);
close(fd[1]);
wait(&status);
wait(&status);
}
}
The output is error for every line read because of sed:expression -e #1, character 1: unknown command: `''
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void pipe_exec(int pfd[], char *cmd_args[], int redirect_output)
{
printf("%s, pid %d\n", cmd_args[0], getpid());
if (redirect_output)
dup2(pfd[1], 1);
else
dup2(pfd[0], 0);
close(pfd[0]);
close(pfd[1]);
execvp(cmd_args[0], cmd_args);
printf("Error in execvp\n");
exit(1);
}
void sender(char *str_, char *unused1, char **unused2)
{
int status, pid, fd[2];
char *cmd1[] = { "echo", str_, NULL };
char *sed[] = { "sed", "s/[^:]*://", NULL };
if (pipe(fd) < 0)
exit(100);
pid = fork();
if (pid == 0)
pipe_exec(fd, cmd1, 1);
pid = fork();
if (pid == 0)
pipe_exec(fd, sed, 0);
close(fd[0]);
close(fd[1]);
wait(&status);
wait(&status);
}
int
main(void)
{
sender("hello: bye bye", NULL, NULL);
return (0);
}

Creating a pipe in c between two programs

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);
}

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.

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

Resources