user/echo.c
About this file
echo prints its arguments to standard output, separated by single spaces and followed by
a newline: echo hello world prints hello world. Combined with the shell’s
redirection it is the quickest way to create a small file (echo hi > f).
The program shows how arguments reach a process. The shell splits the command line at
spaces and passes the words to exec; the kernel copies them onto the new program’s
user stack (kexec), and they arrive here as argc and argv. Since the
shell has already split the words, any run of spaces between them is gone: echo a b
prints a b. xv6’s shell does not understand quotes either, so echo 'a b' prints
'a b'.
The only system calls are write (sys_write) and exit
(sys_exit).
Read before: user/cat.c. Read next: user/sh.c, to see how the shell builds
argv.
Headers
The usual three. kernel/stat.h is not needed here (no struct stat is used); most
xv6 programs include it out of habit.
main(): print each argument, then a newline
The loop starts at i = 1 because argv[0] is the program’s own name.
Each argument is written with strlen as its length, which works because the
kernel placed each one in memory as a NUL-terminated string. After every argument
except the last comes a space; after the last comes a newline.
Everything goes to descriptor 1, standard output, with plain
write instead of printf. That is efficient: one system call per argument and one
per separator. The user library’s printf would cost one write per character,
because its putc writes a single byte at a time (user/printf.c).
Two details. With no arguments the loop body never runs, so echo alone prints
nothing at all, not even a newline (Unix echo prints an empty line). And the return
values of write are ignored: if output fails, echo still exits with status 0
(exit status).
Visit the arguments after the program name, in order.
Write argument i, without its terminating NUL.
Is there another argument after this one?
Yes: separate them with one space.
No: end the line.
Exit with status 0. A user program in xv6 should end with exit; returning from
main also works, because the library’s start calls exit with main’s
return value.