Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / compat / ibcs2 / ibcs2_ioctl.c
blob33ec0d02c0276d709a7ff02b46018a8ba4b6a242
1 /* $NetBSD: ibcs2_ioctl.c,v 1.44 2008/04/30 14:07:13 ad Exp $ */
3 /*
4 * Copyright (c) 1994, 1995 Scott Bartram
5 * All rights reserved.
7 * based on compat/sunos/sun_ioctl.c
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: ibcs2_ioctl.c,v 1.44 2008/04/30 14:07:13 ad Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/namei.h>
35 #include <sys/dirent.h>
36 #include <sys/proc.h>
37 #include <sys/file.h>
38 #include <sys/stat.h>
39 #include <sys/filedesc.h>
40 #include <sys/ioctl.h>
41 #include <sys/kernel.h>
42 #include <sys/mbuf.h>
43 #include <sys/mman.h>
44 #include <sys/mount.h>
45 #include <sys/reboot.h>
46 #include <sys/resource.h>
47 #include <sys/resourcevar.h>
48 #include <sys/signal.h>
49 #include <sys/signalvar.h>
50 #include <sys/socket.h>
51 #include <sys/termios.h>
52 #include <sys/time.h>
53 #include <sys/times.h>
54 #include <sys/tty.h>
55 #include <sys/vnode.h>
56 #include <sys/uio.h>
57 #include <sys/wait.h>
58 #include <sys/utsname.h>
59 #include <sys/unistd.h>
61 #include <net/if.h>
62 #include <sys/syscallargs.h>
64 #include <compat/ibcs2/ibcs2_types.h>
65 #include <compat/ibcs2/ibcs2_signal.h>
66 #include <compat/ibcs2/ibcs2_socksys.h>
67 #include <compat/ibcs2/ibcs2_stropts.h>
68 #include <compat/ibcs2/ibcs2_syscallargs.h>
69 #include <compat/ibcs2/ibcs2_termios.h>
70 #include <compat/ibcs2/ibcs2_util.h>
73 * iBCS2 ioctl calls.
76 static const struct speedtab sptab[] = {
77 { 0, 0 },
78 { 50, 1 },
79 { 75, 2 },
80 { 110, 3 },
81 { 134, 4 },
82 { 135, 4 },
83 { 150, 5 },
84 { 200, 6 },
85 { 300, 7 },
86 { 600, 8 },
87 { 1200, 9 },
88 { 1800, 10 },
89 { 2400, 11 },
90 { 4800, 12 },
91 { 9600, 13 },
92 { 19200, 14 },
93 { 38400, 15 },
94 { -1, -1 }
97 static const u_long s2btab[] = {
99 50,
101 110,
102 134,
103 150,
104 200,
105 300,
106 600,
107 1200,
108 1800,
109 2400,
110 4800,
111 9600,
112 19200,
113 38400,
116 static void stios2btios(struct ibcs2_termios *, struct termios *);
117 static void btios2stios(struct termios *, struct ibcs2_termios *);
118 static void stios2stio(struct ibcs2_termios *, struct ibcs2_termio *);
119 static void stio2stios(struct ibcs2_termio *, struct ibcs2_termios *);
121 static void
122 stios2btios(struct ibcs2_termios *st, struct termios *bt)
124 u_long l, r;
126 l = st->c_iflag; r = 0;
127 if (l & IBCS2_IGNBRK) r |= IGNBRK;
128 if (l & IBCS2_BRKINT) r |= BRKINT;
129 if (l & IBCS2_IGNPAR) r |= IGNPAR;
130 if (l & IBCS2_PARMRK) r |= PARMRK;
131 if (l & IBCS2_INPCK) r |= INPCK;
132 if (l & IBCS2_ISTRIP) r |= ISTRIP;
133 if (l & IBCS2_INLCR) r |= INLCR;
134 if (l & IBCS2_IGNCR) r |= IGNCR;
135 if (l & IBCS2_ICRNL) r |= ICRNL;
136 if (l & IBCS2_IXON) r |= IXON;
137 if (l & IBCS2_IXANY) r |= IXANY;
138 if (l & IBCS2_IXOFF) r |= IXOFF;
139 if (l & IBCS2_IMAXBEL) r |= IMAXBEL;
140 bt->c_iflag = r;
142 l = st->c_oflag; r = 0;
143 if (l & IBCS2_OPOST) r |= OPOST;
144 if (l & IBCS2_ONLCR) r |= ONLCR;
145 if (l & IBCS2_TAB3) r |= OXTABS;
146 bt->c_oflag = r;
148 l = st->c_cflag; r = 0;
149 switch (l & IBCS2_CSIZE) {
150 case IBCS2_CS5: r |= CS5; break;
151 case IBCS2_CS6: r |= CS6; break;
152 case IBCS2_CS7: r |= CS7; break;
153 case IBCS2_CS8: r |= CS8; break;
155 if (l & IBCS2_CSTOPB) r |= CSTOPB;
156 if (l & IBCS2_CREAD) r |= CREAD;
157 if (l & IBCS2_PARENB) r |= PARENB;
158 if (l & IBCS2_PARODD) r |= PARODD;
159 if (l & IBCS2_HUPCL) r |= HUPCL;
160 if (l & IBCS2_CLOCAL) r |= CLOCAL;
161 bt->c_cflag = r;
162 bt->c_ispeed = bt->c_ospeed = s2btab[l & 0x0f];
164 l = st->c_lflag; r = 0;
165 if (l & IBCS2_ISIG) r |= ISIG;
166 if (l & IBCS2_ICANON) r |= ICANON;
167 if (l & IBCS2_ECHO) r |= ECHO;
168 if (l & IBCS2_ECHOE) r |= ECHOE;
169 if (l & IBCS2_ECHOK) r |= ECHOK;
170 if (l & IBCS2_ECHONL) r |= ECHONL;
171 if (l & IBCS2_NOFLSH) r |= NOFLSH;
172 if (l & IBCS2_TOSTOP) r |= TOSTOP;
173 bt->c_lflag = r;
175 bt->c_cc[VINTR] =
176 st->c_cc[IBCS2_VINTR] ? st->c_cc[IBCS2_VINTR] : _POSIX_VDISABLE;
177 bt->c_cc[VQUIT] =
178 st->c_cc[IBCS2_VQUIT] ? st->c_cc[IBCS2_VQUIT] : _POSIX_VDISABLE;
179 bt->c_cc[VERASE] =
180 st->c_cc[IBCS2_VERASE] ? st->c_cc[IBCS2_VERASE] : _POSIX_VDISABLE;
181 bt->c_cc[VKILL] =
182 st->c_cc[IBCS2_VKILL] ? st->c_cc[IBCS2_VKILL] : _POSIX_VDISABLE;
183 if (bt->c_lflag & ICANON) {
184 bt->c_cc[VEOF] =
185 st->c_cc[IBCS2_VEOF] ? st->c_cc[IBCS2_VEOF] : _POSIX_VDISABLE;
186 bt->c_cc[VEOL] =
187 st->c_cc[IBCS2_VEOL] ? st->c_cc[IBCS2_VEOL] : _POSIX_VDISABLE;
188 } else {
189 bt->c_cc[VMIN] = st->c_cc[IBCS2_VMIN];
190 bt->c_cc[VTIME] = st->c_cc[IBCS2_VTIME];
192 bt->c_cc[VEOL2] =
193 st->c_cc[IBCS2_VEOL2] ? st->c_cc[IBCS2_VEOL2] : _POSIX_VDISABLE;
194 #if 0
195 bt->c_cc[VSWTCH] =
196 st->c_cc[IBCS2_VSWTCH] ? st->c_cc[IBCS2_VSWTCH] : _POSIX_VDISABLE;
197 #endif
198 bt->c_cc[VSTART] =
199 st->c_cc[IBCS2_VSTART] ? st->c_cc[IBCS2_VSTART] : _POSIX_VDISABLE;
200 bt->c_cc[VSTOP] =
201 st->c_cc[IBCS2_VSTOP] ? st->c_cc[IBCS2_VSTOP] : _POSIX_VDISABLE;
202 bt->c_cc[VSUSP] =
203 st->c_cc[IBCS2_VSUSP] ? st->c_cc[IBCS2_VSUSP] : _POSIX_VDISABLE;
204 bt->c_cc[VDSUSP] = _POSIX_VDISABLE;
205 bt->c_cc[VREPRINT] = _POSIX_VDISABLE;
206 bt->c_cc[VDISCARD] = _POSIX_VDISABLE;
207 bt->c_cc[VWERASE] = _POSIX_VDISABLE;
208 bt->c_cc[VLNEXT] = _POSIX_VDISABLE;
209 bt->c_cc[VSTATUS] = _POSIX_VDISABLE;
212 static void
213 btios2stios(struct termios *bt, struct ibcs2_termios *st)
215 int i;
216 u_long l, r;
218 l = bt->c_iflag; r = 0;
219 if (l & IGNBRK) r |= IBCS2_IGNBRK;
220 if (l & BRKINT) r |= IBCS2_BRKINT;
221 if (l & IGNPAR) r |= IBCS2_IGNPAR;
222 if (l & PARMRK) r |= IBCS2_PARMRK;
223 if (l & INPCK) r |= IBCS2_INPCK;
224 if (l & ISTRIP) r |= IBCS2_ISTRIP;
225 if (l & INLCR) r |= IBCS2_INLCR;
226 if (l & IGNCR) r |= IBCS2_IGNCR;
227 if (l & ICRNL) r |= IBCS2_ICRNL;
228 if (l & IXON) r |= IBCS2_IXON;
229 if (l & IXANY) r |= IBCS2_IXANY;
230 if (l & IXOFF) r |= IBCS2_IXOFF;
231 if (l & IMAXBEL) r |= IBCS2_IMAXBEL;
232 st->c_iflag = r;
234 l = bt->c_oflag; r = 0;
235 if (l & OPOST) r |= IBCS2_OPOST;
236 if (l & ONLCR) r |= IBCS2_ONLCR;
237 if (l & OXTABS) r |= IBCS2_TAB3;
238 st->c_oflag = r;
240 l = bt->c_cflag; r = 0;
241 switch (l & CSIZE) {
242 case CS5: r |= IBCS2_CS5; break;
243 case CS6: r |= IBCS2_CS6; break;
244 case CS7: r |= IBCS2_CS7; break;
245 case CS8: r |= IBCS2_CS8; break;
247 if (l & CSTOPB) r |= IBCS2_CSTOPB;
248 if (l & CREAD) r |= IBCS2_CREAD;
249 if (l & PARENB) r |= IBCS2_PARENB;
250 if (l & PARODD) r |= IBCS2_PARODD;
251 if (l & HUPCL) r |= IBCS2_HUPCL;
252 if (l & CLOCAL) r |= IBCS2_CLOCAL;
253 st->c_cflag = r;
255 l = bt->c_lflag; r = 0;
256 if (l & ISIG) r |= IBCS2_ISIG;
257 if (l & ICANON) r |= IBCS2_ICANON;
258 if (l & ECHO) r |= IBCS2_ECHO;
259 if (l & ECHOE) r |= IBCS2_ECHOE;
260 if (l & ECHOK) r |= IBCS2_ECHOK;
261 if (l & ECHONL) r |= IBCS2_ECHONL;
262 if (l & NOFLSH) r |= IBCS2_NOFLSH;
263 if (l & TOSTOP) r |= IBCS2_TOSTOP;
264 st->c_lflag = r;
266 i = ttspeedtab(bt->c_ospeed, sptab);
267 if (i >= 0)
268 st->c_cflag |= i;
270 st->c_cc[IBCS2_VINTR] =
271 bt->c_cc[VINTR] != _POSIX_VDISABLE ? bt->c_cc[VINTR] : 0;
272 st->c_cc[IBCS2_VQUIT] =
273 bt->c_cc[VQUIT] != _POSIX_VDISABLE ? bt->c_cc[VQUIT] : 0;
274 st->c_cc[IBCS2_VERASE] =
275 bt->c_cc[VERASE] != _POSIX_VDISABLE ? bt->c_cc[VERASE] : 0;
276 st->c_cc[IBCS2_VKILL] =
277 bt->c_cc[VKILL] != _POSIX_VDISABLE ? bt->c_cc[VKILL] : 0;
278 if (bt->c_lflag & ICANON) {
279 st->c_cc[IBCS2_VEOF] =
280 bt->c_cc[VEOF] != _POSIX_VDISABLE ? bt->c_cc[VEOF] : 0;
281 st->c_cc[IBCS2_VEOL] =
282 bt->c_cc[VEOL] != _POSIX_VDISABLE ? bt->c_cc[VEOL] : 0;
283 } else {
284 st->c_cc[IBCS2_VMIN] = bt->c_cc[VMIN];
285 st->c_cc[IBCS2_VTIME] = bt->c_cc[VTIME];
287 st->c_cc[IBCS2_VEOL2] =
288 bt->c_cc[VEOL2] != _POSIX_VDISABLE ? bt->c_cc[VEOL2] : 0;
289 st->c_cc[IBCS2_VSWTCH] =
291 st->c_cc[IBCS2_VSUSP] =
292 bt->c_cc[VSUSP] != _POSIX_VDISABLE ? bt->c_cc[VSUSP] : 0;
293 st->c_cc[IBCS2_VSTART] =
294 bt->c_cc[VSTART] != _POSIX_VDISABLE ? bt->c_cc[VSTART] : 0;
295 st->c_cc[IBCS2_VSTOP] =
296 bt->c_cc[VSTOP] != _POSIX_VDISABLE ? bt->c_cc[VSTOP] : 0;
298 st->c_line = 0;
301 static void
302 stios2stio(struct ibcs2_termios *ts, struct ibcs2_termio *t)
305 t->c_iflag = ts->c_iflag;
306 t->c_oflag = ts->c_oflag;
307 t->c_cflag = ts->c_cflag;
308 t->c_lflag = ts->c_lflag;
309 t->c_line = ts->c_line;
310 memcpy(t->c_cc, ts->c_cc, IBCS2_NCC);
313 static void
314 stio2stios(struct ibcs2_termio *t, struct ibcs2_termios *ts)
317 ts->c_iflag = t->c_iflag;
318 ts->c_oflag = t->c_oflag;
319 ts->c_cflag = t->c_cflag;
320 ts->c_lflag = t->c_lflag;
321 ts->c_line = t->c_line;
322 memcpy(ts->c_cc, t->c_cc, IBCS2_NCC);
326 ibcs2_sys_ioctl(struct lwp *l, const struct ibcs2_sys_ioctl_args *uap, register_t *retval)
328 /* {
329 syscallarg(int) fd;
330 syscallarg(int) cmd;
331 syscallarg(void *) data;
332 } */
333 struct proc *p = l->l_proc;
334 struct file *fp;
335 int (*ctl)(struct file *, u_long, void *);
336 struct termios bts;
337 struct ibcs2_termios sts;
338 struct ibcs2_termio st;
339 struct sys_ioctl_args bsd_ua;
340 int error, t;
342 SCARG(&bsd_ua, fd) = SCARG(uap, fd);
343 SCARG(&bsd_ua, data) = SCARG(uap, data);
345 /* Handle the easy ones first */
346 switch ((unsigned long)SCARG(uap, cmd)) {
347 case IBCS2_TIOCGWINSZ:
348 SCARG(&bsd_ua, com) = TIOCGWINSZ;
349 return sys_ioctl(l, &bsd_ua, retval);
351 case IBCS2_TIOCSWINSZ:
352 SCARG(&bsd_ua, com) = TIOCSWINSZ;
353 return sys_ioctl(l, &bsd_ua, retval);
355 case IBCS2_TIOCGPGRP:
356 return copyout(&p->p_pgrp->pg_id, SCARG(uap, data),
357 sizeof(p->p_pgrp->pg_id));
359 case IBCS2_TIOCSPGRP: /* XXX - is uap->data a pointer to pgid? */
361 struct sys_setpgid_args sa;
363 SCARG(&sa, pid) = 0;
364 SCARG(&sa, pgid) = (int)SCARG(uap, data);
365 if ((error = sys_setpgid(l, &sa, retval)) != 0)
366 return error;
367 return 0;
370 case IBCS2_TCGETSC: /* SCO console - get scancode flags */
371 case IBCS2_TCSETSC: /* SCO console - set scancode flags */
372 return ENOSYS;
374 case IBCS2_SIOCSOCKSYS:
375 return ibcs2_socksys(l, (const void *)uap, retval);
377 case IBCS2_I_NREAD: /* STREAMS */
378 SCARG(&bsd_ua, com) = FIONREAD;
379 return sys_ioctl(l, &bsd_ua, retval);
380 default:
381 break;
384 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) {
385 DPRINTF(("ibcs2_ioctl(%d): bad fd %d ", p->p_pid,
386 SCARG(uap, fd)));
387 return EBADF;
390 if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
391 DPRINTF(("ibcs2_ioctl(%d): bad fp flag ", p->p_pid));
392 error = EBADF;
393 goto out;
396 ctl = fp->f_ops->fo_ioctl;
398 switch ((unsigned long)SCARG(uap, cmd)) {
399 case IBCS2_TCGETA:
400 case IBCS2_XCGETA:
401 case IBCS2_OXCGETA:
402 if ((error = (*ctl)(fp, TIOCGETA, &bts)) != 0)
403 goto out;
405 btios2stios(&bts, &sts);
406 if (SCARG(uap, cmd) == IBCS2_TCGETA) {
407 stios2stio(&sts, &st);
408 error = copyout(&st, SCARG(uap, data), sizeof(st));
409 if (error)
410 DPRINTF(("ibcs2_ioctl(%d): copyout failed ",
411 p->p_pid));
412 } else
413 error = copyout(&sts, SCARG(uap, data), sizeof(sts));
414 break;
416 case IBCS2_TCSETA:
417 case IBCS2_TCSETAW:
418 case IBCS2_TCSETAF:
419 if ((error = copyin(SCARG(uap, data), &st, sizeof(st))) != 0) {
420 DPRINTF(("ibcs2_ioctl(%d): TCSET copyin failed ",
421 p->p_pid));
422 goto out;
425 /* get full BSD termios so we don't lose information */
426 if ((error = (*ctl)(fp, TIOCGETA, &bts)) != 0) {
427 DPRINTF(("ibcs2_ioctl(%d): TCSET ctl failed fd %d ",
428 p->p_pid, SCARG(uap, fd)));
429 goto out;
433 * convert to iBCS2 termios, copy in information from
434 * termio, and convert back, then set new values.
436 btios2stios(&bts, &sts);
437 stio2stios(&st, &sts);
438 stios2btios(&sts, &bts);
440 t = SCARG(uap, cmd) - IBCS2_TCSETA + TIOCSETA;
441 error = (*ctl)(fp, t, &bts);
442 break;
444 case IBCS2_XCSETA:
445 case IBCS2_XCSETAW:
446 case IBCS2_XCSETAF:
447 if ((error = copyin(SCARG(uap, data), &sts, sizeof(sts))) != 0)
448 goto out;
450 stios2btios(&sts, &bts);
451 t = SCARG(uap, cmd) - IBCS2_XCSETA + TIOCSETA;
452 error = (*ctl)(fp, t, &bts);
453 break;
455 case IBCS2_OXCSETA:
456 case IBCS2_OXCSETAW:
457 case IBCS2_OXCSETAF:
458 if ((error = copyin(SCARG(uap, data), &sts, sizeof(sts))) != 0)
459 goto out;
460 stios2btios(&sts, &bts);
461 t = SCARG(uap, cmd) - IBCS2_OXCSETA + TIOCSETA;
462 error = (*ctl)(fp, t, &bts);
463 break;
465 case IBCS2_TCSBRK:
466 t = (int) SCARG(uap, data);
467 t = (t ? t : 1) * hz * 4;
468 t /= 10;
469 if ((error = (*ctl)(fp, TIOCSBRK, NULL)) != 0)
470 goto out;
471 error = tsleep(&t, PZERO | PCATCH, "ibcs2_tcsbrk", t);
472 if (error == EINTR || error == ERESTART) {
473 (void)(*ctl)(fp, TIOCCBRK, NULL);
474 error = EINTR;
475 } else
476 error = (*ctl)(fp, TIOCCBRK, NULL);
477 break;
479 case IBCS2_TCXONC:
480 switch ((int)SCARG(uap, data)) {
481 case 0:
482 case 1:
483 DPRINTF(("ibcs2_ioctl(%d): TCXONC ", p->p_pid));
484 error = ENOSYS;
485 break;
486 case 2:
487 error = (*ctl)(fp, TIOCSTOP, NULL);
488 break;
489 case 3:
490 error = (*ctl)(fp, TIOCSTART, (void *)1);
491 break;
492 default:
493 error = EINVAL;
494 break;
496 break;
498 case IBCS2_TCFLSH:
499 switch ((int)SCARG(uap, data)) {
500 case 0:
501 t = FREAD;
502 break;
503 case 1:
504 t = FWRITE;
505 break;
506 case 2:
507 t = FREAD | FWRITE;
508 break;
509 default:
510 error = EINVAL;
511 goto out;
513 error = (*ctl)(fp, TIOCFLUSH, &t);
514 break;
516 case IBCS2_FIONBIO:
517 if ((error = copyin(SCARG(uap, data), &t, sizeof(t))) != 0)
518 goto out;
519 error = (*ctl)(fp, FIONBIO, (void *)&t);
520 break;
522 default:
523 DPRINTF(("ibcs2_ioctl(%d): unknown cmd 0x%x ",
524 p->p_pid, SCARG(uap, cmd)));
525 error = ENOSYS;
526 break;
528 out:
529 fd_putfile(SCARG(uap, fd));
530 return error;
534 ibcs2_sys_gtty(struct lwp *l, const struct ibcs2_sys_gtty_args *uap, register_t *retval)
536 /* {
537 syscallarg(int) fd;
538 syscallarg(struct sgttyb *) tb;
539 } */
540 struct file *fp;
541 struct sgttyb tb;
542 struct ibcs2_sgttyb itb;
543 int error;
545 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) {
546 DPRINTF(("ibcs2_sys_gtty(%d): bad fd %d ", curproc->p_pid,
547 SCARG(uap, fd)));
548 return EBADF;
550 if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
551 DPRINTF(("ibcs2_sys_gtty(%d): bad fp flag ", curproc->p_pid));
552 error = EBADF;
553 goto out;
556 error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETP, (void *)&tb);
557 if (error)
558 goto out;
560 fd_putfile(SCARG(uap, fd));
562 itb.sg_ispeed = tb.sg_ispeed;
563 itb.sg_ospeed = tb.sg_ospeed;
564 itb.sg_erase = tb.sg_erase;
565 itb.sg_kill = tb.sg_kill;
566 itb.sg_flags = tb.sg_flags & ~(IBCS2_GHUPCL|IBCS2_GXTABS);
567 return copyout((void *)&itb, SCARG(uap, tb), sizeof(itb));
568 out:
569 fd_putfile(SCARG(uap, fd));
570 return error;