* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* %sccs.include.redist.c%
* from: Utah $Hdr: hpux_compat.c 1.64 93/08/05$
* @(#)hpux_compat.c 8.5 (Berkeley) %G%
* Various HP-UX compatibility routines
#include <sys/signalvar.h>
#include <sys/filedesc.h>
#include <machine/vmparam.h>
#include <hp/hpux/hpux.h>
#include <hp/hpux/hpux_termio.h>
/* SYS5 style UTSNAME info */
struct hpuxutsname protoutsname
= {
"4.4bsd", "", "0.5", "B", "9000/3?0", ""
/* 6.0 and later style context */
"standalone HP-MC68040 HP-MC68881 HP-MC68020 HP-MC68010 localroot default";
"standalone HP-MC68881 HP-MC68020 HP-MC68010 localroot default";
"standalone HP-MC68020 HP-MC68010 localroot default";
char domainname
[MAXHOSTNAMELEN
] = "unknown";
/* indexed by BSD errno */
short bsdtohpuxerrnomap
[NERR
] = {
/*00*/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
/*10*/ 10, 45, 12, 13, 14, 15, 16, 17, 18, 19,
/*20*/ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
/*30*/ 30, 31, 32, 33, 34, 246, 245, 244, 216, 217,
/*40*/ 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
/*50*/ 228, 229, 230, 231, 232, 233, 234, 235, 236, 237,
/*60*/ 238, 239, 249, 248, 241, 242, 247,BERR
,BERR
,BERR
,
/*70*/ 70, 71,BERR
,BERR
,BERR
,BERR
,BERR
, 46, 251,BERR
,
notimp(p
, uap
, retval
, code
, argsize
)
register_t
*uap
, *retval
;
register int *argp
= uap
;
extern char *hpuxsyscallnames
[];
printf("HP-UX %s(", hpuxsyscallnames
[code
]);
while (argsize
-= sizeof (register_t
))
printf("%x%c", *argp
++, argsize
? ',' : ')');
error
= nosys(p
, uap
, retval
);
error
= nosys(p
, uap
, retval
);
uprintf("HP-UX system call %d not implemented\n", code
);
* HP-UX fork and vfork need to map the EAGAIN return value appropriately.
struct hpuxwait3_args
*uap
;
error
= fork(p
, uap
, retval
);
hpuxvfork(p
, uap
, retval
)
struct hpuxwait3_args
*uap
;
error
= vfork(p
, uap
, retval
);
hpuxexecv(p
, uap
, retval
)
struct hpuxexecv_args
*uap
;
return (execve(p
, uap
, retval
));
* HP-UX versions of wait and wait3 actually pass the parameters
* (status pointer, options, rusage) into the kernel rather than
* handling it in the C library stub. We also need to map any
* termination signal from BSD to HP-UX.
hpuxwait3(p
, uap
, retval
)
struct hpuxwait3_args
*uap
;
/* rusage pointer must be zero */
p
->p_md
.md_regs
[PS
] = PSL_ALLCC
;
p
->p_md
.md_regs
[R0
] = uap
->options
;
p
->p_md
.md_regs
[R1
] = uap
->rusage
;
return (hpuxwait(p
, uap
, retval
));
struct hpuxwait_args
*uap
;
statp
= uap
->status
; /* owait clobbers first arg */
error
= compat_43_wait(p
, uap
, retval
);
* HP-UX wait always returns EINTR when interrupted by a signal
* (well, unless its emulating a BSD process, but we don't bother...)
sig
= (retval
[1] >> 8) & 0xFF;
retval
[1] = (bsdtohpuxsig(sig
) << 8) | WSTOPPED
;
retval
[1] = (retval
[1] & 0xFF00) |
bsdtohpuxsig(sig
& 0x7F) | (sig
& 0x80);
if (suword((caddr_t
)statp
, retval
[1]))
struct hpuxwaitpid_args
{
struct rusage
*rusage
; /* wait4 arg */
hpuxwaitpid(p
, uap
, retval
)
struct hpuxwaitpid_args
*uap
;
int rv
, sig
, xstat
, error
;
error
= wait4(p
, uap
, retval
);
* HP-UX wait always returns EINTR when interrupted by a signal
* (well, unless its emulating a BSD process, but we don't bother...)
* Wait4 already wrote the status out to user space,
* pull it back, change the signal portion, and write
rv
= fuword((caddr_t
)uap
->status
);
rv
= W_STOPCODE(bsdtohpuxsig(sig
));
} else if (WIFSIGNALED(rv
)) {
rv
= W_EXITCODE(xstat
, bsdtohpuxsig(sig
)) |
(void)suword((caddr_t
)uap
->status
, rv
);
hpuxcreat(p
, uap
, retval
)
register struct hpuxcreat_args
*uap
;
openuap
.fname
= uap
->fname
;
openuap
.crtmode
= uap
->fmode
;
openuap
.mode
= O_WRONLY
| O_CREAT
| O_TRUNC
;
return (open(p
, &openuap
, retval
));
* XXX extensions to the fd_ofileflags flags.
* Hate to put this there, but they do need to be per-file.
#define UF_NONBLOCK_ON 0x10
#define UF_FNDELAY_ON 0x20
#define UF_FIONBIO_ON 0x40
* Must remap some bits in the mode mask.
* O_CREAT, O_TRUNC, and O_EXCL must be remapped,
* O_NONBLOCK is remapped and remembered,
* O_FNDELAY is remembered,
* O_SYNCIO is removed entirely.
register struct hpuxopen_args
*uap
;
~(HPUXNONBLOCK
|HPUXFSYNCIO
|HPUXFEXCL
|HPUXFTRUNC
|HPUXFCREAT
);
* simulate the pre-NFS behavior that opening a
* file for READ+CREATE ignores the CREATE (unless
* EXCL is set in which case we will return the
if ((mode
& HPUXFEXCL
) || (FFLAGS(mode
) & FWRITE
))
error
= open(p
, uap
, retval
);
* Record non-blocking mode for fcntl, read, write, etc.
if (error
== 0 && (uap
->mode
& O_NDELAY
))
p
->p_fd
->fd_ofileflags
[*retval
] |=
(mode
& HPUXNONBLOCK
) ? UF_NONBLOCK_ON
: UF_FNDELAY_ON
;
hpuxfcntl(p
, uap
, retval
)
register struct hpuxfcntl_args
*uap
;
int mode
, error
, flg
= F_POSIX
;
if ((unsigned)uap
->fdes
>= p
->p_fd
->fd_nfiles
||
(fp
= p
->p_fd
->fd_ofiles
[uap
->fdes
]) == NULL
)
pop
= &p
->p_fd
->fd_ofileflags
[uap
->fdes
];
if (uap
->arg
& HPUXNONBLOCK
)
if (uap
->arg
& HPUXNDELAY
)
if (*pop
& (UF_NONBLOCK_ON
|UF_FNDELAY_ON
|UF_FIONBIO_ON
))
uap
->arg
&= ~(HPUXNONBLOCK
|HPUXFSYNCIO
|HPUXFREMOTE
);
if (fp
->f_type
!= DTYPE_VNODE
)
vp
= (struct vnode
*)fp
->f_data
;
/* Copy in the lock structure */
error
= copyin((caddr_t
)uap
->arg
, (caddr_t
)&hfl
, sizeof (hfl
));
fl
.l_start
= hfl
.hl_start
;
fl
.l_whence
= hfl
.hl_whence
;
if (fl
.l_whence
== SEEK_CUR
)
fl
.l_start
+= fp
->f_offset
;
if ((fp
->f_flag
& FREAD
) == 0)
return (VOP_ADVLOCK(vp
, (caddr_t
)p
, F_SETLK
, &fl
, flg
));
if ((fp
->f_flag
& FWRITE
) == 0)
return (VOP_ADVLOCK(vp
, (caddr_t
)p
, F_SETLK
, &fl
, flg
));
return (VOP_ADVLOCK(vp
, (caddr_t
)p
, F_UNLCK
, &fl
,
if (fp
->f_type
!= DTYPE_VNODE
)
vp
= (struct vnode
*)fp
->f_data
;
/* Copy in the lock structure */
error
= copyin((caddr_t
)uap
->arg
, (caddr_t
)&hfl
, sizeof (hfl
));
fl
.l_start
= hfl
.hl_start
;
fl
.l_whence
= hfl
.hl_whence
;
if (fl
.l_whence
== SEEK_CUR
)
fl
.l_start
+= fp
->f_offset
;
if (error
= VOP_ADVLOCK(vp
, (caddr_t
)p
, F_GETLK
, &fl
, F_POSIX
))
hfl
.hl_start
= fl
.l_start
;
hfl
.hl_whence
= fl
.l_whence
;
return (copyout((caddr_t
)&hfl
, (caddr_t
)uap
->arg
, sizeof (hfl
)));
error
= fcntl(p
, uap
, retval
);
if (error
== 0 && uap
->cmd
== F_GETFL
) {
*retval
&= ~(O_CREAT
|O_TRUNC
|O_EXCL
);
if (*pop
& UF_NONBLOCK_ON
)
if ((*pop
& UF_FNDELAY_ON
) == 0)
* Read and write calls. Same as BSD except for non-blocking behavior.
* There are three types of non-blocking reads/writes in HP-UX checked
* in the following order:
* O_NONBLOCK: return -1 and errno == EAGAIN
* FIOSNBIO: return -1 and errno == EWOULDBLOCK
error
= read(p
, uap
, retval
);
if (error
== EWOULDBLOCK
) {
char *fp
= &p
->p_fd
->fd_ofileflags
[uap
->fd
];
if (*fp
& UF_NONBLOCK_ON
) {
} else if (*fp
& UF_FNDELAY_ON
) {
hpuxwrite(p
, uap
, retval
)
error
= write(p
, uap
, retval
);
if (error
== EWOULDBLOCK
) {
char *fp
= &p
->p_fd
->fd_ofileflags
[uap
->fd
];
if (*fp
& UF_NONBLOCK_ON
) {
} else if (*fp
& UF_FNDELAY_ON
) {
hpuxreadv(p
, uap
, retval
)
error
= readv(p
, uap
, retval
);
if (error
== EWOULDBLOCK
) {
char *fp
= &p
->p_fd
->fd_ofileflags
[uap
->fd
];
if (*fp
& UF_NONBLOCK_ON
) {
} else if (*fp
& UF_FNDELAY_ON
) {
hpuxwritev(p
, uap
, retval
)
error
= writev(p
, uap
, retval
);
if (error
== EWOULDBLOCK
) {
char *fp
= &p
->p_fd
->fd_ofileflags
[uap
->fd
];
if (*fp
& UF_NONBLOCK_ON
) {
} else if (*fp
& UF_FNDELAY_ON
) {
* 4.3bsd dup allows dup2 to come in on the same syscall entry
* and hence allows two arguments. HP-UX dup has only one arg.
register struct hpuxdup_args
*uap
;
register struct filedesc
*fdp
= p
->p_fd
;
if (((unsigned)uap
->i
) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->i
]) == NULL
)
if (error
= fdalloc(p
, 0, &fd
))
fdp
->fd_ofileflags
[fd
] = fdp
->fd_ofileflags
[uap
->i
] &~ UF_EXCLOSE
;
if (fd
> fdp
->fd_lastfile
)
hpuxutssys(p
, uap
, retval
)
register struct hpuxutssys_args
*uap
;
/* fill in machine type */
protoutsname
.machine
[6] = '2';
/* includes 318 and 319 */
protoutsname
.machine
[6] = '3';
protoutsname
.machine
[6] = '4';
protoutsname
.machine
[6] = '5';
protoutsname
.machine
[6] = '6';
protoutsname
.machine
[6] = '7';
protoutsname
.machine
[6] = '7';
protoutsname
.machine
[7] = '5';
protoutsname
.machine
[6] = '8';
protoutsname
.machine
[5] = '4';
protoutsname
.machine
[6] = '3';
protoutsname
.machine
[7] = '3';
/* copy hostname (sans domain) to nodename */
for (i
= 0; i
< 8 && hostname
[i
] != '.'; i
++)
protoutsname
.nodename
[i
] = hostname
[i
];
protoutsname
.nodename
[i
] = '\0';
error
= copyout((caddr_t
)&protoutsname
, (caddr_t
)uap
->uts
,
sizeof(struct hpuxutsname
));
if (uap
->dev
> hostnamelen
+ 1)
uap
->dev
= hostnamelen
+ 1;
error
= copyout((caddr_t
)hostname
, (caddr_t
)uap
->uts
,
case 4: /* sethostname */
struct hpuxsysconf_args
{
hpuxsysconf(p
, uap
, retval
)
struct hpuxsysconf_args
*uap
;
/* clock ticks per second */
case HPUX_SYSCONF_CLKTICK
:
case HPUX_SYSCONF_OPENMAX
:
case HPUX_SYSCONF_CPUTYPE
:
*retval
= HPUX_SYSCONF_CPUM020
;
*retval
= HPUX_SYSCONF_CPUM030
;
*retval
= HPUX_SYSCONF_CPUM040
;
uprintf("HP-UX sysconf(%d) not implemented\n", uap
->name
);
struct hpuxstat_args
*uap
;
return (hpuxstat1(uap
->fname
, uap
->hsb
, FOLLOW
, p
));
hpuxlstat(p
, uap
, retval
)
struct hpuxlstat_args
*uap
;
return (hpuxstat1(uap
->fname
, uap
->hsb
, NOFOLLOW
, p
));
hpuxfstat(p
, uap
, retval
)
register struct hpuxfstat_args
*uap
;
register struct filedesc
*fdp
= p
->p_fd
;
register struct file
*fp
;
if (((unsigned)uap
->fdes
) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fdes
]) == NULL
)
error
= vn_stat((struct vnode
*)fp
->f_data
, &sb
, p
);
error
= soo_stat((struct socket
*)fp
->f_data
, &sb
, p
);
/* is this right for sockets?? */
error
= bsdtohpuxstat(&sb
, uap
->hsb
);
hpuxulimit(p
, uap
, retval
)
register struct hpuxulimit_args
*uap
;
limp
= &p
->p_rlimit
[RLIMIT_FSIZE
];
if (uap
->newlimit
> limp
->rlim_max
&&
(error
= suser(p
->p_ucred
, &p
->p_acflag
)))
limp
->rlim_cur
= limp
->rlim_max
= uap
->newlimit
;
*retval
= limp
->rlim_max
/ 512;
limp
= &p
->p_rlimit
[RLIMIT_DATA
];
*retval
= ctob(p
->p_vmspace
->vm_tsize
) + limp
->rlim_max
;
* Map "real time" priorities 0 (high) thru 127 (low) into nice
* values -16 (high) thru -1 (low).
hpuxrtprio(cp
, uap
, retval
)
register struct hpuxrtprio_args
*uap
;
if (uap
->prio
< RTPRIO_MIN
&& uap
->prio
> RTPRIO_MAX
&&
uap
->prio
!= RTPRIO_NOCHG
&& uap
->prio
!= RTPRIO_RTOFF
)
else if ((p
= pfind(uap
->pid
)) == 0)
*retval
= (nice
+ 16) << 3;
nice
= (uap
->prio
>> 3) - 16;
error
= donice(cp
, p
, nice
);
hpuxadvise(p
, uap
, retval
)
struct hpuxadvise_args
*uap
;
p
->p_md
.md_flags
|= MDP_HPUXMMAP
;
hpuxptrace(p
, uap
, retval
)
struct hpuxptrace_args
*uap
;
uap
->data
= hpuxtobsdsig(uap
->data
);
* Big, cheezy hack: hpuxtobsduoff is really intended
* to be called in the child context (procxmt) but we
* do it here in the parent context to avoid hacks in
* the MI sys_process.c file. This works only because
* we can access the child's md_regs pointer and it
* has the correct value (the child has already trapped
if ((cp
= pfind(uap
->pid
)) == 0)
uap
->addr
= (int *) hpuxtobsduoff(uap
->addr
, &isps
, cp
);
* Since HP-UX PS is only 16-bits in ar0, requests
* to write PS actually contain the PS in the high word
* and the high half of the PC (the following register)
* in the low word. Move the PS value to where BSD
if (isps
&& uap
->req
== PT_WRITE_U
)
error
= ptrace(p
, uap
, retval
);
* Align PS as HP-UX expects it (see WRITE_U comment above).
* Note that we do not return the high part of PC like HP-UX
* would, but the HP-UX debuggers don't require it.
if (isps
&& error
== 0 && uap
->req
== PT_READ_U
)
struct hpuxgetdomainname_args
{
hpuxgetdomainname(p
, uap
, retval
)
register struct hpuxgetdomainname_args
*uap
;
if (uap
->len
> domainnamelen
+ 1)
uap
->len
= domainnamelen
+ 1;
return (copyout(domainname
, uap
->domainname
, uap
->len
));
struct hpuxsetdomainname_args
{
hpuxsetdomainname(p
, uap
, retval
)
register struct hpuxsetdomainname_args
*uap
;
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
if (uap
->len
> sizeof (domainname
) - 1)
domainnamelen
= uap
->len
;
error
= copyin(uap
->domainname
, domainname
, uap
->len
);
domainname
[domainnamelen
] = 0;
hpuxshmat(p
, uap
, retval
)
return (shmat(p
, uap
, retval
));
hpuxshmdt(p
, uap
, retval
)
return (shmdt(p
, uap
, retval
));
hpuxshmget(p
, uap
, retval
)
return (shmget(p
, uap
, retval
));
hpuxshmctl(p
, uap
, retval
)
return (hpuxshmctl1(p
, uap
, retval
, 0));
hpuxnshmctl(p
, uap
, retval
)
return (hpuxshmctl1(p
, uap
, retval
, 1));
* Handle HP-UX specific commands.
hpuxshmctl1(p
, uap
, retval
, isnew
)
struct hpuxshmctl_args
*uap
;
register struct shmid_ds
*shp
;
register struct ucred
*cred
= p
->p_ucred
;
struct hpuxshmid_ds sbuf
;
if (error
= shmvalid(uap
->shmid
))
shp
= &shmsegs
[uap
->shmid
% SHMMMNI
];
/* don't really do anything, but make them think we did */
if (cred
->cr_uid
&& cred
->cr_uid
!= shp
->shm_perm
.uid
&&
cred
->cr_uid
!= shp
->shm_perm
.cuid
)
error
= ipcaccess(&shp
->shm_perm
, IPC_R
, cred
);
sbuf
.shm_perm
.uid
= shp
->shm_perm
.uid
;
sbuf
.shm_perm
.gid
= shp
->shm_perm
.gid
;
sbuf
.shm_perm
.cuid
= shp
->shm_perm
.cuid
;
sbuf
.shm_perm
.cgid
= shp
->shm_perm
.cgid
;
sbuf
.shm_perm
.mode
= shp
->shm_perm
.mode
;
sbuf
.shm_perm
.seq
= shp
->shm_perm
.seq
;
sbuf
.shm_perm
.key
= shp
->shm_perm
.key
;
sbuf
.shm_segsz
= shp
->shm_segsz
;
sbuf
.shm_ptbl
= shp
->shm_handle
; /* XXX */
sbuf
.shm_lpid
= shp
->shm_lpid
;
sbuf
.shm_cpid
= shp
->shm_cpid
;
sbuf
.shm_nattch
= shp
->shm_nattch
;
sbuf
.shm_cnattch
= shp
->shm_nattch
; /* XXX */
sbuf
.shm_atime
= shp
->shm_atime
;
sbuf
.shm_dtime
= shp
->shm_dtime
;
sbuf
.shm_ctime
= shp
->shm_ctime
;
error
= copyout((caddr_t
)&sbuf
, uap
->buf
, sizeof sbuf
);
if (cred
->cr_uid
&& cred
->cr_uid
!= shp
->shm_perm
.uid
&&
cred
->cr_uid
!= shp
->shm_perm
.cuid
) {
error
= copyin(uap
->buf
, (caddr_t
)&sbuf
, sizeof sbuf
);
shp
->shm_perm
.uid
= sbuf
.shm_perm
.uid
;
shp
->shm_perm
.gid
= sbuf
.shm_perm
.gid
;
shp
->shm_perm
.mode
= (shp
->shm_perm
.mode
& ~0777)
| (sbuf
.shm_perm
.mode
& 0777);
shp
->shm_ctime
= time
.tv_sec
;
return (shmctl(p
, uap
, retval
));
* Fake semaphore routines, just don't return an error.
* Should be adequate for starbase to run.
hpuxsemctl(p
, uap
, retval
)
struct hpuxsemctl_args
*uap
;
/* XXX: should do something here */
hpuxsemget(p
, uap
, retval
)
struct hpuxsemget_args
*uap
;
/* XXX: should do something here */
hpuxsemop(p
, uap
, retval
)
struct hpuxsemop_args
*uap
;
/* XXX: should do something here */
* HP-UX mmap() emulation (mainly for shared library support).
struct hpuxmmap_args
*uap
;
nargs
.flags
= uap
->flags
&
~(HPUXMAP_FIXED
|HPUXMAP_REPLACE
|HPUXMAP_ANON
);
if (uap
->flags
& HPUXMAP_FIXED
)
nargs
.flags
|= MAP_FIXED
;
if (uap
->flags
& HPUXMAP_ANON
)
nargs
.fd
= (nargs
.flags
& MAP_ANON
) ? -1 : uap
->fd
;
return (mmap(p
, &nargs
, retval
));
/* convert from BSD to HP-UX errno */
if (err
< 0 || err
>= NERR
)
return((int)bsdtohpuxerrnomap
[err
]);
hpuxstat1(fname
, hsb
, follow
, p
)
NDINIT(&nd
, LOOKUP
, follow
| LOCKLEAF
, UIO_USERSPACE
, fname
, p
);
error
= vn_stat(nd
.ni_vp
, &sb
, p
);
error
= bsdtohpuxstat(&sb
, hsb
);
extern int grfopen(dev_t dev
, int oflags
, int devtype
, struct proc
*p
);
extern int hilopen(dev_t dev
, int oflags
, int devtype
, struct proc
*p
);
bzero((caddr_t
)&ds
, sizeof(ds
));
ds
.hst_dev
= (u_short
)sb
->st_dev
;
ds
.hst_ino
= (u_long
)sb
->st_ino
;
ds
.hst_mode
= sb
->st_mode
;
ds
.hst_nlink
= sb
->st_nlink
;
ds
.hst_uid
= (u_short
)sb
->st_uid
;
ds
.hst_gid
= (u_short
)sb
->st_gid
;
ds
.hst_rdev
= bsdtohpuxdev(sb
->st_rdev
);
/* XXX: I don't want to talk about it... */
if ((sb
->st_mode
& S_IFMT
) == S_IFCHR
) {
if (cdevsw
[major(sb
->st_rdev
)].d_open
== grfopen
)
ds
.hst_rdev
= grfdevno(sb
->st_rdev
);
if (cdevsw
[major(sb
->st_rdev
)].d_open
== hilopen
)
ds
.hst_rdev
= hildevno(sb
->st_rdev
);
if (sb
->st_size
< (quad_t
)1 << 32)
ds
.hst_size
= (long)sb
->st_size
;
ds
.hst_atime
= sb
->st_atime
;
ds
.hst_mtime
= sb
->st_mtime
;
ds
.hst_ctime
= sb
->st_ctime
;
ds
.hst_blksize
= sb
->st_blksize
;
ds
.hst_blocks
= sb
->st_blocks
;
return(copyout((caddr_t
)&ds
, (caddr_t
)hsb
, sizeof(ds
)));
* HP-UX ioctl system call. The differences here are:
* IOC_IN also means IOC_VOID if the size portion is zero.
* no FIOCLEX/FIONCLEX/FIOASYNC/FIOGETOWN/FIOSETOWN
* the sgttyb struct is 2 bytes longer
hpuxioctl(p
, uap
, retval
)
register struct hpuxioctl_args
*uap
;
register struct filedesc
*fdp
= p
->p_fd
;
register struct file
*fp
;
if (com
== HPUXTIOCGETP
|| com
== HPUXTIOCSETP
)
return (getsettty(p
, uap
->fdes
, com
, uap
->cmarg
));
if (((unsigned)uap
->fdes
) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fdes
]) == NULL
)
if ((fp
->f_flag
& (FREAD
|FWRITE
)) == 0)
* Interpret high order word to find
* amount of data to be copied to/from the
if (size
> sizeof (stkbuf
)) {
memp
= (caddr_t
)malloc((u_long
)size
, M_IOCTLOPS
, M_WAITOK
);
error
= copyin(uap
->cmarg
, data
, (u_int
)size
);
*(caddr_t
*)data
= uap
->cmarg
;
} else if ((com
&IOC_OUT
) && size
)
* Zero the buffer so the user always
* gets back something deterministic.
*(caddr_t
*)data
= uap
->cmarg
;
char *ofp
= &fdp
->fd_ofileflags
[uap
->fdes
];
* Only set/clear if O_NONBLOCK/FNDELAY not in effect
if ((*ofp
& (UF_NONBLOCK_ON
|UF_FNDELAY_ON
)) == 0) {
tmp
= *ofp
& UF_FIONBIO_ON
;
error
= (*fp
->f_ops
->fo_ioctl
)(fp
, FIONBIO
,
error
= (*fp
->f_ops
->fo_ioctl
)(fp
, TIOCCONS
, data
, p
);
/* BSD-style job control ioctls */
*(int *)data
&= HPUXLTOSTOP
;
if (*(int *)data
& HPUXLTOSTOP
)
/* simple mapping cases */
error
= (*fp
->f_ops
->fo_ioctl
)
(fp
, hpuxtobsdioctl(com
), data
, p
);
if (error
== 0 && com
== HPUXTIOCLGET
) {
if (*(int *)data
& LTOSTOP
)
*(int *)data
= HPUXLTOSTOP
;
/* SYS 5 termio and POSIX termios */
error
= hpuxtermio(uap
->fdes
, com
, data
, p
);
error
= (*fp
->f_ops
->fo_ioctl
)(fp
, com
, data
, p
);
* Copy any data to user, size was
* already set and checked above.
if (error
== 0 && (com
&IOC_OUT
) && size
)
error
= copyout(data
, uap
->cmarg
, (u_int
)size
);
* Man page lies, behaviour here is based on observed behaviour.
struct hpuxgetcontext_args
{
hpuxgetcontext(p
, uap
, retval
)
struct hpuxgetcontext_args
*uap
;
if (machineid
== HP_380
) {
len
= min(uap
->len
, sizeof(hpux040context
));
error
= copyout(hpux040context
, uap
->buf
, len
);
*retval
= sizeof(hpux040context
);
len
= min(uap
->len
, sizeof(hpuxcontext
));
error
= copyout(hpuxcontext
, uap
->buf
, (u_int
)len
);
*retval
= sizeof(hpuxcontext
);
* This is the equivalent of BSD getpgrp but with more restrictions.
* Note we do not check the real uid or "saved" uid.
struct hpuxgetpgrp2_args
{
hpuxgetpgrp2(cp
, uap
, retval
)
register struct hpuxgetpgrp2_args
*uap
;
if (cp
->p_ucred
->cr_uid
&& p
->p_ucred
->cr_uid
!= cp
->p_ucred
->cr_uid
&&
* This is the equivalent of BSD setpgrp but with more restrictions.
* Note we do not check the real uid or "saved" uid or pgrp.
struct hpuxsetpgrp2_args
{
hpuxsetpgrp2(p
, uap
, retval
)
struct hpuxsetpgrp2_args
*uap
;
/* empirically determined */
if (uap
->pgrp
< 0 || uap
->pgrp
>= 30000)
return (setpgid(p
, uap
, retval
));
* XXX Same as old BSD setre[ug]id right now. Need to consider saved ids.
struct hpuxsetresuid_args
{
hpuxsetresuid(p
, uap
, retval
)
struct hpuxsetresuid_args
*uap
;
register struct pcred
*pc
= p
->p_cred
;
register uid_t ruid
, euid
;
* Allow setting real uid to previous effective, for swapping real and
* effective. This should be:
* if (ruid != pc->p_ruid &&
* (error = suser(pc->pc_ucred, &p->p_acflag)))
if (ruid
!= pc
->p_ruid
&& ruid
!= pc
->pc_ucred
->cr_uid
/* XXX */ &&
(error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
euid
= pc
->pc_ucred
->cr_uid
;
if (euid
!= pc
->pc_ucred
->cr_uid
&& euid
!= pc
->p_ruid
&&
euid
!= pc
->p_svuid
&& (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
* Everything's okay, do it. Copy credentials so other references do
pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
pc
->pc_ucred
->cr_uid
= euid
;
struct hpuxsetresgid_args
{
hpuxsetresgid(p
, uap
, retval
)
struct hpuxsetresgid_args
*uap
;
register struct pcred
*pc
= p
->p_cred
;
register gid_t rgid
, egid
;
* Allow setting real gid to previous effective, for swapping real and
* effective. This didn't really work correctly in 4.[23], but is
* preserved so old stuff doesn't fail. This should be:
* if (rgid != pc->p_rgid &&
* (error = suser(pc->pc_ucred, &p->p_acflag)))
if (rgid
!= pc
->p_rgid
&& rgid
!= pc
->pc_ucred
->cr_groups
[0] /* XXX */ &&
(error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
egid
= pc
->pc_ucred
->cr_groups
[0];
if (egid
!= pc
->pc_ucred
->cr_groups
[0] && egid
!= pc
->p_rgid
&&
egid
!= pc
->p_svgid
&& (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
pc
->pc_ucred
->cr_groups
[0] = egid
;
hpuxgetrlimit(p
, uap
, retval
)
struct hpuxrlimit_args
*uap
;
if (uap
->which
> HPUXRLIMIT_NOFILE
)
if (uap
->which
== HPUXRLIMIT_NOFILE
)
uap
->which
= RLIMIT_NOFILE
;
return (compat_43_getrlimit(p
, uap
, retval
));
hpuxsetrlimit(p
, uap
, retval
)
struct hpuxrlimit_args
*uap
;
if (uap
->which
> HPUXRLIMIT_NOFILE
)
if (uap
->which
== HPUXRLIMIT_NOFILE
)
uap
->which
= RLIMIT_NOFILE
;
return (compat_43_setrlimit(p
, uap
, retval
));
* XXX: simple recognition hack to see if we can make grmd work.
hpuxlockf(p
, uap
, retval
)
struct hpuxlockf_args
*uap
;
struct hpuxgetaccess_args
{
hpuxgetaccess(p
, uap
, retval
)
register struct hpuxgetaccess_args
*uap
;
register struct ucred
*cred
;
register struct vnode
*vp
;
* Build an appropriate credential structure
cred
= crdup(p
->p_ucred
);
case 65502: /* UID_EUID */
case 65503: /* UID_RUID */
cred
->cr_uid
= p
->p_cred
->p_ruid
;
case 65504: /* UID_SUID */
case -1: /* NGROUPS_EGID */
case -5: /* NGROUPS_EGID_SUPP */
case -2: /* NGROUPS_RGID */
cred
->cr_gid
= p
->p_cred
->p_rgid
;
case -6: /* NGROUPS_RGID_SUPP */
cred
->cr_gid
= p
->p_cred
->p_rgid
;
case -3: /* NGROUPS_SGID */
case -7: /* NGROUPS_SGID_SUPP */
case -4: /* NGROUPS_SUPP */
if (cred
->cr_ngroups
> 1)
cred
->cr_gid
= cred
->cr_groups
[1];
if (uap
->ngroups
> 0 && uap
->ngroups
<= NGROUPS
)
error
= copyin((caddr_t
)uap
->gidset
,
uap
->ngroups
* sizeof(lgroups
[0]));
for (gid
= 0; gid
< uap
->ngroups
; gid
++)
cred
->cr_groups
[gid
] = lgroups
[gid
];
cred
->cr_ngroups
= uap
->ngroups
;
* Lookup file using caller's effective IDs.
NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
* Use the constructed credentials for access checks.
if (VOP_ACCESS(vp
, VREAD
, cred
, p
) == 0)
if (vn_writechk(vp
) == 0 && VOP_ACCESS(vp
, VWRITE
, cred
, p
) == 0)
/* XXX we return X_OK for root on VREG even if not */
if (VOP_ACCESS(vp
, VEXEC
, cred
, p
) == 0)
#define UOFF(f) ((int)&((struct user *)0)->f)
#define HPUOFF(f) ((int)&((struct hpuxuser *)0)->f)
/* simplified FP structure */
* Brutal hack! Map HP-UX u-area offsets into BSD k-stack offsets.
hpuxtobsduoff(off
, isps
, p
)
register int *ar0
= p
->p_md
.md_regs
;
/* u_ar0 field; procxmt puts in U_ar0 */
if ((int)off
== HPUOFF(hpuxu_ar0
))
/* FP registers from PCB */
hp
= (struct hpuxfp
*)HPUOFF(hpuxu_fp
);
bp
= (struct bsdfp
*)UOFF(u_pcb
.pcb_fpregs
);
if (off
>= hp
->hpfp_ctrl
&& off
< &hp
->hpfp_ctrl
[3])
return((int)&bp
->ctrl
[off
- hp
->hpfp_ctrl
]);
if (off
>= hp
->hpfp_reg
&& off
< &hp
->hpfp_reg
[24])
return((int)&bp
->reg
[off
- hp
->hpfp_reg
]);
* Everything else we recognize comes from the kernel stack,
* so we convert off to an absolute address (if not already)
if (off
< (int *)ctob(UPAGES
))
off
= (int *)((u_int
)off
+ (u_int
)kstack
);
* We know that the HP-UX registers are in the same order as ours.
* The only difference is that their PS is 2 bytes instead of a
* padded 4 like ours throwing the alignment off.
if (off
>= ar0
&& off
< &ar0
[18]) {
* PS: return low word and high word of PC as HP-UX would
* XXX we don't do this since HP-UX adb doesn't rely on
* it and passing such an offset to procxmt will cause
* it to fail anyway. Instead, we just set the offset
* to PS and let hpuxptrace() shift up the value returned.
raddr
= (u_int
) &((short *)ar0
)[PS
*2+1];
raddr
= (u_int
) &ar0
[(int)(off
- ar0
)];
* PC: off will be &u.u_ar0[16.5] since HP-UX saved PS
else if (off
== (int *)&(((short *)ar0
)[PS
*2+1]))
raddr
= (u_int
) &ar0
[PC
];
raddr
= (u_int
) &ar0
[(int)(off
- ar0
)];
return((int)(raddr
- (u_int
)kstack
));
* Kludge up a uarea dump so that HP-UX debuggers can find out
* what they need. IMPORTANT NOTE: we do not EVEN attempt to
* convert the entire user struct.
struct proc
*p
= curproc
;
faku
= (struct hpuxuser
*)malloc((u_long
)ctob(1), M_TEMP
, M_WAITOK
);
* Make sure there is no mistake about this
* being a real user structure.
bzero((caddr_t
)faku
, ctob(1));
* Fill in the process sizes.
faku
->hpuxu_tsize
= p
->p_vmspace
->vm_tsize
;
faku
->hpuxu_dsize
= p
->p_vmspace
->vm_dsize
;
faku
->hpuxu_ssize
= p
->p_vmspace
->vm_ssize
;
* Fill in the exec header for CDB.
* This was saved back in exec(). As far as I can tell CDB
* only uses this information to verify that a particular
* core file goes with a particular binary.
bcopy((caddr_t
)p
->p_addr
->u_md
.md_exec
,
(caddr_t
)&faku
->hpuxu_exdata
, sizeof (struct hpux_exec
));
* Adjust user's saved registers (on kernel stack) to reflect
* HP-UX order. Note that HP-UX saves the SR as 2 bytes not 4
* so we have to move it up.
faku
->hpuxu_ar0
= p
->p_md
.md_regs
;
foop
= (short *) p
->p_md
.md_regs
;
* Copy 68881 registers from our PCB format to HP-UX format
bp
= (struct bsdfp
*) &p
->p_addr
->u_pcb
.pcb_fpregs
;
bcopy((caddr_t
)bp
->save
, (caddr_t
)faku
->hpuxu_fp
.hpfp_save
,
bcopy((caddr_t
)bp
->ctrl
, (caddr_t
)faku
->hpuxu_fp
.hpfp_ctrl
,
bcopy((caddr_t
)bp
->reg
, (caddr_t
)faku
->hpuxu_fp
.hpfp_reg
,
* Dump this artfully constructed page in place of the
error
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
)faku
, ctob(1), (off_t
)0,
UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
,
* Dump the remaining UPAGES-1 pages normally
error
= vn_rdwr(UIO_WRITE
, vp
, kstack
+ ctob(1),
ctob(UPAGES
-1), (off_t
)ctob(1), UIO_SYSSPACE
,
IO_NODELOCKED
|IO_UNIT
, cred
, (int *)NULL
, p
);
free((caddr_t
)faku
, M_TEMP
);
* The remaining routines are essentially the same as those in kern_xxx.c
* and vfs_xxx.c as defined under "#ifdef COMPAT". We replicate them here
* to avoid HPUXCOMPAT dependencies in those files and to make sure that
* HP-UX compatibility still works even when COMPAT is not defined.
* These are still needed as of HP-UX 7.05.
/* ye ole stat structure */
compat_43_hpuxsetpgrp(p
, uap
, retval
)
if (p
->p_pid
!= p
->p_pgid
)
enterpgrp(p
, p
->p_pid
, 0);
compat_43_hpuxtime(p
, uap
, retval
)
register struct ohpuxtime_args
*uap
;
error
= copyout((caddr_t
)&time
.tv_sec
, (caddr_t
)uap
->tp
,
*(time_t *)retval
= time
.tv_sec
;
compat_43_hpuxstime(p
, uap
, retval
)
register struct ohpuxstime_args
*uap
;
if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
boottime
.tv_sec
+= tv
.tv_sec
- time
.tv_sec
;
s
= splhigh(); time
= tv
; splx(s
);
compat_43_hpuxftime(p
, uap
, retval
)
register struct ohpuxftime_args
*uap
;
tb
.millitm
= time
.tv_usec
/ 1000;
tb
.timezone
= tz
.tz_minuteswest
;
tb
.dstflag
= tz
.tz_dsttime
;
return (copyout((caddr_t
)&tb
, (caddr_t
)uap
->tp
, sizeof (tb
)));
compat_43_hpuxalarm(p
, uap
, retval
)
register struct ohpuxalarm_args
*uap
;
untimeout(realitexpire
, (caddr_t
)p
);
timerclear(&p
->p_realtimer
.it_interval
);
if (timerisset(&p
->p_realtimer
.it_value
) &&
timercmp(&p
->p_realtimer
.it_value
, &time
, >))
*retval
= p
->p_realtimer
.it_value
.tv_sec
- time
.tv_sec
;
timerclear(&p
->p_realtimer
.it_value
);
p
->p_realtimer
.it_value
= time
;
p
->p_realtimer
.it_value
.tv_sec
+= uap
->deltat
;
timeout(realitexpire
, (caddr_t
)p
, hzto(&p
->p_realtimer
.it_value
));
compat_43_hpuxnice(p
, uap
, retval
)
register struct ohpuxnice_args
*uap
;
error
= donice(p
, p
, (p
->p_nice
-NZERO
)+uap
->niceness
);
*retval
= p
->p_nice
- NZERO
;
compat_43_hpuxtimes(p
, uap
, retval
)
register struct ohpuxtimes_args
*uap
;
calcru(p
, &ru
, &rs
, NULL
);
atms
.tms_utime
= hpuxscale(&ru
);
atms
.tms_stime
= hpuxscale(&rs
);
atms
.tms_cutime
= hpuxscale(&p
->p_stats
->p_cru
.ru_utime
);
atms
.tms_cstime
= hpuxscale(&p
->p_stats
->p_cru
.ru_stime
);
error
= copyout((caddr_t
)&atms
, (caddr_t
)uap
->tmsb
, sizeof (atms
));
*(time_t *)retval
= hpuxscale(&time
) - hpuxscale(&boottime
);
* Doesn't exactly do what the documentation says.
* What we really do is return 1/HPUX_HZ-th of a second since that
register struct timeval
*tvp
;
return (tvp
->tv_sec
* HPUX_HZ
+ tvp
->tv_usec
* HPUX_HZ
/ 1000000);
* Set IUPD and IACC times on file.
compat_43_hpuxutime(p
, uap
, retval
)
register struct ohpuxutime_args
*uap
;
register struct vnode
*vp
;
error
= copyin((caddr_t
)uap
->tptr
, (caddr_t
)tv
, sizeof (tv
));
tv
[0] = tv
[1] = time
.tv_sec
;
vattr
.va_atime
.ts_sec
= tv
[0];
vattr
.va_atime
.ts_nsec
= 0;
vattr
.va_mtime
.ts_sec
= tv
[1];
vattr
.va_mtime
.ts_nsec
= 0;
NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
, uap
->fname
, p
);
if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
error
= VOP_SETATTR(vp
, &vattr
, nd
.ni_cnd
.cn_cred
, p
);
compat_43_hpuxpause(p
, uap
, retval
)
(void) tsleep(kstack
, PPAUSE
| PCATCH
, "pause", 0);
/* always return EINTR rather than ERESTART... */
* The old fstat system call.
compat_43_hpuxfstat(p
, uap
, retval
)
register struct ohpuxfstat_args
*uap
;
register struct filedesc
*fdp
= p
->p_fd
;
if (((unsigned)uap
->fd
) >= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[uap
->fd
]) == NULL
)
if (fp
->f_type
!= DTYPE_VNODE
)
return (compat_43_hpuxstat1((struct vnode
*)fp
->f_data
, uap
->sb
, p
));
* Old stat system call. This version follows links.
compat_43_hpuxstat(p
, uap
, retval
)
register struct ohpuxstat_args
*uap
;
NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
, uap
->fname
, p
);
error
= compat_43_hpuxstat1(nd
.ni_vp
, uap
->sb
, p
);
compat_43_hpuxstat1(vp
, ub
, p
)
error
= vn_stat(vp
, &sb
, p
);
ohsb
.ohst_dev
= sb
.st_dev
;
ohsb
.ohst_ino
= sb
.st_ino
;
ohsb
.ohst_mode
= sb
.st_mode
;
ohsb
.ohst_nlink
= sb
.st_nlink
;
ohsb
.ohst_uid
= sb
.st_uid
;
ohsb
.ohst_gid
= sb
.st_gid
;
ohsb
.ohst_rdev
= sb
.st_rdev
;
if (sb
.st_size
< (quad_t
)1 << 32)
ohsb
.ohst_size
= sb
.st_size
;
ohsb
.ohst_atime
= sb
.st_atime
;
ohsb
.ohst_mtime
= sb
.st_mtime
;
ohsb
.ohst_ctime
= sb
.st_ctime
;
return (copyout((caddr_t
)&ohsb
, (caddr_t
)ub
, sizeof(ohsb
)));