Execute a Program: the execvp() System Call
The created child process does not have to run the same program as the parent process does. The exec type system calls allow a process to run any program files, which include a binary executable or a shell script. On this page, we only discuss one such system call: execvp(). The execvp() system call requires two arguments:- The first argument is a character string that contains the name of a file to be executed.
- The second argument is a pointer to an array of character strings. More precisely, its type is char **, which is exactly identical to the argv array used in the main program:
Note that this argument must be terminated by a zero.
int main(int argc, char **argv)
execvp() returns a negative value if the execution fails (e.g., the request file does not exist).
The following is an example (in file shell.c). Click here to download a copy.
Function parse() takes an input line and returns a zero-terminated array of char pointers, each of which points to a zero-terminated character string. This function loops until a binary zero is found, which means the end of the input line line is reached. If the current character of line is not a binary zero, parse() skips all white spaces and replaces them with binary zeros so that a string is effectively terminated. Once parse() finds a non-white space, the address of that location is saved to the current position of argv and the index is advanced. Then, parse() skips all non-whtitespace characters. This process repeats until the end of string line is reached and at that moment argv is terminated with a zero.
#include <stdio.h> #include <sys/types.h> void parse(char *line, char **argv) { while (*line != '\0') { /* if not the end of line ....... */ while (*line == ' ' || *line == '\t' || *line == '\n') *line++ = '\0'; /* replace white spaces with 0 */ *argv++ = line; /* save the argument position */ while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n') line++; /* skip the argument until ... */ } *argv = '\0'; /* mark the end of argument list */ } void execute(char **argv) { pid_t pid; int status; if ((pid = fork()) < 0) { /* fork a child process */ printf("*** ERROR: forking child process failed\n"); exit(1); } else if (pid == 0) { /* for the child process: */ if (execvp(*argv, argv) < 0) { /* execute the command */ printf("*** ERROR: exec failed\n"); exit(1); } } else { /* for the parent: */ while (wait(&status) != pid) /* wait for completion */ ; } } void main(void) { char line[1024]; /* the input line */ char *argv[64]; /* the command line argument */ while (1) { /* repeat until done .... */ printf("Shell -> "); /* display a prompt */ gets(line); /* read in the command line */ printf("\n"); parse(line, argv); /* parse the line */ if (strcmp(argv[0], "exit") == 0) /* is it an "exit"? */ exit(0); /* exit if it is */ execute(argv); /* otherwise, execute the command */ } }
For example, if the input line is a string as follows:
Function parse() will return array argv[] with the following content:
"cp abc.CC xyz.TT"
The main program is very simple. It prints out a command prompt, reads in a line, parses it using function parse(), and determines if the name is "exit". If it is "exit", use exit() to terminate the execution of this program; otherwise, the main uses execute() to execute the command.
No comments:
Post a Comment