I am a bit of a newbie in programming Linux in C (I searched for similar threads but none helped), so I got stuck at the following problem :
I want to create a shell in C for Linux (using fork(), exec(), pipe(), that gets a command with parameters and pipes as input from the terminal stdin (ex. "sort foo | uniq -c | wc -l"), it executes it and then asks for the next command etc.
I separated the different commands, their parameters etc, I created 1 child process for each one, but I can't chain the output of each child process to the input of the next one (and the last output at stdout in terminal).
Could anyone help do the correct piping to get it up and running ??
For any more info, just ask... Thanks in advance
The full code is below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define P_READ 0
#define P_WRITE 1
pid_t pID, chID;
char input[100];
char * params[100][100];
char * funcs[100];
char * par;
char * fun;
int i, j, k, stat, infd[2], outfd[2];
//Pipe read
void read_en(int * infd)
{
dup2(infd[P_READ], STDIN_FILENO);
close(infd[P_READ]);
close(infd[P_WRITE]);
}
//Pipe write
void write_en(int * outfd)
{
dup2(outfd[P_WRITE], STDOUT_FILENO);
close(outfd[P_READ]);
close(outfd[P_WRITE]);
}
//Fork, read from pipe, write to pipe, exec
void fork_chain(int * infd, int * outfd, int i)
{
pID = fork();
if (pID == 0)
{
if (infd != NULL)
{
read_en(infd);
}
if (outfd != NULL)
{
write_en(outfd);
}
execvp(params[i][0], params[i]);
fprintf(stderr, "Command not found!\n");
exit(1);
}
else if (pID < 0)
{
fprintf(stderr, "Fork error!\n");
exit(1);
}
else
{
chID = waitpid(-1, &stat, 0);
}
}
int main()
{
printf("\n$");
fgets(input, sizeof(input), stdin);
strtok(input, "\n");
while (strcmp(input, "exit") != 0)
{
//Separate each command
k = 0;
fun = strtok(input, "|");
while (fun != NULL)
{
funcs[k] = fun;
fun = strtok(NULL, "|");
k++;
}
//Separate each command's parameters
for (i = 0; i < k; i++)
{
j = 0;
par = strtok(funcs[i], " ");
while (par != NULL)
{
params[i][j] = par;
par = strtok(NULL, " ");
j++;
}
params[i][j] = NULL;
}
//Fork, pipe and exec for each command
for (i = 0; i < k; i++)
{
if (i == 0)
{
pipe(outfd);
fork_chain(NULL, outfd, 0);
infd[P_READ] = outfd[P_READ];
infd[P_WRITE] = outfd[P_WRITE];
}
else if (i == k-1)
{
fork_chain(infd, NULL, 1);
close(infd[P_READ]);
close(infd[P_WRITE]);
}
else
{
pipe(outfd);
fork_chain(infd, outfd, i);
close(infd[P_READ]);
close(infd[P_WRITE]);
infd[P_READ] = outfd[P_READ];
infd[P_WRITE] = outfd[P_WRITE];
}
}
//Ask for next input
printf("\n$");
fgets(input, sizeof(input), stdin);
strtok(input, "\n");
}
return (0);
}