i am trying to create a shell program to execute piped command. When i call ls from forked child & wc from parent it works fine. but if i call wc also from forked child parent keeps on waiting (i don't know why this is happening).
void execPiped(char** Args,char** pipedArgs)
{
int pfds[2];
pipe(pfds);
pid_t pid1 = fork();
if (pid1 == -1)
{
printf("\nFailed forking child..");
return;
}
else if (pid1 == 0) //CHILD 1 EXECUTING
{
close(1); //close STDOUT
dup(pfds[1]); //set pfds as STDOUT
close(pfds[0]); //we don't need this
if (execvp(Args[0], Args) < 0)
{
printf("\nCould not execute command..");
exit(1);
}
}
else {
pid_t pid2 = fork();
if (pid2 == -1)
{
printf("\nFailed forking child..");
return;
}
else if (pid2 == 0) //CHILD 2 EXECUTING
{
close(0); //close STDIN
dup(pfds[0]); //set pfds as STDIN
close(pfds[1]); //we don't need this
if (execvp(pipedArgs[0], pipedArgs) < 0)
{
printf("\nCould not execute command..");
exit(1);
}
}
else { //Parent Executing
//Wating for Children to exit
wait(NULL);
wait(NULL);
}
return;
}
}
Related
I making custom shell in c and when i give arguments for pipe it doesn't work as it should.
// Function where the piped system commands is executed
void execArgsPiped(char** parsed, char** parsedpipe)
{
// 0 is read end, 1 is write end
int pipefd[2];
pid_t p1, p2;
if (pipe(pipefd) < 0) {
red();
printf("\nPipe could not be initialized");
resetColor();
return;
}
p1 = fork();
if (p1 < 0) {
red();
printf("\nCould not fork");
return;
}
if (p1 == 0) {
// Child 1 executing..
// It only needs to write at the write end
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
if (execvp(parsed[0], parsed) < 0) {
red();
printf("\nCould not execute command 1..");
resetColor();
exit(0);
}
} else {
// Parent executing
p2 = fork();
if (p2 < 0) {
red();
printf("\nCould not fork");
resetColor();
return;
}
// Child 2 executing..
// It only needs to read at the read end
if (p2 == 0) {
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
if (execvp(parsedpipe[0], parsedpipe) < 0) {
red();
printf("\nCould not execute command 2..");
resetColor();
exit(0);
}
} else {
// parent executing, waiting for two children
wait(NULL);
wait(NULL);
}
}
}
For example calling /bin/cat filename | more, displays first two lines of file and shell breaks, or /bin/cat filename | cowsay nothing happens just breaks shell.
HELP
For anyone wondering read and write end closed before piping can end so code should look like.
// Function where the piped system commands is executed
void execArgsPiped(char** parsed, char** parsedpipe)
{
pid_t pid;
int fd[2];
pipe(fd);
pid = fork();
if(pid==0)
{
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[READ_END]);
close(fd[WRITE_END]);
if (execv(parsed[0], parsed) < 0) {
printf("\nCould not execute command..");
}
exit(1);
}
else
{
pid=fork();
if(pid==0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
if (execv(parsedpipe[0], parsedpipe) < 0) {
printf("\nCould not execute command..");
}
exit(1);
}
else
{
int status;
close(fd[READ_END]);
close(fd[WRITE_END]);
waitpid(pid, &status, 0);
}
}
}
I'm trying to pipe two different processes to implement the terminal's functionality "|".
I need the new child to execute a command itself, and fork another process to execute a different command using the first process's output, then output the final process's results on the terminal.
Here's my code, I keep the original parent untouched because I need to continue executing the other parts of my program afterwards.
int exec_pipe(char **args, int index, int *i, char**** jobs){
int fd1[2];
pid_t pid, wpid;
int status;
int savedStdOut = dup(1);
int savedStdIn = dup(fileno(stdin));
if (pipe(fd1)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
pid = fork();
if (pid < 0)
{
fprintf(stderr, "fork Failed" );
return 1;
}else if (pid == 0)
{
// Child process
close(fd1[0]);
dup2(fd1[1], 1);
printf("%s\n", args[index - 1]);
if (execvp(args[0], args) == -1)
{
printf("command not found\n");
}
int childId = fork();
if(childId < 0){
fprintf(stderr, "fork Failed" );
return 1;
}else if(childId == 0){
// child of child of parent
fdopen(fd1[1], "r");
dup2(fd1[1], savedStdOut);
if (execvp(args[index + 1], args) == -1)
{
printf("command not found\n");
}
exit(EXIT_FAILURE);
}else {
// parent of child of child of parent
do
{
wpid = waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status)); // wait for child until it's exited or been killed
fdopen(savedStdIn, "r");
close(fd1[0]);
close(fd1[1]);
}
}else{
// Parent process
do
{
wpid = waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status)); // wait for child until it's exited or been killed
}
return 1;
}
I'm getting a "No such file or directory" error with the program ending with exit code 9.
Solved it based on some comments, thanks all!
int fd1[2];
pid_t pid;
// allocate two pipe sets
if (pipe(fd1) < 0)
{
perror("Failed to create pipe.");
return EXIT_FAILURE;
}
// launch first child process.
if ((pid = fork()) < 0)
{
perror("Failed to fork child(1)");
return EXIT_FAILURE;
}
if (pid == 0)
{
// child
// stdout = fd1(write)
if(strcmp(args[0], args[index - 1]) == 0)
{
dup2(fd1[WRITE], STDOUT_FILENO);
close(fd1[READ]);
close(fd1[WRITE]);
execlp(args[0], args[0], (char*) NULL);
fprintf(stderr, "failed to execute '%s'\n", args[0]);
exit(1);
}else{
dup2(fd1[WRITE], STDOUT_FILENO);
close(fd1[READ]);
close(fd1[WRITE]);
execlp(args[0], args[0], args[index - 1], (char*) NULL);
fprintf(stderr, "failed to execute '%s'\n", args[0]);
exit(1);
}
}else
{
// parent
// fork once more.
if ((pid = fork()) < 0)
{
perror("Failed to fork child(2)");
return EXIT_FAILURE;
}
if (pid == 0)
{
// child of child
// stdin = fd1(read)
dup2(fd1[READ], STDIN_FILENO);
close(fd1[WRITE]);
close(fd1[READ]);
execlp(args[index + 1], args[index + 1], (char*) NULL);
fprintf(stderr, "failed to execute '%s'\n", args[index + 1]);
exit(1);
}else{
int status;
close(fd1[READ]);
close(fd1[WRITE]);
waitpid(pid, &status, 0);
}
}
I have written the below method to fork and execute commands separated by multiple pipes( test with : ls -lrt | grep "check" | wc -l . However it is not resulting in any output, could any one please spot my mistake. Thanks.
void execCmd (pInfo *info)
{
int i, j, k, m;
struct comType *comm, *comm1, *comm2;
if(info->noOfPipes > 2)
{
// DOES NOT WORK
printf("Start\n");
comm=&(info->cArr[0]);
comm2=&(info->cArr[(info->ppNum)-1]);
int fds[2];
pipe(fds);
pid_t pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
printf("1st child execution here\n");
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
execvp(comm->cmd,comm->parms);
}
for (k=1;k<=((info->ppNum)-1);k++)
{
printf("For loop executionn number %d",k);
comm1=&(info->cArr[k]);
printf ("comm 1 : %s\n",comm1->cmd);
pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
//2nd to n-1 child process
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
execvp(comm1->cmd,comm1->parms);
}
wait(NULL);
}
pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
//nth child process
printf("Last child execution\n");
close(fds[1]);
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
execvp(comm2->cmd,comm2->parms);
}
close(fds[0]);
close(fds[1]);
wait(NULL);
wait(NULL);
}
}
This following code should give you an idea how to implement the pipelining:
#define STDIN 0
#define STDOUT 1
void exec_cmd(struct comType cmd) {
execvp(cmd->cmd, cmd->params);
}
void pipeCmds(struct comType* cmds) {
int fd[cmds_length * 2] = {0};
pid_t pid = 0;
for (int i = 0; i < cmds_length; i++) {
if (pid = fork() == 0) {
//child: make this cmd's output the other cmd's input
pipe(fd + (2*i) );
close(STDOUT);
dup(fd[i]);
if(i > 0) {
close(STDIN);
dup(fd[i-1]);
}
exec_cmd(cmds[i]);
close(fd[i]);
}
}
}
Note that the main idea is that each command is executed in a separate process (via fork) and the output goes to the next command's input rather than to the default stdout(with file descriptor 1), and the same for the input - stdin (file descriptor 0).
I am implementing a shell in C. This is the function i use for piping. When i put "ls | a" in the code (i.e. pipe a valid command with invalid one),It doesnt exit the child process like it should. How do i make it go back to main function?
same thing happens when i do ps | ls or ps | pwd etc. but ls | ps works the same as in bash. i know ls | ps or ps | ls dont make sense but atleast they should give same output as bash.
void exec3(char **args, char **args2){
int fd[2];
pid_t pid,pid1;
int status;
pipe(fd);
int e=0;
if ((pid = fork()) < 0) {
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if ((pid1 = fork()) < 0) {
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if (pid == 0 && pid1!=0){
printf("in 1\n");
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
if(execvp(args[0],args)<0){
printf("**error in exec");
close(fd[0]);
close(fd[1]);
exit(1);
}
//printf("exiting 1\n");
exit(0);
}
else if (pid1 == 0 && pid!=0) {
printf("in 2\n");
close(0);
dup(fd[0]);
close(fd[1]);
close(fd[0]);
if((e=execvp(args2[0],args2))<0){
printf("**error in exec2 ");
close(fd[0]);
close(fd[1]);
exit(1);
}
exit(0);
}
else {
close(fd[0]);
close(fd[1]);
fflush(stdout) ;
while (wait(&status) != pid);
while (wait(&status) != pid1);
}
}
You are close to the solution. Look at how popen() is implemented, that is what you are trying to do.
I am trying to execute "sudo conntrack -E -p udp -e NEW" command and then pipe the output of this command to "logger" command, but this doesnt work. anything obvious that is going wrong?
so parent is the "sudo conntrack...." which forks the child "logger ..."
void main () {
pid_t pid;
int status;
int j=0;
int exe_process;
FILE *prt1;
FILE *prt2;
int fd[2];
char *arg[]={ "sudo", "/usr/sbin/conntrack", "-E", "-p", "udp", "-e", "NEW", NULL };
char *arg1[]={ "/usr/bin/logger", "-t", "log-conntrack", "-p", "daemon.notice", NULL };
if (pipe(fd) < 0)
printf("pipe error\n");
if ((pid = fork()) < 0) /* fork a child process */
{
printf("ERROR: forking child process failed\n");
exit(1);
}
else if (pid > 0) /* for the parent process: */
{
printf("In parent process %d\n",getpid());
close(fd[0]);
if (execvp("/usr/sbin/conntrack", arg) < 0) /* execute the command */
{
printf("ERROR: exec failed\n");
exit(1);
}
prt1=fdopen(fd[1], "ab");
}
else /* for the child: */
{
printf("In parent child %d\n",getpid());
close(fd[1]);
prt2=fdopen(fd[0], "rb");
if (execvp("/usr/bin/logger", arg1) < 0) /* execute the command */
{
printf("ERROR: exec failed\n");
exit(1);
}
}
}
That's pretty much correct but the main problem is that you need dup() instead of what you are trying to do with fdopen. dup will redirect stdin/stdout the way you want.
else if (pid > 0) /* for the parent process: */
{
printf("In parent process %d\n",getpid());
close(fd[0]);
close(1);
dup(fd[1]);
if (execvp("/usr/sbin/conntrack", arg) < 0) /* execute the command */
{
printf("ERROR: exec failed\n");
exit(1);
}
//prt1=fdopen(fd[1], "ab");
}
And in the child:
close(0);
dup(fd[0]);