I've been studying UNIX and system calls and I came across a low-level and tricky questions. The question asks what system calls are called for this command:
grep word1 word2 > file.txt
I did some research and I was unable to find a huge number of resources on the underlying UNIX calls. However, it seems to me that the answer would be open (to open and the file descriptor for the file file.txt), then dup2 (to change the STDOUT of grep to the file descriptor of open), then write to write the STDOUT of grep (which is now the file descriptor of file.txt), and finally close(), to close the file descriptor of file.txt... However, I have no idea if I am right or on the correct path, can anyone with experience in UNIX enlighten me on this topic?
You are on correct direction in your research. This command is very helpful to trace system calls in any program:
strace
On my PC it shows output (without stream redirection):
$ strace grep abc ss.txt
execve("/bin/grep", ["grep", "abc", "ss.txt"], [/* 237 vars */]) = 0
brk(0) = 0x13de000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1785694000
close(3) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
stat("ss.txt", {st_mode=S_IFREG|0644, st_size=13, ...}) = 0
open("ss.txt", O_RDONLY) = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fffa0e4f370) = -1 ENOTTY (Inappropriate ioctl for device)
read(3, "abc\n123\n321\n\n", 32768) = 13
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f178568c000
write(1, "abc\n", 4abc
) = 4
read(3, "", 32768) = 0
close(3) = 0
close(1) = 0
munmap(0x7f178568c000, 4096) = 0
close(2) = 0
exit_group(0) = ?
Related
I have a directory with a single file, one.txt. If I run ls | cat, it works fine. However, if I try to strace both sides of this pipeline, I do see the output of the command as well as strace, but the process doesn't finish.
strace ls 2> >(stdbuf -o 0 sed 's/^/command1:/') | strace cat 2> >(stdbuf -o 0 sed 's/^/command2:/')
The output I get is:
command2:execve("/usr/bin/cat", ["cat"], [/* 50 vars */]) = 0
command2:brk(0) = 0x1938000
command2:mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f87e5a93000
command2:access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
<snip>
command2:open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
command2:fstat(3, {st_mode=S_IFREG|0644, st_size=106070960, ...}) = 0
command2:mmap(NULL, 106070960, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f87def8a000
command2:close(3) = 0
command2:fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
command2:fstat(0, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
command2:fadvise64(0, 0, 0, POSIX_FADV_SEQUENTIAL) = -1 ESPIPE (Illegal seek)
command2:read(0, "command1:execve(\"/usr/bin/ls\", ["..., 65536) = 4985
command1:execve("/usr/bin/ls", ["ls"], [/* 50 vars */]) = 0
command1:brk(0) = 0x1190000
command1:mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fae869c3000
command1:access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
<snip>
command1:close(3) = 0
command1:fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
command2:write(1, "command1:close(3) "..., 115) = 115
command2:read(0, "command1:mmap(NULL, 4096, PROT_R"..., 65536) = 160
command1:mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fae869c2000
one.txt
command1:write(1, "one.txt\n", 8) = 8
command2:write(1, "command1:mmap(NULL, 4096, PROT_R"..., 160) = 160
command2:read(0, "command1:close(1) "..., 65536) = 159
command1:close(1) = 0
command1:munmap(0x7fae869c2000, 4096) = 0
command1:close(2) = 0
command2:write(1, "command1:close(1) "..., 159) = 159
command2:read(0, "command1:exit_group(0) "..., 65536) = 53
command1:exit_group(0) = ?
command2:write(1, "command1:exit_group(0) "..., 53) = 53
command2:read(0, "command1:+++ exited with 0 +++\n", 65536) = 31
command1:+++ exited with 0 +++
command2:write(1, "command1:+++ exited with 0 +++\n", 31) = 31
and it hangs from then on. ps reveals that both commands in the pipeline (ls and cat here) are running.
I am on RHEL7 running Bash version 4.2.46.
I put a strace on your strace:
strace bash -c 'strace true 2> >(cat > /dev/null)'
It hangs on a wait4, indicating that it's stuck waiting on children. ps f confirms this:
24740 pts/19 Ss 0:00 /bin/bash
24752 pts/19 S+ 0:00 \_ strace true
24753 pts/19 S+ 0:00 \_ /bin/bash
24755 pts/19 S+ 0:00 \_ cat
Based on this, my working theory is that this effect is a deadlock because:
strace waits on all children, even the ones it didn't spawn directly
Bash spawns the process substitution as a child of the process. Since the process substitution is attached to stderr, it essentially waits for the parent to exit.
This suggests at least two workarounds, both of which appear to work:
strace -D ls 2> >(nl)
{ strace ls; true; } 2> >(nl)
-D, to quote the man page, "[runs the] tracer process as a detached grandchild, not as parent of the tracee". The second one forces bash to do another fork to run strace by adding another command to do after.
In both cases, the extra forks mean that the process substitution doesn't end up as strace's child, avoiding the issue.
I'm trying to write a simple script that loads my localhost network by setting up a netcat listener and piping random data to netcat broadcaster. My script is simple:
nc -l 2020 > /dev/null &
yes SOME_VERY_LARGE_STRING | nc localhost 2020 > /dev/null
Running each of those commands in different terminal windows has the desired effect. However, running from a bash script results in some data being transmitted before a SIGPIPE signal being sent to yes. This broken pipe can be verified by replacing the above with:
strace yes SOME_VERY_LARGE_STRING | nc localhost 2020 > /dev/null
which results in the following output:
execve("/usr/bin/yes", ["yes", "SOME_VERY_LARGE_STRING"], [/* 75 vars */]nc: Address already in use
) = 0
brk(0) = 0x1d53000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f04f185b000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/home/eddy/OpenSource/ros_packages/devel/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/home/eddy/OpenSource/ros_packages/devel/lib/tls/x86_64", 0x7fff4531cc20) = -1 ENOENT (No such file or directory)
open("/home/eddy/OpenSource/ros_packages/devel/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/home/eddy/OpenSource/ros_packages/devel/lib/tls", 0x7fff4531cc20) = -1 ENOENT (No such file or directory)
open("/home/eddy/OpenSource/ros_packages/devel/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/home/eddy/OpenSource/ros_packages/devel/lib/x86_64", 0x7fff4531cc20) = -1 ENOENT (No such file or directory)
open("/home/eddy/OpenSource/ros_packages/devel/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/home/eddy/OpenSource/ros_packages/devel/lib", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
open("/opt/ros/indigo/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/ros/indigo/lib/tls/x86_64", 0x7fff4531cc20) = -1 ENOENT (No such file or directory)
open("/opt/ros/indigo/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/ros/indigo/lib/tls", 0x7fff4531cc20) = -1 ENOENT (No such file or directory)
open("/opt/ros/indigo/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/ros/indigo/lib/x86_64", 0x7fff4531cc20) = -1 ENOENT (No such file or directory)
open("/opt/ros/indigo/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/opt/ros/indigo/lib", {st_mode=S_IFDIR|0755, st_size=16384, ...}) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=165844, ...}) = 0
mmap(NULL, 165844, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f04f1832000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P \2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1857312, ...}) = 0
mmap(NULL, 3965632, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f04f1272000
mprotect(0x7f04f1430000, 2097152, PROT_NONE) = 0
mmap(0x7f04f1630000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1be000) = 0x7f04f1630000
mmap(0x7f04f1636000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f04f1636000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f04f1831000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f04f182f000
arch_prctl(ARCH_SET_FS, 0x7f04f182f740) = 0
mprotect(0x7f04f1630000, 16384, PROT_READ) = 0
mprotect(0x605000, 4096, PROT_READ) = 0
mprotect(0x7f04f185d000, 4096, PROT_READ) = 0
munmap(0x7f04f1832000, 165844) = 0
brk(0) = 0x1d53000
brk(0x1d74000) = 0x1d74000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=7216688, ...}) = 0
mmap(NULL, 7216688, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f04f0b90000
close(3) = 0
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f04f185a000
write(1, "SOME_VERY_LARGE_STRING\nSOME_VERY"..., 4096) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=11094, si_uid=1000} ---
+++ killed by SIGPIPE +++
It would appear that netcat is failing with Address already in use. Why would that happen?
I downloaded a OctoPi and unziped the file in my local filesystem (EXT4):
$ unzip 2014-09-09-wheezy-octopi-0.10.0.zip
Just one file was unzipped:
-rwxrwxr-x 1 user user 3276800000 Oct 27 14:46 2014-09-09-wheezy-octopi-0.10.0.img
now I want to use image for SD card, but even cat file writes error (now as root, i tried that with user before):
# cat 2014-09-09-wheezy-octopi-0.10.0.img
cat: 2014-09-09-wheezy-octopi-0.10.0.img: Operation not permitted
I tried unzipping it to another location (different fs, USB stick) but it has the same behaviour.
also I tried the strace:
# strace cat 2014-09-09-wheezy-octopi-0.10.0.img
execve("/bin/cat", ["cat", "2014-09-09-wheezy-octopi-0.10.0."...], [/* 27 vars */]) = 0
brk(0) = 0x718000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1fb2a65000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=166255, ...}) = 0
mmap(NULL, 166255, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1fb2a3c000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1844160, ...}) = 0
mmap(NULL, 3949184, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1fb2480000
mprotect(0x7f1fb263a000, 2097152, PROT_NONE) = 0
mmap(0x7f1fb283a000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7f1fb283a000
mmap(0x7f1fb2840000, 17024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1fb2840000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1fb2a3b000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1fb2a39000
arch_prctl(ARCH_SET_FS, 0x7f1fb2a39740) = 0
mprotect(0x7f1fb283a000, 16384, PROT_READ) = 0
mprotect(0x60b000, 4096, PROT_READ) = 0
mprotect(0x7f1fb2a67000, 4096, PROT_READ) = 0
munmap(0x7f1fb2a3c000, 166255) = 0
brk(0) = 0x718000
brk(0x739000) = 0x739000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3165552, ...}) = 0
mmap(NULL, 3165552, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1fb217b000
close(3) = 0
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 1), ...}) = 0
open("2014-09-09-wheezy-octopi-0.10.0.img", O_RDONLY) = -1 EPERM (Operation not permitted)
write(2, "cat: ", 5cat: ) = 5
write(2, "2014-09-09-wheezy-octopi-0.10.0."..., 352014-09-09-wheezy-octopi-0.10.0.img) = 35
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1fb2a64000
read(3, "# Locale name alias data base.\n#"..., 4096) = 2570
read(3, "", 4096) = 0
close(3) = 0
munmap(0x7f1fb2a64000, 4096) = 0
open("/usr/share/locale/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_US/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpacsudo k/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": Operation not permitted", 25: Operation not permitted) = 25
write(2, "\n", 1
) = 1
close(1) = 0
close(2) = 0
exit_group(1) = ?
+++ exited with 1 +++
On different system (checked just one) I was able to read it.
I have Kubuntu 14.10 x64 with latest updates.
Linux mycomp 3.16.0-28-generic #38-Ubuntu SMP Fri Dec 12 17:37:40 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
Actually I write the image via pipes (it works):
unzip -p ... | pv | dd ...
but I want to know, why the file is not readable and where I do mistake.
....
Later I have the same experience with rapsbian:
wget -O 2014-12-24-wheezy-raspbian.zip http://downloads.raspberrypi.org/raspbian_latest
rename
mv 2014-09-09-wheezy-octopi-0.10.0.img initrd.gz
and then do unzip
As per the man page /proc/pid/exe is a symlink containing the actual path of the executed command..
when I run valgrind on my program, I see that /proc/pid/exe points to /usr/lib64/valgrind/amd64-linux/memcheck
lnx-host> which valgrind
/usr/bin/valgrind
Any idea why /proc/pid/exe points to usr/lib64/valgrind/amd64-linux/memcheck when I am invoking it as valgrind ?
In my code I am trying to get the executable name from the pid, and in this case expecting to see valgrind.
memcheck is the default tool used by Valgrind, unless you tell it to use another of the tools, such as callgrind.
Use --tool=<name> to specify the tool you want to invoke.
Side-note: is your /usr/bin/valgrind also a script just like it is by default? Why not play with that to do what you want to achieve? On my system that invokes first of all /usr/bin/valgrind.bin and then the respective (backend) tool (/usr/lib/valgrind/memcheck-amd64-linux).
Relevant output from strace:
execve("/usr/bin/valgrind", ["valgrind", "./myprog"], [/* 35 vars */]) = 0
stat("/home/user/HEAD/myprog", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
execve("/usr/bin/valgrind.bin", ["/usr/bin/valgrind.bin", "./myprog"], [/* 39 vars */]) = 0
open("./myprog", O_RDONLY) = 3
execve("/usr/lib/valgrind/memcheck-amd64-linux", ["/usr/bin/valgrind.bin", "./myprog"], [/* 40 vars */]) = 0
getcwd("/home/user/HEAD/myprog", 4095) = 25
open("./myprog", O_RDONLY) = 3
stat("./myprog", {st_mode=S_IFREG|0755, st_size=1886240, ...}) = 0
readlink("/proc/self/fd/3", "/home/user/HEAD/myprog/myprog", 4096) = 31
readlink("/proc/self/fd/3", "/home/user/HEAD/myprog/myprog", 4096) = 31
open("./myprog", O_RDONLY) = 3
write(1015, "./myprog", 8) = 8
write(1016, "==23547== Command: ./myprog\n", 28==23547== Command: ./myprog
stat("/home/user/HEAD/myprog/myprog", {st_mode=S_IFREG|0755, st_size=1886240, ...}) = 0
open("/home/user/HEAD/myprog/myprog", O_RDONLY) = 3
stat("/home/user/HEAD/myprog/myprog", {st_mode=S_IFREG|0755, st_size=1886240, ...}) = 0
open("/home/user/HEAD/myprog/myprog", O_RDONLY) = 3
open("/home/user/HEAD/myprog/myprog", O_RDONLY) = 3
readlink("/proc/self/fd/3", "/home/user/HEAD/myprog/myprog", 4096) = 31
getcwd("/home/user/HEAD/myprog", 4096) = 25
lstat("/home/user/HEAD/myprog/myprog", {st_mode=S_IFREG|0755, st_size=1886240, ...}) = 0
open("/home/user/HEAD/myprog/datafile", O_RDONLY) = 3
access("/home/user/HEAD/myprog/datafile", F_OK) = 0
open("/home/user/HEAD/myprog/datafile", O_RDONLY) = 3
open("/home/user/HEAD/myprog/datafile", O_RDONLY) = 4
You'll notice that all execve calls are not referring to ./myprog but instead to the Valgrind wrapper script, the binary and then the backend tool:
execve("/usr/bin/valgrind", ["valgrind", "./myprog"], [/* 35 vars */]) = 0
execve("/usr/bin/valgrind.bin", ["/usr/bin/valgrind.bin", "./myprog"], [/* 39 vars */]) = 0
execve("/usr/lib/valgrind/memcheck-amd64-linux", ["/usr/bin/valgrind.bin", "./myprog"], [/* 40 vars */]) = 0
When I do a vi filename from the command prompt, what fuse functions are called if I am using the fusexmp example ? I could guess mknod, open are called.
When I do a write ie when i do :wq write is called. is that right.
There's no fantastically easy way to see which FUSE functions are called for any given file operation, but running strace(1) will record the system calls, which is quite close to the FUSE functions:
$ strace -o /tmp/vim.all vim /etc/motd
A lot of those system calls aren't related to the one file specifically, but to the process of loading vim, its dynamically linked libraries, your local configuration, and all its supporting files.
Here's some selected lines that refer to the /etc/motd that I opened:
stat("/etc/motd", {st_mode=S_IFREG|0644, st_size=183, ...}) = 0
stat("/etc/motd", {st_mode=S_IFREG|0644, st_size=183, ...}) = 0
stat("/etc/motd", {st_mode=S_IFREG|0644, st_size=183, ...}) = 0
stat("/etc/motd", {st_mode=S_IFREG|0644, st_size=183, ...}) = 0
access("/etc/motd", W_OK) = -1 EACCES (Permission denied)
open("/etc/motd", O_RDONLY) = 7
close(7) = 0
open("/etc/motd", O_RDONLY) = 7
read(7, "Welcome to Ubuntu 11.04 (GNU/Lin"..., 8192) = 183
read(7, "", 65536) = 0
close(7) = 0
stat("/etc/motd", {st_mode=S_IFREG|0644, st_size=183, ...}) = 0
The intervening lines make the repeated stat(2) calls a little less silly looking.