Using fork and execve to Run Programs

Một phần của tài liệu Computer systems a programmers perspective randal e bryant, david r ohallaron (Trang 788 - 791)

Section 8.4 Process Control 753

Programs such as Unix shells and Web servers make heavy use of the fork and execve functions. A shell is an interactive application-level program that runs other programs on behalf of the user. The original she!\ was the sh program, which was followed by variants such as csh, tcsh, ksh, and bash. A shell performs a sequence of read/evaluate steps a9d then terminates. The read step reads a command line from the user. The evaluate step parses the command line and runs programs on behalf of the user.

Figure 8.23 shows the main routine of a simple shell. The shell prints a command-line prompt, waits for the user to type a command line on stdin, and then evaluates the command line.

Figure 8.24 shows the code that evaluates the command line. Its first task is to call the parseline function (Figure 8.25), which parses the space-separated command-line arguments and builds the argv vector that will eventually be passed to execve. The first argument is assumed to be either the name of a built-in shell command that is interpreted immediately, or an executable object file that will be loaded and run in the context of a new child process.

If the last argument is an'&' character, then parseline returns 1, indicating that the program should be executed in the background (the shell does not wait for it to compl~te ). Otherwise, it returns 0, indicating that the program should be run in the foreground (the shell waits for it to complete).

_,,, " ' ] . -.. ,., "f' ãl;"' ;'<'f' ~ :t- ãl't" ã -'r'' ,,,_, ttã IF' ... ti( t .,J)' 'ii . ..,, H l"j' ~

Asic;I~. Prow~-m~ yerws proce~se~- .. -1

i ã~1)1../' 1l

t1 H'

This is a ~ood place to .pause and make ,sure you understand the dis\inction between a program aqd

~process'. A programãiS '( c'olfecti01i"of e6Cle a11,d data; programs cah1'xisLas dbject files on disk or as

segn1~1,1ts ii{ ,?~fl' address Spa~e. A "Process i;'Ja sP.~cifiC':tinslailce .6i'si~prograrif in execution; a~ program.

"always'nin's'ii:dhe "COjltexi onom~ proeess. Underst'anding this distinction is important if you want fo uriderStanCT iiieãtO'i:-1( ~no e'Ơ.912Ve tfupC~iOns:ã The~fg\fk furic'tiO,n fUhs the Same Progãram. in a new child

"process that'is )l dupli~ate of t'hkp\lr~nt:Th.e:execvs'fuhcti,;-Il'f<lads'~nd 'nilis'a new program 'in the cqntext of th~ cnrr,~nt prpcess. 'While it ove~it~s t)le adc(ress sp,ace ol' th~ fltrr,ent process, it does not createã a newyroi;,ess, 1:he l)~'Y p.rogr~m,, ~t~U liy& i~~ sa~~:r.rrr. ã~vd it inherlfs'all of, the file descriptors

!hat were open ~t"the time of th'.~, call to t11,e e~e~v: ,p.inctton. ;t,J

.l' ,}.• '~ ..,, t,, ã~ 4\

I

t

754 Chapter 8 Exceptional Control Flow

- - - code/ecf!shellex.c 1 #include 11csapp.h"

2 #define MAXARGS 128

3

4 /* Function prototypes */

5 void eval(char *cmdline);

6 int parseline(char *buf, char **argv);

7 int builtin_command(char **argv);

8

9 int main()

10 {

11 char cmdline[MAXLINE] j /* Command line */

12

13 while (1) {

14 / • Read •/

15 printf("> 11) ;

16 Fgets(cmdline, MAXLINE, stdin);

17 if (feof (stdin))

18 exit(O);

19 20 21 22 23 }

}

/* Evaluate */

eval(cmdline);

- - - code/ecflshellex.c Figure 8.23 The main routine for a simple shell program.

After parsing the command line, the eval function calls the buil tin_ command function, which checks whether the first command-line argument is a built-in shell command. If so, it interprets the command immediately and returns 1. Otherwise, it returns 0. Our simple shell has just one built-in command, the quit command, which terminates the shell. Real shells have numerous commands, such as pwd,

jobs, and fg.

If builtin_command returns 0, then the shell creates a child process and executes the requested program inside the child. If the user has asked for the program to run in the background, then the shell returns to the top of the loop and waits for the next command line. Otherwise the shell uses the waitpid function to wait for the job to terminate. When the job terminates, the shell goes on to the next iteration.

Notice that this simple shell is flawed because it does not reap any of its background children. !=orrecting this fl~"( requires the use of signals, which we describe in the next section.

•l ãSection 8.4 Process Control 7..55 - - - codelecfrshel/ex.c

I* eval - Evaluate a command line */

2 void eval(char *cmdline)

3 {

4 char •argv[MAXARGS]; •/• Argument list execve() •I

5 char buf[MAXLINE]; /*Holds modified conunand line*/

6 int bg; /* Should the job run in bg or fg? */

7 pid_t pid; /* Process id */

8 9 10 11 12 13

strcpy(buf. cmdline),;ã !n

bg = parseline(buf, argv);

if (argv[O] == NULL)

return; I* Ignore empty lines */

14 if (!builtin_comman,d(argv)) {

15 if ( (pid = Fork()) == 0) { /• Child runs user~jpb •/

16 if (execve(argv[O]. argv, environ) < O) {

17 printf(11%s: Command not found.\n1' , argv[O]);

18 exit(O)j

19 20 21

} }

22 I* Parent waits for foreground job to terminate */

23 if ( ! bg) {

24 int status;ã

25 if (waitpid(pid, &status, 0) < 0)

26 unix_error("waitfg: ;waitpid<~rror");

27 }

28 else

29 printf("%d %s11, pid, cmdline);

30 }

31 return;

32 } 33

34 /* If first arg is a builtin command', run it and return <tfue */

35 int builtin_command(char **a~gv) {

36 37 38 39 40

if (!strcmp(argv[O], 11quit11) ) /* quit command *I exit(O);

i f (!strcmp(argv[O], "&"))

1Z.ettlrn 1;

/* Ignore singleton & */

41 return O; I* Not a ~uiltin command */

42 ., }

---~----code{ecflshellex.c

Figure 8.24 eval evaluates the shell cb'mmand line. '

756 Chapter 8 Exceptional Control Flow

- - - code/ecflshellex.c /* parseline - Parse the command line and build the argv array */

2 int parseline(char *buf, char **argv)

3 {

4 5 6 7 8 9 10 11

char *delimj int argc;

int bg;

buf[strlen(buf)-1]

while (•buf && (•buf buf++;

/* Points to first space delimiter *f /* Number of args */

!• Background job? •/

' '. ' /* Replace trailing 1\n1 with space */

')) /* Ignore leading spaces */

12 /* Build the argv list */

13 argc = 0;

14 while ((delim = strchr(buf,' '))) { 15 argv[argc++] = buf;

16 *delim = 1\01; 17 buf = delim'+ lj

18 while (•buf && (•buf ' ')) /• Ignore spaces •/

19

20 }

buf++;

21 argv [argc] = NULL;

22

23 if (argc == 0) !• Ignore blank line •/

24 return 1;

25

26 I* Should the job run in theã~background? */

27 i f ((bg = (•argv[argc-1] == '&')) != 0) 28 argv[--argc] = NULL;

29

30 return bg;

31 }

- - - code!ecflshellex.c Figure 8.25 parseline parses a line of input for the shell.

Một phần của tài liệu Computer systems a programmers perspective randal e bryant, david r ohallaron (Trang 788 - 791)

Tải bản đầy đủ (PDF)

(1.120 trang)