fopen,
fclose,
fscanf and
fprintf for I/O. We know from last class, that
these standard libary routines must, at some point, use system
calls to do thier job. The basic I/O system calls are
open,
close,
read and
write. Whereas C standard library routines use
FILE* (file stream pointer)
objects to reference connections to files,
system calls use file descriptors. How they fit into the
kernel's I/O architecture was explained last class.
In this lab, you'll implement the basic wc
functionality using system calls for I/O.
Your simple wc function will take a list of
files and print the total number of bytes in all the files
put together.
| Operation/concept | C standard library | system call |
| reference to file connection | file stream ponter (FILE*) | file descriptor (int) |
| open a file connection | FILE *fopen(const char *filename, const char *mode); |
int open(const char *path, int oflag, /* mode_t mode */); |
| close file connection | int fclose(FILE *stream); |
int close(int fildes); |
| read from file connection | int fscanf(FILE *restrict stream, const char *restrict format, ...); |
ssize_t read(int fildes, void *buf, size_t nbyte); |
| write to file connection | int fprintf(FILE *restrict stream, const char *restrict format,/* args*/ ...); |
ssize_t write(int fildes, const void *buf, size_t nbyte); |
| predefined file connections | stdin, stdout, stderr |
STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO (0, 1 and
2, respectively) |
lab06 dirctory.
Copy these questions into a file ans.txt (in your
lab06 directory) and add
the answers to the questions. Do this before the rest of the lab!
man -s2 open.
Describe open's return value.
man -s2 open. Here's a quote:
"Bitwise-inclusive-OR" is a single "|". SoValues for oflag are constructed by a bitwise-inclusive-OR of flags from the following list, defined in <fcntl.h>. ...
a|b is the bitwise-OR
of a and b. This means that
the ith bit of the result is the OR of the ith bits of
a and b. Given this, read the man page and explain
the differences between these three calls to open:
open("foo",O_WRONLY);
open("foo",O_WRONLY|O_APPEND);
open("foo",O_WRONLY|O_CREAT);
STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
which are just long, descriptive names for 0, 1 and 2.
Read the man page for dup2.
int fd = open("foo",O_RDONLY);
dup2(fd,STDIN_FILENO);
man -s2 close and describe one
circumstance that could cause a call
to close to fail.
ssize_t write(int fildes, const void *buf, size_t nbyte);and consider the following call to write, which is a correct call:
write(2,"hi\n",3);
man -s2 read. Look at the return
value. Note that if end-of-file is encountered and
nothing is read in, the return value is 0. This is
different from fscanf!
Here's the prototype:
ssize_t read(int fildes, void *buf, size_t nbyte);
Explain why the folllowing two function calls are OK
char c; char B[20]; read(0,&c,1); read(0,B,20);but this call is not:
char *p; read(0,p,1);
man -s2 dup. If the call
int fd = dup(1);... is made, what would change in the process's file descriptor table, and what would change in the system open file table entry that file descriptor 1 refers to? HINT: You might want to look at the Class 9 notes to remind yourself about these kernel structures.
mywc that reads a character/byte at a time
from standard input using the read system call,
and writes out the number of characters/bytes read 'til end of file.
You may use fprintf to produce the output.
Here's an example run:
bash$ mywc < /usr/bin/gs 8304168
time utility takes a shell-command string,
executes it, and returs the number of seconds of "user" time,
"system" time, and actual "wall-clock" time required to
execute. Use it to time your solution to Part 1, i.e.
bash$ time mywc < /usr/bin/gsand record the number in ans.txt. Now modify your
lab06.c
so that your mywc calls to read attempt to read 100
characters/bytes at a time into a 100-character array. Rerun
the timing command, and add the new time to ans.c
along with an explanation for the difference in the times.
NOTE: pay close attention to read's return value
in order to get this right!
lab06.c
so that your mywc accepts a command-line
argument.
With no arguments, the program runs as before, with an
argument, however, it treats the argument as a file name and
reads from that file instead of standard input. Note that you
need to spit out error messages and exit if the filename is
bad. Read the man page for open in order to do
that.
Here are some example runs:
bash$ mywc < /usr/bin/gs 8304168 bash$ mywc /usr/bin/gs 8304168 bash$ mywc lkjlkjk mywc: Error! File "lkjlkjk" not found!
lab06.c
so that your mywc accepts an arbitrary number of
command-line arguments, each of which are file names.
Your mywc program should return the total
combined number
of characters/bytes in all the files listed on the command
line. If none are listed, return the number of bytes read
from standard input, as before.
Here are some example runs:
bash$ mywc < /usr/bin/gs 8304168 bash$ mywc /usr/bin/gs /etc/hosts /usr/include/math.h 8315730 bash$ mywc /usr/bin/gs /etc/hosts lkjlkjk /usr/include/math.h mywc: Error! File "lkjlkjk" not found!
lab06 directory via the usual submit
script.