Report: “ls -l”
Survivor’s logbook — by Roberto Ribeiro and Luciana Sarachu
Back home
What an intense journey! We are four crew members in the ship, two teams with the sole mission of discovering how the linux command interpreter works inside. My team is Luciana Sarachu and me. An excellent mix of “nerdism” at different levels of experience. Many things have happened, a rollercoster of emotions and we are back safe and sound. We made this report requested by Holberton School and it includes the story of our jornal.
Opening the doors
After several days of testing we are certain that in all cases, when it receives an order, its behavior always follows a series of patterns.
print_prompt
That blinking cursor is the shell waiting for instructions, it’s the beginning of an infinite loop (as long as everything goes right). We start writing — “$ l” — the system knows that we are entering something through its standard input and starts reading it while it stores it and displays what we type in the console. We keep typing until we get our “$ ls -l” command line. This is when everything starts…. We press enter….
get_line
The getline function is the one that is reading what we were typing, and saves everything in a string.
get_tokenization
We already entered the system unnoticed, but to it we are just a bunch of characters together with no apparent meaning. To give you an idea, our ship is at the beginning of the word “ls”.
We move forward, led by the system, to the tokenization process. This is the moment where the initial string is splitted into different bits, the first bit is where the letters start from until you find the first blank space and so on. Each bit is called a token. This action is done with the strtok function. Now the string we were in was transformed into a new string that has two tokens. We are in the first one with the “ls” and the next one has the “-l” stored.
built_ins
Leaving get_tokenization the system ejects us and we land precisely in the command check. The first check’s purpose is knowing if the command we enter is a built-in system function or not, since if it is a bultin are executed directly. We stay still without making noise in order to go through undetected. We see how they control the “ls” and decide what to do. We know we are not a bultin and we hold on tight to prepare for the next jump.
get_path
Again we are driven to a new function. The system must determine if the entire command is a program and can be executed. We share with the crew a nut mix while we observe how the shell loads the environment variable to determine in which we are and from where it should perform the execution. A light is turned on with the word “PATH” and its value contains all the absolute paths that are known in the system where there are programs to be executed. This value is stored in a new variable. Again, strtok is used to split the first path and uses as a delimiter the symbol “:”.
A new loop starts. It takes the first route, saves it into a new variable, adds at the end the symbol “/”; and then takes the token we are in, the one containing “ls” and adds it at the end again saving everything into a new variable. It’s time to check if “ls” is in that path, so it calls syscall “stat” to report if that file exists in that path. And so on until the correct path is found. From so many loops we are dizzy, but we see how the system fits us in the correct path: “/bin/ls”. The “stat” gives the ok and it comes a new jump to the new function that includes the execution process. Fasten your seat belts.
init_execution
Going to the new function, we see how the system calls the fork() function to clone itself, creating a new process (child process) to be executed at the same time as the first process (parent process). This is done so that the shell can return to the prompt after it completes or fails. The call to the branching system () will give the child process a PID, or a process identification number of 0, which helps differentiate it from the parent process which will be given a non-zero PID. While the execution is taking place the parent process will use a syscall wait(), to make sure it waits until the child process has been executed and completely finished.
If everything goes well, our ship will enter the child process and will be issued in the execution of the execve function.
And here we go, in the first element of the argv[] array, hidden in the “/bin/ls”, being issued from the system.
After this brief but complex process, we are going to get the output of our initial input “ls -l”: the program will print on screen all unhidden files and directories in the current working directory in long format.
What happens next is hard to get in an experiment, but we know
that the system continues its loops returning to the starting point
Ready for the next trip
We continue our return trip without any drawback… If you have any doubts about specific things, we are at your service. Have a good trip!