xref: /original-bsd/sys/hp/hpux/hpux_compat.c (revision 21eed380)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1990 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department.
9  *
10  * %sccs.include.redist.c%
11  *
12  * from: Utah $Hdr: hpux_compat.c 1.55 92/12/26$
13  *
14  *	@(#)hpux_compat.c	7.33 (Berkeley) 12/27/92
15  */
16 
17 /*
18  * Various HP-UX compatibility routines
19  */
20 
21 #ifdef HPUXCOMPAT
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/signalvar.h>
26 #include <sys/kernel.h>
27 #include <sys/filedesc.h>
28 #include <sys/proc.h>
29 #include <sys/buf.h>
30 #include <sys/wait.h>
31 #include <sys/file.h>
32 #include <sys/namei.h>
33 #include <sys/vnode.h>
34 #include <sys/ioctl.h>
35 #include <sys/ptrace.h>
36 #include <sys/stat.h>
37 #include <sys/syslog.h>
38 #include <sys/malloc.h>
39 #include <sys/mount.h>
40 #include <sys/ipc.h>
41 #include <sys/user.h>
42 #include <sys/mman.h>
43 
44 #include <machine/cpu.h>
45 #include <machine/reg.h>
46 #include <machine/psl.h>
47 #include <machine/vmparam.h>
48 #include <hp/hpux/hpux.h>
49 #include <hp/hpux/hpux_termio.h>
50 
51 #ifdef DEBUG
52 int unimpresponse = 0;
53 #endif
54 
55 /* SYS5 style UTSNAME info */
56 struct hpuxutsname protoutsname = {
57 	"4.4bsd", "", "0.5", "B", "9000/3?0", ""
58 };
59 
60 /* 6.0 and later style context */
61 #if defined(HP380)
62 char hpux040context[] =
63     "standalone HP-MC68040 HP-MC68881 HP-MC68020 HP-MC68010 localroot default";
64 #endif
65 #ifdef FPCOPROC
66 char hpuxcontext[] =
67 	"standalone HP-MC68881 HP-MC68020 HP-MC68010 localroot default";
68 #else
69 char hpuxcontext[] =
70 	"standalone HP-MC68020 HP-MC68010 localroot default";
71 #endif
72 
73 /* YP domainname */
74 char	domainname[MAXHOSTNAMELEN] = "unknown";
75 int	domainnamelen = 7;
76 
77 #define NERR	79
78 #define BERR	1000
79 
80 /* indexed by BSD errno */
81 short bsdtohpuxerrnomap[NERR] = {
82 /*00*/	  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
83 /*10*/	 10,  45,  12,  13,  14,  15,  16,  17,  18,  19,
84 /*20*/	 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
85 /*30*/	 30,  31,  32,  33,  34, 246, 245, 244, 216, 217,
86 /*40*/	218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
87 /*50*/	228, 229, 230, 231, 232, 233, 234, 235, 236, 237,
88 /*60*/	238, 239, 249, 248, 241, 242, 247,BERR,BERR,BERR,
89 /*70*/   70,  71,BERR,BERR,BERR,BERR,BERR,  46,BERR
90 };
91 
92 notimp(p, uap, retval, code, nargs)
93 	struct proc *p;
94 	int *uap, *retval;
95 	int code, nargs;
96 {
97 	int error = 0;
98 #ifdef DEBUG
99 	register int *argp = uap;
100 	extern char *hpuxsyscallnames[];
101 
102 	printf("HP-UX %s(", hpuxsyscallnames[code]);
103 	if (nargs)
104 		while (nargs--)
105 			printf("%x%c", *argp++, nargs? ',' : ')');
106 	else
107 		printf(")");
108 	printf("\n");
109 	switch (unimpresponse) {
110 	case 0:
111 		error = nosys(p, uap, retval);
112 		break;
113 	case 1:
114 		error = EINVAL;
115 		break;
116 	}
117 #else
118 	error = nosys(p, uap, retval);
119 #endif
120 	uprintf("HP-UX system call %d not implemented\n", code);
121 	return (error);
122 }
123 
124 struct hpuxexecv_args {
125 	char	*fname;
126 	char	**argp;
127 	char	**envp;
128 };
129 hpuxexecv(p, uap, retval)
130 	struct proc *p;
131 	struct hpuxexecv_args *uap;
132 	int *retval;
133 {
134 	extern int execve();
135 
136 	uap->envp = NULL;
137 	return (execve(p, uap, retval));
138 }
139 
140 /*
141  * HP-UX versions of wait and wait3 actually pass the parameters
142  * (status pointer, options, rusage) into the kernel rather than
143  * handling it in the C library stub.  We also need to map any
144  * termination signal from BSD to HP-UX.
145  */
146 struct hpuxwait3_args {
147 	int	*status;
148 	int	options;
149 	int	rusage;
150 };
151 hpuxwait3(p, uap, retval)
152 	struct proc *p;
153 	struct hpuxwait3_args *uap;
154 	int *retval;
155 {
156 	/* rusage pointer must be zero */
157 	if (uap->rusage)
158 		return (EINVAL);
159 	p->p_md.md_regs[PS] = PSL_ALLCC;
160 	p->p_md.md_regs[R0] = uap->options;
161 	p->p_md.md_regs[R1] = uap->rusage;
162 	return (hpuxwait(p, uap, retval));
163 }
164 
165 struct hpuxwait_args {
166 	int	*status;
167 };
168 hpuxwait(p, uap, retval)
169 	struct proc *p;
170 	struct hpuxwait_args *uap;
171 	int *retval;
172 {
173 	int sig, *statp, error;
174 
175 	statp = uap->status;	/* owait clobbers first arg */
176 	error = owait(p, uap, retval);
177 	/*
178 	 * HP-UX wait always returns EINTR when interrupted by a signal
179 	 * (well, unless its emulating a BSD process, but we don't bother...)
180 	 */
181 	if (error == ERESTART)
182 		error = EINTR;
183 	if (error)
184 		return (error);
185 	sig = retval[1] & 0xFF;
186 	if (sig == WSTOPPED) {
187 		sig = (retval[1] >> 8) & 0xFF;
188 		retval[1] = (bsdtohpuxsig(sig) << 8) | WSTOPPED;
189 	} else if (sig)
190 		retval[1] = (retval[1] & 0xFF00) |
191 			bsdtohpuxsig(sig & 0x7F) | (sig & 0x80);
192 	if (statp)
193 		if (suword((caddr_t)statp, retval[1]))
194 			error = EFAULT;
195 	return (error);
196 }
197 
198 struct hpuxwaitpid_args {
199 	int	pid;
200 	int	*status;
201 	int	options;
202 	struct	rusage *rusage;	/* wait4 arg */
203 };
204 hpuxwaitpid(p, uap, retval)
205 	struct proc *p;
206 	struct hpuxwaitpid_args *uap;
207 	int *retval;
208 {
209 	int rv, sig, xstat, error;
210 
211 	uap->rusage = 0;
212 	error = wait4(p, uap, retval);
213 	/*
214 	 * HP-UX wait always returns EINTR when interrupted by a signal
215 	 * (well, unless its emulating a BSD process, but we don't bother...)
216 	 */
217 	if (error == ERESTART)
218 		error = EINTR;
219 	if (error)
220 		return (error);
221 	if (uap->status) {
222 		/*
223 		 * Wait4 already wrote the status out to user space,
224 		 * pull it back, change the signal portion, and write
225 		 * it back out.
226 		 */
227 		rv = fuword((caddr_t)uap->status);
228 		if (WIFSTOPPED(rv)) {
229 			sig = WSTOPSIG(rv);
230 			rv = W_STOPCODE(bsdtohpuxsig(sig));
231 		} else if (WIFSIGNALED(rv)) {
232 			sig = WTERMSIG(rv);
233 			xstat = WEXITSTATUS(rv);
234 			rv = W_EXITCODE(xstat, bsdtohpuxsig(sig)) |
235 				WCOREDUMP(rv);
236 		}
237 		(void)suword((caddr_t)uap->status, rv);
238 	}
239 	return (error);
240 }
241 
242 /*
243  * Must remap some bits in the mode mask.
244  * O_CREAT, O_TRUNC, and O_EXCL must be remapped,
245  * O_SYNCIO (0100000) is removed entirely.
246  */
247 struct hpuxopen_args {
248 	char	*fname;
249 	int	mode;
250 	int	crtmode;
251 };
252 hpuxopen(p, uap, retval)
253 	struct proc *p;
254 	register struct hpuxopen_args *uap;
255 	int *retval;
256 {
257 	int mode;
258 
259 	mode = uap->mode;
260 	uap->mode &= ~(HPUXFSYNCIO|HPUXFEXCL|HPUXFTRUNC|HPUXFCREAT);
261 	if (mode & HPUXFCREAT) {
262 		/*
263 		 * simulate the pre-NFS behavior that opening a
264 		 * file for READ+CREATE ignores the CREATE (unless
265 		 * EXCL is set in which case we will return the
266 		 * proper error).
267 		 */
268 		if ((mode & HPUXFEXCL) || (FFLAGS(mode) & FWRITE))
269 			uap->mode |= O_CREAT;
270 	}
271 	if (mode & HPUXFTRUNC)
272 		uap->mode |= O_TRUNC;
273 	if (mode & HPUXFEXCL)
274 		uap->mode |= O_EXCL;
275 	return (open(p, uap, retval));
276 }
277 
278 /*
279  * Old creat system call.
280  */
281 struct hpuxcreat_args {
282 	char	*fname;
283 	int	fmode;
284 };
285 hpuxcreat(p, uap, retval)
286 	struct proc *p;
287 	register struct hpuxcreat_args *uap;
288 	int *retval;
289 {
290 	struct nargs {
291 		char	*fname;
292 		int	mode;
293 		int	crtmode;
294 	} openuap;
295 
296 	openuap.fname = uap->fname;
297 	openuap.crtmode = uap->fmode;
298 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
299 	return (open(p, &openuap, retval));
300 }
301 
302 /* XXX */
303 #define	UF_FNDELAY_ON	0x20
304 #define	UF_FIONBIO_ON	0x40
305 /* XXX */
306 
307 struct hpuxfcntl_args {
308 	int	fdes;
309 	int	cmd;
310 	int	arg;
311 };
312 hpuxfcntl(p, uap, retval)
313 	struct proc *p;
314 	register struct hpuxfcntl_args *uap;
315 	int *retval;
316 {
317 	int mode, error;
318 	char *fp;
319 
320 	if (uap->cmd == F_GETFL || uap->cmd == F_SETFL) {
321 		if ((unsigned)uap->fdes >= p->p_fd->fd_nfiles ||
322 		    p->p_fd->fd_ofiles[uap->fdes] == NULL)
323 			return (EBADF);
324 		fp = &p->p_fd->fd_ofileflags[uap->fdes];
325 	}
326 	switch (uap->cmd) {
327 	case F_SETFL:
328 		if (uap->arg & FNONBLOCK)
329 			*fp |= UF_FNDELAY_ON;
330 		else {
331 			*fp &= ~UF_FNDELAY_ON;
332 			if (*fp & UF_FIONBIO_ON)
333 				uap->arg |= FNONBLOCK;
334 		}
335 		uap->arg &= ~(HPUXFSYNCIO|HPUXFREMOTE|FUSECACHE);
336 		break;
337 	case F_GETFL:
338 	case F_DUPFD:
339 	case F_GETFD:
340 	case F_SETFD:
341 		break;
342 	default:
343 		return (EINVAL);
344 	}
345 	error = fcntl(p, uap, retval);
346 	if (error == 0 && uap->cmd == F_GETFL) {
347 		mode = *retval;
348 		*retval &= ~(O_CREAT|O_TRUNC|O_EXCL|FUSECACHE);
349 		if ((mode & FNONBLOCK) && (*fp & UF_FNDELAY_ON) == 0)
350 			*retval &= ~FNONBLOCK;
351 		if (mode & O_CREAT)
352 			*retval |= HPUXFCREAT;
353 		if (mode & O_TRUNC)
354 			*retval |= HPUXFTRUNC;
355 		if (mode & O_EXCL)
356 			*retval |= HPUXFEXCL;
357 	}
358 	return (error);
359 }
360 
361 /*
362  * Read and write should return a 0 count when an operation
363  * on a VNODE would block, not an error.
364  *
365  * In 6.2 and 6.5 sockets appear to return EWOULDBLOCK.
366  * In 7.0 the behavior for sockets depends on whether FNONBLOCK is in effect.
367  */
368 struct hpuxread_args {
369 	int	fd;
370 };
371 hpuxread(p, uap, retval)
372 	struct proc *p;
373 	struct hpuxread_args *uap;
374 	int *retval;
375 {
376 	int error;
377 
378 	error = read(p, uap, retval);
379 	if (error == EWOULDBLOCK &&
380 	    (p->p_fd->fd_ofiles[uap->fd]->f_type == DTYPE_VNODE ||
381 	     p->p_fd->fd_ofileflags[uap->fd] & UF_FNDELAY_ON)) {
382 		error = 0;
383 		*retval = 0;
384 	}
385 	return (error);
386 }
387 
388 struct hpuxwrite_args {
389 	int	fd;
390 };
391 hpuxwrite(p, uap, retval)
392 	struct proc *p;
393 	struct hpuxwrite_args *uap;
394 	int *retval;
395 {
396 	int error;
397 
398 	error = write(p, uap, retval);
399 	if (error == EWOULDBLOCK &&
400 	    (p->p_fd->fd_ofiles[uap->fd]->f_type == DTYPE_VNODE ||
401 	     p->p_fd->fd_ofileflags[uap->fd] & UF_FNDELAY_ON)) {
402 		error = 0;
403 		*retval = 0;
404 	}
405 	return (error);
406 }
407 
408 struct hpuxreadv_args {
409 	int	fd;
410 };
411 hpuxreadv(p, uap, retval)
412 	struct proc *p;
413 	struct hpuxreadv_args *uap;
414 	int *retval;
415 {
416 	int error;
417 
418 	error = readv(p, uap, retval);
419 	if (error == EWOULDBLOCK &&
420 	    (p->p_fd->fd_ofiles[uap->fd]->f_type == DTYPE_VNODE ||
421 	     p->p_fd->fd_ofileflags[uap->fd] & UF_FNDELAY_ON)) {
422 		error = 0;
423 		*retval = 0;
424 	}
425 	return (error);
426 }
427 
428 struct hpuxwritev_args {
429 	int	fd;
430 };
431 hpuxwritev(p, uap, retval)
432 	struct proc *p;
433 	struct hpuxwritev_args *uap;
434 	int *retval;
435 {
436 	int error;
437 
438 	error = writev(p, uap, retval);
439 	if (error == EWOULDBLOCK &&
440 	    (p->p_fd->fd_ofiles[uap->fd]->f_type == DTYPE_VNODE ||
441 	     p->p_fd->fd_ofileflags[uap->fd] & UF_FNDELAY_ON)) {
442 		error = 0;
443 		*retval = 0;
444 	}
445 	return (error);
446 }
447 
448 /*
449  * 4.3bsd dup allows dup2 to come in on the same syscall entry
450  * and hence allows two arguments.  HP-UX dup has only one arg.
451  */
452 struct hpuxdup_args {
453 	int	i;
454 };
455 hpuxdup(p, uap, retval)
456 	struct proc *p;
457 	register struct hpuxdup_args *uap;
458 	int *retval;
459 {
460 	register struct filedesc *fdp = p->p_fd;
461 	struct file *fp;
462 	int fd, error;
463 
464 	if (((unsigned)uap->i) >= fdp->fd_nfiles ||
465 	    (fp = fdp->fd_ofiles[uap->i]) == NULL)
466 		return (EBADF);
467 	if (error = fdalloc(p, 0, &fd))
468 		return (error);
469 	fdp->fd_ofiles[fd] = fp;
470 	fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE;
471 	fp->f_count++;
472 	if (fd > fdp->fd_lastfile)
473 		fdp->fd_lastfile = fd;
474 	*retval = fd;
475 	return (0);
476 }
477 
478 struct hpuxutssys_args {
479 	struct hpuxutsname *uts;
480 	int dev;
481 	int request;
482 };
483 hpuxutssys(p, uap, retval)
484 	struct proc *p;
485 	register struct hpuxutssys_args *uap;
486 	int *retval;
487 {
488 	register int i;
489 	int error;
490 
491 	switch (uap->request) {
492 	/* uname */
493 	case 0:
494 		/* fill in machine type */
495 		switch (machineid) {
496 		case HP_320:
497 			protoutsname.machine[6] = '2';
498 			break;
499 		/* includes 318 and 319 */
500 		case HP_330:
501 			protoutsname.machine[6] = '3';
502 			break;
503 		case HP_340:
504 			protoutsname.machine[6] = '4';
505 			break;
506 		case HP_350:
507 			protoutsname.machine[6] = '5';
508 			break;
509 		case HP_360:
510 			protoutsname.machine[6] = '6';
511 			break;
512 		case HP_370:
513 			protoutsname.machine[6] = '7';
514 			break;
515 		/* includes 345 */
516 		case HP_375:
517 			protoutsname.machine[6] = '7';
518 			protoutsname.machine[7] = '5';
519 			break;
520 		/* includes 425 */
521 		case HP_380:
522 			protoutsname.machine[6] = '8';
523 			break;
524 		case HP_433:
525 			protoutsname.machine[5] = '4';
526 			protoutsname.machine[6] = '3';
527 			protoutsname.machine[7] = '3';
528 			break;
529 		}
530 		/* copy hostname (sans domain) to nodename */
531 		for (i = 0; i < 8 && hostname[i] != '.'; i++)
532 			protoutsname.nodename[i] = hostname[i];
533 		protoutsname.nodename[i] = '\0';
534 		error = copyout((caddr_t)&protoutsname, (caddr_t)uap->uts,
535 				sizeof(struct hpuxutsname));
536 		break;
537 
538 	/* gethostname */
539 	case 5:
540 		/* uap->dev is length */
541 		if (uap->dev > hostnamelen + 1)
542 			uap->dev = hostnamelen + 1;
543 		error = copyout((caddr_t)hostname, (caddr_t)uap->uts,
544 				uap->dev);
545 		break;
546 
547 	case 1:	/* ?? */
548 	case 2:	/* ustat */
549 	case 3:	/* ?? */
550 	case 4:	/* sethostname */
551 	default:
552 		error = EINVAL;
553 		break;
554 	}
555 	return (error);
556 }
557 
558 struct hpuxsysconf_args {
559 	int	name;
560 };
561 hpuxsysconf(p, uap, retval)
562 	struct proc *p;
563 	struct hpuxsysconf_args *uap;
564 	int *retval;
565 {
566 	switch (uap->name) {
567 
568 	/* open files */
569 	case HPUX_SYSCONF_OPENMAX:
570 		*retval = NOFILE;
571 		break;
572 
573 	/* architecture */
574 	case HPUX_SYSCONF_CPUTYPE:
575 		switch (machineid) {
576 		case HP_320:
577 		case HP_330:
578 		case HP_350:
579 			*retval = HPUX_SYSCONF_CPUM020;
580 			break;
581 		case HP_340:
582 		case HP_360:
583 		case HP_370:
584 		case HP_375:
585 			*retval = HPUX_SYSCONF_CPUM030;
586 			break;
587 		case HP_380:
588 		case HP_433:
589 			*retval = HPUX_SYSCONF_CPUM040;
590 			break;
591 		}
592 		break;
593 	default:
594 		uprintf("HP-UX sysconf(%d) not implemented\n", uap->name);
595 		return (EINVAL);
596 	}
597 	return (0);
598 }
599 
600 struct hpuxstat_args {
601 	char	*fname;
602 	struct hpuxstat *hsb;
603 };
604 hpuxstat(p, uap, retval)
605 	struct proc *p;
606 	struct hpuxstat_args *uap;
607 	int *retval;
608 {
609 	return (hpuxstat1(uap->fname, uap->hsb, FOLLOW, p));
610 }
611 
612 struct hpuxlstat_args {
613 	char	*fname;
614 	struct hpuxstat *hsb;
615 };
616 hpuxlstat(p, uap, retval)
617 	struct proc *p;
618 	struct hpuxlstat_args *uap;
619 	int *retval;
620 {
621 	return (hpuxstat1(uap->fname, uap->hsb, NOFOLLOW, p));
622 }
623 
624 struct hpuxfstat_args {
625 	int	fdes;
626 	struct	hpuxstat *hsb;
627 };
628 hpuxfstat(p, uap, retval)
629 	struct proc *p;
630 	register struct hpuxfstat_args *uap;
631 	int *retval;
632 {
633 	register struct filedesc *fdp = p->p_fd;
634 	register struct file *fp;
635 	struct stat sb;
636 	int error;
637 
638 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
639 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
640 		return (EBADF);
641 
642 	switch (fp->f_type) {
643 
644 	case DTYPE_VNODE:
645 		error = vn_stat((struct vnode *)fp->f_data, &sb, p);
646 		break;
647 
648 	case DTYPE_SOCKET:
649 		error = soo_stat((struct socket *)fp->f_data, &sb, p);
650 		break;
651 
652 	default:
653 		panic("fstat");
654 		/*NOTREACHED*/
655 	}
656 	/* is this right for sockets?? */
657 	if (error == 0)
658 		error = bsdtohpuxstat(&sb, uap->hsb);
659 	return (error);
660 }
661 
662 struct hpuxulimit_args {
663 	int	cmd;
664 	long	newlimit;
665 };
666 hpuxulimit(p, uap, retval)
667 	struct proc *p;
668 	register struct hpuxulimit_args *uap;
669 	long *retval;
670 {
671 	struct rlimit *limp;
672 	int error = 0;
673 
674 	limp = &p->p_rlimit[RLIMIT_FSIZE];
675 	switch (uap->cmd) {
676 	case 2:
677 		uap->newlimit *= 512;
678 		if (uap->newlimit > limp->rlim_max &&
679 		    (error = suser(p->p_ucred, &p->p_acflag)))
680 			break;
681 		limp->rlim_cur = limp->rlim_max = uap->newlimit;
682 		/* else fall into... */
683 
684 	case 1:
685 		*retval = limp->rlim_max / 512;
686 		break;
687 
688 	case 3:
689 		limp = &p->p_rlimit[RLIMIT_DATA];
690 		*retval = ctob(p->p_vmspace->vm_tsize) + limp->rlim_max;
691 		break;
692 
693 	default:
694 		error = EINVAL;
695 		break;
696 	}
697 	return (error);
698 }
699 
700 /*
701  * Map "real time" priorities 0 (high) thru 127 (low) into nice
702  * values -16 (high) thru -1 (low).
703  */
704 struct hpuxrtprio_args {
705 	int pid;
706 	int prio;
707 };
708 hpuxrtprio(cp, uap, retval)
709 	struct proc *cp;
710 	register struct hpuxrtprio_args *uap;
711 	int *retval;
712 {
713 	struct proc *p;
714 	int nice, error;
715 
716 	if (uap->prio < RTPRIO_MIN && uap->prio > RTPRIO_MAX &&
717 	    uap->prio != RTPRIO_NOCHG && uap->prio != RTPRIO_RTOFF)
718 		return (EINVAL);
719 	if (uap->pid == 0)
720 		p = cp;
721 	else if ((p = pfind(uap->pid)) == 0)
722 		return (ESRCH);
723 	nice = p->p_nice;
724 	if (nice < NZERO)
725 		*retval = (nice + 16) << 3;
726 	else
727 		*retval = RTPRIO_RTOFF;
728 	switch (uap->prio) {
729 
730 	case RTPRIO_NOCHG:
731 		return (0);
732 
733 	case RTPRIO_RTOFF:
734 		if (nice >= NZERO)
735 			return (0);
736 		nice = NZERO;
737 		break;
738 
739 	default:
740 		nice = (uap->prio >> 3) - 16;
741 		break;
742 	}
743 	error = donice(cp, p, nice);
744 	if (error == EACCES)
745 		error = EPERM;
746 	return (error);
747 }
748 
749 struct hpuxadvise_args {
750 	int	arg;
751 };
752 hpuxadvise(p, uap, retval)
753 	struct proc *p;
754 	struct hpuxadvise_args *uap;
755 	int *retval;
756 {
757 	int error = 0;
758 
759 	switch (uap->arg) {
760 	case 0:
761 		p->p_md.md_flags |= MDP_HPUXMMAP;
762 		break;
763 	case 1:
764 		ICIA();
765 		break;
766 	case 2:
767 		DCIA();
768 		break;
769 	default:
770 		error = EINVAL;
771 		break;
772 	}
773 	return (error);
774 }
775 
776 struct hpuxptrace_args {
777 	int	req;
778 	int	pid;
779 	int	*addr;
780 	int	data;
781 };
782 hpuxptrace(p, uap, retval)
783 	struct proc *p;
784 	struct hpuxptrace_args *uap;
785 	int *retval;
786 {
787 	int error, isps = 0;
788 	struct proc *cp;
789 
790 	switch (uap->req) {
791 	/* map signal */
792 	case PT_STEP:
793 	case PT_CONTINUE:
794 		if (uap->data) {
795 			uap->data = hpuxtobsdsig(uap->data);
796 			if (uap->data == 0)
797 				uap->data = NSIG;
798 		}
799 		break;
800 	/* map u-area offset */
801 	case PT_READ_U:
802 	case PT_WRITE_U:
803 		/*
804 		 * Big, cheezy hack: hpuxtobsduoff is really intended
805 		 * to be called in the child context (procxmt) but we
806 		 * do it here in the parent context to avoid hacks in
807 		 * the MI sys_process.c file.  This works only because
808 		 * we can access the child's md_regs pointer and it
809 		 * has the correct value (the child has already trapped
810 		 * into the kernel).
811 		 */
812 		if ((cp = pfind(uap->pid)) == 0)
813 			return (ESRCH);
814 		uap->addr = (int *) hpuxtobsduoff(uap->addr, &isps, cp);
815 
816 		/*
817 		 * Since HP-UX PS is only 16-bits in ar0, requests
818 		 * to write PS actually contain the PS in the high word
819 		 * and the high half of the PC (the following register)
820 		 * in the low word.  Move the PS value to where BSD
821 		 * expects it.
822 		 */
823 		if (isps && uap->req == PT_WRITE_U)
824 			uap->data >>= 16;
825 		break;
826 	}
827 	error = ptrace(p, uap, retval);
828 	/*
829 	 * Align PS as HP-UX expects it (see WRITE_U comment above).
830 	 * Note that we do not return the high part of PC like HP-UX
831 	 * would, but the HP-UX debuggers don't require it.
832 	 */
833 	if (isps && error == 0 && uap->req == PT_READ_U)
834 		*retval <<= 16;
835 	return (error);
836 }
837 
838 struct hpuxgetdomainname_args {
839 	char	*domainname;
840 	u_int	len;
841 };
842 hpuxgetdomainname(p, uap, retval)
843 	struct proc *p;
844 	register struct hpuxgetdomainname_args *uap;
845 	int *retval;
846 {
847 	if (uap->len > domainnamelen + 1)
848 		uap->len = domainnamelen + 1;
849 	return (copyout(domainname, uap->domainname, uap->len));
850 }
851 
852 struct hpuxsetdomainname_args {
853 	char	*domainname;
854 	u_int	len;
855 };
856 hpuxsetdomainname(p, uap, retval)
857 	struct proc *p;
858 	register struct hpuxsetdomainname_args *uap;
859 	int *retval;
860 {
861 	int error;
862 
863 	if (error = suser(p->p_ucred, &p->p_acflag))
864 		return (error);
865 	if (uap->len > sizeof (domainname) - 1)
866 		return (EINVAL);
867 	domainnamelen = uap->len;
868 	error = copyin(uap->domainname, domainname, uap->len);
869 	domainname[domainnamelen] = 0;
870 	return (error);
871 }
872 
873 #ifdef SYSVSHM
874 #include <sys/shm.h>
875 
876 hpuxshmat(p, uap, retval)
877 	struct proc *p;
878 	int *uap, *retval;
879 {
880 	return (shmat(p, uap, retval));
881 }
882 
883 hpuxshmdt(p, uap, retval)
884 	struct proc *p;
885 	int *uap, *retval;
886 {
887 	return (shmdt(p, uap, retval));
888 }
889 
890 hpuxshmget(p, uap, retval)
891 	struct proc *p;
892 	int *uap, *retval;
893 {
894 	return (shmget(p, uap, retval));
895 }
896 
897 /*
898  * Handle HP-UX specific commands.
899  */
900 struct hpuxshmctl_args {
901 	int shmid;
902 	int cmd;
903 	caddr_t buf;
904 };
905 hpuxshmctl(p, uap, retval)
906 	struct proc *p;
907 	struct hpuxshmctl_args *uap;
908 	int *retval;
909 {
910 	register struct shmid_ds *shp;
911 	register struct ucred *cred = p->p_ucred;
912 	int error;
913 
914 	if (error = shmvalid(uap->shmid))
915 		return (error);
916 	shp = &shmsegs[uap->shmid % SHMMMNI];
917 	if (uap->cmd == SHM_LOCK || uap->cmd == SHM_UNLOCK) {
918 		/* don't really do anything, but make them think we did */
919 		if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid &&
920 		    cred->cr_uid != shp->shm_perm.cuid)
921 			return (EPERM);
922 		return (0);
923 	}
924 	return (shmctl(p, uap, retval));
925 }
926 #endif
927 
928 /*
929  * Fake semaphore routines, just don't return an error.
930  * Should be adequate for starbase to run.
931  */
932 struct hpuxsemctl_args {
933 	int semid;
934 	u_int semnum;
935 	int cmd;
936 	int arg;
937 };
938 hpuxsemctl(p, uap, retval)
939 	struct proc *p;
940 	struct hpuxsemctl_args *uap;
941 	int *retval;
942 {
943 	/* XXX: should do something here */
944 	return (0);
945 }
946 
947 struct hpuxsemget_args {
948 	key_t key;
949 	int nsems;
950 	int semflg;
951 };
952 hpuxsemget(p, uap, retval)
953 	struct proc *p;
954 	struct hpuxsemget_args *uap;
955 	int *retval;
956 {
957 	/* XXX: should do something here */
958 	return (0);
959 }
960 
961 struct hpuxsemop_args {
962 	int semid;
963 	struct sembuf *sops;
964 	u_int nsops;
965 };
966 hpuxsemop(p, uap, retval)
967 	struct proc *p;
968 	struct hpuxsemop_args *uap;
969 	int *retval;
970 {
971 	/* XXX: should do something here */
972 	return (0);
973 }
974 
975 /*
976  * HP-UX mmap() emulation (mainly for shared library support).
977  */
978 struct hpuxmmap_args {
979 	caddr_t	addr;
980 	int	len;
981 	int	prot;
982 	int	flags;
983 	int	fd;
984 	long	pos;
985 };
986 hpuxmmap(p, uap, retval)
987 	struct proc *p;
988 	struct hpuxmmap_args *uap;
989 	int *retval;
990 {
991 	struct mmap_args {
992 		caddr_t	addr;
993 		int	len;
994 		int	prot;
995 		int	flags;
996 		int	fd;
997 		long	pad;
998 		off_t	pos;
999 	} nargs;
1000 
1001 	nargs.addr = uap->addr;
1002 	nargs.len = uap->len;
1003 	nargs.prot = uap->prot;
1004 	nargs.flags = uap->flags &
1005 		~(HPUXMAP_FIXED|HPUXMAP_REPLACE|HPUXMAP_ANON);
1006 	if (uap->flags & HPUXMAP_FIXED)
1007 		nargs.flags |= MAP_FIXED;
1008 	if (uap->flags & HPUXMAP_ANON)
1009 		nargs.flags |= MAP_ANON;
1010 	nargs.fd = (nargs.flags & MAP_ANON) ? -1 : uap->fd;
1011 	nargs.pos = uap->pos;
1012 	return (smmap(p, &nargs, retval));
1013 }
1014 
1015 /* convert from BSD to HP-UX errno */
1016 bsdtohpuxerrno(err)
1017 	int err;
1018 {
1019 	if (err < 0 || err >= NERR)
1020 		return(BERR);
1021 	return((int)bsdtohpuxerrnomap[err]);
1022 }
1023 
1024 hpuxstat1(fname, hsb, follow, p)
1025 	char *fname;
1026 	struct hpuxstat *hsb;
1027 	int follow;
1028 	struct proc *p;
1029 {
1030 	int error;
1031 	struct stat sb;
1032 	struct nameidata nd;
1033 
1034 	NDINIT(&nd, LOOKUP, follow | LOCKLEAF, UIO_USERSPACE, fname, p);
1035 	if (error = namei(&nd))
1036 		return (error);
1037 	error = vn_stat(nd.ni_vp, &sb, p);
1038 	vput(nd.ni_vp);
1039 	if (error == 0)
1040 		error = bsdtohpuxstat(&sb, hsb);
1041 	return (error);
1042 }
1043 
1044 #include "grf.h"
1045 #if NGRF > 0
1046 #ifdef __STDC__
1047 extern int grfopen(dev_t dev, int oflags, int devtype, struct proc *p);
1048 #else
1049 extern int grfopen();
1050 #endif
1051 #endif
1052 
1053 #define	NHIL	1	/* XXX */
1054 #if NHIL > 0
1055 #ifdef __STDC__
1056 extern int hilopen(dev_t dev, int oflags, int devtype, struct proc *p);
1057 #else
1058 extern int hilopen();
1059 #endif
1060 #endif
1061 
1062 #include <sys/conf.h>
1063 
1064 bsdtohpuxstat(sb, hsb)
1065 	struct stat *sb;
1066 	struct hpuxstat *hsb;
1067 {
1068 	struct hpuxstat ds;
1069 
1070 	bzero((caddr_t)&ds, sizeof(ds));
1071 	ds.hst_dev = (u_short)sb->st_dev;
1072 	ds.hst_ino = (u_long)sb->st_ino;
1073 	ds.hst_mode = sb->st_mode;
1074 	ds.hst_nlink = sb->st_nlink;
1075 	ds.hst_uid = (u_short)sb->st_uid;
1076 	ds.hst_gid = (u_short)sb->st_gid;
1077 	ds.hst_rdev = bsdtohpuxdev(sb->st_rdev);
1078 
1079 	/* XXX: I don't want to talk about it... */
1080 	if ((sb->st_mode & S_IFMT) == S_IFCHR) {
1081 #if NGRF > 0
1082 		if (cdevsw[major(sb->st_rdev)].d_open == grfopen)
1083 			ds.hst_rdev = grfdevno(sb->st_rdev);
1084 #endif
1085 #if NHIL > 0
1086 		if (cdevsw[major(sb->st_rdev)].d_open == hilopen)
1087 			ds.hst_rdev = hildevno(sb->st_rdev);
1088 #endif
1089 		;
1090 	}
1091 	if (sb->st_size < (quad_t)1 << 32)
1092 		ds.hst_size = (long)sb->st_size;
1093 	else
1094 		ds.hst_size = -2;
1095 	ds.hst_atime = sb->st_atime;
1096 	ds.hst_mtime = sb->st_mtime;
1097 	ds.hst_ctime = sb->st_ctime;
1098 	ds.hst_blksize = sb->st_blksize;
1099 	ds.hst_blocks = sb->st_blocks;
1100 	return(copyout((caddr_t)&ds, (caddr_t)hsb, sizeof(ds)));
1101 }
1102 
1103 hpuxtobsdioctl(com)
1104 	int com;
1105 {
1106 	switch (com) {
1107 	case HPUXTIOCSLTC:
1108 		com = TIOCSLTC; break;
1109 	case HPUXTIOCGLTC:
1110 		com = TIOCGLTC; break;
1111 	case HPUXTIOCSPGRP:
1112 		com = TIOCSPGRP; break;
1113 	case HPUXTIOCGPGRP:
1114 		com = TIOCGPGRP; break;
1115 	case HPUXTIOCLBIS:
1116 		com = TIOCLBIS; break;
1117 	case HPUXTIOCLBIC:
1118 		com = TIOCLBIC; break;
1119 	case HPUXTIOCLSET:
1120 		com = TIOCLSET; break;
1121 	case HPUXTIOCLGET:
1122 		com = TIOCLGET; break;
1123 	}
1124 	return(com);
1125 }
1126 
1127 /*
1128  * HP-UX ioctl system call.  The differences here are:
1129  *	IOC_IN also means IOC_VOID if the size portion is zero.
1130  *	no FIOCLEX/FIONCLEX/FIOASYNC/FIOGETOWN/FIOSETOWN
1131  *	the sgttyb struct is 2 bytes longer
1132  */
1133 struct hpuxioctl_args {
1134 	int	fdes;
1135 	int	cmd;
1136 	caddr_t	cmarg;
1137 };
1138 hpuxioctl(p, uap, retval)
1139 	struct proc *p;
1140 	register struct hpuxioctl_args *uap;
1141 	int *retval;
1142 {
1143 	register struct filedesc *fdp = p->p_fd;
1144 	register struct file *fp;
1145 	register int com, error;
1146 	register u_int size;
1147 	caddr_t memp = 0;
1148 #define STK_PARAMS	128
1149 	char stkbuf[STK_PARAMS];
1150 	caddr_t data = stkbuf;
1151 
1152 	com = uap->cmd;
1153 
1154 	/* XXX */
1155 	if (com == HPUXTIOCGETP || com == HPUXTIOCSETP)
1156 		return (getsettty(p, uap->fdes, com, uap->cmarg));
1157 
1158 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
1159 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
1160 		return (EBADF);
1161 	if ((fp->f_flag & (FREAD|FWRITE)) == 0)
1162 		return (EBADF);
1163 
1164 	/*
1165 	 * Interpret high order word to find
1166 	 * amount of data to be copied to/from the
1167 	 * user's address space.
1168 	 */
1169 	size = IOCPARM_LEN(com);
1170 	if (size > IOCPARM_MAX)
1171 		return (ENOTTY);
1172 	if (size > sizeof (stkbuf)) {
1173 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
1174 		data = memp;
1175 	}
1176 	if (com&IOC_IN) {
1177 		if (size) {
1178 			error = copyin(uap->cmarg, data, (u_int)size);
1179 			if (error) {
1180 				if (memp)
1181 					free(memp, M_IOCTLOPS);
1182 				return (error);
1183 			}
1184 		} else
1185 			*(caddr_t *)data = uap->cmarg;
1186 	} else if ((com&IOC_OUT) && size)
1187 		/*
1188 		 * Zero the buffer so the user always
1189 		 * gets back something deterministic.
1190 		 */
1191 		bzero(data, size);
1192 	else if (com&IOC_VOID)
1193 		*(caddr_t *)data = uap->cmarg;
1194 
1195 	switch (com) {
1196 
1197 	case HPUXFIOSNBIO:
1198 	{
1199 		char *ofp = &fdp->fd_ofileflags[uap->fdes];
1200 		int tmp;
1201 
1202 		if (*(int *)data)
1203 			*ofp |= UF_FIONBIO_ON;
1204 		else
1205 			*ofp &= ~UF_FIONBIO_ON;
1206 		/*
1207 		 * Only set/clear if FNONBLOCK not in effect
1208 		 */
1209 		if ((*ofp & UF_FNDELAY_ON) == 0) {
1210 			tmp = fp->f_flag & FNONBLOCK;
1211 			error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO,
1212 						       (caddr_t)&tmp, p);
1213 		}
1214 		break;
1215 	}
1216 
1217 	case HPUXTIOCCONS:
1218 		*(int *)data = 1;
1219 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCCONS, data, p);
1220 		break;
1221 
1222 	/* BSD-style job control ioctls */
1223 	case HPUXTIOCLBIS:
1224 	case HPUXTIOCLBIC:
1225 	case HPUXTIOCLSET:
1226 		*(int *)data &= HPUXLTOSTOP;
1227 		if (*(int *)data & HPUXLTOSTOP)
1228 			*(int *)data = LTOSTOP;
1229 		/* fall into */
1230 	case HPUXTIOCLGET:
1231 	case HPUXTIOCSLTC:
1232 	case HPUXTIOCGLTC:
1233 	case HPUXTIOCSPGRP:
1234 	case HPUXTIOCGPGRP:
1235 		error = (*fp->f_ops->fo_ioctl)
1236 			(fp, hpuxtobsdioctl(com), data, p);
1237 		if (error == 0 && com == HPUXTIOCLGET) {
1238 			*(int *)data &= LTOSTOP;
1239 			if (*(int *)data & LTOSTOP)
1240 				*(int *)data = HPUXLTOSTOP;
1241 		}
1242 		break;
1243 
1244 	/* SYS 5 termio and POSIX termios */
1245 	case HPUXTCGETA:
1246 	case HPUXTCSETA:
1247 	case HPUXTCSETAW:
1248 	case HPUXTCSETAF:
1249 	case HPUXTCGETATTR:
1250 	case HPUXTCSETATTR:
1251 	case HPUXTCSETATTRD:
1252 	case HPUXTCSETATTRF:
1253 		error = hpuxtermio(fp, com, data, p);
1254 		break;
1255 
1256 	default:
1257 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
1258 		break;
1259 	}
1260 	/*
1261 	 * Copy any data to user, size was
1262 	 * already set and checked above.
1263 	 */
1264 	if (error == 0 && (com&IOC_OUT) && size)
1265 		error = copyout(data, uap->cmarg, (u_int)size);
1266 	if (memp)
1267 		free(memp, M_IOCTLOPS);
1268 	return (error);
1269 }
1270 
1271 /*
1272  * Man page lies, behaviour here is based on observed behaviour.
1273  */
1274 struct hpuxgetcontext_args {
1275 	char *buf;
1276 	int len;
1277 };
1278 hpuxgetcontext(p, uap, retval)
1279 	struct proc *p;
1280 	struct hpuxgetcontext_args *uap;
1281 	int *retval;
1282 {
1283 	int error = 0;
1284 	register int len;
1285 
1286 #if defined(HP380)
1287 	if (machineid == HP_380) {
1288 		len = min(uap->len, sizeof(hpux040context));
1289 		if (len)
1290 			error = copyout(hpux040context, uap->buf, len);
1291 		if (error == 0)
1292 			*retval = sizeof(hpux040context);
1293 		return (error);
1294 	}
1295 #endif
1296 	len = min(uap->len, sizeof(hpuxcontext));
1297 	if (len)
1298 		error = copyout(hpuxcontext, uap->buf, (u_int)len);
1299 	if (error == 0)
1300 		*retval = sizeof(hpuxcontext);
1301 	return (error);
1302 }
1303 
1304 /*
1305  * This is the equivalent of BSD getpgrp but with more restrictions.
1306  * Note we do not check the real uid or "saved" uid.
1307  */
1308 struct hpuxgetpgrp2_args {
1309 	int pid;
1310 };
1311 hpuxgetpgrp2(cp, uap, retval)
1312 	struct proc *cp;
1313 	register struct hpuxgetpgrp2_args *uap;
1314 	int *retval;
1315 {
1316 	register struct proc *p;
1317 
1318 	if (uap->pid == 0)
1319 		uap->pid = cp->p_pid;
1320 	p = pfind(uap->pid);
1321 	if (p == 0)
1322 		return (ESRCH);
1323 	if (cp->p_ucred->cr_uid && p->p_ucred->cr_uid != cp->p_ucred->cr_uid &&
1324 	    !inferior(p))
1325 		return (EPERM);
1326 	*retval = p->p_pgid;
1327 	return (0);
1328 }
1329 
1330 /*
1331  * This is the equivalent of BSD setpgrp but with more restrictions.
1332  * Note we do not check the real uid or "saved" uid or pgrp.
1333  */
1334 struct hpuxsetpgrp2_args {
1335 	int	pid;
1336 	int	pgrp;
1337 };
1338 hpuxsetpgrp2(p, uap, retval)
1339 	struct proc *p;
1340 	struct hpuxsetpgrp2_args *uap;
1341 	int *retval;
1342 {
1343 	/* empirically determined */
1344 	if (uap->pgrp < 0 || uap->pgrp >= 30000)
1345 		return (EINVAL);
1346 	return (setpgid(p, uap, retval));
1347 }
1348 
1349 /*
1350  * XXX Same as BSD setre[ug]id right now.  Need to consider saved ids.
1351  */
1352 struct hpuxsetresuid_args {
1353 	int	ruid;
1354 	int	euid;
1355 	int	suid;
1356 };
1357 hpuxsetresuid(p, uap, retval)
1358 	struct proc *p;
1359 	struct hpuxsetresuid_args *uap;
1360 	int *retval;
1361 {
1362 	return (osetreuid(p, uap, retval));
1363 }
1364 
1365 struct hpuxsetresgid_args {
1366 	int	rgid;
1367 	int	egid;
1368 	int	sgid;
1369 };
1370 hpuxsetresgid(p, uap, retval)
1371 	struct proc *p;
1372 	struct hpuxsetresgid_args *uap;
1373 	int *retval;
1374 {
1375 	return (osetregid(p, uap, retval));
1376 }
1377 
1378 struct hpuxrlimit_args {
1379 	u_int	which;
1380 	struct	orlimit *rlp;
1381 };
1382 hpuxgetrlimit(p, uap, retval)
1383 	struct proc *p;
1384 	struct hpuxrlimit_args *uap;
1385 	int *retval;
1386 {
1387 	if (uap->which > HPUXRLIMIT_NOFILE)
1388 		return (EINVAL);
1389 	if (uap->which == HPUXRLIMIT_NOFILE)
1390 		uap->which = RLIMIT_NOFILE;
1391 	return (getrlimit(p, uap, retval));
1392 }
1393 
1394 hpuxsetrlimit(p, uap, retval)
1395 	struct proc *p;
1396 	struct hpuxrlimit_args *uap;
1397 	int *retval;
1398 {
1399 	if (uap->which > HPUXRLIMIT_NOFILE)
1400 		return (EINVAL);
1401 	if (uap->which == HPUXRLIMIT_NOFILE)
1402 		uap->which = RLIMIT_NOFILE;
1403 	return (setrlimit(p, uap, retval));
1404 }
1405 
1406 /*
1407  * XXX: simple recognition hack to see if we can make grmd work.
1408  */
1409 struct hpuxlockf_args {
1410 	int fd;
1411 	int func;
1412 	long size;
1413 };
1414 hpuxlockf(p, uap, retval)
1415 	struct proc *p;
1416 	struct hpuxlockf_args *uap;
1417 	int *retval;
1418 {
1419 	return (0);
1420 }
1421 
1422 struct hpuxgetaccess_args {
1423 	char	*path;
1424 	int	uid;
1425 	int	ngroups;
1426 	int	*gidset;
1427 	void	*label;
1428 	void	*privs;
1429 };
1430 hpuxgetaccess(p, uap, retval)
1431 	register struct proc *p;
1432 	register struct hpuxgetaccess_args *uap;
1433 	int *retval;
1434 {
1435 	int lgroups[NGROUPS];
1436 	int error = 0;
1437 	register struct ucred *cred;
1438 	register struct vnode *vp;
1439 	struct nameidata nd;
1440 
1441 	/*
1442 	 * Build an appropriate credential structure
1443 	 */
1444 	cred = crdup(p->p_ucred);
1445 	switch (uap->uid) {
1446 	case 65502:	/* UID_EUID */
1447 		break;
1448 	case 65503:	/* UID_RUID */
1449 		cred->cr_uid = p->p_cred->p_ruid;
1450 		break;
1451 	case 65504:	/* UID_SUID */
1452 		error = EINVAL;
1453 		break;
1454 	default:
1455 		if (uap->uid > 65504)
1456 			error = EINVAL;
1457 		cred->cr_uid = uap->uid;
1458 		break;
1459 	}
1460 	switch (uap->ngroups) {
1461 	case -1:	/* NGROUPS_EGID */
1462 		cred->cr_ngroups = 1;
1463 		break;
1464 	case -5:	/* NGROUPS_EGID_SUPP */
1465 		break;
1466 	case -2:	/* NGROUPS_RGID */
1467 		cred->cr_ngroups = 1;
1468 		cred->cr_gid = p->p_cred->p_rgid;
1469 		break;
1470 	case -6:	/* NGROUPS_RGID_SUPP */
1471 		cred->cr_gid = p->p_cred->p_rgid;
1472 		break;
1473 	case -3:	/* NGROUPS_SGID */
1474 	case -7:	/* NGROUPS_SGID_SUPP */
1475 		error = EINVAL;
1476 		break;
1477 	case -4:	/* NGROUPS_SUPP */
1478 		if (cred->cr_ngroups > 1)
1479 			cred->cr_gid = cred->cr_groups[1];
1480 		else
1481 			error = EINVAL;
1482 		break;
1483 	default:
1484 		if (uap->ngroups > 0 && uap->ngroups <= NGROUPS)
1485 			error = copyin((caddr_t)uap->gidset,
1486 				       (caddr_t)&lgroups[0],
1487 				       uap->ngroups * sizeof(lgroups[0]));
1488 		else
1489 			error = EINVAL;
1490 		if (error == 0) {
1491 			int gid;
1492 
1493 			for (gid = 0; gid < uap->ngroups; gid++)
1494 				cred->cr_groups[gid] = lgroups[gid];
1495 			cred->cr_ngroups = uap->ngroups;
1496 		}
1497 		break;
1498 	}
1499 	/*
1500 	 * Lookup file using caller's effective IDs.
1501 	 */
1502 	if (error == 0) {
1503 		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1504 			uap->path, p);
1505 		error = namei(&nd);
1506 	}
1507 	if (error) {
1508 		crfree(cred);
1509 		return (error);
1510 	}
1511 	/*
1512 	 * Use the constructed credentials for access checks.
1513 	 */
1514 	vp = nd.ni_vp;
1515 	*retval = 0;
1516 	if (VOP_ACCESS(vp, VREAD, cred, p) == 0)
1517 		*retval |= R_OK;
1518 	if (vn_writechk(vp) == 0 && VOP_ACCESS(vp, VWRITE, cred, p) == 0)
1519 		*retval |= W_OK;
1520 	/* XXX we return X_OK for root on VREG even if not */
1521 	if (VOP_ACCESS(vp, VEXEC, cred, p) == 0)
1522 		*retval |= X_OK;
1523 	vput(vp);
1524 	crfree(cred);
1525 	return (error);
1526 }
1527 
1528 extern char kstack[];
1529 #define UOFF(f)		((int)&((struct user *)0)->f)
1530 #define HPUOFF(f)	((int)&((struct hpuxuser *)0)->f)
1531 
1532 /* simplified FP structure */
1533 struct bsdfp {
1534 	int save[54];
1535 	int reg[24];
1536 	int ctrl[3];
1537 };
1538 
1539 /*
1540  * Brutal hack!  Map HP-UX u-area offsets into BSD k-stack offsets.
1541  */
1542 hpuxtobsduoff(off, isps, p)
1543 	int *off, *isps;
1544 	struct proc *p;
1545 {
1546 	register int *ar0 = p->p_md.md_regs;
1547 	struct hpuxfp *hp;
1548 	struct bsdfp *bp;
1549 	register u_int raddr;
1550 
1551 	*isps = 0;
1552 
1553 	/* u_ar0 field; procxmt puts in U_ar0 */
1554 	if ((int)off == HPUOFF(hpuxu_ar0))
1555 		return(UOFF(U_ar0));
1556 
1557 #ifdef FPCOPROC
1558 	/* FP registers from PCB */
1559 	hp = (struct hpuxfp *)HPUOFF(hpuxu_fp);
1560 	bp = (struct bsdfp *)UOFF(u_pcb.pcb_fpregs);
1561 	if (off >= hp->hpfp_ctrl && off < &hp->hpfp_ctrl[3])
1562 		return((int)&bp->ctrl[off - hp->hpfp_ctrl]);
1563 	if (off >= hp->hpfp_reg && off < &hp->hpfp_reg[24])
1564 		return((int)&bp->reg[off - hp->hpfp_reg]);
1565 #endif
1566 
1567 	/*
1568 	 * Everything else we recognize comes from the kernel stack,
1569 	 * so we convert off to an absolute address (if not already)
1570 	 * for simplicity.
1571 	 */
1572 	if (off < (int *)ctob(UPAGES))
1573 		off = (int *)((u_int)off + (u_int)kstack);
1574 
1575 	/*
1576 	 * General registers.
1577 	 * We know that the HP-UX registers are in the same order as ours.
1578 	 * The only difference is that their PS is 2 bytes instead of a
1579 	 * padded 4 like ours throwing the alignment off.
1580 	 */
1581 	if (off >= ar0 && off < &ar0[18]) {
1582 		/*
1583 		 * PS: return low word and high word of PC as HP-UX would
1584 		 * (e.g. &u.u_ar0[16.5]).
1585 		 *
1586 		 * XXX we don't do this since HP-UX adb doesn't rely on
1587 		 * it and passing such an offset to procxmt will cause
1588 		 * it to fail anyway.  Instead, we just set the offset
1589 		 * to PS and let hpuxptrace() shift up the value returned.
1590 		 */
1591 		if (off == &ar0[PS]) {
1592 #if 0
1593 			raddr = (u_int) &((short *)ar0)[PS*2+1];
1594 #else
1595 			raddr = (u_int) &ar0[(int)(off - ar0)];
1596 #endif
1597 			*isps = 1;
1598 		}
1599 		/*
1600 		 * PC: off will be &u.u_ar0[16.5] since HP-UX saved PS
1601 		 * is only 16 bits.
1602 		 */
1603 		else if (off == (int *)&(((short *)ar0)[PS*2+1]))
1604 			raddr = (u_int) &ar0[PC];
1605 		/*
1606 		 * D0-D7, A0-A7: easy
1607 		 */
1608 		else
1609 			raddr = (u_int) &ar0[(int)(off - ar0)];
1610 		return((int)(raddr - (u_int)kstack));
1611 	}
1612 
1613 	/* everything else */
1614 	return(-1);
1615 }
1616 
1617 /*
1618  * Kludge up a uarea dump so that HP-UX debuggers can find out
1619  * what they need.  IMPORTANT NOTE: we do not EVEN attempt to
1620  * convert the entire user struct.
1621  */
1622 hpuxdumpu(vp, cred)
1623 	struct vnode *vp;
1624 	struct ucred *cred;
1625 {
1626 	struct proc *p = curproc;
1627 	int error;
1628 	struct hpuxuser *faku;
1629 	struct bsdfp *bp;
1630 	short *foop;
1631 
1632 	faku = (struct hpuxuser *)malloc((u_long)ctob(1), M_TEMP, M_WAITOK);
1633 	/*
1634 	 * Make sure there is no mistake about this
1635 	 * being a real user structure.
1636 	 */
1637 	bzero((caddr_t)faku, ctob(1));
1638 	/*
1639 	 * Fill in the process sizes.
1640 	 */
1641 	faku->hpuxu_tsize = p->p_vmspace->vm_tsize;
1642 	faku->hpuxu_dsize = p->p_vmspace->vm_dsize;
1643 	faku->hpuxu_ssize = p->p_vmspace->vm_ssize;
1644 	/*
1645 	 * Fill in the exec header for CDB.
1646 	 * This was saved back in exec().  As far as I can tell CDB
1647 	 * only uses this information to verify that a particular
1648 	 * core file goes with a particular binary.
1649 	 */
1650 	bcopy((caddr_t)p->p_addr->u_md.md_exec,
1651 	      (caddr_t)&faku->hpuxu_exdata, sizeof (struct hpux_exec));
1652 	/*
1653 	 * Adjust user's saved registers (on kernel stack) to reflect
1654 	 * HP-UX order.  Note that HP-UX saves the SR as 2 bytes not 4
1655 	 * so we have to move it up.
1656 	 */
1657 	faku->hpuxu_ar0 = p->p_md.md_regs;
1658 	foop = (short *) p->p_md.md_regs;
1659 	foop[32] = foop[33];
1660 	foop[33] = foop[34];
1661 	foop[34] = foop[35];
1662 #ifdef FPCOPROC
1663 	/*
1664 	 * Copy 68881 registers from our PCB format to HP-UX format
1665 	 */
1666 	bp = (struct bsdfp *) &p->p_addr->u_pcb.pcb_fpregs;
1667 	bcopy((caddr_t)bp->save, (caddr_t)faku->hpuxu_fp.hpfp_save,
1668 	      sizeof(bp->save));
1669 	bcopy((caddr_t)bp->ctrl, (caddr_t)faku->hpuxu_fp.hpfp_ctrl,
1670 	      sizeof(bp->ctrl));
1671 	bcopy((caddr_t)bp->reg, (caddr_t)faku->hpuxu_fp.hpfp_reg,
1672 	      sizeof(bp->reg));
1673 #endif
1674 	/*
1675 	 * Slay the dragon
1676 	 */
1677 	faku->hpuxu_dragon = -1;
1678 	/*
1679 	 * Dump this artfully constructed page in place of the
1680 	 * user struct page.
1681 	 */
1682 	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)faku, ctob(1), (off_t)0,
1683 			UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred,
1684 			(int *)NULL, p);
1685 	/*
1686 	 * Dump the remaining UPAGES-1 pages normally
1687 	 */
1688 	if (!error)
1689 		error = vn_rdwr(UIO_WRITE, vp, kstack + ctob(1),
1690 				ctob(UPAGES-1), (off_t)ctob(1), UIO_SYSSPACE,
1691 				IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p);
1692 	free((caddr_t)faku, M_TEMP);
1693 	return(error);
1694 }
1695 
1696 /*
1697  * The remaining routines are essentially the same as those in kern_xxx.c
1698  * and vfs_xxx.c as defined under "#ifdef COMPAT".  We replicate them here
1699  * to avoid HPUXCOMPAT dependencies in those files and to make sure that
1700  * HP-UX compatibility still works even when COMPAT is not defined.
1701  *
1702  * These are still needed as of HP-UX 7.05.
1703  */
1704 #ifdef COMPAT_OHPUX
1705 
1706 #define HPUX_HZ	50
1707 
1708 #include "sys/times.h"
1709 
1710 /* from old timeb.h */
1711 struct hpuxtimeb {
1712 	time_t	time;
1713 	u_short	millitm;
1714 	short	timezone;
1715 	short	dstflag;
1716 };
1717 
1718 /* ye ole stat structure */
1719 struct	ohpuxstat {
1720 	u_short	ohst_dev;
1721 	u_short	ohst_ino;
1722 	u_short ohst_mode;
1723 	short  	ohst_nlink;
1724 	short  	ohst_uid;
1725 	short  	ohst_gid;
1726 	u_short	ohst_rdev;
1727 	int	ohst_size;
1728 	int	ohst_atime;
1729 	int	ohst_mtime;
1730 	int	ohst_ctime;
1731 };
1732 
1733 /*
1734  * SYS V style setpgrp()
1735  */
1736 ohpuxsetpgrp(p, uap, retval)
1737 	register struct proc *p;
1738 	int *uap, *retval;
1739 {
1740 	if (p->p_pid != p->p_pgid)
1741 		enterpgrp(p, p->p_pid, 0);
1742 	*retval = p->p_pgid;
1743 	return (0);
1744 }
1745 
1746 struct ohpuxtime_args {
1747 	long	*tp;
1748 };
1749 ohpuxtime(p, uap, retval)
1750 	struct proc *p;
1751 	register struct ohpuxtime_args *uap;
1752 	int *retval;
1753 {
1754 	int error = 0;
1755 
1756 	if (uap->tp)
1757 		error = copyout((caddr_t)&time.tv_sec, (caddr_t)uap->tp,
1758 				sizeof (long));
1759 	*(time_t *)retval = time.tv_sec;
1760 	return (error);
1761 }
1762 
1763 struct ohpuxstime_args {
1764 	int	time;
1765 };
1766 ohpuxstime(p, uap, retval)
1767 	struct proc *p;
1768 	register struct ohpuxstime_args *uap;
1769 	int *retval;
1770 {
1771 	struct timeval tv;
1772 	int s, error;
1773 
1774 	tv.tv_sec = uap->time;
1775 	tv.tv_usec = 0;
1776 	if (error = suser(p->p_ucred, &p->p_acflag))
1777 		return (error);
1778 
1779 	/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
1780 	boottime.tv_sec += tv.tv_sec - time.tv_sec;
1781 	s = splhigh(); time = tv; splx(s);
1782 	resettodr();
1783 	return (0);
1784 }
1785 
1786 struct ohpuxftime_args {
1787 	struct	hpuxtimeb *tp;
1788 };
1789 ohpuxftime(p, uap, retval)
1790 	struct proc *p;
1791 	register struct ohpuxftime_args *uap;
1792 	int *retval;
1793 {
1794 	struct hpuxtimeb tb;
1795 	int s;
1796 
1797 	s = splhigh();
1798 	tb.time = time.tv_sec;
1799 	tb.millitm = time.tv_usec / 1000;
1800 	splx(s);
1801 	tb.timezone = tz.tz_minuteswest;
1802 	tb.dstflag = tz.tz_dsttime;
1803 	return (copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof (tb)));
1804 }
1805 
1806 struct ohpuxalarm_args {
1807 	int	deltat;
1808 };
1809 ohpuxalarm(p, uap, retval)
1810 	register struct proc *p;
1811 	register struct ohpuxalarm_args *uap;
1812 	int *retval;
1813 {
1814 	int s = splhigh();
1815 
1816 	untimeout(realitexpire, (caddr_t)p);
1817 	timerclear(&p->p_realtimer.it_interval);
1818 	*retval = 0;
1819 	if (timerisset(&p->p_realtimer.it_value) &&
1820 	    timercmp(&p->p_realtimer.it_value, &time, >))
1821 		*retval = p->p_realtimer.it_value.tv_sec - time.tv_sec;
1822 	if (uap->deltat == 0) {
1823 		timerclear(&p->p_realtimer.it_value);
1824 		splx(s);
1825 		return (0);
1826 	}
1827 	p->p_realtimer.it_value = time;
1828 	p->p_realtimer.it_value.tv_sec += uap->deltat;
1829 	timeout(realitexpire, (caddr_t)p, hzto(&p->p_realtimer.it_value));
1830 	splx(s);
1831 	return (0);
1832 }
1833 
1834 struct ohpuxnice_args {
1835 	int	niceness;
1836 };
1837 ohpuxnice(p, uap, retval)
1838 	register struct proc *p;
1839 	register struct ohpuxnice_args *uap;
1840 	int *retval;
1841 {
1842 	int error;
1843 
1844 	error = donice(p, p, (p->p_nice-NZERO)+uap->niceness);
1845 	if (error == 0)
1846 		*retval = p->p_nice - NZERO;
1847 	return (error);
1848 }
1849 
1850 struct ohpuxtimes_args {
1851 	struct	tms *tmsb;
1852 };
1853 ohpuxtimes(p, uap, retval)
1854 	struct proc *p;
1855 	register struct ohpuxtimes_args *uap;
1856 	int *retval;
1857 {
1858 	struct timeval ru, rs;
1859 	struct tms atms;
1860 	int error;
1861 
1862 	calcru(p, &ru, &rs, NULL);
1863 	atms.tms_utime = hpuxscale(&ru);
1864 	atms.tms_stime = hpuxscale(&rs);
1865 	atms.tms_cutime = hpuxscale(&p->p_stats->p_cru.ru_utime);
1866 	atms.tms_cstime = hpuxscale(&p->p_stats->p_cru.ru_stime);
1867 	error = copyout((caddr_t)&atms, (caddr_t)uap->tmsb, sizeof (atms));
1868 	if (error == 0)
1869 		*(time_t *)retval = hpuxscale(&time) - hpuxscale(&boottime);
1870 	return (error);
1871 }
1872 
1873 /*
1874  * Doesn't exactly do what the documentation says.
1875  * What we really do is return 1/HPUX_HZ-th of a second since that
1876  * is what HP-UX returns.
1877  */
1878 hpuxscale(tvp)
1879 	register struct timeval *tvp;
1880 {
1881 	return (tvp->tv_sec * HPUX_HZ + tvp->tv_usec * HPUX_HZ / 1000000);
1882 }
1883 
1884 /*
1885  * Set IUPD and IACC times on file.
1886  * Can't set ICHG.
1887  */
1888 struct ohpuxutime_args {
1889 	char	*fname;
1890 	time_t	*tptr;
1891 };
1892 ohpuxutime(p, uap, retval)
1893 	struct proc *p;
1894 	register struct ohpuxutime_args *uap;
1895 	int *retval;
1896 {
1897 	register struct vnode *vp;
1898 	struct vattr vattr;
1899 	time_t tv[2];
1900 	int error;
1901 	struct nameidata nd;
1902 
1903 	if (uap->tptr) {
1904 		error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
1905 		if (error)
1906 			return (error);
1907 	} else
1908 		tv[0] = tv[1] = time.tv_sec;
1909 	vattr_null(&vattr);
1910 	vattr.va_atime.ts_sec = tv[0];
1911 	vattr.va_atime.ts_nsec = 0;
1912 	vattr.va_mtime.ts_sec = tv[1];
1913 	vattr.va_mtime.ts_nsec = 0;
1914 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
1915 	if (error = namei(&nd))
1916 		return (error);
1917 	vp = nd.ni_vp;
1918 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1919 		error = EROFS;
1920 	else
1921 		error = VOP_SETATTR(vp, &vattr, nd.ni_cnd.cn_cred, p);
1922 	vput(vp);
1923 	return (error);
1924 }
1925 
1926 ohpuxpause(p, uap, retval)
1927 	struct proc *p;
1928 	int *uap, *retval;
1929 {
1930 	(void) tsleep(kstack, PPAUSE | PCATCH, "pause", 0);
1931 	/* always return EINTR rather than ERESTART... */
1932 	return (EINTR);
1933 }
1934 
1935 /*
1936  * The old fstat system call.
1937  */
1938 struct ohpuxfstat_args {
1939 	int	fd;
1940 	struct ohpuxstat *sb;
1941 };
1942 ohpuxfstat(p, uap, retval)
1943 	struct proc *p;
1944 	register struct ohpuxfstat_args *uap;
1945 	int *retval;
1946 {
1947 	register struct filedesc *fdp = p->p_fd;
1948 	struct file *fp;
1949 
1950 	if (((unsigned)uap->fd) >= fdp->fd_nfiles ||
1951 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
1952 		return (EBADF);
1953 	if (fp->f_type != DTYPE_VNODE)
1954 		return (EINVAL);
1955 	return (ohpuxstat1((struct vnode *)fp->f_data, uap->sb, p));
1956 }
1957 
1958 /*
1959  * Old stat system call.  This version follows links.
1960  */
1961 struct ohpuxstat_args {
1962 	char	*fname;
1963 	struct ohpuxstat *sb;
1964 };
1965 ohpuxstat(p, uap, retval)
1966 	struct proc *p;
1967 	register struct ohpuxstat_args *uap;
1968 	int *retval;
1969 {
1970 	int error;
1971 	struct nameidata nd;
1972 
1973 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
1974 	if (error = namei(&nd))
1975 		return (error);
1976 	error = ohpuxstat1(nd.ni_vp, uap->sb, p);
1977 	vput(nd.ni_vp);
1978 	return (error);
1979 }
1980 
1981 int
1982 ohpuxstat1(vp, ub, p)
1983 	struct vnode *vp;
1984 	struct ohpuxstat *ub;
1985 	struct proc *p;
1986 {
1987 	struct ohpuxstat ohsb;
1988 	struct stat sb;
1989 	int error;
1990 
1991 	error = vn_stat(vp, &sb, p);
1992 	if (error)
1993 		return (error);
1994 
1995 	ohsb.ohst_dev = sb.st_dev;
1996 	ohsb.ohst_ino = sb.st_ino;
1997 	ohsb.ohst_mode = sb.st_mode;
1998 	ohsb.ohst_nlink = sb.st_nlink;
1999 	ohsb.ohst_uid = sb.st_uid;
2000 	ohsb.ohst_gid = sb.st_gid;
2001 	ohsb.ohst_rdev = sb.st_rdev;
2002 	if (sb.st_size < (quad_t)1 << 32)
2003 		ohsb.ohst_size = sb.st_size;
2004 	else
2005 		ohsb.ohst_size = -2;
2006 	ohsb.ohst_atime = sb.st_atime;
2007 	ohsb.ohst_mtime = sb.st_mtime;
2008 	ohsb.ohst_ctime = sb.st_ctime;
2009 	return (copyout((caddr_t)&ohsb, (caddr_t)ub, sizeof(ohsb)));
2010 }
2011 #endif
2012 #endif
2013