From 89ab0f0a2dba571a7caee45717135b6245664952 Mon Sep 17 00:00:00 2001 From: bverschueren Date: Sun, 24 May 2015 19:18:09 +0000 Subject: [PATCH] removed some left-over # in the output rephrased I/O added codeblock for I/O enhanced formatting last paragraph add bullet points to output options some rephrasing forgot rm in the bash example rephrase output tuning command some newlines added some more newlines some more newlines and more newlines more newlines some more newlines reformatted with newlines --- syscalls.rst | 92 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/syscalls.rst b/syscalls.rst index 50ee7e9..cb1cce9 100644 --- a/syscalls.rst +++ b/syscalls.rst @@ -23,17 +23,27 @@ Consider the simple script: do echo $line > my_output.txt done < my_input.txt + rm my_input.txt -Executing ---------- +Exec +---- -When invoking this script using ``strace -omy_strace.log -ff ./strace_sample.sh``, the output of every (forked) process is written to strace.log.. -Let's examine the logfile (parts of the output are omitted, let's focus on the relevant stuff) : +When invoking this script using ``strace -omy_strace.log -ff ./strace_sample.sh``, the output of every (forked) process is written to my_strace.log.. +Let's examine the logfile of our parent process (parts of the output are omitted, let's focus on the relevant stuff) : .. code-block:: console execve("./strace_sample.sh", ["./strace_sample.sh"], [/* 17 vars */]) = 0 - <..> + + +``execve`` executes the file "strace_sample.sh" with arguments "./strace_sample.sh" (by convention the first should be the filename to be executed) and 17 environmental variables. +At this point there are already 3 file descriptors open: stdin (fd 0), stdout (fd 1), stderr (fd2). + +I/O +--- + +.. code-block:: console + open("./strace_sample.sh", O_RDONLY|O_LARGEFILE) = 3 <..> read(3, "#!/bin/bash\necho \"one line of te"..., 80) = 80 @@ -44,17 +54,15 @@ Let's examine the logfile (parts of the output are omitted, let's focus on the r read(255, "#!/bin/bash\necho \"one line of te"..., 126) = 126 <..> -I/O ---- - -``execve`` executes the file "strace_sample.sh" with arguments "./strace_sample.sh" (by convention the first should be the filename to be executed) and 17 environmental variables. -Then ``open`` opens the file for reading in file descriptor 3. +``open`` prepares the file for reading in file descriptor 3 (result of the syscall ``open``). Next, ``read`` attempts to read the next 80 bytes from fd (file descriptor) 3. + At this point the interpreter line of the script is read, indicating that the /bin/bash binary needs to be invoked to process the script. ``dup2`` copies the fd 3 to the (new) fd 255. -This is a bash-specific operation, don't mind to much; bash keeps the original file in fd 255 (last of the process' private fd) to free up low-numbered fd's. -Now that our original file is in fd 255, fd 3 is not needed anymore and can be closed by ``close``. -At last the next 126 (rest of the file) bytes are read and stored in the bufferi, now we can start to process the commands in the script file. +This is a bash-specific operation, don't mind too much; bash keeps the original file in fd 255 (last of the process' private fd) to free up low-numbered fd's. + +Now that our original file is open in fd 255, fd 3 is not needed anymore and can be closed by ``close``. +At last the next 126 bytes (rest of the file) are read and stored in the buffer, now we can start to process the commands in the script file. .. code-block:: console @@ -66,19 +74,18 @@ At last the next 126 (rest of the file) bytes are read and stored in the bufferi close(3) = 0 write(1, "one line of text\n", 17) = 17 dup2(10, 1) = 1 - # Copy fd 10 to fd 1 => revert the redirection, this is why the original value of fd 1 was saved <..> close(10) = 0 - # Close fd 10 -First, ``open`` the my_input.txt file in fd 3. -Then, ``fcntl64`` uses F_DUPFD (10) to get the next available fd numbered >=10 and copy fd 1 to the new fd 10. -This saves the original content of fd 1, which is stdout. -Next ``dup2`` copies fd 3 to fd 1 (fd 1 which by the process is still used for stdout) and closes fd 3. -The ``write`` call writes the next 17 bytes to fd 1 (which it sees as stdout, but at this moment it points to my_input.txt). +Now we're going to write to a file using redirection. +First, ``open`` opens/creates the "my_input.txt" file for writing in fd 3. +Then, ``fcntl64`` uses F_DUPFD (10) command to get the next available fd numbered >=10 and copy fd 1 (initially opened for stdout) to the new fd 10. +This saves the original content of fd 1 (stdout), so it can be restored later. + +Next ``dup2`` copies fd 3 to fd 1 so that writing to fd 1 ends up in the file opened by fd 3. +The ``write`` call then writes the next 17 bytes from the buffer to fd 1. Afterwards the redirection is reverted, by copying fd 10 (original value for fd 1) back to fd 1. -fd 1 now points to stdout as desinged by default. -fd 10 is closed as its not needed any longer. +Now fd 1 points to stdout as in our initial situation. The fd's which are not needed any longer are closed. .. code-block:: console @@ -93,12 +100,10 @@ fd 10 is closed as its not needed any longer. open("my_output.txt", O_WRONLY|O_CREAT|O_APPEND|O_LARGEFILE, 0666) = 3 <..> fcntl64(1, F_DUPFD, 10) = 11 - # Copy fd 0 to fd 11 (which is not the lowest available fd >= 10) to save the original stdout <..> dup2(3, 1) = 1 close(3) = 0 write(1, "one line of text\n", 17) = 17 - # Write 17 bytes to fd 1 (which is stdout, redirected to my_output.txt) dup2(11, 1) = 1 <..> close(11) = 0 @@ -107,17 +112,21 @@ fd 10 is closed as its not needed any longer. <..> close(10) -Again, ``open`` my_input.txt in fd 3. +This time we'll both read and write using redirection. + +Again, ``open`` prepares "my_input.txt" for reading in fd 3. This time, save fd 0 (by default stdin) to fd 10. -``dup2`` copies fd 3 to fd 0 (redirecting my_input.txt to stdin) and close fd 3. -Next, read the next 128 bytes from fd 0 (my_input.txt) and save to the buffer. -Next ``open`` "my_output.txt" in fd 3. -Then ``fcntl64`` uses F_DUPFD (10) to get the next available fd >= 10 (which at this point is 11 as fd 10 is already open) and copy fd 1 to it. -Redirect stdout to my_output.txt by copying fd 3 to fd 1 with ``dup2``. -Now fd 3 can be closed. -Finally, write 17 bytes from the buffer to fd 1. +``dup2`` copies fd 3 to fd 0 (redirecting "my_input.txt" to stdin) and close fd 3. +Next, read the next 128 bytes from fd 0 ("my_input.txt") and save to the buffer. + +Then, "my_output.txt" is opened (created) for writing in fd 3. +Now ``fcntl64`` uses F_DUPFD (10) to get the next available fd >= 10 (which at this point is 11 as fd 10 is already open) and copy fd 1 to it. +The fd 3 is copied to fd 1 using ``dup2``. + +Finally, write 17 bytes from the buffer to fd 1, which at this moment points to "my_output.txt". The redirection is reverted by copying fd 11 to fd 1 with ``dup2``, and fd 11 can be closed. -A next attempt to ``read`` from fd 0 is done, resulting in 0 bytes read, indicating the end of file is reached. + +A next attempt to ``read`` from fd 0 results in 0 bytes read, indicating the end of file is reached. The redirection is reverted by copying fd 10 to fd 0 and closing fd 10. ``exec``, ``open``, ``close``, ``read`` and ``write`` are handled. Let's look at creating child processes and removing files. @@ -136,6 +145,12 @@ The logging of this child process is logged in the second my_strace.log. fi execve("/bin/rm", ["rm", "my_input.txt"], [/* 17 vars */]) = 0 <..> + +Unlink +------ + +.. code-block:: console + newfstatat(AT_FDCWD, "my_input.txt", {st_mode=S_IFREG|0644, st_size=17, ...}, AT_SYMLINK_NOFOLLOW) = 0 faccessat(AT_FDCWD, "my_input.txt", W_OK) = 0 unlinkat(AT_FDCWD, "my_input.txt", 0) = 0 @@ -146,8 +161,9 @@ The logging of this child process is logged in the second my_strace.log. fi The ``rm`` command is executed using ``execve``, with arguments "rm" (as per convention this is the filename to be executed) and "my_input.txt". ``newfstatat`` gets the file status and ``faccessat`` check the file permissions of the file. -Finally, ``unlinkat` removes the file's name from the filesystem. -If that name was the last link to a file and no processes have the file open the file is deleted and the space it was using is made available for reuse. + +Finally, ``unlinkat`` removes the file's name from the filesystem. +If that name was the last link to a file and no processes have the file open, the file is deleted and the space it was using is made available for reuse. As a last step for this process the 3 standard fd's are closed, and ``exit_group`` exits all possible threads in the process. Again in the parent's logfile, the interaction with the child process is logged. @@ -194,9 +210,9 @@ This can come in handy to troubleshoot specific system calls. A list of available syscalls can be seen in ``man syscalls``. For more details on a syscall, look it up in the man page. Some syscalls have several variant and might be referenced in strace output with different names; try to look them up without certain prefixes to find the relevant man pages. -For performance reasons the ``-T`` and ``-c`` flags are usefull: +For performance measuring the ``-T`` and ``-c`` flags are usefull: --T Show the time spent in system calls. This records the time difference between the beginning and the end of each system call. --c Count time, calls, and errors for each system call and report a summary on program exit. +- ``-T`` Show the time spent in system calls. This records the time difference between the beginning and the end of each system call. +- ``-c`` Count time, calls, and errors for each system call and report a summary on program exit.