/* * 1.7ReadCommandsFromStandardInputAndExecuteThem.cpp * * Created on: Feb 11, 2015 * Author: sunyj */ #include <sys/wait.h> #include "../apuesunyj.h" int main() { char buf[MAXLINE]; pid_t pid; int status; printf("%% "); // print prompt (printf requires %% to print %) // We use the standard I/O function fgets to read one line at a time from the // standard input. When we type the end-of-file character (which is often // Control-D) as the first character of a line, fgets returns a null pointer, the loop // stops, and the process terminates. In Chapter 18, we describe all the special // terminal characters--end of file, backspace one character, erase entire line, and // so on -- and how to change them. // Because each line returned by fgets is terminated with a newline character, // followed by a null byte, we use the standard C function strlen to calculate the // length of the string, and then replace the newline with a null byte. We do this // because the execlp function wants a null-terminated argument, not a // newline-terminated argument. // We call fork to create a new process, which is a copy of the caller. We say that // the caller is the parent and that the newly created process is the child. Then // fork returns the non-negative process ID of the new child process to the parent, // and returns 0 to the child. Because fork creates a new process, we say that it is // called once--by the parent--but returns twice--in the parent and in the child. // In the child, we call execlp to execute the command that was read from the // standard input. This replaces the child process with the new program file. The // combination of fork followed by exec is called spawning a new process on // some operating systems. In the UNIX System, the two parts are separated into // individual functions. We'll say a lot more about these functions in Chapter 8. // Because the child calls execlp to execute the new program file, the parent // wants to wait for the child to terminate. This is done by calling waitpid, // specifying which process to wait for: the pid argument, which is the process ID // of the child. The waitpid function also returns the termination status of the // child--the status variable--but in this simple program, we don't do anything // with this value. We could examine it to determine how the child terminated // The most fundamental limitation of this program is that we can't pass // arguments to the command we execute. We can't, for example, specify the name // of a directory to list. We can execute ls only on the working directory. To allow // arguments would require that we parse the input line, separating the arguments // by some convention, probably spaces or tabs, and then pass each argument as a // separate parameter to the execlp function. Nevertheless, this program is still a // useful demonstration of the UNIX System's process control functions. while (fgets(buf, MAXLINE, stdin) != NULL) // if I type ls, buf is "ls " 3 character { if (' ' == buf[strlen(buf) - 1]) { buf[strlen(buf) - 1] = 0; // replace newline with null } if ((pid = fork()) < 0) { err_sys("fork error"); } else if (0 == pid) { // child // if the execlp execute successfully, execlp will not return // if it execute failed, return -1, and the error number store in errno variable execlp(buf, buf, static_cast<char*>(0)); err_ret("couldn't execute: %s", buf); return 127; } if ((pid = waitpid(pid, &status, 0)) < 0) { err_sys("waitpid error"); } printf("%% "); } return 0; }