2
votes

I'm working on my homework which is to replicate the unix command shell in C.

I've implemented till single command execution with background running (&).

Now I'm at the stage of implementing pipes and I face this issue, For pipes greater than 1, the children commands with pipe are completed, but the final output doesn't get displayed on stdout (the last command's stdin is replaced with read of last pipe)

dup2(pipes[lst_cmd], 0);

I tried fflush(STDIN_FILENO) at the parent too.

The exit of my program is CONTROL-D, and when i press that, the output gets displayed (also exits since my operation on CONTROL-D is to exit(0)).

I think the output of pipe is in the stdout buffer but doesn't get displayed. Is there anyother means than fflush to get the stuff in the buffer to stdout?

1
Maybe your program doesn't access to controlling terminal,or its parent prevent it to.Amir Naghizadeh
Normally, the last child in a pipeline (eg the sort in ps | sort) has its standard output left unredirected. When that child process writes, it writes to its standard output, which is the same as the standard output of the shell itself. (Obviously, if you write ps | sort > file, then the output goes to the file instead.) The child process has its standard output flushed automatically before it dies; there's nothing for you to do.Jonathan Leffler
what could i do control the terminal?Vinoth
@JonathanLeffler When that child process writes, it writes to its standard output, which is the same as the standard output of the shell itself. but it does not write to the stdout.. it writes only wen i kill my executable.. does this hint lead somewhere?Vinoth
No; I can't see what your code has managed to do. What you're describing is weird. What have you done in your code to fiddle with process groups, controlling ttys, and the like? Can you post an SSCCE (Short, Self-Contained, Correct Example)?Jonathan Leffler

1 Answers

0
votes

Having seen the code (unfair advantage), the primary problem was the process structure combined with not closing pipes thoroughly.

The process structure for a pipeline ps | sort was:

main shell
    - coordinator sub-shell
        - ps
        - sort

The main shell was creating N pipes (N = 1 for ps | sort). The coordinator shell was then created; it would start the N+1 children. It did not, however, wait for them to terminate, nor did it close its copy of the pipes. Nor did the main shell close its copy of the pipes.

The more normal process structure would probably do without the coordinator sub-shell. There are two mechanisms for generating the children. Classically, the main shell would fork one sub-process; it would do the coordination for the first N processes in the pipeline (including creating the pipes in the first place), and then would exec the last process in the pipeline. The main shell waits for the one child to finish, and the exit status of the pipeline is the exit status of the child (aka the last process in the pipeline).

More recently, bash provides a mechanism whereby the main shell gets the status of each child in the pipeline; it does the coordination.

The primary fixes (apart from some mostly minor compilation warnings) were:

  1. main shell closes all pipes after forking coordinator.
  2. main shell waits for coordinator to complete.
  3. coordinator closes all pipes after forking pipeline.
  4. coordinator waits for all processes in pipeline to complete.
  5. coordinator exits (instead of returning to provide duelling dual prompts).

A better fix would eliminate the coordinator sub-shell (it would behave like the classical system described).