execlp redirect stdin in c - 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.

Related

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

C fork and pipe printing pid in order

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

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

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

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