* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* Redistribution is only permitted until one year after the first shipment
* of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
* binary forms are permitted provided that: (1) source distributions retain
* this entire copyright notice and comment, and (2) distributions including
* binaries display the following acknowledgement: This product includes
* software developed by the University of California, Berkeley and its
* contributors'' in the documentation or other materials provided with the
* distribution and in all advertising materials mentioning features or use
* of this software. Neither the name of the University nor the names of
* its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)kern_exec.c 7.30 (Berkeley) 6/30/90
#include "machine/mtpr.h"
#include "../hpux/hpux_exec.h"
* exec system call, with and without environments.
return (execve(p
, uap
, retval
));
char cfname
[MAXCOMLEN
+ 1];
char ex_shell
[MAXINTERP
]; /* #! and interpreter name */
struct hpux_exec ex_hexec
;
register struct ucred
*cred
= u
.u_cred
;
register struct nameidata
*ndp
= &u
.u_nd
;
int resid
, error
, flags
= 0;
ndp
->ni_nameiop
= LOOKUP
| FOLLOW
| LOCKLEAF
;
ndp
->ni_segflg
= UIO_USERSPACE
;
ndp
->ni_dirp
= uap
->fname
;
if (error
= VOP_GETATTR(vp
, &vattr
, cred
))
if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
) {
if ((vp
->v_mount
->mnt_flag
& MNT_NOSUID
) == 0) {
if (vattr
.va_mode
& VSUID
)
if (vattr
.va_mode
& VSGID
)
if (error
= VOP_ACCESS(vp
, VEXEC
, cred
))
if ((p
->p_flag
& STRC
) && (error
= VOP_ACCESS(vp
, VREAD
, cred
)))
if (vp
->v_type
!= VREG
||
(vattr
.va_mode
& (VEXEC
|(VEXEC
>>3)|(VEXEC
>>6))) == 0) {
* Read in first few bytes of file for segment sizes, magic number:
* OMAGIC = plain executable
* ZMAGIC = 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 */
error
= vn_rdwr(UIO_READ
, vp
, (caddr_t
)&exdata
, sizeof (exdata
),
(off_t
)0, UIO_SYSSPACE
, (IO_UNIT
|IO_NODELOCKED
), cred
, &resid
);
if (resid
> sizeof(exdata
) - sizeof(exdata
.ex_exec
) &&
exdata
.ex_shell
[0] != '#') {
switch ((int)exdata
.ex_exec
.a_mid
) {
* An ancient hp200 or hp300 binary, shouldn't happen anymore.
exdata
.ex_exec
.a_magic
= 0;
* HP200 series has a smaller page size so we cannot
* demand-load or even write protect text, so we just
exdata
.ex_exec
.a_magic
= OMAGIC
;
* Save a.out header. This is eventually saved in the pcb,
* but we cannot do that yet in case the exec fails before
* the image is overlayed.
bcopy((caddr_t
)&exdata
.ex_hexec
,
(caddr_t
)&hhead
, sizeof hhead
);
* If version number is 0x2bad this is a native BSD
* binary created via the HPUX SGS. Should not be
* treated as an HPUX binary.
if (exdata
.ex_hexec
.ha_version
!= BSDVNUM
)
* Shuffle important fields to their BSD locations.
* Note that the order in which this is done is important.
exdata
.ex_exec
.a_text
= exdata
.ex_hexec
.ha_text
;
exdata
.ex_exec
.a_data
= exdata
.ex_hexec
.ha_data
;
exdata
.ex_exec
.a_bss
= exdata
.ex_hexec
.ha_bss
;
exdata
.ex_exec
.a_entry
= exdata
.ex_hexec
.ha_entry
;
* For ZMAGIC files, make sizes consistant with those
if (exdata
.ex_exec
.a_magic
== ZMAGIC
) {
ctob(btoc(exdata
.ex_exec
.a_text
));
nc
= exdata
.ex_exec
.a_data
+ exdata
.ex_exec
.a_bss
;
ctob(btoc(exdata
.ex_exec
.a_data
));
nc
-= (int)exdata
.ex_exec
.a_data
;
exdata
.ex_exec
.a_bss
= (nc
< 0) ? 0 : nc
;
switch ((int)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] != '!' ||
for (cp
= &exdata
.ex_shell
[2];; ++cp
) {
if (cp
>= &exdata
.ex_shell
[MAXINTERP
]) {
cp
= &exdata
.ex_shell
[2];
while (*cp
&& *cp
!= ' ')
bcopy((caddr_t
)cp
, (caddr_t
)cfarg
, MAXINTERP
);
ndp
->ni_nameiop
= LOOKUP
| FOLLOW
| LOCKLEAF
;
ndp
->ni_segflg
= UIO_SYSSPACE
;
if (error
= VOP_GETATTR(vp
, &vattr
, cred
))
bcopy((caddr_t
)ndp
->ni_dent
.d_name
, (caddr_t
)cfname
,
cfname
[MAXCOMLEN
] = '\0';
uid
= cred
->cr_uid
; /* shell scripts can't be setuid */
* If the vnode has been modified since we last used it,
* then throw away all its pages and its text table entry.
if (vp
->v_text
&& vp
->v_text
->x_mtime
!= vattr
.va_mtime
.tv_sec
) {
* Try once to release, if it is still busy
* take more drastic action.
if (vp
->v_flag
& VTEXT
) {
* Collect arguments on "file" in swap space.
bno
= rmalloc(argmap
, (long)ctod(clrnd((int)btoc(NCARGS
))));
swkill(p
, "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
* CLBYTES. This way we need only check
* overflow before each buffer allocation.
bp
= getblk(argdev_vp
, bno
+ ctod(nc
/NBPG
), cc
);
error
= copystr(sharg
, cp
, (unsigned)cc
, &len
);
error
= copyinstr((caddr_t
)ap
, cp
, (unsigned)cc
,
} while (error
== ENOENT
);
nc
= (nc
+ NBPW
-1) & ~(NBPW
-1);
error
= getxfile(p
, vp
, &exdata
.ex_exec
, flags
, nc
+ (na
+4)*NBPW
,
for (cc
= 0; cc
< nc
; cc
+= CLBYTES
) {
(void) baddr(argdev_vp
, bno
+ ctod(cc
/NBPG
),
bp
->b_flags
|= B_INVAL
; /* throw away */
vp
->v_text
->x_mtime
= vattr
.va_mtime
.tv_sec
;
* We are now committed to the exec so we can save the exec
* header in the pcb where we can dump it if necessary in core()
if (u
.u_pcb
.pcb_flags
& PCB_HPUXBIN
)
(caddr_t
)u
.u_pcb
.pcb_exec
, sizeof hhead
);
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
)(bno
+ ctod(nc
/ NBPG
)), cc
,
bp
->b_flags
|= B_INVAL
; /* throw away */
error
= copyoutstr(cp
, (caddr_t
)ucp
, (unsigned)cc
,
} while (error
== ENOENT
);
(void) suword((caddr_t
)ap
, 0);
for (nc
= u
.u_lastfile
; nc
>= 0; --nc
) {
if (u
.u_pofile
[nc
] & UF_EXCLOSE
) {
(void) closef(u
.u_ofile
[nc
]);
u
.u_pofile
[nc
] &= ~UF_MAPPED
;
while (u
.u_lastfile
>= 0 && u
.u_ofile
[u
.u_lastfile
] == NULL
)
setregs(exdata
.ex_exec
.a_entry
, retval
);
* Remember file name for accounting.
bcopy((caddr_t
)cfname
, (caddr_t
)p
->p_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
)p
->p_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(p
, vp
, ep
, flags
, nargc
, uid
, gid
)
register struct vnode
*vp
;
register struct exec
*ep
;
int flags
, nargc
, uid
, gid
;
segsz_t ts
, ds
, ids
, uds
, ss
;
register struct ucred
*cred
= u
.u_cred
;
if (ep
->a_mid
== MID_HPUX
)
toff
= sizeof (struct hpux_exec
);
toff
= sizeof (struct exec
);
if (vp
->v_text
&& (vp
->v_text
->x_flag
& XTRC
))
if (ep
->a_text
!= 0 && (vp
->v_flag
& VTEXT
) == 0 &&
register struct file
*fp
;
for (fp
= file
; fp
< fileNFILE
; fp
++) {
if (fp
->f_type
== DTYPE_VNODE
&&
(struct vnode
*)fp
->f_data
== vp
&&
* 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
));
chksize((unsigned)ts
, (unsigned)ids
, (unsigned)uds
, (unsigned)ss
))
* Make sure enough space to start process.
if (error
= swpexpand(ds
, ss
, &u
.u_cdmap
, &u
.u_csmap
))
* At this point, we are 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 ((p
->p_flag
& SVFORK
) == 0) {
if (u
.u_mmap
&& (error
= mmexec(p
)))
while ((p
->p_flag
& SVFDONE
) == 0)
sleep((caddr_t
)p
, PZERO
- 1);
p
->p_flag
&= ~(SVFDONE
|SKEEP
);
u
.u_pcb
.pcb_flags
&= ~(PCB_AST
|PCB_HPUXMMAP
|PCB_HPUXBIN
);
/* remember that we were loaded from an HPUX format file */
if (ep
->a_mid
== MID_HPUX
)
u
.u_pcb
.pcb_flags
|= PCB_HPUXBIN
;
p
->p_flag
&= ~(SPAGV
|SSEQL
|SUANOM
|SHPUX
);
p
->p_flag
|= flags
| SEXEC
;
if ((flags
& SPAGV
) == 0)
(void) vn_rdwr(UIO_READ
, vp
,
(char *)ctob(dptov(p
, 0)),
(off_t
)(toff
+ ep
->a_text
),
UIO_USERSPACE
, (IO_UNIT
|IO_NODELOCKED
), cred
, (int *)0);
xalloc(vp
, ep
, toff
, cred
);
if (p
->p_textp
== 0) { /* use existing code key if shared */
p
->p_ckey
= getcodekey();
p
->p_dkey
= getdatakey();
if ((flags
& SPAGV
) && p
->p_textp
)
vinifod(p
, (struct fpte
*)dptopte(p
, 0),
PG_FTEXT
, p
->p_textp
->x_vptr
,
(long)(1 + ts
/CLSIZE
), (segsz_t
)btoc(ep
->a_data
));
#if defined(vax) || defined(tahoe)
/* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
* set SUID/SGID protections, if no tracing
if ((p
->p_flag
&STRC
)==0) {
if (uid
!= cred
->cr_uid
|| gid
!= cred
->cr_gid
)
u
.u_cred
= cred
= crcopy(cred
);
p
->p_svgid
= cred
->cr_gid
;
u
.u_pcb
.pcb_savacc
.faddr
= (float *)NULL
;