shell (part 2). example r what if we want to support something like this: m ps –le | sort r one...

38
Shell (Part 2)

Upload: natalie-woods

Post on 20-Jan-2016

217 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Shell (Part 2)

Page 2: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example What if we want to support something like

this: ps –le | sort

One process should execute ps –le and another should execute sort

By default a command like ps requires that its output goes to standard output i.e., the terminal (stdout)

The sort command requires that a file be provided as a command line argument from standard input (stdin)

Page 3: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

First Attempt

pid = fork(); if (pid<0) {

perror("Problem forking");exit(1);

} else if (pid>0) {/* parent process */ execlp("ps","ps","-le", NULL);perror("exec problem");exit(1);

} else {/* child process */}

execlp("sort","sort",NULL);perror("exec problem");exit(1);

}

return(0);}

Page 4: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

Why doesn’t this work? The output of the ps -le goes to the terminal

We want it to be the input to the sort The diagram on the next page shows

the status of the file descriptor tables after the fork

Page 5: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Fork and Files

Parent File Descriptor table

01234

stdinstdoutstderr

System file table

Terminal info

01234

stdinstdoutstderr

Child File Descriptor table

Terminal info

Terminal info

Page 6: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

What is Needed?

Assume process P1 is to execute ps –le and that P2 is to execute sort

There is a need for shared memory that allows P1 to write the results of ps –le to the shared memory

P2 should be able to read the results from the shared memory and provide the results to the sort command

Page 7: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Pipes

The pipe function can be used to provide the shared memory

We will first provide a general discussion of the pipe function which is to be followed by a discussion of how it applies to executing ps –le | sort

Page 8: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Pipes

Pipes can be used between processes that have a common ancestor

Typical use: Pipe created by a process Process calls fork() Pipe used between parent and child Allows for communication between

processes

Page 9: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Creating a Pipe

#include <unistd.h> int pipe(int filedes[2]);

Returns 0 if ok, -1 on error Returns two file descriptors

filedes[0] is open for reading filedes[1] is open for writing

Page 10: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example #include <unistd.h>#include <stdio.h>int main(void){

int n; // track of num bytes read int fd[2]; // hold fds of both ends of pipe pid_t pid; // pid of child process char line[80]; // hold text read/written

Page 11: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Continued …

if (pipe(fd) < 0) // create the pipe perror("pipe error");

if ((pid = fork()) < 0) { // fork off a child perror("fork error"); } else if (pid > 0) { // parent process close(fd[0]); // close read end write(fd[1], "hello world\n", 12); // write to it wait(NULL); }…

Page 12: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Continued…

else { // child process close(fd[1]); // close write end n = read(fd[0], line, 80); // read from

pipe write(1, line, n); // echo to

screen } exit(0);}

Page 13: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Fork and Pipes

A fork copies the file descriptor table to the child

The parent should close one of the file descriptors while the child should close the other

Example code on the two previous slides: Parent closes fd[0] since it does not read

from it Child closes fd[1] since it does not write

Page 14: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Fork and Pipes

Parent File Descriptor table

01234

stdinstdoutstderr fd[0]

System file table

pipe info e.g., read offset

01234

stdinstdoutstderrfd[0]

Child File Descriptor table

fd[1]

fd[1]

pipe info e.g., write offset

After Fork

Page 15: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Fork and Pipes

Parent File Descriptor table

01234

stdinstdoutstderr

fd[0] = NULL

System file table

pipe info e.g., read offset

01234

stdinstdoutstderrfd[0]

Child File Descriptor table

fd[1]

fd[1] = NULL

pipe info e.g., write offset

After Closing Ends

Page 16: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Pipes By default, if a writing process attempts

to write to a full pipe, the system will automatically block the process until the pipe is able to receive the data

Likewise, if a read is attempted on an empty pipe, the process will block until data is available

In addition, the process will block if a specified pipe has been opened for reading, but another process has not opened the pipe for writing

Page 17: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Pipe Capacity

The OS has a limit on the buffer space used by the pipe If you hit the limit, write will block

Page 18: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

We will now show how pipes can be used for supporting the execution of ps –le | sort

Page 19: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example First let us

Create shared memory that is to be used by the parent and child processes

This is done using the pipe function The pipe function is executed before the fork

function The results of ps –le should be put into the

shared memory to be used by the child process for sort

See next slide for code The slide after code slide depicts the file

descriptor table and System File table

Page 20: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

int main(int argc, char **argv) { int fds[2]; pid_t pid;

/* attempt to create a pipe */ if (pipe(fds)<0) {

perror("Fatal Error");exit(1);

}

Page 21: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

Parent File Desc. table

01234

fds[0] fds[1]

stdinstdoutstderr

System file table

Terminal info

Terminal info

Terminal info

Shared mem. info: read Shared mem. Info:write

Page 22: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

System file table

Terminal info

Terminal info

Terminal info

Shared mem. Info: read

Shared mem. Info:write

Shared Memory

Page 23: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

Each entry in the system file table has information about the “file” which could be the terminal, disk file or pipe (shared memory)

For shared memory created by the pipe function: The read descriptor includes information

about the last location read from The write descriptor includes information

about the last location written to.

Page 24: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

Let us now add the code for the fork See next slide for the code

Page 25: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

/* create another process */ pid = fork(); if (pid<0) {

perror("Problem forking");exit(1);

}

……………..

What is the status of the file descriptor table

Page 26: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

Parent File Desc. table

01234

fds[0] fds[1]

stdinstdoutstderr

System file table

01234

fds[0] fds[1]

stdinstdoutstderr

Child File Desc.table

Terminal info

Terminal info

Terminal info

Shared mem. Info: read

Shared mem. Info:write

Page 27: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Fork and Pipes

A fork copies the file descriptor table to the child

The parent should close one of the file descriptors while the child should close the other

Page 28: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Fork and Pipes

Parent File Descriptor table

01234

stdinstdoutstderr fd[0]

System file table

pipe info e.g., read offset

01234

stdinstdoutstderrfd[0]

Child File Descriptor table

fd[1]

fd[1]

pipe info e.g., write offset

After Fork

Page 29: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Fork and Pipes

Parent File Descriptor table

01234

stdinstdoutstderr

fd[0] = NULL

System file table

pipe info e.g., read offset

01234

stdinstdoutstderrfd[0]

Child File Descriptor table

fd[1]

fd[1] = NULL

pipe info e.g., write offset

After Closing Ends

Page 30: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

We want the output of the ps –le command to be put into the shared memory

The sort command should read from the shared memory

Two issues: The sort command assumes that it receives its

input from stdin The ps command assumes that it outputs to

stdout We need to “reroute”

This can be done using the dup() function

Page 31: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

dup() and dup2

#include <unistd.h>int dup(int filedes1);int dup2(int filedes1, int filedes2);

Both will duplicate an existing file descriptor dup() returns lowest available file descriptor,

now referring to whatever filedes1 refers to dup2() - filedes2 (if open) will be closed and

then set to refer to whatever filedes1 refers to

Page 32: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example Now we want what would normally go to

the standard output to go to the shared memory

This is done with the following code:if ( dup2(fds[1],STDOUT_FILENO)<0) {

perror("can't dup"); exit(1);}

The new parent file descriptor table is on the next page

Page 33: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

Parent File Desc. table

01234

fds[0]=NULL

fds[1]

stdinstdoutstderr

System file table

01234

fds[0] fds[1]=NULL

stdinstdoutstderr

Child File Desc.table

Terminal info

Terminal info

Terminal info

Shared mem. info: read

Shared mem. info:write

Page 34: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example Now want to set it up so that the child

reads from the shared memory This is done with the following code:

if ( dup2(fds[0],STDIN_FILENO)<0) { perror("can't dup"); exit(1);}

The new child file descriptor is on the next page

Page 35: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

Parent File Desc. table

01234

fds[0]=NULL

fds[1]

stdinstdoutstderr

System file table

01234

fds[0] fds[1]=NULL

stdinstdoutstderr

Child File Desc.table

Terminal info

Terminal info

Terminal info

Shared mem. info: read

Shared mem. info:write

Page 36: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

Let us now put it together

Page 37: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example/* create another process */ pid = fork(); if (pid<0) {

perror("Problem forking");exit(1);

} else if (pid>0) {/* parent process */close(fds[0]);

/* close stdout, reconnect to the writing end of the pipe */if ( dup2(fds[1],STDOUT_FILENO)<0) { perror("can't dup"); exit(1);}

execlp("ps","ps","-le", NULL);perror("exec problem");exit(1);

Page 38: Shell (Part 2). Example r What if we want to support something like this: m ps –le | sort r One process should execute ps –le and another should execute

Example

} else {/* child process */

close(fds[1]);if (dup2(fds[0],STDIN_FILENO) < 0) { perror("can't dup"); exit(1);}execlp("sort","sort",NULL);perror("exec problem");exit(1);

}

return(0);}