xref: /csrg-svn/sys/hp/hpux/hpux_compat.c (revision 43067)
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.33 89/08/23$
13  *
14  *	@(#)hpux_compat.c	7.6 (Berkeley) 06/08/90
15  */
16 
17 /*
18  * Various HPUX compatibility routines
19  */
20 
21 #ifdef HPUXCOMPAT
22 
23 #include "param.h"
24 #include "systm.h"
25 #include "syscontext.h"
26 #include "kernel.h"
27 #include "proc.h"
28 #include "buf.h"
29 #include "wait.h"
30 #include "file.h"
31 #include "vnode.h"
32 #include "ioctl.h"
33 #include "uio.h"
34 #include "ptrace.h"
35 #include "stat.h"
36 #include "syslog.h"
37 #include "malloc.h"
38 #include "mount.h"
39 #include "ipc.h"
40 
41 #include "machine/cpu.h"
42 #include "machine/reg.h"
43 #include "machine/psl.h"
44 #include "machine/vmparam.h"
45 #include "hpux.h"
46 #include "hpux_termio.h"
47 
48 #ifdef DEBUG
49 int unimpresponse = 0;
50 #endif
51 
52 /* "tick" value for HZ==50 */
53 int hpuxtick = 1000000 / 50;
54 
55 /* SYS5 style UTSNAME info */
56 struct hpuxutsname protoutsname = {
57 	"4.4bsd", "", "2.0", "B", "9000/3?0", ""
58 };
59 
60 /* 6.0 and later style context */
61 #ifdef FPCOPROC
62 char hpuxcontext[] =
63 	"standalone HP-MC68881 HP-MC68020 HP-MC68010 localroot default";
64 #else
65 char hpuxcontext[] =
66 	"standalone HP-MC68020 HP-MC68010 localroot default";
67 #endif
68 
69 /* YP domainname */
70 char	domainname[MAXHOSTNAMELEN] = "unknown";
71 int	domainnamelen = 7;
72 
73 #define NERR	79
74 #define BERR	1000
75 
76 /* indexed by BSD errno */
77 short bsdtohpuxerrnomap[NERR] = {
78 /*00*/	  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
79 /*10*/	 10,  45,  12,  13,  14,  15,  16,  17,  18,  19,
80 /*20*/	 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
81 /*30*/	 30,  31,  32,  33,  34, 246, 245, 244, 216, 217,
82 /*40*/	218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
83 /*50*/	228, 229, 230, 231, 232, 233, 234, 235, 236, 237,
84 /*60*/	238, 239, 249, 248, 241, 242, 247,BERR,BERR,BERR,
85 /*70*/   70,  71,BERR,BERR,BERR,BERR,BERR,  46,BERR
86 };
87 
88 notimp(code, nargs)
89 {
90 #ifdef DEBUG
91 	int *argp = u.u_ap;
92 	extern char *hpuxsyscallnames[];
93 
94 	printf("HPUX %s(", hpuxsyscallnames[code]);
95 	if (nargs)
96 		while (nargs--)
97 			printf("%x%c", *argp++, nargs? ',' : ')');
98 	else
99 		printf(")");
100 	printf("\n");
101 	switch (unimpresponse) {
102 	case 0:
103 		nosys();
104 		break;
105 	case 1:
106 		u.u_error = EINVAL;
107 		break;
108 	}
109 #else
110 	nosys();
111 #endif
112 	uprintf("HPUX system call %d not implemented\n", code);
113 }
114 
115 /*
116  * HPUX versions of wait and wait3 actually pass the parameters
117  * (status pointer, options, rusage) into the kernel rather than
118  * handling it in the C library stub.  We also need to map any
119  * termination signal from BSD to HPUX.
120  */
121 hpuxwait3()
122 {
123 	struct a {
124 		int	*status;
125 		int	options;
126 		int	rusage;
127 	} *uap = (struct a *)u.u_ap;
128 
129 	/* rusage pointer must be zero */
130 	if (uap->rusage) {
131 		u.u_error = EINVAL;
132 		return;
133 	}
134 	u.u_ar0[PS] = PSL_ALLCC;
135 	u.u_ar0[R0] = uap->options;
136 	u.u_ar0[R1] = uap->rusage;
137 	hpuxwait();
138 }
139 
140 hpuxwait()
141 {
142 	int sig, *statp;
143 	struct a {
144 		int	*status;
145 	} *uap = (struct a *)u.u_ap;
146 
147 	statp = uap->status;	/* owait clobbers first arg */
148 	owait();
149 	/*
150 	 * HP-UX wait always returns EINTR when interrupted by a signal
151 	 * (well, unless its emulating a BSD process, but we don't bother...)
152 	 */
153 	if (u.u_error == ERESTART)
154 		u.u_error = EINTR;
155 	if (u.u_error)
156 		return;
157 	sig = u.u_r.r_val2 & 0xFF;
158 	if (sig == WSTOPPED) {
159 		sig = (u.u_r.r_val2 >> 8) & 0xFF;
160 		u.u_r.r_val2 = (bsdtohpuxsig(sig) << 8) | WSTOPPED;
161 	} else if (sig)
162 		u.u_r.r_val2 = (u.u_r.r_val2 & 0xFF00) |
163 			bsdtohpuxsig(sig & 0x7F) | (sig & 0x80);
164 	if (statp)
165 		if (suword((caddr_t)statp, u.u_r.r_val2))
166 			u.u_error = EFAULT;
167 }
168 
169 hpuxwaitpid()
170 {
171 	int sig, *statp;
172 	struct a {
173 		int	pid;
174 		int	*status;
175 		int	options;
176 		struct	rusage *rusage;	/* wait4 arg */
177 	} *uap = (struct a *)u.u_ap;
178 
179 	uap->rusage = 0;
180 	wait4();
181 	/*
182 	 * HP-UX wait always returns EINTR when interrupted by a signal
183 	 * (well, unless its emulating a BSD process, but we don't bother...)
184 	 */
185 	if (u.u_error == ERESTART)
186 		u.u_error = EINTR;
187 	if (u.u_error)
188 		return;
189 	sig = u.u_r.r_val2 & 0xFF;
190 	if (sig == WSTOPPED) {
191 		sig = (u.u_r.r_val2 >> 8) & 0xFF;
192 		u.u_r.r_val2 = (bsdtohpuxsig(sig) << 8) | WSTOPPED;
193 	} else if (sig)
194 		u.u_r.r_val2 = (u.u_r.r_val2 & 0xFF00) |
195 			bsdtohpuxsig(sig & 0x7F) | (sig & 0x80);
196 	if (statp)
197 		if (suword((caddr_t)statp, u.u_r.r_val2))
198 			u.u_error = EFAULT;
199 }
200 
201 /*
202  * Must remap some bits in the mode mask.
203  * O_CREAT, O_TRUNC, and O_EXCL must be remapped,
204  * O_SYNCIO (0100000) is removed entirely.
205  */
206 hpuxopen(p, uap, retval)
207 	struct proc *p;
208 	struct args {
209 		char	*fname;
210 		int	mode;
211 		int	crtmode;
212 	} *uap;
213 	int *retval;
214 {
215 	int mode;
216 
217 	mode = uap->mode;
218 	uap->mode &= ~(HPUXFSYNCIO|HPUXFEXCL|HPUXFTRUNC|HPUXFCREAT);
219 	if (mode & HPUXFCREAT) {
220 		/*
221 		 * simulate the pre-NFS behavior that opening a
222 		 * file for READ+CREATE ignores the CREATE (unless
223 		 * EXCL is set in which case we will return the
224 		 * proper error).
225 		 */
226 		if ((mode & HPUXFEXCL) || ((mode-FOPEN) & FWRITE))
227 			uap->mode |= FCREAT;
228 	}
229 	if (mode & HPUXFTRUNC)
230 		uap->mode |= FTRUNC;
231 	if (mode & HPUXFEXCL)
232 		uap->mode |= FEXCL;
233 	RETURN (open(p, uap, retval));
234 }
235 
236 hpuxfcntl()
237 {
238 	register struct a {
239 		int	fdes;
240 		int	cmd;
241 		int	arg;
242 	} *uap = (struct a *)u.u_ap;
243 	int mode;
244 
245 	switch (uap->cmd) {
246 	case F_SETFL:
247 		uap->arg &= ~(HPUXFSYNCIO|HPUXFREMOTE|FUSECACHE);
248 		break;
249 	case F_GETFL:
250 	case F_DUPFD:
251 	case F_GETFD:
252 	case F_SETFD:
253 		break;
254 	default:
255 		u.u_error = EINVAL;
256 		return;
257 	}
258 	fcntl();
259 	if (u.u_error == 0 && uap->arg == F_GETFL) {
260 		mode = u.u_r.r_val1;
261 		u.u_r.r_val1 &= ~(FCREAT|FTRUNC|FEXCL|FUSECACHE);
262 		if (mode & FCREAT)
263 			u.u_r.r_val1 |= HPUXFCREAT;
264 		if (mode & FTRUNC)
265 			u.u_r.r_val1 |= HPUXFTRUNC;
266 		if (mode & FEXCL)
267 			u.u_r.r_val1 |= HPUXFEXCL;
268 	}
269 }
270 
271 /*
272  * Read and write should return a 0 count when an operation
273  * on a VNODE would block, not an error.  Sockets appear to
274  * return EWOULDBLOCK (at least in 6.2).  This is probably
275  * not entirely correct, since the behavior is only defined
276  * for pipes and tty type devices.
277  */
278 hpuxread()
279 {
280 	struct a {
281 		int	fd;
282 	} *uap = (struct a *)u.u_ap;
283 
284 	read();
285 	if (u.u_error == EWOULDBLOCK &&
286 	    u.u_ofile[uap->fd]->f_type == DTYPE_VNODE) {
287 		u.u_error = 0;
288 		u.u_r.r_val1 = 0;
289 	}
290 }
291 
292 hpuxwrite()
293 {
294 	struct a {
295 		int	fd;
296 	} *uap = (struct a *)u.u_ap;
297 
298 	write();
299 	if (u.u_error == EWOULDBLOCK &&
300 	    u.u_ofile[uap->fd]->f_type == DTYPE_VNODE) {
301 		u.u_error = 0;
302 		u.u_r.r_val1 = 0;
303 	}
304 }
305 
306 hpuxreadv()
307 {
308 	struct a {
309 		int	fd;
310 	} *uap = (struct a *)u.u_ap;
311 
312 	readv();
313 	if (u.u_error == EWOULDBLOCK &&
314 	    u.u_ofile[uap->fd]->f_type == DTYPE_VNODE) {
315 		u.u_error = 0;
316 		u.u_r.r_val1 = 0;
317 	}
318 }
319 
320 hpuxwritev()
321 {
322 	struct a {
323 		int	fd;
324 	} *uap = (struct a *)u.u_ap;
325 
326 	writev();
327 	if (u.u_error == EWOULDBLOCK &&
328 	    u.u_ofile[uap->fd]->f_type == DTYPE_VNODE) {
329 		u.u_error = 0;
330 		u.u_r.r_val1 = 0;
331 	}
332 }
333 
334 /*
335  * 4.3bsd dup allows dup2 to come in on the same syscall entry
336  * and hence allows two arguments.  HPUX dup has only one arg.
337  */
338 hpuxdup()
339 {
340 	register struct a {
341 		int	i;
342 	} *uap = (struct a *)u.u_ap;
343 	struct file *fp;
344 	int j;
345 
346 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) {
347 		u.u_error = EBADF;
348 		return;
349 	}
350 	u.u_error = ufalloc(0, &j);
351 	if (u.u_error)
352 		return;
353 	u.u_r.r_val1 = j;
354 	u.u_ofile[j] = fp;
355 	u.u_pofile[j] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
356 	fp->f_count++;
357 	if (j > u.u_lastfile)
358 		u.u_lastfile = j;
359 }
360 
361 hpuxuname()
362 {
363 	register struct a {
364 		struct hpuxutsname *uts;
365 		int dev;
366 		int request;
367 	} *uap = (struct a *)u.u_ap;
368 	register int i;
369 
370 	switch (uap->request) {
371 	/* uname */
372 	case 0:
373 		/* fill in machine type */
374 		switch (machineid) {
375 		case HP_320:
376 			protoutsname.machine[6] = '2';
377 			break;
378 		/* includes 318 and 319 */
379 		case HP_330:
380 			protoutsname.machine[6] = '3';
381 			break;
382 		case HP_340:
383 			protoutsname.machine[6] = '4';
384 			break;
385 		case HP_350:
386 			protoutsname.machine[6] = '5';
387 			break;
388 		case HP_360:
389 			protoutsname.machine[6] = '6';
390 			break;
391 		case HP_370:
392 			protoutsname.machine[6] = '7';
393 			break;
394 		}
395 		/* copy hostname (sans domain) to nodename */
396 		for (i = 0; i < 9 && hostname[i] != '.'; i++)
397 			protoutsname.nodename[i] = hostname[i];
398 		u.u_error = copyout((caddr_t)&protoutsname, (caddr_t)uap->uts,
399 				    sizeof(struct hpuxutsname));
400 		break;
401 	/* ustat - who cares? */
402 	case 2:
403 	default:
404 		u.u_error = EINVAL;
405 		break;
406 	}
407 }
408 
409 hpuxstat()
410 {
411 	struct a {
412 		char	*fname;
413 		struct hpuxstat *hsb;
414 	} *uap = (struct a *)u.u_ap;
415 
416 	u.u_error = hpuxstat1(uap->fname, uap->hsb, FOLLOW);
417 }
418 
419 hpuxlstat()
420 {
421 	struct a {
422 		char	*fname;
423 		struct	hpuxstat *hsb;
424 	} *uap = (struct a *) u.u_ap;
425 
426 	u.u_error = hpuxstat1(uap->fname, uap->hsb, NOFOLLOW);
427 }
428 
429 hpuxfstat()
430 {
431 	register struct file *fp;
432 	register struct a {
433 		int	fdes;
434 		struct	hpuxstat *hsb;
435 	} *uap = (struct a *)u.u_ap;
436 	struct stat sb;
437 
438 	if ((unsigned)uap->fdes >= NOFILE ||
439 	    (fp = u.u_ofile[uap->fdes]) == NULL) {
440 		u.u_error = EBADF;
441 		return;
442 	}
443 	switch (fp->f_type) {
444 
445 	case DTYPE_VNODE:
446 		u.u_error = vn_stat((struct vnode *)fp->f_data, &sb);
447 		break;
448 
449 	case DTYPE_SOCKET:
450 		u.u_error = soo_stat((struct socket *)fp->f_data, &sb);
451 		break;
452 
453 	default:
454 		panic("fstat");
455 		/*NOTREACHED*/
456 	}
457 	/* is this right for sockets?? */
458 	if (u.u_error == 0)
459 		u.u_error = bsdtohpuxstat(&sb, uap->hsb);
460 }
461 
462 hpuxulimit()
463 {
464 	struct a {
465 		int	cmd;
466 		long	newlimit;
467 	} *uap = (struct a *)u.u_ap;
468 	struct rlimit *limp;
469 
470 	limp = &u.u_rlimit[RLIMIT_FSIZE];
471 	switch (uap->cmd) {
472 	case 2:
473 		uap->newlimit *= 512;
474 		if (uap->newlimit > limp->rlim_max &&
475 		    (u.u_error = suser(u.u_cred, &u.u_acflag)))
476 			break;
477 		limp->rlim_cur = limp->rlim_max = uap->newlimit;
478 		/* else fall into... */
479 
480 	case 1:
481 		u.u_r.r_off = limp->rlim_max / 512;
482 		break;
483 
484 	case 3:
485 		limp = &u.u_rlimit[RLIMIT_DATA];
486 		u.u_r.r_off = ctob(u.u_tsize) + limp->rlim_max;
487 		break;
488 
489 	default:
490 		u.u_error = EINVAL;
491 		break;
492 	}
493 }
494 
495 /*
496  * Map "real time" priorities 0 (high) thru 127 (low) into nice
497  * values -16 (high) thru -1 (low).
498  */
499 hpuxrtprio()
500 {
501 	register struct a {
502 		int pid;
503 		int prio;
504 	} *uap = (struct a *)u.u_ap;
505 	struct proc *p;
506 	int nice;
507 
508 	if (uap->prio < RTPRIO_MIN && uap->prio > RTPRIO_MAX &&
509 	    uap->prio != RTPRIO_NOCHG && uap->prio != RTPRIO_RTOFF) {
510 		u.u_error = EINVAL;
511 		return;
512 	}
513 	if (uap->pid == 0)
514 		p = u.u_procp;
515 	else if ((p = pfind(uap->pid)) == 0) {
516 		u.u_error = ESRCH;
517 		return;
518 	}
519 	nice = p->p_nice;
520 	if (nice < NZERO)
521 		u.u_r.r_val1 = (nice + 16) << 3;
522 	else
523 		u.u_r.r_val1 = RTPRIO_RTOFF;
524 	switch (uap->prio) {
525 
526 	case RTPRIO_NOCHG:
527 		return;
528 
529 	case RTPRIO_RTOFF:
530 		if (nice >= NZERO)
531 			return;
532 		nice = NZERO;
533 		break;
534 
535 	default:
536 		nice = (uap->prio >> 3) - 16;
537 		break;
538 	}
539 	donice(p, nice);
540 	if (u.u_error == EACCES)
541 		u.u_error = EPERM;
542 }
543 
544 /*
545  * Kudos to HP folks for using such mnemonic names so I could figure
546  * out what this guy does.
547  */
548 hpuxadvise()
549 {
550 	struct a {
551 		int	arg;
552 	} *uap = (struct a *) u.u_ap;
553 
554 	switch (uap->arg) {
555 	case 0:
556 		u.u_pcb.pcb_flags |= PCB_HPUXMMAP;
557 		break;
558 	case 1:
559 		ICIA();
560 		break;
561 	case 2:
562 		DCIA();
563 		break;
564 	default:
565 		u.u_error = EINVAL;
566 		break;
567 	}
568 }
569 
570 hpuxptrace()
571 {
572 	struct a {
573 		int	req;
574 		int	pid;
575 		int	*addr;
576 		int	data;
577 	} *uap = (struct a *)u.u_ap;
578 
579 	if (uap->req == PT_STEP || uap->req == PT_CONTINUE) {
580 		if (uap->data) {
581 			uap->data = hpuxtobsdsig(uap->data);
582 			if (uap->data == 0)
583 				uap->data = NSIG;
584 		}
585 	}
586 	ptrace();
587 }
588 
589 hpuxgetdomainname()
590 {
591 	register struct a {
592 		char	*domainname;
593 		u_int	len;
594 	} *uap = (struct a *)u.u_ap;
595 
596 	if (uap->len > domainnamelen + 1)
597 		uap->len = domainnamelen + 1;
598 	u.u_error = copyout(domainname, uap->domainname, uap->len);
599 }
600 
601 hpuxsetdomainname()
602 {
603 	register struct a {
604 		char	*domainname;
605 		u_int	len;
606 	} *uap = (struct a *)u.u_ap;
607 
608 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
609 		return;
610 	if (uap->len > sizeof (domainname) - 1) {
611 		u.u_error = EINVAL;
612 		return;
613 	}
614 	domainnamelen = uap->len;
615 	u.u_error = copyin(uap->domainname, domainname, uap->len);
616 	domainname[domainnamelen] = 0;
617 }
618 
619 #ifdef SYSVSHM
620 hpuxshmat()
621 {
622 	shmat(u.u_ap);
623 }
624 
625 hpuxshmctl()
626 {
627 	shmctl(u.u_ap);
628 }
629 
630 hpuxshmdt()
631 {
632 	shmdt(u.u_ap);
633 }
634 
635 hpuxshmget()
636 {
637 	shmget(u.u_ap);
638 }
639 #endif
640 
641 /*
642  * Fake semaphore routines, just don't return an error.
643  * Should be adequate for starbase to run.
644  */
645 hpuxsemctl()
646 {
647 	struct a {
648 		int semid;
649 		u_int semnum;
650 		int cmd;
651 		int arg;
652 	} *uap = (struct a *)u.u_ap;
653 
654 	/* XXX: should do something here */
655 }
656 
657 hpuxsemget()
658 {
659 	struct a {
660 		key_t key;
661 		int nsems;
662 		int semflg;
663 	} *uap = (struct a *)u.u_ap;
664 
665 	/* XXX: should do something here */
666 }
667 
668 hpuxsemop()
669 {
670 	struct a {
671 		int semid;
672 		struct sembuf *sops;
673 		u_int nsops;
674 	} *uap = (struct a *)u.u_ap;
675 
676 	/* XXX: should do something here */
677 }
678 
679 /* convert from BSD to HPUX errno */
680 bsdtohpuxerrno(err)
681 	int err;
682 {
683 	if (err < 0 || err >= NERR)
684 		return(BERR);
685 	return((int)bsdtohpuxerrnomap[err]);
686 }
687 
688 hpuxstat1(fname, hsb, follow)
689 	char *fname;
690 	struct hpuxstat *hsb;
691 	int follow;
692 {
693 	register struct nameidata *ndp = &u.u_nd;
694 	struct stat sb;
695 	int error;
696 
697 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
698 	ndp->ni_segflg = UIO_USERSPACE;
699 	ndp->ni_dirp = fname;
700 	if (error = namei(ndp))
701 		return (error);
702 	error = vn_stat(ndp->ni_vp, &sb);
703 	vput(ndp->ni_vp);
704 	if (error == 0)
705 		error = bsdtohpuxstat(&sb, hsb);
706 	return (error);
707 }
708 
709 #include "grf.h"
710 
711 bsdtohpuxstat(sb, hsb)
712 	struct stat *sb;
713 	struct hpuxstat *hsb;
714 {
715 	struct hpuxstat ds;
716 
717 	bzero((caddr_t)&ds, sizeof(ds));
718 	ds.hst_dev = sb->st_dev;
719 	ds.hst_ino = (u_long)sb->st_ino;
720 	ds.hst_mode = sb->st_mode;
721 	ds.hst_nlink = sb->st_nlink;
722 	ds.hst_uid = (u_short)sb->st_uid;
723 	ds.hst_gid = (u_short)sb->st_gid;
724 #if NGRF > 0
725 	/* XXX: I don't want to talk about it... */
726 	if ((sb->st_mode & S_IFMT) == S_IFCHR && major(sb->st_rdev) == 10)
727 		ds.hst_rdev = grfdevno(sb->st_rdev);
728 	else
729 #endif
730 		ds.hst_rdev = bsdtohpuxdev(sb->st_rdev);
731 	ds.hst_size = sb->st_size;
732 	ds.hst_atime = sb->st_atime;
733 	ds.hst_mtime = sb->st_mtime;
734 	ds.hst_ctime = sb->st_ctime;
735 	ds.hst_blksize = sb->st_blksize;
736 	ds.hst_blocks = sb->st_blocks;
737 	return(copyout((caddr_t)&ds, (caddr_t)hsb, sizeof(ds)));
738 }
739 
740 hpuxtobsdioctl(com)
741 	int com;
742 {
743 	switch (com) {
744 	case HPUXTIOCSLTC:
745 		com = TIOCSLTC; break;
746 	case HPUXTIOCGLTC:
747 		com = TIOCGLTC; break;
748 	case HPUXTIOCSPGRP:
749 		com = TIOCSPGRP; break;
750 	case HPUXTIOCGPGRP:
751 		com = TIOCGPGRP; break;
752 	case HPUXTIOCLBIS:
753 		com = TIOCLBIS; break;
754 	case HPUXTIOCLBIC:
755 		com = TIOCLBIC; break;
756 	case HPUXTIOCLSET:
757 		com = TIOCLSET; break;
758 	case HPUXTIOCLGET:
759 		com = TIOCLGET; break;
760 	}
761 	return(com);
762 }
763 
764 /*
765  * HPUX ioctl system call.  The differences here are:
766  *	IOC_IN also means IOC_VOID if the size portion is zero.
767  *	no FIOCLEX/FIONCLEX/FIONBIO/FIOASYNC/FIOGETOWN/FIOSETOWN
768  *	the sgttyb struct is 2 bytes longer
769  */
770 hpuxioctl()
771 {
772 	register struct file *fp;
773 	struct a {
774 		int	fdes;
775 		int	cmd;
776 		caddr_t	cmarg;
777 	} *uap = (struct a *)u.u_ap;
778 	register int com;
779 	register u_int size;
780 	caddr_t memp = 0;
781 #define STK_PARAMS	128
782 	char stkbuf[STK_PARAMS];
783 	caddr_t data = stkbuf;
784 
785 	com = uap->cmd;
786 
787 	/* XXX */
788 	if (com == HPUXTIOCGETP || com == HPUXTIOCSETP) {
789 		getsettty(uap->fdes, com, uap->cmarg);
790 		return;
791 	}
792 
793 	if ((unsigned)uap->fdes >= NOFILE ||
794 	    (fp = u.u_ofile[uap->fdes]) == NULL) {
795 		u.u_error = EBADF;
796 		return;
797 	}
798 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
799 		u.u_error = EBADF;
800 		return;
801 	}
802 
803 	/*
804 	 * Interpret high order word to find
805 	 * amount of data to be copied to/from the
806 	 * user's address space.
807 	 */
808 	size = IOCPARM_LEN(com);
809 	if (size > IOCPARM_MAX) {
810 		u.u_error = EFAULT;
811 		return;
812 	}
813 	if (size > sizeof (stkbuf)) {
814 		memp = (caddr_t)malloc((u_long)IOCPARM_MAX, M_IOCTLOPS,
815 		    M_WAITOK);
816 		data = memp;
817 	}
818 	if (com&IOC_IN) {
819 		if (size) {
820 			u.u_error = copyin(uap->cmarg, data, (u_int)size);
821 			if (u.u_error) {
822 				if (memp)
823 					free(memp, M_IOCTLOPS);
824 				return;
825 			}
826 		} else
827 			*(caddr_t *)data = uap->cmarg;
828 	} else if ((com&IOC_OUT) && size)
829 		/*
830 		 * Zero the buffer on the stack so the user
831 		 * always gets back something deterministic.
832 		 */
833 		bzero(data, size);
834 	else if (com&IOC_VOID)
835 		*(caddr_t *)data = uap->cmarg;
836 
837 	switch (com) {
838 
839 	case HPUXTIOCCONS:
840 		*(int *)data = 1;
841 		u.u_error = (*fp->f_ops->fo_ioctl)(fp, TIOCCONS, data);
842 		break;
843 
844 	/* BSD-style job control ioctls */
845 	case HPUXTIOCLBIS:
846 	case HPUXTIOCLBIC:
847 	case HPUXTIOCLSET:
848 		*(int *)data &= HPUXLTOSTOP;
849 		if (*(int *)data & HPUXLTOSTOP)
850 			*(int *)data = LTOSTOP;
851 		/* fall into */
852 	case HPUXTIOCLGET:
853 	case HPUXTIOCSLTC:
854 	case HPUXTIOCGLTC:
855 	case HPUXTIOCSPGRP:
856 	case HPUXTIOCGPGRP:
857 		u.u_error = (*fp->f_ops->fo_ioctl)(fp, hpuxtobsdioctl(com), data);
858 		if (u.u_error == 0 && com == HPUXTIOCLGET) {
859 			*(int *)data &= LTOSTOP;
860 			if (*(int *)data & LTOSTOP)
861 				*(int *)data = HPUXLTOSTOP;
862 		}
863 		break;
864 
865 	/* SYS 5 termio */
866 	case HPUXTCGETA:
867 	case HPUXTCSETA:
868 	case HPUXTCSETAW:
869 	case HPUXTCSETAF:
870 		u.u_error = hpuxtermio(fp, com, data);
871 		break;
872 
873 	default:
874 		u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
875 		break;
876 	}
877 	/*
878 	 * Copy any data to user, size was
879 	 * already set and checked above.
880 	 */
881 	if (u.u_error == 0 && (com&IOC_OUT) && size)
882 		u.u_error = copyout(data, uap->cmarg, (u_int)size);
883 	if (memp)
884 		free(memp, M_IOCTLOPS);
885 }
886 
887 /*
888  * Man page lies, behaviour here is based on observed behaviour.
889  */
890 hpuxgetcontext()
891 {
892 	struct a {
893 		char *buf;
894 		int len;
895 	} *uap = (struct a *)u.u_ap;
896 	int error = 0;
897 	register int len;
898 
899 	len = MIN(uap->len, sizeof(hpuxcontext));
900 	if (len)
901 		error = copyout(hpuxcontext, uap->buf, (u_int)len);
902 	if (!error)
903 		u.u_r.r_val1 = sizeof(hpuxcontext);
904 	return(error);
905 }
906 
907 /*
908  * XXX: simple recognition hack to see if we can make grmd work.
909  */
910 hpuxlockf()
911 {
912 	struct a {
913 		int fd;
914 		int func;
915 		long size;
916 	} *uap = (struct a *)u.u_ap;
917 #ifdef DEBUG
918 	log(LOG_DEBUG, "%d: lockf(%d, %d, %d)\n",
919 	    u.u_procp->p_pid, uap->fd, uap->func, uap->size);
920 #endif
921 	return(0);
922 }
923 
924 /*
925  * This is the equivalent of BSD getpgrp but with more restrictions.
926  * Note we do not check the real uid or "saved" uid.
927  */
928 hpuxgetpgrp2()
929 {
930 	register struct proc *p;
931 	register struct a {
932 		int pid;
933 	} *uap = (struct a *)u.u_ap;
934 
935 	if (uap->pid == 0)
936 		uap->pid = u.u_procp->p_pid;
937 	p = pfind(uap->pid);
938 	if (p == 0) {
939 		u.u_error = ESRCH;
940 		return;
941 	}
942 	if (u.u_uid && p->p_uid != u.u_uid && !inferior(p)) {
943 		u.u_error = EPERM;
944 		return;
945 	}
946 	u.u_r.r_val1 = p->p_pgid;
947 }
948 
949 /*
950  * This is the equivalent of BSD setpgrp but with more restrictions.
951  * Note we do not check the real uid or "saved" uid or pgrp.
952  */
953 hpuxsetpgrp2()
954 {
955 	struct a {
956 		int	pid;
957 		int	pgrp;
958 	} *uap = (struct a *)u.u_ap;
959 
960 	/* empirically determined */
961 	if (uap->pgrp < 0 || uap->pgrp >= 30000) {
962 		u.u_error = EINVAL;
963 		return;
964 	}
965 	setpgrp();
966 }
967 
968 /*
969  * Brutal hack!  Map HPUX u-area offsets into BSD u offsets.
970  * No apologies offered, if you don't like it, rewrite it!
971  */
972 
973 #define UOFF(f)		((int)&((struct user *)0)->f)
974 #define HPUOFF(f)	((int)&((struct hpuxuser *)0)->f)
975 
976 /* simplified FP structure */
977 struct bsdfp {
978 	int save[54];
979 	int reg[24];
980 	int ctrl[3];
981 };
982 
983 hpuxtobsduoff(off)
984 	int *off;
985 {
986 	struct hpuxfp *hp;
987 	struct bsdfp *bp;
988 	register u_int raddr;
989 
990 	/* u_ar0 field */
991 	if ((int)off == HPUOFF(hpuxu_ar0))
992 		return(UOFF(u_ar0));
993 
994 #ifdef FPCOPROC
995 	/* 68881 registers from PCB */
996 	hp = (struct hpuxfp *)HPUOFF(hpuxu_fp);
997 	bp = (struct bsdfp *)UOFF(u_pcb.pcb_fpregs);
998 	if (off >= hp->hpfp_ctrl && off < &hp->hpfp_ctrl[3])
999 		return((int)&bp->ctrl[off - hp->hpfp_ctrl]);
1000 	if (off >= hp->hpfp_reg && off < &hp->hpfp_reg[24])
1001 		return((int)&bp->reg[off - hp->hpfp_reg]);
1002 #endif
1003 
1004 	/*
1005 	 * Everything else we recognize comes from the kernel stack,
1006 	 * so we convert off to an absolute address (if not already)
1007 	 * for simplicity.
1008 	 */
1009 	if (off < (int *)ctob(UPAGES))
1010 		off = (int *)((u_int)off + (u_int)&u);
1011 
1012 	/*
1013 	 * 68020 registers.
1014 	 * We know that the HPUX registers are in the same order as ours.
1015 	 * The only difference is that their PS is 2 bytes instead of a
1016 	 * padded 4 like ours throwing the alignment off.
1017 	 */
1018 	if (off >= u.u_ar0 && off < &u.u_ar0[18]) {
1019 		/*
1020 		 * PS: return low word and high word of PC as HP-UX would
1021 		 * (e.g. &u.u_ar0[16.5]).
1022 		 */
1023 		if (off == &u.u_ar0[PS])
1024 			raddr = (u_int) &((short *)u.u_ar0)[PS*2+1];
1025 		/*
1026 		 * PC: off will be &u.u_ar0[16.5]
1027 		 */
1028 		else if (off == (int *)&(((short *)u.u_ar0)[PS*2+1]))
1029 			raddr = (u_int) &u.u_ar0[PC];
1030 		/*
1031 		 * D0-D7, A0-A7: easy
1032 		 */
1033 		else
1034 			raddr = (u_int) &u.u_ar0[(int)(off - u.u_ar0)];
1035 		return((int)(raddr - (u_int)&u));
1036 	}
1037 
1038 	/* everything else */
1039 	return(-1);
1040 }
1041 
1042 /*
1043  * Kludge up a uarea dump so that HPUX debuggers can find out
1044  * what they need.  IMPORTANT NOTE: we do not EVEN attempt to
1045  * convert the entire user struct.
1046  */
1047 hpuxdumpu(vp, cred)
1048 	struct vnode *vp;
1049 	struct ucred *cred;
1050 {
1051 	int error;
1052 	struct hpuxuser *faku;
1053 	struct bsdfp *bp;
1054 	short *foop;
1055 
1056 	faku = (struct hpuxuser *)malloc((u_long)ctob(1), M_TEMP, M_WAITOK);
1057 	/*
1058 	 * Make sure there is no mistake about this
1059 	 * being a real user structure.
1060 	 */
1061 	bzero((caddr_t)faku, ctob(1));
1062 	/*
1063 	 * Fill in the process sizes.
1064 	 */
1065 	faku->hpuxu_tsize = u.u_tsize;
1066 	faku->hpuxu_dsize = u.u_dsize;
1067 	faku->hpuxu_ssize = u.u_ssize;
1068 	/*
1069 	 * Fill in the exec header for CDB.
1070 	 * This was saved back in exec().  As far as I can tell CDB
1071 	 * only uses this information to verify that a particular
1072 	 * core file goes with a particular binary.
1073 	 */
1074 	bcopy((caddr_t)u.u_pcb.pcb_exec,
1075 	      (caddr_t)&faku->hpuxu_exdata, sizeof (struct hpux_exec));
1076 	/*
1077 	 * Adjust user's saved registers (on kernel stack) to reflect
1078 	 * HPUX order.  Note that HPUX saves the SR as 2 bytes not 4
1079 	 * so we have to move it up.
1080 	 */
1081 	faku->hpuxu_ar0 = u.u_ar0;
1082 	foop = (short *) u.u_ar0;
1083 	foop[32] = foop[33];
1084 	foop[33] = foop[34];
1085 	foop[34] = foop[35];
1086 #ifdef FPCOPROC
1087 	/*
1088 	 * Copy 68881 registers from our PCB format to HPUX format
1089 	 */
1090 	bp = (struct bsdfp *) &u.u_pcb.pcb_fpregs;
1091 	bcopy((caddr_t)bp->save, (caddr_t)faku->hpuxu_fp.hpfp_save,
1092 	      sizeof(bp->save));
1093 	bcopy((caddr_t)bp->ctrl, (caddr_t)faku->hpuxu_fp.hpfp_ctrl,
1094 	      sizeof(bp->ctrl));
1095 	bcopy((caddr_t)bp->reg, (caddr_t)faku->hpuxu_fp.hpfp_reg,
1096 	      sizeof(bp->reg));
1097 #endif
1098 	/*
1099 	 * Slay the dragon
1100 	 */
1101 	faku->hpuxu_dragon = -1;
1102 	/*
1103 	 * Dump this artfully constructed page in place of the
1104 	 * user struct page.
1105 	 */
1106 	error = vn_rdwr(UIO_WRITE, vp,
1107 			(caddr_t)faku, ctob(1), (off_t)0,
1108 			UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)0);
1109 	/*
1110 	 * Dump the remaining UPAGES-1 pages normally
1111 	 */
1112 	if (!error)
1113 		error = vn_rdwr(UIO_WRITE, vp, ((caddr_t)&u)+ctob(1),
1114 				ctob(UPAGES-1), (off_t)ctob(1), UIO_SYSSPACE,
1115 				IO_NODELOCKED|IO_UNIT, cred, (int *)0);
1116 	free((caddr_t)faku, M_TEMP);
1117 	return(error);
1118 }
1119 
1120 /*
1121  * The remaining routines are essentially the same as those in kern_xxx.c
1122  * and vfs_xxx.c as defined under "#ifdef COMPAT".  We replicate them here
1123  * to avoid HPUXCOMPAT dependencies in those files and to make sure that
1124  * HP-UX compatibility still works even when COMPAT is not defined.
1125  */
1126 /* #ifdef COMPAT */
1127 
1128 #include "../sys/times.h"
1129 
1130 /* from old timeb.h */
1131 struct hpuxtimeb {
1132 	time_t	time;
1133 	u_short	millitm;
1134 	short	timezone;
1135 	short	dstflag;
1136 };
1137 
1138 /* ye ole stat structure */
1139 struct	ohpuxstat {
1140 	dev_t	ohst_dev;
1141 	u_short	ohst_ino;
1142 	u_short ohst_mode;
1143 	short  	ohst_nlink;
1144 	short  	ohst_uid;
1145 	short  	ohst_gid;
1146 	dev_t	ohst_rdev;
1147 	int	ohst_size;
1148 	int	ohst_atime;
1149 	int	ohst_mtime;
1150 	int	ohst_ctime;
1151 };
1152 
1153 /*
1154  * Right now the following two routines are the same as the 4.3
1155  * osetuid/osetgid calls.  Eventually they need to be changed to
1156  * implement the notion of "saved" ids (whatever that means).
1157  */
1158 ohpuxsetuid()
1159 {
1160 	register uid;
1161 	register struct a {
1162 		int	uid;
1163 	} *uap = (struct a *)u.u_ap;
1164 
1165 	uid = uap->uid;
1166 	if (uid != u.u_procp->p_ruid && uid != u.u_cred->cr_uid &&
1167 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
1168 		return;
1169 	if (u.u_cred->cr_ref > 1)
1170 		u.u_cred = crcopy(u.u_cred);
1171 	u.u_cred->cr_uid = uid;
1172 	u.u_procp->p_uid = uid;
1173 	u.u_procp->p_ruid = uid;
1174 }
1175 
1176 ohpuxsetgid()
1177 {
1178 	register gid;
1179 	register struct a {
1180 		int	gid;
1181 	} *uap = (struct a *)u.u_ap;
1182 
1183 	gid = uap->gid;
1184 	if (u.u_procp->p_rgid != gid && u.u_cred->cr_groups[0] != gid &&
1185 	    (u.u_error = suser(u.u_cred, &u.u_acflag)))
1186 		return;
1187 	if (u.u_cred->cr_ref > 1)
1188 		u.u_cred = crcopy(u.u_cred);
1189 	u.u_procp->p_rgid = gid;
1190 	u.u_cred->cr_groups[0] = gid;
1191 }
1192 
1193 /*
1194  * SYS V style setpgrp()
1195  */
1196 ohpuxsetpgrp()
1197 {
1198 	register struct proc *p = u.u_procp;
1199 
1200 	if (p->p_pid != p->p_pgid)
1201 		pgmv(p, p->p_pid, 0);
1202 	u.u_r.r_val1 = p->p_pgid;
1203 }
1204 
1205 ohpuxtime()
1206 {
1207 	register struct a {
1208 		long	*tp;
1209 	} *uap = (struct a *)u.u_ap;
1210 
1211 	if (uap->tp)
1212 		u.u_error = copyout((caddr_t)&time.tv_sec, (caddr_t)uap->tp,
1213 				    sizeof (long));
1214 	u.u_r.r_time = time.tv_sec;
1215 }
1216 
1217 ohpuxstime()
1218 {
1219 	register struct a {
1220 		int	time;
1221 	} *uap = (struct a *)u.u_ap;
1222 	struct timeval tv;
1223 	int s;
1224 
1225 	tv.tv_sec = uap->time;
1226 	tv.tv_usec = 0;
1227 	u.u_error = suser(u.u_cred, &u.u_acflag);
1228 	if (u.u_error)
1229 		return;
1230 
1231 	/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
1232 	boottime.tv_sec += tv.tv_sec - time.tv_sec;
1233 	s = splhigh(); time = tv; splx(s);
1234 	resettodr();
1235 }
1236 
1237 ohpuxftime()
1238 {
1239 	register struct a {
1240 		struct	hpuxtimeb *tp;
1241 	} *uap;
1242 	struct hpuxtimeb tb;
1243 	int s;
1244 
1245 	uap = (struct a *)u.u_ap;
1246 	s = splhigh();
1247 	tb.time = time.tv_sec;
1248 	tb.millitm = time.tv_usec / 1000;
1249 	splx(s);
1250 	tb.timezone = tz.tz_minuteswest;
1251 	tb.dstflag = tz.tz_dsttime;
1252 	u.u_error = copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof (tb));
1253 }
1254 
1255 ohpuxalarm()
1256 {
1257 	register struct a {
1258 		int	deltat;
1259 	} *uap = (struct a *)u.u_ap;
1260 	register struct proc *p = u.u_procp;
1261 	int s = splhigh();
1262 
1263 	untimeout(realitexpire, (caddr_t)p);
1264 	timerclear(&p->p_realtimer.it_interval);
1265 	u.u_r.r_val1 = 0;
1266 	if (timerisset(&p->p_realtimer.it_value) &&
1267 	    timercmp(&p->p_realtimer.it_value, &time, >))
1268 		u.u_r.r_val1 = p->p_realtimer.it_value.tv_sec - time.tv_sec;
1269 	if (uap->deltat == 0) {
1270 		timerclear(&p->p_realtimer.it_value);
1271 		splx(s);
1272 		return;
1273 	}
1274 	p->p_realtimer.it_value = time;
1275 	p->p_realtimer.it_value.tv_sec += uap->deltat;
1276 	timeout(realitexpire, (caddr_t)p, hzto(&p->p_realtimer.it_value));
1277 	splx(s);
1278 }
1279 
1280 ohpuxnice()
1281 {
1282 	register struct a {
1283 		int	niceness;
1284 	} *uap = (struct a *)u.u_ap;
1285 	register struct proc *p = u.u_procp;
1286 
1287 	donice(p, (p->p_nice-NZERO)+uap->niceness);
1288 	u.u_r.r_val1 = p->p_nice - NZERO;
1289 }
1290 
1291 ohpuxtimes()
1292 {
1293 	register struct a {
1294 		struct	tms *tmsb;
1295 	} *uap = (struct a *)u.u_ap;
1296 	struct tms atms;
1297 
1298 	atms.tms_utime = scale50(&u.u_ru.ru_utime);
1299 	atms.tms_stime = scale50(&u.u_ru.ru_stime);
1300 	atms.tms_cutime = scale50(&u.u_cru.ru_utime);
1301 	atms.tms_cstime = scale50(&u.u_cru.ru_stime);
1302 	u.u_error = copyout((caddr_t)&atms, (caddr_t)uap->tmsb, sizeof (atms));
1303 	if (u.u_error == 0)
1304 		u.u_r.r_time = scale50(&time) - scale50(&boottime);
1305 }
1306 
1307 scale50(tvp)
1308 	register struct timeval *tvp;
1309 {
1310 	extern int hpuxtick;
1311 
1312 	/*
1313 	 * Doesn't exactly do what the documentation says.
1314 	 * What we really do is return 50th of a second since that
1315 	 * is what HZ is on all bobcats I know of.
1316 	 */
1317 	return ((tvp->tv_sec * 50 + tvp->tv_usec / hpuxtick));
1318 }
1319 
1320 /*
1321  * Set IUPD and IACC times on file.
1322  * Can't set ICHG.
1323  */
1324 ohpuxutime()
1325 {
1326 	register struct a {
1327 		char	*fname;
1328 		time_t	*tptr;
1329 	} *uap = (struct a *)u.u_ap;
1330 	struct vattr vattr;
1331 	time_t tv[2];
1332 	register struct vnode *vp;
1333 	register struct nameidata *ndp = &u.u_nd;
1334 
1335 	if (uap->tptr) {
1336 		u.u_error =
1337 			copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
1338 		if (u.u_error)
1339 			return;
1340 	} else
1341 		tv[0] = tv[1] = time.tv_sec;
1342 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1343 	ndp->ni_segflg = UIO_USERSPACE;
1344 	ndp->ni_dirp = uap->fname;
1345 	vattr_null(&vattr);
1346 	vattr.va_atime.tv_sec = tv[0];
1347 	vattr.va_atime.tv_usec = 0;
1348 	vattr.va_mtime.tv_sec = tv[1];
1349 	vattr.va_mtime.tv_usec = 0;
1350 	if (u.u_error = namei(ndp))
1351 		return;
1352 	vp = ndp->ni_vp;
1353 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1354 		u.u_error = EROFS;
1355 	else
1356 		u.u_error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1357 	vput(vp);
1358 }
1359 
1360 ohpuxpause()
1361 {
1362 
1363 	(void) tsleep((caddr_t)&u, PPAUSE | PCATCH, "pause", 0);
1364 	/* always return EINTR rather than ERESTART... */
1365 	RETURN (EINTR);
1366 }
1367 
1368 /*
1369  * The old fstat system call.
1370  */
1371 ohpuxfstat()
1372 {
1373 	register struct a {
1374 		int	fd;
1375 		struct ohpuxstat *sb;
1376 	} *uap = (struct a *)u.u_ap;
1377 	struct file *fp;
1378 	extern struct file *getinode();
1379 
1380 	if ((unsigned)uap->fd >= NOFILE || (fp = u.u_ofile[uap->fd]) == NULL) {
1381 		u.u_error = EBADF;
1382 		return;
1383 	}
1384 	if (fp->f_type != DTYPE_VNODE) {
1385 		u.u_error = EINVAL;
1386 		return;
1387 	}
1388 	u.u_error = ohpuxstat1((struct vnode *)fp->f_data, uap->sb);
1389 }
1390 
1391 /*
1392  * Old stat system call.  This version follows links.
1393  */
1394 ohpuxstat()
1395 {
1396 	register struct a {
1397 		char	*fname;
1398 		struct ohpuxstat *sb;
1399 	} *uap = (struct a *)u.u_ap;
1400 	register struct nameidata *ndp = &u.u_nd;
1401 
1402 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
1403 	ndp->ni_segflg = UIO_USERSPACE;
1404 	ndp->ni_dirp = uap->fname;
1405 	if (u.u_error = namei(ndp))
1406 		return;
1407 	u.u_error = ohpuxstat1(ndp->ni_vp, uap->sb);
1408 	vput(ndp->ni_vp);
1409 }
1410 
1411 int
1412 ohpuxstat1(vp, ub)
1413 	register struct vnode *vp;
1414 	struct ohpuxstat *ub;
1415 {
1416 	struct ohpuxstat ds;
1417 	struct vattr vattr;
1418 	register int error;
1419 
1420 	error = VOP_GETATTR(vp, &vattr, u.u_cred);
1421 	if (error)
1422 		return(error);
1423 	/*
1424 	 * Copy from inode table
1425 	 */
1426 	ds.ohst_dev = vattr.va_fsid;
1427 	ds.ohst_ino = (short)vattr.va_fileid;
1428 	ds.ohst_mode = (u_short)vattr.va_mode;
1429 	ds.ohst_nlink = vattr.va_nlink;
1430 	ds.ohst_uid = (short)vattr.va_uid;
1431 	ds.ohst_gid = (short)vattr.va_gid;
1432 	ds.ohst_rdev = (dev_t)vattr.va_rdev;
1433 	ds.ohst_size = (int)vattr.va_size;
1434 	ds.ohst_atime = (int)vattr.va_atime.tv_sec;
1435 	ds.ohst_mtime = (int)vattr.va_mtime.tv_sec;
1436 	ds.ohst_ctime = (int)vattr.va_ctime.tv_sec;
1437 	return (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)));
1438 }
1439 /* #endif */
1440 
1441 #endif
1442