/* kern_proc.c 4.57 83/01/17 */
#include "../machine/reg.h"
#include "../machine/pte.h"
#include "../machine/psl.h"
#include "../h/descrip.h"
} *uap
= (struct a
*)u
.u_ap
;
} *uap
= (struct a
*)u
.u_ap
;
u
.u_error
= copyout((caddr_t
)hostname
, (caddr_t
)uap
->hostname
, len
);
} *uap
= (struct a
*)u
.u_ap
;
if (uap
->len
> sizeof (hostname
) - 1) {
u
.u_error
= copyin((caddr_t
)uap
->hostname
, hostname
, uap
->len
);
hostname
[hostnamelen
] = 0;
* exec system call, with and without environments.
((struct execa
*)u
.u_ap
)->envp
= NULL
;
register struct execa
*uap
;
char cfname
[MAXNAMLEN
+ 1];
if ((ip
= namei(uchar
, LOOKUP
, 1)) == 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_exdata
.ux_shell
[0] = 0; /* for zero length files */
u
.u_error
= rdwri(UIO_READ
, ip
, (caddr_t
)&u
.u_exdata
, 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_dent
.d_name
, (caddr_t
)cfname
,
(unsigned)(u
.u_dent
.d_namlen
+ 1));
ip
= namei(schar
, LOOKUP
, 1);
* Collect arguments on "file" in swap space.
uap
= (struct execa
*)u
.u_ap
;
if ((bno
= rmalloc(argmap
, (long)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)
if (nc
% (CLSIZE
*NBPG
) == 0) {
bp
= getblk(argdev
, bno
+ ctod(nc
/ NBPG
),
nc
= (nc
+ NBPW
-1) & ~(NBPW
-1);
u
.u_dent
.d_namlen
= strlen(cfname
);
bcopy((caddr_t
)cfname
, (caddr_t
)u
.u_dent
.d_name
,
(unsigned)(u
.u_dent
.d_namlen
+ 1));
getxfile(ip
, nc
+ (na
+4)*NBPW
, uid
, gid
);
for (c
= 0; c
< nc
; c
+= CLSIZE
*NBPG
) {
bp
= baddr(argdev
, bno
+ ctod(c
/ 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
);
if (nc
% (CLSIZE
*NBPG
) == 0) {
bp
= bread(argdev
, bno
+ ctod(nc
/ NBPG
),
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);
rmfree(argmap
, (long)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 &&
register struct file
*fp
;
for (fp
= file
; fp
< fileNFILE
; fp
++) {
if (fp
->f_type
== DTYPE_FILE
&&
fp
->f_inode
== ip
&& (fp
->f_flag
&FWRITE
)) {
* Compute text and data sizes and make sure not too large.
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
));
* 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
|SNUSIG
);
u
.u_procp
->p_flag
|= pagi
;
(char *)ctob(dptov(u
.u_procp
, 0)),
(int)u
.u_exdata
.ux_dsize
,
(int)(sizeof(u
.u_exdata
)+u
.u_exdata
.ux_tsize
),
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(u
.u_exdata
.ux_dsize
));
/* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
#include "../vax/mtpr.h" /* XXX */
swkill(u
.u_procp
, "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
);
* Clear registers on exec
for (rp
= &u
.u_signal
[1], sigmask
= 1L; rp
< &u
.u_signal
[NSIG
];
* Normal or deferring catch; revert to default.
u
.u_procp
->p_siga0
|= sigmask
;
u
.u_procp
->p_siga0
&= ~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;
{ register struct regs
*r
= (struct regs
*)u
.u_ar0
;
for (i
= 0; i
< 8; i
++) {
if (&r
->r_areg
[i
] != &r
->r_sp
)
r
->r_pc
= u
.u_exdata
.ux_entloc
;
for (i
=0; i
<NOFILE
; i
++) {
if (u
.u_pofile
[i
]&UF_EXCLOSE
) {
closef(u
.u_ofile
[i
], 1, u
.u_pofile
[i
]);
u
.u_pofile
[i
] &= ~UF_MAPPED
;
* Remember file name for accounting.
bcopy((caddr_t
)u
.u_dent
.d_name
, (caddr_t
)u
.u_comm
,
(unsigned)(u
.u_dent
.d_namlen
+ 1));
u
.u_eosys
= REALLYRETURN
;
* Exit system call: pass back caller's arg
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
;
struct mbuf
*m
= m_getclr(M_WAIT
, MT_ZOMBIE
);
p
->p_flag
&= ~(STRC
|SULOCK
);
untimeout(realitexpire
, (caddr_t
)p
);
* 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_rlimit
[RLIMIT_FSIZE
].rlim_cur
= RLIM_INFINITY
;
(void) spl5(); /* hack for mem alloc race XXX */
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
;
p
->p_ru
= mtod(m
, struct rusage
*);
ruadd(p
->p_ru
, &u
.u_cru
);
for (q
= proc
; q
< procNPROC
; q
++)
q
->p_osptr
->p_ysptr
= q
->p_ysptr
;
q
->p_ysptr
->p_osptr
= q
->p_osptr
;
proc
[1].p_cptr
->p_ysptr
= q
;
q
->p_osptr
= proc
[1].p_cptr
;
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.
psignal(p
->p_pptr
, SIGCHLD
);
wakeup((caddr_t
)p
->p_pptr
);
if ((u
.u_ar0
[PS
] & PSL_ALLCC
) != PSL_ALLCC
) {
u
.u_error
= wait1(0, (struct rusage
*)0);
rup
= (struct rusage
*)u
.u_ar0
[R1
];
u
.u_error
= wait1(u
.u_ar0
[R0
], &ru
);
(void) copyout((caddr_t
)&ru
, (caddr_t
)rup
, sizeof (struct rusage
));
if ((u
.u_ar0
[PS
] & PSL_ALLCC
) != PSL_ALLCC
) {
u
.u_error
= wait1(0, (struct rusage
*)0);
vtp
= (struct vtimes
*)u
.u_ar0
[R1
];
u
.u_error
= wait1(u
.u_ar0
[R0
], &ru
);
(void) copyout((caddr_t
)&avt
, (caddr_t
)vtp
, 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.
register struct proc
*p
, *q
;
for (p
= proc
; p
< procNPROC
; p
++)
if (p
->p_pptr
== u
.u_procp
) {
if (p
->p_stat
== SZOMB
) {
u
.u_r
.r_val2
= p
->p_xstat
;
ruadd(&u
.u_cru
, p
->p_ru
);
(void) m_free(dtom(p
->p_ru
));
if ((q
= p
->p_pptr
)->p_cptr
== p
)
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_qsave
)) {
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
;
if (u
.u_quota
!= NOQUOT
&& u
.u_quota
->q_plim
&&
u
.u_quota
->q_cnt
>= u
.u_quota
->q_plim
) {
for (p1
= proc
; p1
< procNPROC
; p1
++) {
if (p1
->p_stat
== NULL
) {
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)) {
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_qflags
&= ~QUF_LOGIN
;
u
.u_r
.r_val1
= p2
->p_pid
;
register struct proc
*top
;
register struct proc
*pp
, *p
;
for (p
= top
; npgrp
== -1 || u
.u_uid
== p
->p_uid
||
!u
.u_uid
|| inferior(p
); p
= pp
) {
#define bit(a) (1<<(a-1))
p
->p_sig
&= ~(bit(SIGTSTP
)|bit(SIGTTIN
)|bit(SIGTTOU
));
for (pp
= proc
; pp
< procNPROC
; pp
++)
for (; p
!= top
; p
= p
->p_pptr
)
for (pp
= p
+ 1; pp
< procNPROC
; pp
++)
if (pp
->p_pptr
== p
->p_pptr
)
* Is p an inferior of the current process?
for (; p
!= u
.u_procp
; p
= p
->p_pptr
)
for (p
= &proc
[pidhash
[PIDHASH(pid
)]]; p
!= &proc
[0]; p
= &proc
[p
->p_idhash
])
return ((struct proc
*)0);
* Create a new process-- the internal version of
* It returns 1 in the new process, 0 in the old.
register struct proc
*rpp
, *rip
;
register struct file
*fp
;
* First, just locate a slot for a process
* and copy the useful info from this process into it.
* The panic "cannot happen" because fork has already
* checked for the existence of a slot.
for (rpp
= proc
; rpp
< procNPROC
; rpp
++) {
if (rpp
->p_stat
== NULL
&& p
==NULL
)
if (rpp
->p_pid
==mpid
|| rpp
->p_pgrp
==mpid
)
* Make a proc table entry for the new process.
(rpp
->p_quota
= rip
->p_quota
)->q_cnt
++;
timerclear(&rpp
->p_realtimer
.it_value
);
rpp
->p_flag
= SLOAD
| (rip
->p_flag
& (SPAGI
|SNUSIG
));
rpp
->p_pgrp
= rip
->p_pgrp
;
rpp
->p_nice
= rip
->p_nice
;
rpp
->p_textp
= isvfork
? 0 : rip
->p_textp
;
rpp
->p_ppid
= rip
->p_pid
;
rpp
->p_osptr
= rip
->p_cptr
;
rip
->p_cptr
->p_ysptr
= rpp
;
rpp
->p_siga0
= rip
->p_siga0
;
rpp
->p_siga1
= rip
->p_siga1
;
/* take along any pending signals, like stops? */
rpp
->p_tsize
= rpp
->p_dsize
= rpp
->p_ssize
= 0;
rpp
->p_szpt
= clrnd(ctopt(UPAGES
));
forkstat
.sizvfork
+= rip
->p_dsize
+ rip
->p_ssize
;
rpp
->p_tsize
= rip
->p_tsize
;
rpp
->p_dsize
= rip
->p_dsize
;
rpp
->p_ssize
= rip
->p_ssize
;
rpp
->p_szpt
= rip
->p_szpt
;
forkstat
.sizfork
+= rip
->p_dsize
+ rip
->p_ssize
;
rpp
->p_maxrss
= rip
->p_maxrss
;
p
->p_idhash
= pidhash
[n
];
* Increase reference counts on shared objects.
for (n
= 0; n
< NOFILE
; n
++) {
if (u
.u_pofile
[n
]&UF_SHLOCK
)
fp
->f_inode
->i_shlockc
++;
if (u
.u_pofile
[n
]&UF_EXLOCK
)
fp
->f_inode
->i_exlockc
++;
* Partially simulate the environment
* of the new process so that when it is actually
* created (by copying) it will look right.
* This begins the section where we must prevent the parent
if (procdup(rpp
, isvfork
))
* Make child runnable and add to run queue.
* Cause child to take a non-local goto as soon as it runs.
* On older systems this was done with SSWAP bit in proc
* table; on VAX we use u.u_pcb.pcb_sswap so don't need
* to do rpp->p_flag |= SSWAP. Actually do nothing here.
/* rpp->p_flag |= SSWAP; */
* If vfork make chain from parent process to child
* (where virtal memory is temporarily). Wait for
* child to finish, steal virtual memory back,
* and wakeup child to let it die.
u
.u_procp
->p_xlink
= rpp
;
u
.u_procp
->p_flag
|= SNOVM
;
while (rpp
->p_flag
& SVFORK
)
sleep((caddr_t
)rpp
, PZERO
- 1);
if ((rpp
->p_flag
& SLOAD
) == 0)
uaccess(rpp
, Vfmap
, &vfutl
);
vpassvm(rpp
, u
.u_procp
, &vfutl
, &u
, Vfmap
);
u
.u_procp
->p_flag
&= ~SNOVM
;