Reproduce the pipe command - c

I have a school project which consists of reproducing the shell pipe command between two commands that the operator will choose as it pleases.
./pipex infile "ls -l" "wc -l" outfile
should be equivalent to
< infile ls -l | wc -l > outfile
Here is my way of doing it:
void first_child(char **argv, char **envp, int pipefd[2], int fd[2])
{
char **cmd_and_options1;
char *path_ultime1;
int pid1;
pipefd[0] = open(argv[1], O_RDONLY);
pid1 = fork();
if (pid1 == -1)
error();
if (pid1 == 0)
{
dup2(fd[1], STDOUT_FILENO);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
close(fd[1]);
execve(path_ultime1, cmd_and_options1, envp);
}
}
void second_child(char **argv, char **envp, int pipefd[2], int fd[2])
{
char **cmd_and_options2;
char *path_ultime2;
int pid2;
pipefd[1] = open(argv[4], O_CREAT | O_WRONLY | O_TRUNC, 0777);
pid2 = fork();
if (pid2 == -1)
error();
if (pid2 == 0)
{
dup2(fd[0], STDIN_FILENO);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
close(fd[0]);
execve(path_ultime2, cmd_and_options2, envp);
}
}
int main(int argc, char *argv[], char **envp)
{
int pipefd[2];
int fd[2];
char **cmd_and_options1;
char **cmd_and_options2;
char *path_ultime1;
char *path_ultime2;
(void)argc;
cmd_and_options1 = ft_split(argv[2], ' ');
cmd_and_options2 = ft_split(argv[3], ' ');
path_ultime1 = find_path(cmd_and_options1[0], envp);
path_ultime2 = find_path(cmd_and_options2[0], envp);
if (pipe(fd) == -1)
error();
first_child(&argv[1], envp, &pipefd[0], &fd[0]);
second_child(&argv[4], envp, &pipefd[1], &fd[1]);
close(pipefd[0]);
close(pipefd[1]);
close(fd[0]);
close(fd[1]);
waitpid(-1, NULL, 0);
waitpid(-1, NULL, 0);
return (0);
}
Roles of my find_path function:
extract the contents of PATH from the envp
use split() to delimit the paths according to ":" and store them in a double pointer
use strjoin() to append a "/" to the end of each path, and add the user command
test each path with access() then return the valid path
char *find_path(char *cmd, char **envp)
{
char **array_of_paths;
char *path_ultime;
int i;
char *temp;
i = 0;
while (ft_strnstr(envp[i], "PATH=", 5) == 0)
i++;
array_of_paths = ft_split(envp[i] + 5, ':');
i = 0;
while (array_of_paths[i])
{
temp = ft_strjoin(array_of_paths[i], "/");
path_ultime = ft_strjoin(temp, cmd);
free(temp);
if (access(path_ultime, F_OK | X_OK) == 0)
return (path_ultime);
i++;
}
return (0);
}
When I put all my code in the main(), my program worked.
But when I try to separate it into functions it doesn't work anymore and I don't understand what the problem is.

Related

Reproduce the shell pipe command

I have a school project which consists of reproducing the shell pipe command between two commands that the operator will choose as it pleases.
./pipex infile "ls -l" "wc -l" outfile
should be equivalent to
< infile ls -l | wc -l > outfile
Roles of my find_path function:
extract the contents of PATH from the envp
use split() to delimit the paths according to ":" and store them in a double pointer
use strjoin() to append a "/" to the end of each path, and add the user command
test each path with access() then return the valid path
char *find_path(char *cmd, char **envp)
{
char **array_of_paths;
char *path_ultime;
int i;
char *temp;
i = 0;
while (ft_strnstr(envp[i], "PATH=", 5) == 0)
i++;
array_of_paths = ft_split(envp[i] + 5, ':');
i = 0;
while (array_of_paths[i])
{
temp = ft_strjoin(array_of_paths[i], "/");
path_ultime = ft_strjoin(temp, cmd);
free(temp);
if (access(path_ultime, F_OK | X_OK) == 0)
return (path_ultime);
i++;
}
return (0);
}
My main takes care of:
split the argv[2] and the argv[3] with a space as delimiter, to keep only the command "ls" or "wc", and not the options
classic stuff like pipe(), fork(), execve() …
int main(int argc, char *argv[], char **envp)
{
(void)argc;
pid_t pid1;
pid_t pid2;
int fd[2];
char **cmd_and_options1;
char **cmd_and_options2;
char *path_ultime1;
char *path_ultime2;
cmd_and_options1 = ft_split(argv[2], ' ');
cmd_and_options2 = ft_split(argv[3], ' ');
path_ultime1 = find_path(cmd_and_options1[0], envp);
path_ultime2 = find_path(cmd_and_options2[0], envp);
if (pipe(fd) == -1)
return (1);
pid1 = fork();
if (pid1 == -1)
return (1);
if (pid1 == 0) // First child
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execve(path_ultime1, cmd_and_options1, envp);
}
pid2 = fork();
if (pid2 == -1)
return (1);
if (pid2 == 0) // Second child
{
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execve(path_ultime2, cmd_and_options2, envp);
}
close(fd[0]);
close(fd[1]);
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
return (0);
}
A friend told me that I lacked the management of the input and output file (argv[1] and argv[4]) that the operator will enter but I don't really understand what that means.
I know I have to use open() somewhere...
Can you give me some clues?

Simulating multi pipes "|" with a loop in c

I'm trying to simulate Unix shell multi pipes in c and I found a source code of a function doing the same thing but I didn't understand it well, if you can please explaint to me how's works, I know that pipe fd[2] creates fd[0] read input, and fd[1] write input as well dup2 close selected FD and duplicate it to FD through the pipe.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
/*
* loop over commands by sharing
* pipes.
*/
static void
pipeline(char ***cmd)
{
int fd[2];
pid_t pid;
int fdd = 0; /* Backup */
while (*cmd != NULL) {
pipe(fd); /* Sharing bidiflow */
if ((pid = fork()) == -1) {
perror("fork");
exit(1);
}
else if (pid == 0) {
dup2(fdd, 0);
if (*(cmd + 1) != NULL) {
dup2(fd[1], 1);
}
close(fd[0]);
execvp((*cmd)[0], *cmd);
exit(1);
}
else {
wait(NULL); /* Collect childs */
close(fd[1]);
fdd = fd[0];
cmd++;
}
}
}
/*
* Compute multi-pipeline based
* on a command list.
*/
int
main(int argc, char *argv[])
{
char *ls[] = {"ls", "-al", NULL};
char *rev[] = {"rev", NULL};
char *nl[] = {"nl", NULL};
char *cat[] = {"cat", "-e", NULL};
char **cmd[] = {ls, rev, nl, cat, NULL};
pipeline(cmd);
return (0);
}

pipe redirection issue, lost data

I want to reproduce this shell behaviour with a small c program:
< file cmd1 | cmd2
So it takes three arguments and can be executed this way for exemple:
./a.out foo /bin/cat /usr/bin/wc
Here's my code, without error checking:
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
static void exe_cmd(char *cmd, char **env)
{
int pid;
char *av[] = {cmd, NULL};
pid = fork();
if (pid == 0)
{
execve(av[0], av, env);
exit(0);
}
waitpid(pid, NULL, 0);
}
static void left_pipe_side(int fd[2], char *cmd, char *path, char **env)
{
int file;
file = open(path, O_RDONLY);
dup2(fd[1], STDOUT_FILENO); // Can be commented out to see the first command output
dup2(file, STDIN_FILENO);
close(fd[0]);
close(fd[1]);
close(file);
exe_cmd(cmd, env);
}
static void right_pipe_side(int fd[2], char *cmd, char **env)
{
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
close(fd[0]);
exe_cmd(cmd, env);
}
int main(int ac, char **av, char **env)
{
int fd[2];
pid_t pid;
pid = fork();
pipe(fd);
if (pid == 0)
{
left_pipe_side(fd, av[2], av[1], env);
exit(0);
}
right_pipe_side(fd, av[3], env);
waitpid(pid, NULL, 0);
return (0);
}
My problem is that the output of wc as the second command will always be 0 0 0, as if the input were empty (but the given file contains text).
If I comment out the line where I dup fd[1] to stdout in the left pipe side, the first command will output correctly, so I don't understand why the redirection makes this data "disappear"
You open pipe after fork, so each process has it's own very unrelated pipe. Open it before, so that it's shared between processes.
pipe(fd);
pid = fork();
in your code, you open the pipe after the fork so that's mean every process has its own pipe and that's not how pipes work
you have to open the pipes before the fork that's make the process linked with your pipe.
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
static void exe_cmd(char *cmd, char **env)
{
int pid;
char *av[] = {cmd, NULL};
pid = fork();
if (pid == 0)
{
execve(av[0], av, env);
exit(0);
}
waitpid(pid, NULL, 0);
}
static void left_pipe_side(int fd[2], char *cmd, char *path, char **env)
{
int file;
file = open(path, O_RDONLY);
dup2(fd[1], STDOUT_FILENO); // Can be commented out to see the first command output
dup2(file, STDIN_FILENO);
close(fd[0]);
close(fd[1]);
close(file);
exe_cmd(cmd, env);
}
static void right_pipe_side(int fd[2], char *cmd, char **env)
{
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
close(fd[0]);
exe_cmd(cmd, env);
}
int main(int ac, char **av, char **env)
{
int fd[2];
pid_t pid;
/************************ the error part **********************/
// pid = fork();
// pipe(fd);
pipe(fd);
pid = fork();
/**************************************************************/
if (pid == 0)
{
left_pipe_side(fd, av[2], av[1], env);
exit(0);
}
right_pipe_side(fd, av[3], env);
waitpid(pid, NULL, 0);
return (0);
}

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

Fork/Dup2/Exec not working with mkstemp

Why does word count output 0 0 0 in the following program?
int main(int argc, char **argv) {
pid_t pid = fork();
const char *data = "THIS IS MY DATA.";
if(pid == 0) {
// Child Process
char *tmpname = malloc(15);
strcpy(tmpname, "/tmp/datXXXXXX");
int f = mkstemp(tmpname);
//int f = open("tmpfile", O_RDWR | O_CREAT, S_IRWXU);
if(f == -1) {
perror("");
return;
}
int written = write(f, data, strlen(data));
dup2(f, STDIN_FILENO);
close(f);
char *wcargs[5] = {"wc", NULL};
execvp("wc", wcargs);
fprintf(stderr, "ERROR");
}
return 1;
}
Try rewinding stdin after the dup2() using lseek(0, 0, SEEK_SET). In your code, wc will be trying to read from the end of the file and obviously won't have any bytes to read.

Resources