/* kern_proc.c 4.12 81/04/28 */
#include "/usr/include/wait.h"
* exec system call, with and without environments.
((struct execa
*)u
.u_ap
)->envp
= NULL
;
register struct execa
*uap
;
if ((ip
= namei(uchar
, 0)) == 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, ux_mag:
* 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
u
.u_base
= (caddr_t
)&u
.u_exdata
;
u
.u_count
= sizeof(u
.u_exdata
);
if (u
.u_count
> sizeof(u
.u_exdata
) - sizeof(u
.u_exdata
.Ux_A
)
&& u
.u_exdata
.ux_shell
[0] != '#') {
switch (u
.u_exdata
.ux_mag
) {
u
.u_exdata
.ux_dsize
+= u
.u_exdata
.ux_tsize
;
if (u
.u_exdata
.ux_tsize
== 0) {
if (u
.u_exdata
.ux_shell
[0] != '#' ||
u
.u_exdata
.ux_shell
[1] != '!' ||
cp
= &u
.u_exdata
.ux_shell
[2]; /* skip "#!" */
while (cp
< &u
.u_exdata
.ux_shell
[SHSIZE
]) {
cp
= &u
.u_exdata
.ux_shell
[2];
while (*cp
&& *cp
!= ' ')
bcopy((caddr_t
)cp
, (caddr_t
)cfarg
, SHSIZE
);
bcopy((caddr_t
)u
.u_dbuf
, (caddr_t
)cfname
, DIRSIZ
);
* Collect arguments on "file" in swap space.
uap
= (struct execa
*)u
.u_ap
;
if ((bno
= rmalloc(argmap
, ctod(clrnd((int) btoc(NCARGS
))))) == 0) {
swkill(u
.u_procp
, "exece");
if (uap
->argp
) for (;;) {
if (indir
&& (na
== 1 || na
== 2 && sharg
))
ap
= fuword((caddr_t
)uap
->argp
);
if (ap
==NULL
&& uap
->envp
) {
if ((ap
= fuword((caddr_t
)uap
->envp
)) == NULL
)
if (indir
&& na
== 2 && sharg
!= NULL
)
else if ((c
= fubyte((caddr_t
)ap
++)) < 0)
(daddr_t
)(dbtofsb(bno
)+(nc
>>BSHIFT
)));
nc
= (nc
+ NBPW
-1) & ~(NBPW
-1);
bcopy((caddr_t
)cfname
, (caddr_t
)u
.u_dbuf
, DIRSIZ
);
getxfile(ip
, nc
+ (na
+4)*NBPW
, uid
, gid
);
for (c
= 0; c
< nc
; c
+= BSIZE
)
if (bp
= baddr(argdev
, dbtofsb(bno
)+(c
>>BSHIFT
))) {
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
);
(daddr_t
)(dbtofsb(bno
)+(nc
>>BSHIFT
)));
bp
->b_flags
|= B_AGE
; /* throw away */
bp
->b_flags
&= ~B_DELWRI
; /* cancel io */
(void) subyte((caddr_t
)ucp
++, (c
= *cp
++));
(void) suword((caddr_t
)ap
, 0);
(void) suword((caddr_t
)ucp
, 0);
rmfree(argmap
, ctod(clrnd((int) btoc(NCARGS
))), bno
);
* Read in and set up memory for executed file.
getxfile(ip
, nargc
, uid
, gid
)
register struct inode
*ip
;
register size_t ts
, ds
, ss
;
if (u
.u_exdata
.ux_mag
== 0413)
if(u
.u_exdata
.ux_tsize
!=0 && (ip
->i_flag
&ITEXT
)==0 && ip
->i_count
!=1) {
register struct file
*fp
;
for (fp
= file
; fp
< fileNFILE
; fp
++)
if (fp
->f_inode
== ip
&& (fp
->f_flag
&FWRITE
)) {
* find text and data sizes
* try them out for possible
ts
= clrnd(btoc(u
.u_exdata
.ux_tsize
));
ds
= clrnd(btoc((u
.u_exdata
.ux_dsize
+u
.u_exdata
.ux_bsize
)));
ss
= clrnd(SSIZE
+ btoc(nargc
));
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
|SNUSIG
);
u
.u_procp
->p_flag
|= pagi
;
u
.u_base
= (char *)ctob(ts
);
u
.u_offset
= sizeof(u
.u_exdata
)+u
.u_exdata
.ux_tsize
;
u
.u_count
= u
.u_exdata
.ux_dsize
;
if (pagi
&& u
.u_procp
->p_textp
)
vinifod((struct fpte
*)dptopte(u
.u_procp
, 0),
PG_FTEXT
, u
.u_procp
->p_textp
->x_iptr
,
1 + ts
/CLSIZE
, (int)btoc(u
.u_exdata
.ux_dsize
));
/* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
* set SUID/SGID protections, if no tracing
if ((u
.u_procp
->p_flag
&STRC
)==0) {
psignal(u
.u_procp
, SIGTRAP
);
* Clear registers on exec
for(rp
= &u
.u_signal
[0], sigmask
= 1L; rp
< &u
.u_signal
[NSIG
];
* Normal or deferring catch; revert to default.
u
.u_procp
->p_siga0
|= sigmask
;
u
.u_procp
->p_siga1
&= ~sigmask
;
u
.u_procp
->p_siga1
|= sigmask
;
u
.u_procp
->p_siga1
&= ~sigmask
;
for(rp = &u.u_ar0[0]; rp < &u.u_ar0[16];)
u
.u_ar0
[PC
] = u
.u_exdata
.ux_entloc
+ 2; /* skip over entry mask */
for(i
=0; i
<NOFILE
; i
++) {
if (u
.u_pofile
[i
]&EXCLOSE
) {
u
.u_pofile
[i
] &= ~EXCLOSE
;
* Remember file name for accounting.
bcopy((caddr_t
)u
.u_dbuf
, (caddr_t
)u
.u_comm
, DIRSIZ
);
uap
= (struct a
*)u
.u_ap
;
exit((uap
->rval
& 0377) << 8);
* Save u. area for parent to look at.
* Wake up parent and init processes,
* and dispose of children.
register struct proc
*p
, *q
;
p
->p_flag
&= ~(STRC
|SULOCK
);
* Release virtual memory. If we resulted from
* a vfork(), instead give the resources back to
if ((p
->p_flag
& SVFORK
) == 0)
while ((p
->p_flag
& SVFDONE
) == 0)
sleep((caddr_t
)p
, PZERO
- 1);
for(i
=0; i
<NOFILE
; i
++) {
u
.u_limit
[LIM_FSIZE
] = INFINITY
;
/* spl7(); /* clock will get mad because of overlaying */
pidhash
[i
] = p
->p_idhash
;
for (i
= pidhash
[i
]; i
!= 0; i
= proc
[i
].p_idhash
)
if (proc
[i
].p_idhash
== x
) {
proc
[i
].p_idhash
= p
->p_idhash
;
((struct xproc
*)p
)->xp_xstat
= rv
; /* overlay */
((struct xproc
*)p
)->xp_vm
= u
.u_vm
; /* overlay */
vmsadd(&((struct xproc
*)p
)->xp_vm
, &u
.u_cvm
);
for(q
= proc
; q
< procNPROC
; q
++)
wakeup((caddr_t
)&proc
[1]);
* Traced processes are killed
* since their existence means someone is screwing up.
* Stopped processes are sent a hangup and a continue.
* This is designed to be ``safe'' for setuid
* processes since they must be willing to tolerate
} else if (q
->p_stat
== SSTOP
) {
* Protect this process from future
* tty signals, clear TSTP/TTIN/TTOU if pending,
* and set SDETACH bit on procs.
wakeup((caddr_t
)p
->p_pptr
);
psignal(p
->p_pptr
, SIGCHLD
);
if ((u
.u_ar0
[PS
] & PSL_ALLCC
) != PSL_ALLCC
) {
wait1(0, (struct vtimes
*)0);
vp
= (struct vtimes
*)u
.u_ar0
[R1
];
(void) copyout((caddr_t
)&vm
, (caddr_t
)vp
, sizeof (struct vtimes
));
* Search for a terminated (zombie) child,
* finally lay it to rest, and collect its status.
* Look also for stopped (traced) children,
* and pass back status from them.
for(p
= proc
; p
< procNPROC
; p
++)
if(p
->p_pptr
== u
.u_procp
) {
u
.u_r
.r_val2
= ((struct xproc
*)p
)->xp_xstat
;
((struct xproc
*)p
)->xp_xstat
= 0;
*vp
= ((struct xproc
*)p
)->xp_vm
;
vmsadd(&u
.u_cvm
, &((struct xproc
*)p
)->xp_vm
);
((struct xproc
*)p
)->xp_vm
= zvms
;
if (p
->p_stat
== SSTOP
&& (p
->p_flag
&SWTED
)==0 &&
(p
->p_flag
&STRC
|| options
&WUNTRACED
)) {
u
.u_r
.r_val2
= (p
->p_cursig
<<8) | WSTOPPED
;
if ((u
.u_procp
->p_flag
&SNUSIG
) && setjmp(u
.u_qsav
)) {
sleep((caddr_t
)u
.u_procp
, PWAIT
);
if (swpexpand(u
.u_dsize
, u
.u_ssize
, &u
.u_cdmap
, &u
.u_csmap
) == 0) {
register struct proc
*p1
, *p2
;
for(p1
= proc
; p1
< procNPROC
; p1
++) {
if (p1
->p_stat
==NULL
&& p2
==NULL
)
if (p1
->p_uid
==u
.u_uid
&& p1
->p_stat
!=NULL
)
* not su and too many procs owned; or
* not su and would take last slot.
if (p2
==NULL
|| (u
.u_uid
!=0 && (p2
==procNPROC
-1 || a
>MAXUPRC
))) {
(void) vsexpand(0, &u
.u_cdmap
, 1);
(void) vsexpand(0, &u
.u_csmap
, 1);
u
.u_r
.r_val1
= p1
->p_pid
;
u
.u_r
.r_val2
= 1; /* child */
u
.u_r
.r_val1
= p2
->p_pid
;
* -- bad planning: "break" is a dirty word in C.
n
= btoc(((struct a
*)u
.u_ap
)->nsiz
);
n
-= ctos(u
.u_tsize
) * stoc(1);
d
= clrnd(n
- u
.u_dsize
);
if (ctob(u
.u_dsize
+d
) > u
.u_limit
[LIM_DATA
]) {
if (chksize(u
.u_tsize
, u
.u_dsize
+d
, u
.u_ssize
))
if (swpexpand(u
.u_dsize
+d
, u
.u_ssize
, &u
.u_dmap
, &u
.u_smap
)==0)