This video introduces the exec family of system and library calls, and the "fork/exec/wait" idiom. So far we've seen fork and wait. The fork system call creates a new process; the wait system call waits for a process to terminate and collects its exit status. But what does that child process do? We might have code of our own which we want it to execute, and that's the model we've seen so far. Or, we might have a situation like when we type commands to the shell, where the shell forks and the child process executes a separate program. For example, you type "ls" to the shell prompt; the shell forks; the child process runs the "ls" program; and the parent process does a wait() so that the next shell prompt is not printed until "ls" has terminated. This is what the exec system call does. When a process calls exec, it gets REPLACED with a different program, which it specifies. The child process gets replaced with the ls program. The replacement program is the same process, in that it has the same process ID number, and the same connection to the parent process. When that parent process calls wait(), it now waits for the ls program. The code looks like this: We call fork. If it returns -1 for error, we call perror(), and do not proceed. Otherwise, if fork succeeds, there are now two processes. One process called fork(), but two processes got a return from fork! The two processes differ in the return value from fork, which is how they decide which is which and what to do next. If fork() returns zero, then we are the child process. Here we call a member of the exec family named "execl". The six different exec functions differ only in how the arguments to them are packaged up, not in what the function does. One of the six exec functions is the actual system call, and the other five just repackage their arguments and then call the real system call. In this case we're calling execl. 'l' stands for "list". The various arguments to the command are just listed there as separate parameters. For hard-coded commands like this, execl is often the easiest call to use. The first argument is the program to execute. The subsequent arguments are argv. Here we're giving ls an argv[0] of "ls", and an argv[1] of "file". Now, you might be expecting us to check the return value from execl for an error condition. My failure to check the return value is not borne out of optimism that it succeeds. Quite the opposite -- at this point in the code I'm assuming that execl has failed! Why do I assume THAT? Because, if the exec succeeds, we won't be here! What exec does is to replace this program with another one. If ls is running instead of us, we won't be here. However, if there is an error, then we will be here, and we don't have to check for error, we know there's an error, that's why we're still here. So we can proceed to call perror() and terminate this process with a non-zero exit status. All this is in the child. This was all just if x equals zero, meaning that fork said that we are the child process. Alternatively, if fork returns a positive number, then we are the parent process. The parent process will in this case _wait_ for the child process, in the way you've seen before in these videos. The other exec family call you will need in this course is execve(). It takes an array argument which is all of the argv values. Again the first argument to execve is the file path name to execute. The second argument is an array of argv members. The third argument is the "environment" -- the list of environment variables. There's a global variable named "environ" which you can just pass along so that environment variables are inherited in the way we expect. You may be wondering where argc is, or how execve knows the size of the array passed as its second argument. The answer is that the array has a marker in it to indicate the end -- after all of the argv values, you put a NULL pointer, as we're doing here, and that marks the end of the array. Note that we left space for it when figuring out how large to make the array.