25
Lecture: Putting it all together: Launching Programs
Outline:
Announcements
fork()
loads a new program
Loading a new program: The execs
The Environment of a Unix Process
Example: exectest.c
Shell Examples
Selected Midterm Solutions
25.1
Announcements
• Coming attractions:
Event
Subject
Due Date
Notes
lab07
forkit
Fri
Jun 4
23:59
Use your own discretion with respect to timing/due dates.
• Final plans
• timer lab reminder
• pow(3), just no...
25.2
fork()
loads a new program
25.3
Loading a new program: The execs
syscall
prototype
execl
int execl( const char *path, const char *arg, ...);
execlp
int execlp( const char *file, const char *arg, ...);
execle
int execle( const char *path, const char *arg , ..., char * const envp[]);
execv
int execv( const char *path, char *const argv[]);
execvp
int execvp( const char *file, char *const argv[]);
execve
int execve (const char *filename, char *const argv [], char *const envp[]);
25.4
The Environment of a Unix Process
One of the things we discussed as being preserved is the environment
• main() is called with argc and argv (by crt0, added by the linker). These args come from the
kernel.
argc
is the count, argv is a null terminated array of pointers to strings.
• Each has its own uid, gid, pid (getpid()), pwd, etc.
• Every process has a parent (getppid());
• and its own environment— a series of strings
fork()
exec()
Preserves:
• open file descriptors (dup()-style)
• identity
• current working directory
• current root directory
• signal mask and handlers
• umask
• environment
• resource limits
• process id
• parent process id
• real uid and gid
• open file descriptors (dup()-style)
(unless close-on-exec is set)
• pending alarms
• current working directory
• current root directory
• umask
• environment
• signal mask
• pending signals
• run time values
Changes:
• process id
• parent process id
• return value of fork()
• pending alarms are cleared
• interval timers are cleared
• pending signals are cleared
• child’s run times are reset
• effective uid and gid if suid
• just about everything else (entire
contents of memory)
but now, a NULL-terminated global list of strings:
char *environ[]
SYNOPSIS
#include <stdlib.h>
char *getenv(const char *name);
int setenv(const char *name, const char *value, int overwrite);
void unsetenv(const char *name);
FWIW, this explains the difference between shell variables and environment variables.
25.4.1
Example: exectest.c
How to launch another process:
1. create pipe(s)
2. fork()—file descriptors are duped on fork()
3. child: use dup2() to dup appropriate ends to approprate fds
4. parent and child both close un-used ends
5. child execs program...
Figures 106 and 105 show an example of using a pipe to read the output of a child process execing
/bin/ls.
void cat (int in, int out) {
/* copy the infile to the outfile */
int num;
char buffer[MAX];
while ( (num=read(in, buffer, MAX)) > 0 ) {
if ( write(out,buffer,num) < 0 ) {
perror("write");
break;
}
}
if ( num < 0 ) {
perror("read");
}
}
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define READ END 0
#define WRITE END 1
#define MAX 256
void cat (int in, int out) ;
int main(int argc, char *argv[]){
int newpipe[2];
pid t child;
char *prog;
if ( pipe(newpipe) < 0 ) {
perror("pipe");
exit(−1);
}
child=fork();
if ( child == 0 ) {
/* child */
if ( dup2(newpipe[WRITE END], STDOUT FILENO) == −1 ) {
perror("dup2");
}
close(newpipe[READ END]);
/* we’re not going to use it */
prog = "/bin/ls";
execl(prog,prog,NULL);
perror("exec");
exit(−1);
/* child exits by this point whether or not exec() succeeds */
}
/* only parent gets here */
close(newpipe[WRITE END]);
/* otherwise program (cat) will hang */
cat(newpipe[READ END],STDOUT FILENO);
wait(NULL);
/* what’re we gonna do if it fails? */
return 0;
o r i g i n a l s t d i n o r i g i n a l s t d o u t 0 1 2 3 4 5 6 7 i n t o n e [ 2 ] ; i n t t w o [ 2 ] ; ---here---p i ---here---p e ( o n e ) ; p i p e ( t w o ) ; fork(); fork(); fork(); c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; wait(); o r i g i n a l s t d e r r
Figure 107: At the start of the program
o r i g i n a l s t d i n o r i g i n a l s t d o u t 0 1 2 3 4 5 6 7 i n t o n e [ 2 ] ; i n t t w o [ 2 ] ; p i p e ( o n e ) ; p i p e ( t w o ) ; ---here---fork(); fork(); fork(); c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; wait(); o r i g i n a l s t d e r r w r i t e e n d p i p e 1 r e a d e n d w r i t e e n d p i p e 2 r e a d e n d
Figure 108: Before the forks
25.4.2
Shell Examples
• Fork all children: don’t do them sequentially. (otherwise deadlock may result. (also consider
the effect on signal handling))
o r i g i n a l s t d i n 0 1 2 3 4 5 6 7 i n t o n e [ 2 ] ; i n t t w o [ 2 ] ; p i p e ( o n e ) ; p i p e ( t w o ) ; fork(); fork(); fork(); ---here---c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; wait(); 0 1 2 3 4 5 6 7 ... ---here---d u p 2 ( o n e [ W R I T E ] , S T D O U T _ F I L E N O ) ; c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; e x e c ( l s ) ; 0 1 2 3 4 5 6 7 ... ---here---d u p 2 ( o n e [ R E A D ] , S T D I N _ F I L E N O ) ; d u p 2 ( t w o [ W R I T E ] , S T D O U T _ F I L E N O ) ; c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; e x e c ( s o r t ) ; 0 1 2 3 4 5 6 7 ... ---here---d u p 2 ( t w o [ R E A D ] , S T D I N _ F I L E N O ) ; c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; e x e c ( m o r e ) ; o r i g i n a l s t d o u t o r i g i n a l s t d e r r w r i t e e n d p i p e 1 r e a d e n d w r i t e e n d p i p e 2 r e a d e n d
Figure 109: After the forks
o r i g i n a l s t d i n 0 1 2 3 4 5 6 7 i n t o n e [ 2 ] ; i n t t w o [ 2 ] ; p i p e ( o n e ) ; p i p e ( t w o ) ; fork(); fork(); fork(); c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; ---here---wait(); 0 1 2 3 4 5 6 7 ... d u p 2 ( o n e [ W R I T E ] , S T D O U T _ F I L E N O ) ; c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; ---here---e x ---here---e c ( l s ) ; o r i g i n a l s t d o u t o r i g i n a l s t d e r r w r i t e e n d p i p e 1 r e a d e n d 0 1 2 3 4 5 6 7 ... d u p 2 ( o n e [ R E A D ] , S T D I N _ F I L E N O ) ; d u p 2 ( t w o [ W R I T E ] , S T D O U T _ F I L E N O ) ; c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; ---here---e x ---here---e c ( s o r t ) ; w r i t e e n d p i p e 2 r e a d e n d 0 1 2 3 4 5 6 7 ... d u p 2 ( t w o [ R E A D ] , S T D I N _ F I L E N O ) ; c l o s e ( o n e [ 0 ] ) ; c l o s e ( o n e [ 1 ] ) ; c l o s e ( t w o [ 0 ] ) ; c l o s e ( t w o [ 1 ] ) ; ---here---e x ---here---e c ( m o r ---here---e ) ;