* Copyright (c) 1982 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)kern_exec.c 6.13 (Berkeley) %G%
#include "../machine/reg.h"
#include "../machine/pte.h"
#include "../machine/psl.h"
* exec system call, with and without environments.
((struct execa
*)u
.u_ap
)->envp
= NULL
;
register struct execa
*uap
;
int na
, ne
, ucp
, ap
, len
, cc
;
char cfname
[MAXCOMLEN
+ 1];
char ex_shell
[SHSIZE
]; /* #! and name of interpreter */
register struct nameidata
*ndp
= &u
.u_nd
;
ndp
->ni_nameiop
= LOOKUP
| FOLLOW
;
ndp
->ni_segflg
= UIO_USERSPACE
;
ndp
->ni_dirp
= ((struct execa
*)u
.u_ap
)->fname
;
if ((ip
= namei(ndp
)) == NULL
)
if ((u
.u_procp
->p_flag
&STRC
) && access(ip
, IREAD
))
if ((ip
->i_mode
& IFMT
) != IFREG
||
(ip
->i_mode
& (IEXEC
|(IEXEC
>>3)|(IEXEC
>>6))) == 0) {
* Read in first few bytes of file for segment sizes, magic number:
* 413 = demand paged RO text
* Also an ASCII line beginning with #! is
* the file name of a ``shell'' and arguments may be prepended
* to the argument list if given here.
* SHELL NAMES ARE LIMITED IN LENGTH.
* ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
exdata
.ex_shell
[0] = '\0'; /* for zero length files */
u
.u_error
= rdwri(UIO_READ
, ip
, (caddr_t
)&exdata
, sizeof (exdata
),
if (resid
> sizeof(exdata
) - sizeof(exdata
.ex_exec
) &&
exdata
.ex_shell
[0] != '#') {
switch (exdata
.ex_exec
.a_magic
) {
exdata
.ex_exec
.a_data
+= exdata
.ex_exec
.a_text
;
exdata
.ex_exec
.a_text
= 0;
if (exdata
.ex_exec
.a_text
== 0) {
if (exdata
.ex_shell
[0] != '#' ||
exdata
.ex_shell
[1] != '!' ||
cp
= &exdata
.ex_shell
[2]; /* skip "#!" */
while (cp
< &exdata
.ex_shell
[SHSIZE
]) {
cp
= &exdata
.ex_shell
[2];
while (*cp
&& *cp
!= ' ')
bcopy((caddr_t
)cp
, (caddr_t
)cfarg
, SHSIZE
);
ndp
->ni_nameiop
= LOOKUP
| FOLLOW
;
ndp
->ni_segflg
= UIO_SYSSPACE
;
bcopy((caddr_t
)ndp
->ni_dent
.d_name
, (caddr_t
)cfname
,
cfname
[MAXCOMLEN
] = '\0';
* Collect arguments on "file" in swap space.
uap
= (struct execa
*)u
.u_ap
;
bno
= rmalloc(argmap
, (long)ctod(clrnd((int)btoc(NCARGS
))));
swkill(u
.u_procp
, "exec: no swap space");
* Copy arguments into file in argdev area.
if (uap
->argp
) for (;;) {
uap
->argp
++; /* ignore argv[0] */
} else if (indir
&& (na
== 1 && cfarg
[0])) {
} else if (indir
&& (na
== 1 || na
== 2 && cfarg
[0]))
ap
= fuword((caddr_t
)uap
->argp
);
if (ap
== NULL
&& uap
->envp
) {
if ((ap
= fuword((caddr_t
)uap
->envp
)) != NULL
)
* We depend on NCARGS being a multiple of
* CLSIZE*NBPG. This way we need only check
* overflow before each buffer allocation.
bp
= getblk(argdev
, bno
+ ctod(nc
/NBPG
), cc
);
error
= copystr(sharg
, cp
, cc
, &len
);
error
= copyinstr((caddr_t
)ap
, cp
, cc
, &len
);
} while (error
== ENOENT
);
nc
= (nc
+ NBPW
-1) & ~(NBPW
-1);
getxfile(ip
, &exdata
.ex_exec
, nc
+ (na
+4)*NBPW
, uid
, gid
);
for (cc
= 0; cc
< nc
; cc
+= CLSIZE
*NBPG
) {
bp
= baddr(argdev
, bno
+ ctod(cc
/NBPG
), CLSIZE
*NBPG
);
bp
->b_flags
|= B_AGE
; /* throw away */
bp
->b_flags
&= ~B_DELWRI
; /* cancel io */
ucp
= USRSTACK
- nc
- NBPW
;
ap
= ucp
- na
*NBPW
- 3*NBPW
;
(void) suword((caddr_t
)ap
, na
-ne
);
(void) suword((caddr_t
)ap
, 0);
(void) suword((caddr_t
)ap
, ucp
);
bp
= bread(argdev
, bno
+ ctod(nc
/ NBPG
), cc
);
bp
->b_flags
|= B_AGE
; /* throw away */
bp
->b_flags
&= ~B_DELWRI
; /* cancel io */
error
= copyoutstr(cp
, (caddr_t
)ucp
, cc
, &len
);
} while (error
== ENOENT
);
(void) suword((caddr_t
)ap
, 0);
* Reset caught signals. Held signals
* remain held through p_sigmask.
while (u
.u_procp
->p_sigcatch
) {
nc
= ffs(u
.u_procp
->p_sigcatch
);
u
.u_procp
->p_sigcatch
&= ~sigmask(nc
);
u
.u_signal
[nc
] = SIG_DFL
;
* Reset stack state to the user stack.
* Clear set of signals caught on the signal stack.
for (nc
= u
.u_lastfile
; nc
>= 0; --nc
) {
if (u
.u_pofile
[nc
] & UF_EXCLOSE
) {
u
.u_pofile
[nc
] &= ~UF_MAPPED
;
while (u
.u_lastfile
>= 0 && u
.u_ofile
[u
.u_lastfile
] == NULL
)
setregs(exdata
.ex_exec
.a_entry
);
* Remember file name for accounting.
bcopy((caddr_t
)cfname
, (caddr_t
)u
.u_comm
, MAXCOMLEN
);
if (ndp
->ni_dent
.d_namlen
> MAXCOMLEN
)
ndp
->ni_dent
.d_namlen
= MAXCOMLEN
;
bcopy((caddr_t
)ndp
->ni_dent
.d_name
, (caddr_t
)u
.u_comm
,
(unsigned)(ndp
->ni_dent
.d_namlen
+ 1));
rmfree(argmap
, (long)ctod(clrnd((int) btoc(NCARGS
))), bno
);
* Read in and set up memory for executed file.
getxfile(ip
, ep
, nargc
, uid
, gid
)
register struct inode
*ip
;
register struct exec
*ep
;
size_t ts
, ds
, ids
, uds
, ss
;
if (ip
->i_flag
& IXMOD
) { /* XXX */
if (ep
->a_text
!= 0 && (ip
->i_flag
&ITEXT
) == 0 &&
register struct file
*fp
;
for (fp
= file
; fp
< fileNFILE
; fp
++) {
if (fp
->f_type
== DTYPE_INODE
&&
(struct inode
*)fp
->f_data
== ip
&&
* Compute text and data sizes and make sure not too large.
* NB - Check data and bss separately as they may overflow
ts
= clrnd(btoc(ep
->a_text
));
ids
= clrnd(btoc(ep
->a_data
));
uds
= clrnd(btoc(ep
->a_bss
));
ds
= clrnd(btoc(ep
->a_data
+ ep
->a_bss
));
ss
= clrnd(SSIZE
+ btoc(nargc
));
if (chksize((unsigned)ts
, (unsigned)ids
, (unsigned)uds
, (unsigned)ss
))
* Make sure enough space to start process.
if (swpexpand(ds
, ss
, &u
.u_cdmap
, &u
.u_csmap
) == NULL
)
* At this point, committed to the new image!
* Release virtual memory resources of old process, and
* initialize the virtual memory of the new process.
* If we resulted from vfork(), instead wakeup our
* parent who will set SVFDONE when he has taken back
if ((u
.u_procp
->p_flag
& SVFORK
) == 0)
u
.u_procp
->p_flag
&= ~SVFORK
;
u
.u_procp
->p_flag
|= SKEEP
;
wakeup((caddr_t
)u
.u_procp
);
while ((u
.u_procp
->p_flag
& SVFDONE
) == 0)
sleep((caddr_t
)u
.u_procp
, PZERO
- 1);
u
.u_procp
->p_flag
&= ~(SVFDONE
|SKEEP
);
u
.u_procp
->p_flag
&= ~(SPAGI
|SSEQL
|SUANOM
|SOUSIG
);
u
.u_procp
->p_flag
|= pagi
;
(char *)ctob(dptov(u
.u_procp
, 0)),
(int)(sizeof (struct exec
) + ep
->a_text
),
if (pagi
&& u
.u_procp
->p_textp
)
vinifod((struct fpte
*)dptopte(u
.u_procp
, 0),
PG_FTEXT
, u
.u_procp
->p_textp
->x_iptr
,
(long)(1 + ts
/CLSIZE
), (int)btoc(ep
->a_data
));
/* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
swkill(u
.u_procp
, "exec: I/O error mapping pages");
* set SUID/SGID protections, if no tracing
if ((u
.u_procp
->p_flag
&STRC
)==0) {
psignal(u
.u_procp
, SIGTRAP
);