CSci 4061 Introduction to Operating Systems
Input/Output: Low-level cont’d File descriptor magic Chapter 4
Re-direction: another key CS concept!
• What is the default input/output location? shell> cat foo.bar
shell> cat foo.bar > baz.out (show it) What is this?
How does this work? Let’s build up to this
1. duplicating file descriptors 2. fd preservation
1. Duplicating File Descriptors
Sometimes you need to change what an fd points to (why? redirection)
#include
int dup2 (int fd1, int fd2);
Closes fd2 (if open) -> frees up fd2
Makes fd2 now point to what fd1 points to
Filter and Re-direction (cont’d)
shell> cat foo.bar > baz.out
What is happening? … writes to stdout are
redirected to baz.out … but how?
Output redirection (my_cat.c)
fd = open (“baz.out”, O_CREAT|O_WRONLY, …); dup2 (fd, 1); // 1 now refers to fd
close (fd); // might as well …
write (1, …); // writes to “standard out” => baz.out
[look at fd table]
Filter and Re-direction (cont’d)
stdin stderr
[0] [2] Before redirection
my_cat
stdin
[0]
my_cat
[1] stdout stderr
[2] After redirection
[1]
baz.out
Filter and Re-direction (cont’d)
Output redirection (my_cat.c)
fd = open (“baz.out”, O_CREAT|O_WRONLY, …); dup2 (fd, 1); //close stdout and 1 refer to fd close (fd); // not needed but good style
write (1, …); // writes to “standard out” => baz.out
“lost” stdout – how can we re-open it?
fd = open (“/dev/tty”, O_WRONLY);
Input Re-Direction
• How would we handle input redirection?
shell> wc –c Hi there jon ^D
shell>13
Suppose I want to use a file instead
shell> wc –c < mydata.txt
Input Re-Direction (cont’d) my_wc.c:
fd = open (“mydata.txt”, O_RDONLY, ...); dup2 (fd, 0);
close (fd); // not needed but good style
// reads from “standard in” directed to mydata.txt
read (0, ...);
Filter and Re-Direction (cont’d)
• Re-directing within a single process not so useful, let’s return to the shell
• If I want to read/write to a file, just do it!
• How does the shell actually do it for us?
shell> cat foo.bar > baz.out
// cat delivers output to stdout and we don’t // want to modify the code of cat or ls or ….
Step 2: fd preservation
2. File Descriptor Preservation
FDs inheritance through fork FDs preserved through exec
File Descriptor Inheritance
FDs and FD table are inherited by children! Important later.
int fd, fd1, fd2, pid;
fd = open (“my_file”, O_RDONLY, 0); pid = fork ();
if (pid != 0) {
read (fd, …);
fd1 = open (“foo”, …);
}
else {
read (fd, …); // the same fd fd2 = open (“bar”, …);
…
}
[show fd table]
I/O Redirection
cat foo > bar wc < baz
• Duplication via dup2 • Preservation of fd’s
File Descriptor Preservation
FDs preserved through exec.
int fd, fd1, fd2, pid;
fd = open (“my_file”, O_RDONLY, 0); pid = fork ();
if (pid != 0) {
read (fd, ...);
fd1 = open (“foo”, ...);
} else {
read (fd, ...);
fd2 = open (“bar”, ...); // fd’s preserved through exec! execl (“cat ...”);
... }
The Shell: fd’s preserved via exec
shell> cat source_file
int fd, pid;
fd = open (“source_file”, O_RDONLY, 0); pid = fork ();
if (pid != 0) { // shell parent
read (fd, …);
}
else {
// shell child read (fd, ….); // fd inherited
// fd’s preserved through exec!
execl (“cat …”);
… }
Inside cat …
write (1, …);
…..
By default cat writes to stdout
This is true of virtually all shell commands/programs
The Shell: dup + preservation
shell> cat source_file > output_file_name
int fd1, fd2, pid;
pid = fork ();
if (pid != 0) { // shell parent
…
wait (NULL);
}
else { // shell child
// redirect name of file provided to the shell ‘>’ case
}
fd2 = open (“output_file_name”, O_WRONLY); dup2 (fd2, 1);
execl (“cat …”);
inside “cat”
write (1, …);