What happens when you type ls -l in the shell ?
ls is a shell command that lists files and directories within a directory. With the -l option, ls will list out files and directories in long list format.
What really happens ?
The shell reads the command from standard input that was entered by the user. Second, after you type your command, the shell reads what you typed using the getline function. The getline function reads the entered line as one string, from the standard input and stores it in a buffer.
The getline() Function:
The latest and most trendy function for reading a string of text is getline(). It’s a new C library function, having appeared around 2010 or so.
You might not have heard of the getline() function, and a few C programmers avoid it because it uses — brace yourself — pointers! Even so, it’s a good line-input function, and something you should be familiar with, even if you don’t plan on using it.
Here’s a typical getline() statement:
The getline() function is prototyped in the
stdio.h header file. Here are the three arguments:
&buffer is the address of the first character position where the input string will be stored. It’s not the base address of the buffer, but of the first character in the buffer. This pointer type (a pointer-pointer or the
** thing) causes massive confusion.
&size is the address of the variable that holds the size of the input buffer, another pointer.
stdin is the input file handle. So you could use getline() to read a line of text from a file, but when
stdin is specified, standard input is read.
After reading the line and storing it in the buffer, the getline returns an int/ssize_t which is equal to:
- The number of characters read, on success, without including the terminating null byte of the string.
2. -1, on failure to read a line (including end-of-file condition).
Parsing The User Input:
A string tokenization function is called which splits the command line into tokens. In our shell, we used a function called
strtok() which took the line to tokenize and the delimiter to define token boundaries
Take for example the command:
ls -la /
We have the name of the binary (ls) and its arguments.
the command could also be:
$ ls -la /
We are going to write a function that will store our command (without spaces) in a char ** Which will give:
The shell checks if the first token (the main command itself) is an alias, and if so, replaces the alias with the actual command.
The shell will typically look in its system files for defined aliases. If the
ls command is an alias for something else, the shell will replace the
ls token with the string for the command that
ls represents so that the correct operation takes place in the subsequent steps.
To execute our order we will use syscall
We must use syscall
forkto create a new process and launch our command in it.
fork() system call is used to create child processes in a C program. fork() is used where parallel processing is required in your application. The fork() system function is defined in the headers sys/types.h and unistd.h. In a program where you use fork, you also have to use wait() system call. wait() system call is used to wait in the parent process for the child process to finish. To finish a child process, the exit() system call is used in the child process. The wait() function is defined in the header sys/wait.h and the exit() function is defined in the header stdlib.h.
fork returns twice: once in the parent and once in the child. After calling
fork, the program can use the fork return value to tell whether executing in the parent or child.
- If the return value is
0the program executes in the new child process.
- If the return value is greater than zero, the program executes in the parent process and the return value is the process ID (PID) of the created child process.
- On failure
NB : By sending a simple command like holberton to our shell,
execvewe return -1 and
perror display ./hsh: 3: holberton: not found.
To find where a program is, we need to use the environment variable
If we execute the command:
$> echo $PATH
We are going to have an output that looks like this:
These are the files (separated by ‘:’) or our Shell will look for our binary to execute.
We now need to write the function that will concatenate our path and the binary.
You must retrieve the content of the $ PATH variable with the function
getenv. It takes a single parameter which is the variable we are looking for and returns a pointer to the content of the variable passed as a parameter.
If our binary is not in any folder, we can warn the user by one
Command not found, otherwise we can execute our execve: D.
The function that retrieves the content of the $ PATH variable and returns the absolute path :D
At this point, our shell executes a command but has no builtin or environment.