The "Systems" Interview - a Few Pointers
Note: This article is about Systems Programming on Linux platforms.
This kind of interview checks what you know about what happens beneath the command-line surface. Down there, processes are created and terminated, output is collected, and system calls are made. Things get complicated quickly for anyone who is unprepared.
$ ls
This classic interview question has been asked for more than 15 years. It may not come up much anymore (as of 2016), but the answer is still instructive. The question is not about the file listing that appears on screen, but about everything that happens to produce it.
- The shell parses the command line and identifies the command and its arguments (none here).
- The shell works out whether the command is:
- a built-in (internal) command,
- an alias, or
- an external binary that must be located.
- On most systems,
lsis an alias for the real binary plus an option such as--color=auto. - As a safety step, the current directory is validated with
stat(".")before anything is executed. - The shell searches for the binary by walking through each directory in the
PATHenvironment variable. It appends the command name to each one and callsstat()on the result.lsis usually in/bin, so the search stops once/bin/lsis confirmed as executable. - The shell creates a new process with
fork(), then calls anexec()-family function to run the binary with the arguments determined earlier. - Boilerplate startup code runs: shared libraries are loaded, memory is allocated, signal masks are set, signal handlers are installed, and so on.
- Now the interesting part begins:
lsreads/proc/filesystemsand loads the current locale.- It opens the current directory with
opendir(). - It enumerates the entries with
readdir()and closes the directory withclosedir()(more memory may be allocated along the way). - It writes the directory contents to standard output with
write(1, ...).
- Finally,
lsreleases its memory and exits.
It’s more involved than it first looks, isn’t it?
$ ls | tee list.txt
The basic idea is simple: the standard output of ls is piped into the standard input of tee.
NB: stderr is not redirected in this case, so error messages will most likely go straight to the console.
The shell still parses and executes everything. The earlier details still apply: built-in vs. alias vs. external command, and a stat() in each PATH directory until the binary is found. The difference is that the shell now identifies and launches two external commands (ls and tee), each in its own process.
The “magic” happens before fork() and exec(). Roughly:
- The shell asks the kernel for an unnamed pipe with the
pipe()system call, which returns a read end and a write end. - The write end of the pipe is duplicated with
dup2()onto the stdout of the process that will runls. - The read end of the same pipe is duplicated with
dup2()onto the stdin of the process that will runtee. - The shell collects the exit codes of both child processes. Even if the first one produces no output, the second one still runs, with empty input.
An interviewer who knows this area well will probe how fork() and exec() behave at the kernel level. A strong candidate should be able to explain the following.
fork()duplicates the current process. Logically, nearly everything is copied: memory, file descriptors, and kernel resources such as references to shared memory segments or semaphores. Only the PID differs. If the process has several threads, only the thread that callsfork()is duplicated, which can cause many hard-to-find bugs.- Copy-on-write: the memory is not actually copied up front. Pages are marked read-only, and if either parent or child tries to modify one, a page fault occurs. The kernel then quietly duplicates the page and lets the write proceed.
exec()replaces the process image with that of the new binary, and the kernel frees the previously allocated memory. File descriptors without the close-on-exec flag (O_CLOEXEC) stay open and are available to the new program. By default, stdin, stdout, and stderr do not have this flag set.
As you can see, this kind of interview can get tough quickly. Fortunately, only a few companies run such “systems interviews,” and only for certain roles. If you have one coming up and spent a few minutes reading this, you’re likely better prepared than before. At least, that’s the hope. Thanks for reading!