xv6, line by line
user/cat.c

user/cat.c

C · 43 lines · annotated 100% · user program / library · upstream

About this file

cat (“concatenate”) copies files to standard output, one after another. cat README prints the file; cat a b > c joins two files into a third; plain cat with no arguments copies its standard input to its standard output, which makes it useful at either end of a pipeline.

It is the smallest complete example of the Unix I/O model seen from user space: open a file by name to get a file descriptor, read from it in chunks until read returns 0 (end of file), write each chunk to descriptor 1, close the descriptor. Because read and write work the same way on files, the console and pipes, cat never needs to know which kind of object it is copying.

Each call goes through a stub in user/usys.S that executes ecall, and lands in the kernel in sys_open, sys_read, sys_write or sys_close (kernel/sysfile.c).

Read before: user/user.h (the system-call declarations). Read next: user/echo.c, then user/grep.c and user/wc.c, which follow the same pattern.

5char buf[512];
7void
8cat(int fd)
9{
10 int n;
12 while ((n = read(fd, buf, sizeof(buf))) > 0) {
13 if (write(1, buf, n) != n) {
14 fprintf(2, "cat: write error\n");
15 exit(1);
16 }
17 }
18 if (n < 0) {
19 fprintf(2, "cat: read error\n");
20 exit(1);
21 }
24int
25main(int argc, char *argv[])
27 int fd, i;
29 if (argc <= 1) {
30 cat(0);
31 exit(0);
32 }
34 for (i = 1; i < argc; i++) {
35 if ((fd = open(argv[i], O_RDONLY)) < 0) {
36 fprintf(2, "cat: cannot open %s\n", argv[i]);
37 exit(1);
38 }
41 }
42 exit(0);