What happens when you type ls -l in the shell (Simple_shell project)
Published: 2020-04-19 15:21:43

Recently I and my partner we have write a Simple_shell project source code, in which we need to recreate a user interface works the same way as Unix shell that takes commands form the keyboard and gives them to OS to perform. So basically we had to deal with the creation of a prompt where the user can type a command and hit enter to execute it. In this topic we’ll take “ls” command as a command line example to unearth with details what happen behind the scene.

Overview:

    What is shell
    What is terminal
    What is a command line
    Understand how OS perform task/program
    Creating processes
    Execute “ls -l” command
    How shell works “general steps”

1- What is Shell:

In Unix system logically there are two different areas: the Kernel and the utilities (or everything else), and basically all accessed through the Shell.

The Kernel is the heart of the Unix system and it’s resides in the memory of the computer from the boot time and keeps on until the shutdown. The utilities resides in the computer disk and are only brought into memory and executed as requested. Basically every Unix command it’s an utility/program resides in the disk and it’s only brought into memory only at your request. For example if you execute a command line such as “ls” to list the files in a given directory, the Unix system loads the program into memory and specifies the actions following of the source code. Our shell is also an program and it’s brought to memory only et the request and it allow to you to interact with the Kernel to execute other programs or applications.

It’s important to recognize that the shell is just a program. It has no special privileges on the system, meaning that anyone with sufficient expertise and enthusiasm can create their own shell. That’s why so many different variations or “flavors” of the shell exist today, including the older Bourne shell, developed by Stephen Bourne; the Korn shell, developed by David Korn; the “Bourne again shell,” mainly used on Linux systems; and the C shell, developed by Bill Joy. They were all designed to serve specific purposes and have their own unique capabilities and personalities.

2- What is the terminal:

In the old days, terminals were physical devices that were connected to the Unix hardware through a direct wire. Nowadays, however, terminal programs let you stay within your Linux, Mac or Windows environment and interact with the system over the network in a managed window. So terminal it’s an emulator allows the user type and execute programs from the keyboard.

3- What is a command line:

The command line is a text interface for the computer, it’s Often referred to as the shell, terminal, console, prompt or various other names. From the command line you can pass can navigate through files and directory on you computer. Also command line is a quick, powerful, text-based interface developers use to more effectively and efficiently communicate with computers to accomplish a wider set of tasks.

4- Understand how Shell perform task/program:

During the booting of system, the kernel execute the “init” process as a boot loader that loads kernel image and call start_kernel(), also its role is to create all processes that are responsible to execute all programs set in the OS from a script stored in the file /etc/inittab, so from this resume the init is the parent of all processes and its ID is 1 (init can resist to signal 9 that kill processes and it starts running from the boot of the system until it’s shutdown).
the init process with PID 1 and all processes children after.
5- Creating process:

The concept of processes is fundamental to the Unix/Linux operating systems, and all running instance of a program is known as a process. The way to distinguish processes has it’s by ID or identifier and each process has it’s own ID. The ID is a non negative number and associated with the process.

To create a process Unix system has it’s own tools and are what we call system calls. The fork() function it’s a system call to create a new process and technically a child process, for example if we want to run a program or execute a command from terminal like in our case, the system create a child process to perform by fork an existing ID parent process and it’s terminate generally by creating two IDs one is the PID identifier of the parent and the second is ID identifier of the child, to be sure that the call process is terminate we can use the call system wait() to block parent process until it’s done:

pid_t wait(int *status);

If the parent process has more than one child we can use the system call waitpid():

pid_t waitpid(pid_t pid, int *status, int options);

By default, waitpid() waits only for terminated children, but this behavior is modifiable via the options argument, as described below.

The value of pid can be:

    * < -1 : Wait for any child process whose process group ID is equal to the absolute value of pid.
    * -1 : Wait for any child process.
    0 : Wait for any child process whose process group ID is equal to that of the calling process.
    * > 0 : Wait for the child whose process ID is equal to the value of pid.

The value of options is an OR of zero or more of the following constants:

    * WNOHANG : Return immediately if no child has exited.
    * WUNTRACED : Also return if a child has stopped. Status for traced children which have stopped is provided even if this option is not specified.
    * WCONTINUED : Also return if a stopped child has been resumed by delivery of SIGCONT.

creation of the child process and wait for its status from the parent.

6- Execute “ls -l” command:

Now we have different process run the same program, to execute another program we can exec() family system call. In our case we used the execve() function which by definition execute a binary executable or a script. The function returns nothing on success and -1 on error.

int execve(const char *filename, char *const array[], char *const envp[])

    -The first parameter must be the path of a binary executable or a script.
    -The second must be an array of pointers on a character (char *const array[]), and the last pointer must be set to NULL.
    -The third parameter must be an environment.

7- Extra: How shell works “general steps”:

Basically, there 3 steps to perform a command or an executable in shell.

First: typically shell would read and execute its configuration files. These change aspects of the shell’s behavior.

Second: the shell reads commands from stdin (which could be interactive, or a file) and executes them.

Finally: After its commands are executed, the shell executes any shutdown commands, frees up any memory, and terminates.

Note: the code shared above is a part of the simple_shell project source code.