It will print out "fd2 = 4".
Process:
Unix processes begin life with open descriptors assigned to stdin (descriptor 0), stdout (descriptor 1), and stderr (descriptor 2). The open
function always returns the lowest unopened descriptor, so the first call to open
returns descriptor 3. The second call to open
returns descriptor 4. The call to the close function frees up descriptor 4. The final call to open returns descriptor 4 again, and thus the output of the program is fd2 = 4.
#include "csapp.h"
int main(int argc, char **argv)
{
ssize_t n;
rio_t rio;
char buf[MAXBUF];
Rio_readinitb(&rio, STDIN_FILENO);
while ((n = Rio_readnb(&rio, buf, MAXBUF)) != 0)
Rio_writen(STDOUT_FILENO, buf, n);
}
#include "csapp.h"
int main(int argc, char **argv)
{
struct stat stat;
char *type, *readok;
int fd;
if (argc != 2) {
fprintf(stderr, "Usage: %s <descriptor>\n", argv[0]);
exit(1);
}
// Convert argument to integer
fd = atoi(argv[1]);
Fstat(fd, &stat);
if (S_ISREG(stat.st_mode)) /* Determine file type */
type ="regular";
else if (S_ISDIR(stat.st_mode))
type = "directory";
else
type = "other";
if ((stat.st_mode & S_IRUSR)) /* Check read access */
readok = "yes";
else
readok = "no";
printf("type: %s, read: %s\n", type, readok);
exit(0);
}
The pseudocode should be as follows:
if (Fork() == 0) { /* child */
/* Pseudocode for the shell executing right here */
int fd = Open("foo.txt", O_RDONLY, 0); // Open the file for reading
// Error check for file opening
if (fd < 0) {
// Handle error
}
Dup2(fd, 0); // Using dup2 to explicitly set it to 0
Close(fd); // Close the original file descriptor returned by open
Execve("fstatcheck", argv, envp);
}
The issue with the command fstatcheck 3 < foo.txt
is related to how shell handles file descriptor redirection and how file descriptors are passed to programs.
With < foo.txt
, the shell sets up file descriptor 0 to be a read descriptor for the file foo.txt
. However, when we specify 3
as an argument to fstatcheck
, we're actually telling it to look at file descriptor 3.
3
: This is an argument tofstatcheck
and does not directly correlate with the file descriptor being used by the shell for the redirection.< foo.txt
: This tells the shell to redirectfoo.txt
to standard input forfstatcheck
.
So, when fstatcheck
tries to use file descriptor 3, it's not associated with foo.txt
(which is on file descriptor 0).
We can use shell features to duplicate the file descriptor so that foo.txt
is also available on file descriptor 3, as shown in the below:
exec 3<foo.txt
fstatcheck 3
We can check argc
. If argc
> 1, an infile
is provided, and it is opened with Open
, which returns a file descriptor. Otherwise, no infile
is provided, and fd is set to STDIN_FILENO
.
int main(int argc, char **argv)
{
ssize_t n;
rio_t rio;
char buf[MAXLINE];
int fd;
if (argc > 1)
fd = Open(argv[1], O_RONLY, 0);
else
fd = STDIN_FILENO;
Rio_readinitb(&rio, fd);
while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0)
Rio_writen(STDOUT_FILENO, buf, n);
/* Close fd if it's not standard input */
if (fd != STDIN_FILENO) {
Close(fd);
}
}