xref: /netbsd-src/sys/compat/sunos32/sunos32_ioctl.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: sunos32_ioctl.c,v 1.35 2019/04/23 07:45:06 msaitoh Exp $	*/
2 /* from: NetBSD: sunos_ioctl.c,v 1.35 2001/02/03 22:20:02 mrg Exp 	*/
3 
4 /*
5  * Copyright (c) 2001 Matthew R. Green
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
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,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * Copyright (c) 1993 Markus Wild.
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. The name of the author may not be used to endorse or promote products
40  *    derived from this software without specific prior written permission
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
43  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
46  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
51  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52  *
53  * loosely from: Header: sunos_ioctl.c,v 1.7 93/05/28 04:40:43 torek Exp
54  */
55 
56 #include <sys/cdefs.h>
57 __KERNEL_RCSID(0, "$NetBSD: sunos32_ioctl.c,v 1.35 2019/04/23 07:45:06 msaitoh Exp $");
58 
59 #if defined(_KERNEL_OPT)
60 #include "opt_compat_netbsd32.h"
61 #include "opt_execfmt.h"
62 #endif
63 
64 #include <sys/param.h>
65 #include <sys/proc.h>
66 #include <sys/systm.h>
67 #include <sys/file.h>
68 #include <sys/filedesc.h>
69 #include <sys/ioctl.h>
70 #include <sys/termios.h>
71 #include <sys/tty.h>
72 #include <sys/socket.h>
73 #include <sys/audioio.h>
74 #include <sys/vnode.h>
75 #include <sys/mount.h>
76 #include <sys/disklabel.h>
77 #include <sys/syscallargs.h>
78 
79 #include <miscfs/specfs/specdev.h>
80 
81 #include <net/if.h>
82 
83 #include <dev/sun/disklabel.h>
84 
85 #include <compat/sys/sockio.h>
86 
87 #include <compat/sunos/sunos.h>
88 #include <compat/sunos/sunos_syscallargs.h>
89 #include <compat/netbsd32/netbsd32.h>
90 #include <compat/netbsd32/netbsd32_syscallargs.h>
91 #include <compat/sunos32/sunos32.h>
92 #include <compat/sunos32/sunos32_syscallargs.h>
93 #include <compat/common/compat_util.h>
94 
95 /*
96  * SunOS ioctl calls.
97  * This file is something of a hodge-podge.
98  * Support gets added as things turn up....
99  */
100 
101 static const struct speedtab sptab[] = {
102 	{ 0, 0 },
103 	{ 50, 1 },
104 	{ 75, 2 },
105 	{ 110, 3 },
106 	{ 134, 4 },
107 	{ 135, 4 },
108 	{ 150, 5 },
109 	{ 200, 6 },
110 	{ 300, 7 },
111 	{ 600, 8 },
112 	{ 1200, 9 },
113 	{ 1800, 10 },
114 	{ 2400, 11 },
115 	{ 4800, 12 },
116 	{ 9600, 13 },
117 	{ 19200, 14 },
118 	{ 38400, 15 },
119 	{ -1, -1 }
120 };
121 
122 static const netbsd32_u_long s2btab[] = {
123 	0,
124 	50,
125 	75,
126 	110,
127 	134,
128 	150,
129 	200,
130 	300,
131 	600,
132 	1200,
133 	1800,
134 	2400,
135 	4800,
136 	9600,
137 	19200,
138 	38400,
139 };
140 
141 static void stios2btios(struct sunos_termios *, struct termios *);
142 static void btios2stios(struct termios *, struct sunos_termios *);
143 static void stios2stio(struct sunos_termios *, struct sunos_termio *);
144 static void stio2stios(struct sunos_termio *, struct sunos_termios *);
145 
146 /*
147  * These two conversion functions have mostly been done
148  * with some perl cut&paste, then hand-edited to comment
149  * out what doesn't exist under NetBSD.
150  * A note from Markus's code:
151  *	(l & BITMASK1) / BITMASK1 * BITMASK2  is translated
152  *	optimally by gcc m68k, much better than any ?: stuff.
153  *	Code may vary with different architectures of course.
154  *
155  * I don't know what optimizer you used, but seeing divu's and
156  * bfextu's in the m68k assembly output did not encourage me...
157  * as well, gcc on the sparc definitely generates much better
158  * code with `?:'.
159  */
160 
161 static void
162 stios2btios(struct sunos_termios *st, struct termios *bt)
163 {
164 	netbsd32_u_long l, r;
165 
166 	l = st->c_iflag;
167 	r = 	((l & 0x00000001) ? IGNBRK	: 0);
168 	r |=	((l & 0x00000002) ? BRKINT	: 0);
169 	r |=	((l & 0x00000004) ? IGNPAR	: 0);
170 	r |=	((l & 0x00000008) ? PARMRK	: 0);
171 	r |=	((l & 0x00000010) ? INPCK	: 0);
172 	r |=	((l & 0x00000020) ? ISTRIP	: 0);
173 	r |= 	((l & 0x00000040) ? INLCR	: 0);
174 	r |=	((l & 0x00000080) ? IGNCR	: 0);
175 	r |=	((l & 0x00000100) ? ICRNL	: 0);
176 	/*	((l & 0x00000200) ? IUCLC	: 0) */
177 	r |=	((l & 0x00000400) ? IXON	: 0);
178 	r |=	((l & 0x00000800) ? IXANY	: 0);
179 	r |=	((l & 0x00001000) ? IXOFF	: 0);
180 	r |=	((l & 0x00002000) ? IMAXBEL	: 0);
181 	bt->c_iflag = r;
182 
183 	l = st->c_oflag;
184 	r = 	((l & 0x00000001) ? OPOST	: 0);
185 	/*	((l & 0x00000002) ? OLCUC	: 0) */
186 	r |=	((l & 0x00000004) ? ONLCR	: 0);
187 	/*	((l & 0x00000008) ? OCRNL	: 0) */
188 	/*	((l & 0x00000010) ? ONOCR	: 0) */
189 	/*	((l & 0x00000020) ? ONLRET	: 0) */
190 	/*	((l & 0x00000040) ? OFILL	: 0) */
191 	/*	((l & 0x00000080) ? OFDEL	: 0) */
192 	/*	((l & 0x00000100) ? NLDLY	: 0) */
193 	/*	((l & 0x00000100) ? NL1		: 0) */
194 	/*	((l & 0x00000600) ? CRDLY	: 0) */
195 	/*	((l & 0x00000200) ? CR1		: 0) */
196 	/*	((l & 0x00000400) ? CR2		: 0) */
197 	/*	((l & 0x00000600) ? CR3		: 0) */
198 	/*	((l & 0x00001800) ? TABDLY	: 0) */
199 	/*	((l & 0x00000800) ? TAB1	: 0) */
200 	/*	((l & 0x00001000) ? TAB2	: 0) */
201 	r |=	((l & 0x00001800) ? OXTABS	: 0);
202 	/*	((l & 0x00002000) ? BSDLY	: 0) */
203 	/*	((l & 0x00002000) ? BS1		: 0) */
204 	/*	((l & 0x00004000) ? VTDLY	: 0) */
205 	/*	((l & 0x00004000) ? VT1		: 0) */
206 	/*	((l & 0x00008000) ? FFDLY	: 0) */
207 	/*	((l & 0x00008000) ? FF1		: 0) */
208 	/*	((l & 0x00010000) ? PAGEOUT	: 0) */
209 	/*	((l & 0x00020000) ? WRAP	: 0) */
210 	bt->c_oflag = r;
211 
212 	l = st->c_cflag;
213 	switch (l & 0x00000030) {
214 	case 0:
215 		r = CS5;
216 		break;
217 	case 0x00000010:
218 		r = CS6;
219 		break;
220 	case 0x00000020:
221 		r = CS7;
222 		break;
223 	case 0x00000030:
224 		r = CS8;
225 		break;
226 	}
227 	r |=	((l & 0x00000040) ? CSTOPB	: 0);
228 	r |=	((l & 0x00000080) ? CREAD	: 0);
229 	r |= 	((l & 0x00000100) ? PARENB	: 0);
230 	r |=	((l & 0x00000200) ? PARODD	: 0);
231 	r |=	((l & 0x00000400) ? HUPCL	: 0);
232 	r |=	((l & 0x00000800) ? CLOCAL	: 0);
233 	/*	((l & 0x00001000) ? LOBLK	: 0) */
234 	r |=	((l & 0x80000000) ? (CRTS_IFLOW|CCTS_OFLOW) : 0);
235 	bt->c_cflag = r;
236 
237 	bt->c_ispeed = bt->c_ospeed = s2btab[l & 0x0000000f];
238 
239 	l = st->c_lflag;
240 	r = 	((l & 0x00000001) ? ISIG	: 0);
241 	r |=	((l & 0x00000002) ? ICANON	: 0);
242 	/*	((l & 0x00000004) ? XCASE	: 0) */
243 	r |=	((l & 0x00000008) ? ECHO	: 0);
244 	r |=	((l & 0x00000010) ? ECHOE	: 0);
245 	r |=	((l & 0x00000020) ? ECHOK	: 0);
246 	r |=	((l & 0x00000040) ? ECHONL	: 0);
247 	r |= 	((l & 0x00000080) ? NOFLSH	: 0);
248 	r |=	((l & 0x00000100) ? TOSTOP	: 0);
249 	r |=	((l & 0x00000200) ? ECHOCTL	: 0);
250 	r |=	((l & 0x00000400) ? ECHOPRT	: 0);
251 	r |=	((l & 0x00000800) ? ECHOKE	: 0);
252 	/*	((l & 0x00001000) ? DEFECHO	: 0) */
253 	r |=	((l & 0x00002000) ? FLUSHO	: 0);
254 	r |=	((l & 0x00004000) ? PENDIN	: 0);
255 	bt->c_lflag = r;
256 
257 	bt->c_cc[VINTR]    = st->c_cc[0]  ? st->c_cc[0]  : _POSIX_VDISABLE;
258 	bt->c_cc[VQUIT]    = st->c_cc[1]  ? st->c_cc[1]  : _POSIX_VDISABLE;
259 	bt->c_cc[VERASE]   = st->c_cc[2]  ? st->c_cc[2]  : _POSIX_VDISABLE;
260 	bt->c_cc[VKILL]    = st->c_cc[3]  ? st->c_cc[3]  : _POSIX_VDISABLE;
261 	bt->c_cc[VEOF]     = st->c_cc[4]  ? st->c_cc[4]  : _POSIX_VDISABLE;
262 	bt->c_cc[VEOL]     = st->c_cc[5]  ? st->c_cc[5]  : _POSIX_VDISABLE;
263 	bt->c_cc[VEOL2]    = st->c_cc[6]  ? st->c_cc[6]  : _POSIX_VDISABLE;
264     /*	bt->c_cc[VSWTCH]   = st->c_cc[7]  ? st->c_cc[7]  : _POSIX_VDISABLE; */
265 	bt->c_cc[VSTART]   = st->c_cc[8]  ? st->c_cc[8]  : _POSIX_VDISABLE;
266 	bt->c_cc[VSTOP]    = st->c_cc[9]  ? st->c_cc[9]  : _POSIX_VDISABLE;
267 	bt->c_cc[VSUSP]    = st->c_cc[10] ? st->c_cc[10] : _POSIX_VDISABLE;
268 	bt->c_cc[VDSUSP]   = st->c_cc[11] ? st->c_cc[11] : _POSIX_VDISABLE;
269 	bt->c_cc[VREPRINT] = st->c_cc[12] ? st->c_cc[12] : _POSIX_VDISABLE;
270 	bt->c_cc[VDISCARD] = st->c_cc[13] ? st->c_cc[13] : _POSIX_VDISABLE;
271 	bt->c_cc[VWERASE]  = st->c_cc[14] ? st->c_cc[14] : _POSIX_VDISABLE;
272 	bt->c_cc[VLNEXT]   = st->c_cc[15] ? st->c_cc[15] : _POSIX_VDISABLE;
273 	bt->c_cc[VSTATUS]  = st->c_cc[16] ? st->c_cc[16] : _POSIX_VDISABLE;
274 
275 	/* if `raw mode', create native VMIN/VTIME from SunOS VEOF/VEOL */
276 	bt->c_cc[VMIN]	   = (bt->c_lflag & ICANON) ? 1 : bt->c_cc[VEOF];
277 	bt->c_cc[VTIME]	   = (bt->c_lflag & ICANON) ? 1 : bt->c_cc[VEOL];
278 }
279 
280 
281 static void
282 btios2stios(struct termios *bt, struct sunos_termios *st)
283 {
284 	netbsd32_u_long l, r;
285 	int s;
286 
287 	l = bt->c_iflag;
288 	r = 	((l &  IGNBRK) ? 0x00000001	: 0);
289 	r |=	((l &  BRKINT) ? 0x00000002	: 0);
290 	r |=	((l &  IGNPAR) ? 0x00000004	: 0);
291 	r |=	((l &  PARMRK) ? 0x00000008	: 0);
292 	r |=	((l &   INPCK) ? 0x00000010	: 0);
293 	r |=	((l &  ISTRIP) ? 0x00000020	: 0);
294 	r |=	((l &   INLCR) ? 0x00000040	: 0);
295 	r |=	((l &   IGNCR) ? 0x00000080	: 0);
296 	r |=	((l &   ICRNL) ? 0x00000100	: 0);
297 	/*	((l &   IUCLC) ? 0x00000200	: 0) */
298 	r |=	((l &    IXON) ? 0x00000400	: 0);
299 	r |=	((l &   IXANY) ? 0x00000800	: 0);
300 	r |=	((l &   IXOFF) ? 0x00001000	: 0);
301 	r |=	((l & IMAXBEL) ? 0x00002000	: 0);
302 	st->c_iflag = r;
303 
304 	l = bt->c_oflag;
305 	r =	((l &   OPOST) ? 0x00000001	: 0);
306 	/*	((l &   OLCUC) ? 0x00000002	: 0) */
307 	r |=	((l &   ONLCR) ? 0x00000004	: 0);
308 	/*	((l &   OCRNL) ? 0x00000008	: 0) */
309 	/*	((l &   ONOCR) ? 0x00000010	: 0) */
310 	/*	((l &  ONLRET) ? 0x00000020	: 0) */
311 	/*	((l &   OFILL) ? 0x00000040	: 0) */
312 	/*	((l &   OFDEL) ? 0x00000080	: 0) */
313 	/*	((l &   NLDLY) ? 0x00000100	: 0) */
314 	/*	((l &     NL1) ? 0x00000100	: 0) */
315 	/*	((l &   CRDLY) ? 0x00000600	: 0) */
316 	/*	((l &     CR1) ? 0x00000200	: 0) */
317 	/*	((l &     CR2) ? 0x00000400	: 0) */
318 	/*	((l &     CR3) ? 0x00000600	: 0) */
319 	/*	((l &  TABDLY) ? 0x00001800	: 0) */
320 	/*	((l &    TAB1) ? 0x00000800	: 0) */
321 	/*	((l &    TAB2) ? 0x00001000	: 0) */
322 	r |=	((l &  OXTABS) ? 0x00001800	: 0);
323 	/*	((l &   BSDLY) ? 0x00002000	: 0) */
324 	/*	((l &     BS1) ? 0x00002000	: 0) */
325 	/*	((l &   VTDLY) ? 0x00004000	: 0) */
326 	/*	((l &     VT1) ? 0x00004000	: 0) */
327 	/*	((l &   FFDLY) ? 0x00008000	: 0) */
328 	/*	((l &     FF1) ? 0x00008000	: 0) */
329 	/*	((l & PAGEOUT) ? 0x00010000	: 0) */
330 	/*	((l &    WRAP) ? 0x00020000	: 0) */
331 	st->c_oflag = r;
332 
333 	l = bt->c_cflag;
334 	switch (l & CSIZE) {
335 	case CS5:
336 		r = 0;
337 		break;
338 	case CS6:
339 		r = 0x00000010;
340 		break;
341 	case CS7:
342 		r = 0x00000020;
343 		break;
344 	case CS8:
345 		r = 0x00000030;
346 		break;
347 	}
348 	r |=	((l &  CSTOPB) ? 0x00000040	: 0);
349 	r |=	((l &   CREAD) ? 0x00000080	: 0);
350 	r |=	((l &  PARENB) ? 0x00000100	: 0);
351 	r |=	((l &  PARODD) ? 0x00000200	: 0);
352 	r |=	((l &   HUPCL) ? 0x00000400	: 0);
353 	r |=	((l &  CLOCAL) ? 0x00000800	: 0);
354 	/*	((l &   LOBLK) ? 0x00001000	: 0) */
355 	r |=	((l & (CRTS_IFLOW|CCTS_OFLOW)) ? 0x80000000 : 0);
356 	st->c_cflag = r;
357 
358 	l = bt->c_lflag;
359 	r =	((l &    ISIG) ? 0x00000001	: 0);
360 	r |=	((l &  ICANON) ? 0x00000002	: 0);
361 	/*	((l &   XCASE) ? 0x00000004	: 0) */
362 	r |=	((l &    ECHO) ? 0x00000008	: 0);
363 	r |=	((l &   ECHOE) ? 0x00000010	: 0);
364 	r |=	((l &   ECHOK) ? 0x00000020	: 0);
365 	r |=	((l &  ECHONL) ? 0x00000040	: 0);
366 	r |=	((l &  NOFLSH) ? 0x00000080	: 0);
367 	r |=	((l &  TOSTOP) ? 0x00000100	: 0);
368 	r |=	((l & ECHOCTL) ? 0x00000200	: 0);
369 	r |=	((l & ECHOPRT) ? 0x00000400	: 0);
370 	r |=	((l &  ECHOKE) ? 0x00000800	: 0);
371 	/*	((l & DEFECHO) ? 0x00001000	: 0) */
372 	r |=	((l &  FLUSHO) ? 0x00002000	: 0);
373 	r |=	((l &  PENDIN) ? 0x00004000	: 0);
374 	st->c_lflag = r;
375 
376 	s = ttspeedtab(bt->c_ospeed, sptab);
377 	if (s >= 0)
378 		st->c_cflag |= s;
379 
380 	st->c_cc[0] = bt->c_cc[VINTR]   != _POSIX_VDISABLE? bt->c_cc[VINTR]:0;
381 	st->c_cc[1] = bt->c_cc[VQUIT]   != _POSIX_VDISABLE? bt->c_cc[VQUIT]:0;
382 	st->c_cc[2] = bt->c_cc[VERASE]  != _POSIX_VDISABLE? bt->c_cc[VERASE]:0;
383 	st->c_cc[3] = bt->c_cc[VKILL]   != _POSIX_VDISABLE? bt->c_cc[VKILL]:0;
384 	st->c_cc[4] = bt->c_cc[VEOF]    != _POSIX_VDISABLE? bt->c_cc[VEOF]:0;
385 	st->c_cc[5] = bt->c_cc[VEOL]    != _POSIX_VDISABLE? bt->c_cc[VEOL]:0;
386 	st->c_cc[6] = bt->c_cc[VEOL2]   != _POSIX_VDISABLE? bt->c_cc[VEOL2]:0;
387 	st->c_cc[7] = 0;
388 		/*    bt->c_cc[VSWTCH]  != _POSIX_VDISABLE? bt->c_cc[VSWTCH]: */
389 	st->c_cc[8] = bt->c_cc[VSTART]  != _POSIX_VDISABLE? bt->c_cc[VSTART]:0;
390 	st->c_cc[9] = bt->c_cc[VSTOP]   != _POSIX_VDISABLE? bt->c_cc[VSTOP]:0;
391 	st->c_cc[10]= bt->c_cc[VSUSP]   != _POSIX_VDISABLE? bt->c_cc[VSUSP]:0;
392 	st->c_cc[11]= bt->c_cc[VDSUSP]  != _POSIX_VDISABLE? bt->c_cc[VDSUSP]:0;
393 	st->c_cc[12]= bt->c_cc[VREPRINT]!= _POSIX_VDISABLE? bt->c_cc[VREPRINT]:0;
394 	st->c_cc[13]= bt->c_cc[VDISCARD]!= _POSIX_VDISABLE? bt->c_cc[VDISCARD]:0;
395 	st->c_cc[14]= bt->c_cc[VWERASE] != _POSIX_VDISABLE? bt->c_cc[VWERASE]:0;
396 	st->c_cc[15]= bt->c_cc[VLNEXT]  != _POSIX_VDISABLE? bt->c_cc[VLNEXT]:0;
397 	st->c_cc[16]= bt->c_cc[VSTATUS] != _POSIX_VDISABLE? bt->c_cc[VSTATUS]:0;
398 
399 	if (!(bt->c_lflag & ICANON)) {
400 		/* SunOS stores VMIN/VTIME in VEOF/VEOL (if ICANON is off) */
401 		st->c_cc[4] = bt->c_cc[VMIN];
402 		st->c_cc[5] = bt->c_cc[VTIME];
403 	}
404 
405 	st->c_line = 0;
406 }
407 
408 static void
409 stios2stio(struct sunos_termios *ts, struct sunos_termio *t)
410 {
411 	t->c_iflag = ts->c_iflag;
412 	t->c_oflag = ts->c_oflag;
413 	t->c_cflag = ts->c_cflag;
414 	t->c_lflag = ts->c_lflag;
415 	t->c_line  = ts->c_line;
416 	memcpy(t->c_cc, ts->c_cc, 8);
417 }
418 
419 static void
420 stio2stios(struct sunos_termio *t, struct sunos_termios *ts)
421 {
422 	ts->c_iflag = t->c_iflag;
423 	ts->c_oflag = t->c_oflag;
424 	ts->c_cflag = t->c_cflag;
425 	ts->c_lflag = t->c_lflag;
426 	ts->c_line  = t->c_line;
427 	memcpy(ts->c_cc, t->c_cc, 8); /* don't touch the upper fields! */
428 }
429 
430 
431 static int
432 sunos32_do_ioctl(int fd, int cmd, void *arg, struct lwp *l)
433 {
434 	file_t *fp;
435 	struct vnode *vp;
436 	int error;
437 
438 	if ((error = fd_getvnode(fd, &fp)) != 0)
439 		return error;
440 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
441 		fd_putfile(fd);
442 		return EBADF;
443 	}
444 	error = fp->f_ops->fo_ioctl(fp, cmd, arg);
445 	if (error == EIO && cmd == TIOCGPGRP) {
446 		vp = fp->f_vnode;
447 		if (vp != NULL && vp->v_type == VCHR && major(vp->v_rdev) == 21)
448 			error = ENOTTY;
449 	}
450 	fd_putfile(fd);
451 	return error;
452 }
453 
454 int
455 sunos32_sys_ioctl(struct lwp *l, const struct sunos32_sys_ioctl_args *uap,
456     register_t *retval)
457 {
458 	/* {
459 		int	fd;
460 		netbsd32_u_long	com;
461 		netbsd32_caddr_t	data;
462 	} */
463 	struct netbsd32_ioctl_args bsd_ua;
464 	int error;
465 
466 	SCARG(&bsd_ua, fd) = SCARG(uap, fd);
467 	SCARG(&bsd_ua, com) = SCARG(uap, com);
468 	SCARG(&bsd_ua, data) = SCARG(uap, data);
469 
470 	switch (SCARG(uap, com)) {
471 	case _IOR('t', 0, int):
472 		SCARG(&bsd_ua, com) = TIOCGETD;
473 		break;
474 	case _IOW('t', 1, int):
475 	    {
476 		int disc;
477 
478 		if ((error = copyin(SCARG_P32(uap, data), &disc,
479 		    sizeof disc)) != 0)
480 			return error;
481 
482 		/* map SunOS NTTYDISC into our termios discipline */
483 		if (disc == 2)
484 			disc = 0;
485 		/* all other disciplines are not supported by NetBSD */
486 		if (disc)
487 			return ENXIO;
488 
489 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCSETD, &disc, l);
490 	    }
491 	case _IOW('t', 101, int):	/* sun SUNOS_TIOCSSOFTCAR */
492 	    {
493 		int x;	/* unused */
494 
495 		return copyin(SCARG_P32(uap, data), &x, sizeof x);
496 	    }
497 	case _IOR('t', 100, int):	/* sun SUNOS_TIOCSSOFTCAR */
498 	    {
499 		int x = 0;
500 
501 		return copyout(&x, SCARG_P32(uap, data), sizeof x);
502 	    }
503 	case _IO('t', 36): 		/* sun TIOCCONS, no parameters */
504 	    {
505 		int on = 1;
506 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCCONS, &on, l);
507 	    }
508 	case _IOW('t', 37, struct sunos_ttysize):
509 	    {
510 		struct winsize ws;
511 		struct sunos_ttysize ss;
512 
513 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGWINSZ, &ws,
514 		    l);
515 		if (error != 0)
516 			return error;
517 
518 		error = copyin(SCARG_P32(uap, data), &ss, sizeof(ss));
519 		if (error != 0)
520 			return error;
521 
522 		ws.ws_row = ss.ts_row;
523 		ws.ws_col = ss.ts_col;
524 
525 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCSWINSZ, &ws, l);
526 	    }
527 	case _IOW('t', 38, struct sunos_ttysize):
528 	    {
529 		struct winsize ws;
530 		struct sunos_ttysize ss;
531 
532 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGWINSZ, &ws,
533 		    l);
534 		if (error != 0)
535 			return error;
536 
537 		ss.ts_row = ws.ws_row;
538 		ss.ts_col = ws.ws_col;
539 
540 		return copyout(&ss, SCARG_P32(uap, data), sizeof(ss));
541 	    }
542 	case _IOW('t', 130, int):	/* TIOCSETPGRP: posix variant */
543 		SCARG(&bsd_ua, com) = TIOCSPGRP;
544 		break;
545 	case _IOR('t', 131, int):	/* TIOCGETPGRP: posix variant */
546 	    {
547 		/*
548 		 * sigh, must do error translation on pty devices
549 		 * (see also kern/tty_pty.c)
550 		 */
551 		int pgrp;
552 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGPGRP, &pgrp,
553 		    l);
554 		if (error)
555 			return error;
556 		return copyout(&pgrp, SCARG_P32(uap, data), sizeof(pgrp));
557 	    }
558 	case _IO('t', 132):
559 		SCARG(&bsd_ua, com) = TIOCSCTTY;
560 		break;
561 	case SUNOS_TCGETA:
562 	case SUNOS_TCGETS:
563 	    {
564 		struct termios bts;
565 		struct sunos_termios sts;
566 		struct sunos_termio st;
567 
568 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGETA, &bts,
569 		    l);
570 		if (error != 0)
571 			return error;
572 
573 		btios2stios (&bts, &sts);
574 		if (SCARG(uap, com) == SUNOS_TCGETA) {
575 			stios2stio (&sts, &st);
576 			return copyout(&st, SCARG_P32(uap, data), sizeof(st));
577 		} else
578 			return copyout(&sts, SCARG_P32(uap, data),
579 			    sizeof(sts));
580 		/*NOTREACHED*/
581 	    }
582 	case SUNOS_TCSETA:
583 	case SUNOS_TCSETAW:
584 	case SUNOS_TCSETAF:
585 	    {
586 		struct termios bts;
587 		struct sunos_termios sts;
588 		struct sunos_termio st;
589 
590 		if ((error = copyin(SCARG_P32(uap, data), &st,
591 		    sizeof(st))) != 0)
592 			return error;
593 
594 		/* get full BSD termios so we don't lose information */
595 		if ((error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGETA,
596 		    &bts, l)) != 0)
597 			return error;
598 
599 		/*
600 		 * convert to sun termios, copy in information from
601 		 * termio, and convert back, then set new values.
602 		 */
603 		btios2stios(&bts, &sts);
604 		stio2stios(&st, &sts);
605 		stios2btios(&sts, &bts);
606 
607 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd),
608 		    SCARG(uap, com) - SUNOS_TCSETA + TIOCSETA, &bts, l);
609 	    }
610 	case SUNOS_TCSETS:
611 	case SUNOS_TCSETSW:
612 	case SUNOS_TCSETSF:
613 	    {
614 		struct termios bts;
615 		struct sunos_termios sts;
616 
617 		if ((error = copyin(SCARG_P32(uap, data), &sts,
618 		    sizeof(sts))) != 0)
619 			return error;
620 		stios2btios (&sts, &bts);
621 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd),
622 		    SCARG(uap, com) - SUNOS_TCSETS + TIOCSETA, &bts, l);
623 	    }
624 /*
625  * Pseudo-tty ioctl translations.
626  */
627 	case _IOW('t', 32, int): {	/* TIOCTCNTL */
628 		int error1, on;
629 
630 		error1 = copyin(SCARG_P32(uap, data), &on, sizeof(on));
631 		if (error1)
632 			return error1;
633 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCUCNTL, &on, l);
634 	}
635 	case _IOW('t', 33, int): {	/* TIOCSIGNAL */
636 		int error1, sig;
637 
638 		error1 = copyin(SCARG_P32(uap, data), &sig, sizeof(sig));
639 		if (error1)
640 			return error1;
641 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCSIG, &sig, l);
642 	}
643 
644 /*
645  * Socket ioctl translations.
646  */
647 #define IFREQ_IN(a) { \
648 	struct oifreq ifreq; \
649 	error = copyin(SCARG_P32(uap, data), &ifreq, sizeof(ifreq)); \
650 	if (error) \
651 		return error; \
652 	return sunos32_do_ioctl(SCARG(&bsd_ua, fd), a, &ifreq, l); \
653 }
654 #define IFREQ_INOUT(a) { \
655 	struct oifreq ifreq; \
656 	error = copyin(SCARG_P32(uap, data), &ifreq, sizeof(ifreq)); \
657 	if (error) \
658 		return error; \
659 	if ((error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), a, &ifreq, l)) != 0) \
660 		return error; \
661 	return copyout(&ifreq, SCARG_P32(uap, data), sizeof(ifreq)); \
662 }
663 
664 	case _IOW('i', 12, struct oifreq):
665 		/* SIOCSIFADDR */
666 		break;
667 
668 	case _IOWR('i', 13, struct oifreq):
669 		IFREQ_INOUT(OOSIOCGIFADDR);
670 
671 	case _IOW('i', 14, struct oifreq):
672 		/* SIOCSIFDSTADDR */
673 		break;
674 
675 	case _IOWR('i', 15, struct oifreq):
676 		IFREQ_INOUT(OOSIOCGIFDSTADDR);
677 
678 	case _IOW('i', 16, struct oifreq):
679 		/* SIOCSIFFLAGS */
680 		break;
681 
682 	case _IOWR('i', 17, struct oifreq):
683 		/* SIOCGIFFLAGS */
684 		break;
685 
686 	case _IOW('i', 21, struct oifreq):
687 		IFREQ_IN(SIOCSIFMTU);
688 
689 	case _IOWR('i', 22, struct oifreq):
690 		IFREQ_INOUT(SIOCGIFMTU);
691 
692 	case _IOWR('i', 23, struct oifreq):
693 		IFREQ_INOUT(SIOCGIFBRDADDR);
694 
695 	case _IOW('i', 24, struct oifreq):
696 		IFREQ_IN(SIOCSIFBRDADDR);
697 
698 	case _IOWR('i', 25, struct oifreq):
699 		IFREQ_INOUT(OOSIOCGIFNETMASK);
700 
701 	case _IOW('i', 26, struct oifreq):
702 		IFREQ_IN(SIOCSIFNETMASK);
703 
704 	case _IOWR('i', 27, struct oifreq):
705 		IFREQ_INOUT(SIOCGIFMETRIC);
706 
707 	case _IOWR('i', 28, struct oifreq):
708 		IFREQ_IN(SIOCSIFMETRIC);
709 
710 	case _IOW('i', 30, struct arpreq):
711 		/* SIOCSARP */
712 		break;
713 
714 	case _IOWR('i', 31, struct arpreq):
715 		/* SIOCGARP */
716 		break;
717 
718 	case _IOW('i', 32, struct arpreq):
719 		/* SIOCDARP */
720 		break;
721 
722 	case _IOW('i', 18, struct oifreq):	/* SIOCSIFMEM */
723 	case _IOWR('i', 19, struct oifreq):	/* SIOCGIFMEM */
724 	case _IOW('i', 40, struct oifreq):	/* SIOCUPPER */
725 	case _IOW('i', 41, struct oifreq):	/* SIOCLOWER */
726 	case _IOW('i', 44, struct oifreq):	/* SIOCSETSYNC */
727 	case _IOWR('i', 45, struct oifreq):	/* SIOCGETSYNC */
728 	case _IOWR('i', 46, struct oifreq):	/* SIOCSDSTATS */
729 	case _IOWR('i', 47, struct oifreq):	/* SIOCSESTATS */
730 	case _IOW('i', 48, int):		/* SIOCSPROMISC */
731 	case _IOW('i', 49, struct oifreq):	/* SIOCADDMULTI */
732 	case _IOW('i', 50, struct oifreq):	/* SIOCDELMULTI */
733 		return EOPNOTSUPP;
734 
735 	case _IOWR('i', 20, struct oifconf):	/* SIOCGIFCONF */
736 	    {
737 		struct oifconf ifcf;
738 
739 		/*
740 		 * XXX: two more problems
741 		 * 1. our sockaddr's are variable length, not always
742 		 *    sizeof(sockaddr)
743 		 * 2. this returns a name per protocol, ie. it returns two
744 		 *    "lo0"'s
745 		 */
746 		error = copyin(SCARG_P32(uap, data), &ifcf, sizeof(ifcf));
747 		if (error)
748 			return error;
749 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), OOSIOCGIFCONF,
750 		    &ifcf, l);
751 		if (error)
752 			return error;
753 		return copyout(&ifcf, SCARG_P32(uap, data), sizeof(ifcf));
754 	    }
755 
756 /*
757  * Audio ioctl translations.
758  */
759 	case _IOR('A', 1, struct sunos_audio_info):	/* AUDIO_GETINFO */
760 	sunos_au_getinfo:
761 	    {
762 		struct audio_info aui;
763 		struct sunos_audio_info sunos_aui;
764 
765 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), AUDIO_GETINFO, &aui, l);
766 		if (error)
767 			return error;
768 
769 		sunos_aui.play = *(struct sunos_audio_prinfo *)&aui.play;
770 		sunos_aui.record = *(struct sunos_audio_prinfo *)&aui.record;
771 
772 		/* `avail_ports' is `seek' in BSD */
773 		sunos_aui.play.avail_ports = AUDIO_SPEAKER | AUDIO_HEADPHONE;
774 		sunos_aui.record.avail_ports = AUDIO_SPEAKER | AUDIO_HEADPHONE;
775 
776 		sunos_aui.play.waiting = 0;
777 		sunos_aui.record.waiting = 0;
778 		sunos_aui.play.eof = 0;
779 		sunos_aui.record.eof = 0;
780 		sunos_aui.monitor_gain = 0; /* aui.__spare; XXX */
781 		/*XXXsunos_aui.output_muted = 0;*/
782 		/*XXX*/sunos_aui.reserved[0] = 0;
783 		/*XXX*/sunos_aui.reserved[1] = 0;
784 		/*XXX*/sunos_aui.reserved[2] = 0;
785 		/*XXX*/sunos_aui.reserved[3] = 0;
786 
787 		return copyout(&sunos_aui, SCARG_P32(uap, data),
788 				sizeof(sunos_aui));
789 	    }
790 
791 	case _IOWR('A', 2, struct sunos_audio_info):	/* AUDIO_SETINFO */
792 	    {
793 		struct audio_info aui;
794 		struct sunos_audio_info sunos_aui;
795 
796 		error = copyin(SCARG_P32(uap, data), &sunos_aui,
797 		    sizeof(sunos_aui));
798 		if (error)
799 			return error;
800 
801 		aui.play = *(struct audio_prinfo *)&sunos_aui.play;
802 		aui.record = *(struct audio_prinfo *)&sunos_aui.record;
803 		/* aui.__spare = sunos_aui.monitor_gain; */
804 		aui.blocksize = ~0;
805 		aui.hiwat = ~0;
806 		aui.lowat = ~0;
807 		/* XXX somebody check this please. - is: aui.backlog = ~0; */
808 		aui.mode = ~0;
809 		/*
810 		 * The bsd driver does not distinguish between paused and
811 		 * active. (In the sun driver, not active means samples are
812 		 * not output at all, but paused means the last streams buffer
813 		 * is drained and then output stops.)  If either are 0, then
814 		 * when stop output. Otherwise, if either are non-zero,
815 		 * we resume.
816 		 */
817 		if (sunos_aui.play.pause == 0 || sunos_aui.play.active == 0)
818 			aui.play.pause = 0;
819 		else if (sunos_aui.play.pause != (u_char)~0 ||
820 			 sunos_aui.play.active != (u_char)~0)
821 			aui.play.pause = 1;
822 		if (sunos_aui.record.pause == 0 || sunos_aui.record.active == 0)
823 			aui.record.pause = 0;
824 		else if (sunos_aui.record.pause != (u_char)~0 ||
825 			 sunos_aui.record.active != (u_char)~0)
826 			aui.record.pause = 1;
827 
828 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), AUDIO_SETINFO,
829 		    &aui, l);
830 		if (error)
831 			return error;
832 		/* Return new state */
833 		goto sunos_au_getinfo;
834 	    }
835 	case _IO('A', 3):	/* AUDIO_DRAIN */
836 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), AUDIO_DRAIN, NULL,
837 		    l);
838 	case _IOR('A', 4, int):	/* AUDIO_GETDEV */
839 	    {
840 		int devtype = SUNOS_AUDIO_DEV_AMD;
841 		return copyout(&devtype, SCARG_P32(uap, data),
842 		    sizeof(devtype));
843 	    }
844 
845 /*
846  * Selected streams ioctls.
847  */
848 #define SUNOS_S_FLUSHR		1
849 #define SUNOS_S_FLUSHW		2
850 #define SUNOS_S_FLUSHRW		3
851 
852 #define SUNOS_S_INPUT		1
853 #define SUNOS_S_HIPRI		2
854 #define SUNOS_S_OUTPUT		4
855 #define SUNOS_S_MSG		8
856 
857 	case _IO('S', 5):	/* I_FLUSH */
858 	    {
859 		int tmp = 0;
860 		switch ((intptr_t)SCARG_P32(uap, data)) {
861 		case SUNOS_S_FLUSHR:	tmp = FREAD; break;
862 		case SUNOS_S_FLUSHW:	tmp = FWRITE; break;
863 		case SUNOS_S_FLUSHRW:	tmp = FREAD|FWRITE; break;
864 		}
865                 return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCFLUSH, &tmp, l);
866 	    }
867 	case _IO('S', 9):	/* I_SETSIG */
868 	    {
869 		int on = 1;
870 		if (((intptr_t)SCARG_P32(uap, data) &
871 		    (SUNOS_S_HIPRI|SUNOS_S_INPUT)) == SUNOS_S_HIPRI)
872 			return EOPNOTSUPP;
873                 return sunos32_do_ioctl(SCARG(&bsd_ua, fd), FIOASYNC, &on, l);
874 	    }
875 	/*
876 	 * SunOS disk ioctls, taken from arch/sparc/sparc/disksubr.c
877 	 * (which was from the old sparc/scsi/sun_disklabel.c), and
878 	 * modified to suite.
879 	 */
880 	case SUN_DKIOCGGEOM:
881             {
882 		struct disklabel dl;
883 
884 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), DIOCGDINFO,
885 		    &dl, l);
886 		if (error)
887 			return error;
888 
889 #define datageom	((struct sun_dkgeom *)SCARG_P32(uap, data))
890 		/* XXX can't do memset() on a user address (dsl) */
891 		memset(SCARG_P32(uap, data), 0, sizeof(*datageom));
892 
893 		datageom->sdkc_ncylinders = dl.d_ncylinders;
894 		datageom->sdkc_acylinders = dl.d_acylinders;
895 		datageom->sdkc_ntracks = dl.d_ntracks;
896 		datageom->sdkc_nsectors = dl.d_nsectors;
897 		datageom->sdkc_interleave = dl.d_interleave;
898 		datageom->sdkc_sparespercyl = dl.d_sparespercyl;
899 		datageom->sdkc_rpm = dl.d_rpm;
900 		datageom->sdkc_pcylinders = dl.d_ncylinders + dl.d_acylinders;
901 #undef datageom
902 		break;
903 	    }
904 
905 	case SUN_DKIOCINFO:
906 		/* Homey don't do DKIOCINFO */
907 		/* XXX can't do memset() on a user address (dsl) */
908 		memset(SCARG_P32(uap, data), 0, sizeof(struct sun_dkctlr));
909 		break;
910 
911 	case SUN_DKIOCGPART:
912             {
913 		struct partinfo pi;
914 		struct disklabel label;
915 		int fd = SCARG(&bsd_ua, fd);
916 
917 		error = sunos32_do_ioctl(fd, DIOCGPARTINFO, &pi, l);
918 		if (error)
919 			return error;
920 		error = sunos32_do_ioctl(fd, DIOCGDINFO, &label, l);
921 		if (error)
922 			return error;
923 
924 		if (label.d_secpercyl == 0)
925 			return ERANGE;	/* XXX */
926 		if (pi.pi_offset % label.d_secpercyl != 0)
927 			return ERANGE;	/* XXX */
928 		/* XXX can't do direct writes to a user address (dsl) */
929 #define datapart	((struct sun_dkpart *)SCARG_P32(uap, data))
930 		datapart->sdkp_cyloffset = pi.pi_offset / label.d_secpercyl;
931 		datapart->sdkp_nsectors = pi.pi_size;
932 #undef datapart
933 	    }
934 
935 	}
936 	return netbsd32_ioctl(l, &bsd_ua, retval);
937 }
938 
939 /* SunOS fcntl(2) cmds not implemented */
940 #define SUN_F_RGETLK	10
941 #define SUN_F_RSETLK	11
942 #define SUN_F_CNVT	12
943 #define SUN_F_RSETLKW	13
944 
945 /* SunOS flock translation */
946 struct sunos_flock {
947 	short	l_type;
948 	short	l_whence;
949 	netbsd32_long	l_start;
950 	netbsd32_long	l_len;
951 	short	l_pid;
952 	short	l_xxx;
953 };
954 
955 static void bsd_to_sunos_flock(struct flock *, struct sunos_flock *);
956 static void sunos_to_bsd_flock(struct sunos_flock *, struct flock *);
957 
958 #define SUNOS_F_RDLCK	1
959 #define	SUNOS_F_WRLCK	2
960 #define SUNOS_F_UNLCK	3
961 
962 static void
963 bsd_to_sunos_flock(struct flock *iflp, struct sunos_flock *oflp)
964 {
965 	switch (iflp->l_type) {
966 	case F_RDLCK:
967 		oflp->l_type = SUNOS_F_RDLCK;
968 		break;
969 	case F_WRLCK:
970 		oflp->l_type = SUNOS_F_WRLCK;
971 		break;
972 	case F_UNLCK:
973 		oflp->l_type = SUNOS_F_UNLCK;
974 		break;
975 	default:
976 		oflp->l_type = -1;
977 		break;
978 	}
979 
980 	oflp->l_whence = (short)iflp->l_whence;
981 	oflp->l_start = (netbsd32_long)iflp->l_start;
982 	oflp->l_len = (netbsd32_long)iflp->l_len;
983 	oflp->l_pid = (short)iflp->l_pid;
984 	oflp->l_xxx = 0;
985 }
986 
987 
988 static void
989 sunos_to_bsd_flock(struct sunos_flock *iflp, struct flock *oflp)
990 {
991 	switch (iflp->l_type) {
992 	case SUNOS_F_RDLCK:
993 		oflp->l_type = F_RDLCK;
994 		break;
995 	case SUNOS_F_WRLCK:
996 		oflp->l_type = F_WRLCK;
997 		break;
998 	case SUNOS_F_UNLCK:
999 		oflp->l_type = F_UNLCK;
1000 		break;
1001 	default:
1002 		oflp->l_type = -1;
1003 		break;
1004 	}
1005 
1006 	oflp->l_whence = iflp->l_whence;
1007 	oflp->l_start = (off_t) iflp->l_start;
1008 	oflp->l_len = (off_t) iflp->l_len;
1009 	oflp->l_pid = (pid_t) iflp->l_pid;
1010 
1011 }
1012 static struct {
1013 	netbsd32_long	sun_flg;
1014 	netbsd32_long	bsd_flg;
1015 } sunfcntl_flgtab[] = {
1016 	/* F_[GS]ETFLags that differ: */
1017 #define SUN_FSETBLK	0x0010
1018 #define SUN_SHLOCK	0x0080
1019 #define SUN_EXLOCK	0x0100
1020 #define SUN_FNBIO	0x1000
1021 #define SUN_FSYNC	0x2000
1022 #define SUN_NONBLOCK	0x4000
1023 #define SUN_FNOCTTY	0x8000
1024 	{ SUN_NONBLOCK, O_NONBLOCK },
1025 	{ SUN_FNBIO, O_NONBLOCK },
1026 	{ SUN_SHLOCK, O_SHLOCK },
1027 	{ SUN_EXLOCK, O_EXLOCK },
1028 	{ SUN_FSYNC, O_FSYNC },
1029 	{ SUN_FSETBLK, 0 },
1030 	{ SUN_FNOCTTY, 0 }
1031 };
1032 
1033 int
1034 sunos32_sys_fcntl(struct lwp *l, const struct sunos32_sys_fcntl_args *uap,
1035     register_t *retval)
1036 {
1037 	/* {
1038 		syscallarg(int) fd;
1039 		syscallarg(int) cmd;
1040 		syscallarg(netbsd32_voidp) arg;
1041 	} */
1042 	struct sys_fcntl_args bsd_ua;
1043 	uintptr_t flg;
1044 	int n, ret;
1045 
1046 	SCARG(&bsd_ua, fd) = SCARG(uap, fd);
1047 	SCARG(&bsd_ua, cmd) = SCARG(uap, cmd);
1048 	SCARG(&bsd_ua, arg) = SCARG_P32(uap, arg);
1049 
1050 	switch (SCARG(uap, cmd)) {
1051 	case F_SETFL:
1052 		flg = (intptr_t)SCARG_P32(uap, arg);
1053 		n = sizeof(sunfcntl_flgtab) / sizeof(sunfcntl_flgtab[0]);
1054 		while (--n >= 0) {
1055 			if (flg & sunfcntl_flgtab[n].sun_flg) {
1056 				flg &= ~sunfcntl_flgtab[n].sun_flg;
1057 				flg |= sunfcntl_flgtab[n].bsd_flg;
1058 			}
1059 		}
1060 		SCARG(&bsd_ua, arg) = (void *)flg;
1061 		break;
1062 
1063 	case F_GETLK:
1064 	case F_SETLK:
1065 	case F_SETLKW:
1066 		{
1067 			int error;
1068 			struct sunos_flock	ifl;
1069 			struct flock		fl;
1070 
1071 			error = copyin(SCARG_P32(uap, arg), &ifl, sizeof ifl);
1072 			if (error)
1073 				return error;
1074 			sunos_to_bsd_flock(&ifl, &fl);
1075 
1076 			error = do_fcntl_lock(SCARG(uap, fd), SCARG(uap, cmd),
1077 			    &fl);
1078 			if (error || SCARG(uap, cmd) != F_GETLK)
1079 				return error;
1080 
1081 			bsd_to_sunos_flock(&fl, &ifl);
1082 			return copyout(&ifl, SCARG_P32(uap, arg), sizeof ifl);
1083 		}
1084 		break;
1085 	case SUN_F_RGETLK:
1086 	case SUN_F_RSETLK:
1087 	case SUN_F_CNVT:
1088 	case SUN_F_RSETLKW:
1089 		return EOPNOTSUPP;
1090 	}
1091 
1092 	ret = sys_fcntl(l, &bsd_ua, retval);
1093 	if (ret != 0)
1094 		return ret;
1095 
1096 	switch (SCARG(uap, cmd)) {
1097 	case F_GETFL:
1098 		n = sizeof(sunfcntl_flgtab) / sizeof(sunfcntl_flgtab[0]);
1099 		ret = *retval;
1100 		while (--n >= 0) {
1101 			if (ret & sunfcntl_flgtab[n].bsd_flg) {
1102 				ret &= ~sunfcntl_flgtab[n].bsd_flg;
1103 				ret |= sunfcntl_flgtab[n].sun_flg;
1104 			}
1105 		}
1106 		*retval = ret;
1107 		break;
1108 	}
1109 
1110 	return 0;
1111 }
1112