xref: /netbsd/sys/compat/sunos32/sunos32_ioctl.c (revision 6550d01e)
1 /*	$NetBSD: sunos32_ioctl.c,v 1.29 2008/05/29 14:51:26 mrg 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.29 2008/05/29 14:51:26 mrg 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 ((fp = fd_getfile(fd)) == NULL)
439 		return EBADF;
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 = (struct vnode *)fp->f_data;
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, register_t *retval)
456 {
457 	/* {
458 		int	fd;
459 		netbsd32_u_long	com;
460 		netbsd32_caddr_t	data;
461 	} */
462 	struct netbsd32_ioctl_args bsd_ua;
463 	int error;
464 
465 	SCARG(&bsd_ua, fd) = SCARG(uap, fd);
466 	SCARG(&bsd_ua, com) = SCARG(uap, com);
467 	SCARG(&bsd_ua, data) = SCARG(uap, data);
468 
469 	switch (SCARG(uap, com)) {
470 	case _IOR('t', 0, int):
471 		SCARG(&bsd_ua, com) = TIOCGETD;
472 		break;
473 	case _IOW('t', 1, int):
474 	    {
475 		int disc;
476 
477 		if ((error = copyin(SCARG_P32(uap, data), &disc,
478 		    sizeof disc)) != 0)
479 			return error;
480 
481 		/* map SunOS NTTYDISC into our termios discipline */
482 		if (disc == 2)
483 			disc = 0;
484 		/* all other disciplines are not supported by NetBSD */
485 		if (disc)
486 			return ENXIO;
487 
488 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCSETD, &disc, l);
489 	    }
490 	case _IOW('t', 101, int):	/* sun SUNOS_TIOCSSOFTCAR */
491 	    {
492 		int x;	/* unused */
493 
494 		return copyin(SCARG_P32(uap, data), &x, sizeof x);
495 	    }
496 	case _IOR('t', 100, int):	/* sun SUNOS_TIOCSSOFTCAR */
497 	    {
498 		int x = 0;
499 
500 		return copyout(&x, SCARG_P32(uap, data), sizeof x);
501 	    }
502 	case _IO('t', 36): 		/* sun TIOCCONS, no parameters */
503 	    {
504 		int on = 1;
505 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCCONS, &on, l);
506 	    }
507 	case _IOW('t', 37, struct sunos_ttysize):
508 	    {
509 		struct winsize ws;
510 		struct sunos_ttysize ss;
511 
512 		if ((error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGWINSZ, &ws, l)) != 0)
513 			return (error);
514 
515 		if ((error = copyin(SCARG_P32(uap, data), &ss, sizeof (ss))) != 0)
516 			return error;
517 
518 		ws.ws_row = ss.ts_row;
519 		ws.ws_col = ss.ts_col;
520 
521 		return (sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCSWINSZ, &ws, l));
522 	    }
523 	case _IOW('t', 38, struct sunos_ttysize):
524 	    {
525 		struct winsize ws;
526 		struct sunos_ttysize ss;
527 
528 		if ((error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGWINSZ, &ws, l)) != 0)
529 			return (error);
530 
531 		ss.ts_row = ws.ws_row;
532 		ss.ts_col = ws.ws_col;
533 
534 		return copyout(&ss, SCARG_P32(uap, data), sizeof (ss));
535 	    }
536 	case _IOW('t', 130, int):	/* TIOCSETPGRP: posix variant */
537 		SCARG(&bsd_ua, com) = TIOCSPGRP;
538 		break;
539 	case _IOR('t', 131, int):	/* TIOCGETPGRP: posix variant */
540 	    {
541 		/*
542 		 * sigh, must do error translation on pty devices
543 		 * (see also kern/tty_pty.c)
544 		 */
545 		int pgrp;
546 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGPGRP, &pgrp, l);
547 		if (error)
548 			return (error);
549 		return copyout(&pgrp, SCARG_P32(uap, data), sizeof(pgrp));
550 	    }
551 	case _IO('t', 132):
552 		SCARG(&bsd_ua, com) = TIOCSCTTY;
553 		break;
554 	case SUNOS_TCGETA:
555 	case SUNOS_TCGETS:
556 	    {
557 		struct termios bts;
558 		struct sunos_termios sts;
559 		struct sunos_termio st;
560 
561 		if ((error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGETA, &bts, l)) != 0)
562 			return error;
563 
564 		btios2stios (&bts, &sts);
565 		if (SCARG(uap, com) == SUNOS_TCGETA) {
566 			stios2stio (&sts, &st);
567 			return copyout(&st, SCARG_P32(uap, data),
568 			    sizeof (st));
569 		} else
570 			return copyout(&sts, SCARG_P32(uap, data),
571 			    sizeof (sts));
572 		/*NOTREACHED*/
573 	    }
574 	case SUNOS_TCSETA:
575 	case SUNOS_TCSETAW:
576 	case SUNOS_TCSETAF:
577 	    {
578 		struct termios bts;
579 		struct sunos_termios sts;
580 		struct sunos_termio st;
581 
582 		if ((error = copyin(SCARG_P32(uap, data), &st,
583 		    sizeof (st))) != 0)
584 			return error;
585 
586 		/* get full BSD termios so we don't lose information */
587 		if ((error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCGETA, &bts, l)) != 0)
588 			return error;
589 
590 		/*
591 		 * convert to sun termios, copy in information from
592 		 * termio, and convert back, then set new values.
593 		 */
594 		btios2stios(&bts, &sts);
595 		stio2stios(&st, &sts);
596 		stios2btios(&sts, &bts);
597 
598 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), SCARG(uap, com) - SUNOS_TCSETA + TIOCSETA,
599 		    &bts, l);
600 	    }
601 	case SUNOS_TCSETS:
602 	case SUNOS_TCSETSW:
603 	case SUNOS_TCSETSF:
604 	    {
605 		struct termios bts;
606 		struct sunos_termios sts;
607 
608 		if ((error = copyin(SCARG_P32(uap, data), &sts,
609 		    sizeof (sts))) != 0)
610 			return error;
611 		stios2btios (&sts, &bts);
612 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), SCARG(uap, com) - SUNOS_TCSETS + TIOCSETA,
613 		    &bts, l);
614 	    }
615 /*
616  * Pseudo-tty ioctl translations.
617  */
618 	case _IOW('t', 32, int): {	/* TIOCTCNTL */
619 		int error1, on;
620 
621 		error1 = copyin(SCARG_P32(uap, data), &on, sizeof (on));
622 		if (error1)
623 			return error1;
624 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCUCNTL, &on, l);
625 	}
626 	case _IOW('t', 33, int): {	/* TIOCSIGNAL */
627 		int error1, sig;
628 
629 		error1 = copyin(SCARG_P32(uap, data), &sig, sizeof (sig));
630 		if (error1)
631 			return error1;
632 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCSIG, &sig, l);
633 	}
634 
635 /*
636  * Socket ioctl translations.
637  */
638 #define IFREQ_IN(a) { \
639 	struct oifreq ifreq; \
640 	error = copyin(SCARG_P32(uap, data), &ifreq, sizeof (ifreq)); \
641 	if (error) \
642 		return error; \
643 	return sunos32_do_ioctl(SCARG(&bsd_ua, fd), a, &ifreq, l); \
644 }
645 #define IFREQ_INOUT(a) { \
646 	struct oifreq ifreq; \
647 	error = copyin(SCARG_P32(uap, data), &ifreq, sizeof (ifreq)); \
648 	if (error) \
649 		return error; \
650 	if ((error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), a, &ifreq, l)) != 0) \
651 		return error; \
652 	return copyout(&ifreq, SCARG_P32(uap, data), sizeof (ifreq)); \
653 }
654 
655 	case _IOW('i', 12, struct oifreq):
656 		/* SIOCSIFADDR */
657 		break;
658 
659 	case _IOWR('i', 13, struct oifreq):
660 		IFREQ_INOUT(OOSIOCGIFADDR);
661 
662 	case _IOW('i', 14, struct oifreq):
663 		/* SIOCSIFDSTADDR */
664 		break;
665 
666 	case _IOWR('i', 15, struct oifreq):
667 		IFREQ_INOUT(OOSIOCGIFDSTADDR);
668 
669 	case _IOW('i', 16, struct oifreq):
670 		/* SIOCSIFFLAGS */
671 		break;
672 
673 	case _IOWR('i', 17, struct oifreq):
674 		/* SIOCGIFFLAGS */
675 		break;
676 
677 	case _IOW('i', 21, struct oifreq):
678 		IFREQ_IN(SIOCSIFMTU);
679 
680 	case _IOWR('i', 22, struct oifreq):
681 		IFREQ_INOUT(SIOCGIFMTU);
682 
683 	case _IOWR('i', 23, struct oifreq):
684 		IFREQ_INOUT(SIOCGIFBRDADDR);
685 
686 	case _IOW('i', 24, struct oifreq):
687 		IFREQ_IN(SIOCSIFBRDADDR);
688 
689 	case _IOWR('i', 25, struct oifreq):
690 		IFREQ_INOUT(OOSIOCGIFNETMASK);
691 
692 	case _IOW('i', 26, struct oifreq):
693 		IFREQ_IN(SIOCSIFNETMASK);
694 
695 	case _IOWR('i', 27, struct oifreq):
696 		IFREQ_INOUT(SIOCGIFMETRIC);
697 
698 	case _IOWR('i', 28, struct oifreq):
699 		IFREQ_IN(SIOCSIFMETRIC);
700 
701 	case _IOW('i', 30, struct arpreq):
702 		/* SIOCSARP */
703 		break;
704 
705 	case _IOWR('i', 31, struct arpreq):
706 		/* SIOCGARP */
707 		break;
708 
709 	case _IOW('i', 32, struct arpreq):
710 		/* SIOCDARP */
711 		break;
712 
713 	case _IOW('i', 18, struct oifreq):	/* SIOCSIFMEM */
714 	case _IOWR('i', 19, struct oifreq):	/* SIOCGIFMEM */
715 	case _IOW('i', 40, struct oifreq):	/* SIOCUPPER */
716 	case _IOW('i', 41, struct oifreq):	/* SIOCLOWER */
717 	case _IOW('i', 44, struct oifreq):	/* SIOCSETSYNC */
718 	case _IOWR('i', 45, struct oifreq):	/* SIOCGETSYNC */
719 	case _IOWR('i', 46, struct oifreq):	/* SIOCSDSTATS */
720 	case _IOWR('i', 47, struct oifreq):	/* SIOCSESTATS */
721 	case _IOW('i', 48, int):		/* SIOCSPROMISC */
722 	case _IOW('i', 49, struct oifreq):	/* SIOCADDMULTI */
723 	case _IOW('i', 50, struct oifreq):	/* SIOCDELMULTI */
724 		return EOPNOTSUPP;
725 
726 	case _IOWR('i', 20, struct oifconf):	/* SIOCGIFCONF */
727 	    {
728 		struct oifconf ifcf;
729 
730 		/*
731 		 * XXX: two more problems
732 		 * 1. our sockaddr's are variable length, not always sizeof(sockaddr)
733 		 * 2. this returns a name per protocol, ie. it returns two "lo0"'s
734 		 */
735 		error = copyin(SCARG_P32(uap, data), &ifcf,
736 		    sizeof (ifcf));
737 		if (error)
738 			return error;
739 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), OOSIOCGIFCONF, &ifcf, l);
740 		if (error)
741 			return error;
742 		return copyout(&ifcf, SCARG_P32(uap, data),
743 		    sizeof (ifcf));
744 	    }
745 
746 /*
747  * Audio ioctl translations.
748  */
749 	case _IOR('A', 1, struct sunos_audio_info):	/* AUDIO_GETINFO */
750 	sunos_au_getinfo:
751 	    {
752 		struct audio_info aui;
753 		struct sunos_audio_info sunos_aui;
754 
755 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), AUDIO_GETINFO, &aui, l);
756 		if (error)
757 			return error;
758 
759 		sunos_aui.play = *(struct sunos_audio_prinfo *)&aui.play;
760 		sunos_aui.record = *(struct sunos_audio_prinfo *)&aui.record;
761 
762 		/* `avail_ports' is `seek' in BSD */
763 		sunos_aui.play.avail_ports = AUDIO_SPEAKER | AUDIO_HEADPHONE;
764 		sunos_aui.record.avail_ports = AUDIO_SPEAKER | AUDIO_HEADPHONE;
765 
766 		sunos_aui.play.waiting = 0;
767 		sunos_aui.record.waiting = 0;
768 		sunos_aui.play.eof = 0;
769 		sunos_aui.record.eof = 0;
770 		sunos_aui.monitor_gain = 0; /* aui.__spare; XXX */
771 		/*XXXsunos_aui.output_muted = 0;*/
772 		/*XXX*/sunos_aui.reserved[0] = 0;
773 		/*XXX*/sunos_aui.reserved[1] = 0;
774 		/*XXX*/sunos_aui.reserved[2] = 0;
775 		/*XXX*/sunos_aui.reserved[3] = 0;
776 
777 		return copyout(&sunos_aui, SCARG_P32(uap, data),
778 				sizeof (sunos_aui));
779 	    }
780 
781 	case _IOWR('A', 2, struct sunos_audio_info):	/* AUDIO_SETINFO */
782 	    {
783 		struct audio_info aui;
784 		struct sunos_audio_info sunos_aui;
785 
786 		error = copyin(SCARG_P32(uap, data), &sunos_aui,
787 		    sizeof (sunos_aui));
788 		if (error)
789 			return error;
790 
791 		aui.play = *(struct audio_prinfo *)&sunos_aui.play;
792 		aui.record = *(struct audio_prinfo *)&sunos_aui.record;
793 		/* aui.__spare = sunos_aui.monitor_gain; */
794 		aui.blocksize = ~0;
795 		aui.hiwat = ~0;
796 		aui.lowat = ~0;
797 		/* XXX somebody check this please. - is: aui.backlog = ~0; */
798 		aui.mode = ~0;
799 		/*
800 		 * The bsd driver does not distinguish between paused and
801 		 * active. (In the sun driver, not active means samples are
802 		 * not output at all, but paused means the last streams buffer
803 		 * is drained and then output stops.)  If either are 0, then
804 		 * when stop output. Otherwise, if either are non-zero,
805 		 * we resume.
806 		 */
807 		if (sunos_aui.play.pause == 0 || sunos_aui.play.active == 0)
808 			aui.play.pause = 0;
809 		else if (sunos_aui.play.pause != (u_char)~0 ||
810 			 sunos_aui.play.active != (u_char)~0)
811 			aui.play.pause = 1;
812 		if (sunos_aui.record.pause == 0 || sunos_aui.record.active == 0)
813 			aui.record.pause = 0;
814 		else if (sunos_aui.record.pause != (u_char)~0 ||
815 			 sunos_aui.record.active != (u_char)~0)
816 			aui.record.pause = 1;
817 
818 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), AUDIO_SETINFO, &aui, l);
819 		if (error)
820 			return error;
821 		/* Return new state */
822 		goto sunos_au_getinfo;
823 	    }
824 	case _IO('A', 3):	/* AUDIO_DRAIN */
825 		return sunos32_do_ioctl(SCARG(&bsd_ua, fd), AUDIO_DRAIN, NULL, l);
826 	case _IOR('A', 4, int):	/* AUDIO_GETDEV */
827 	    {
828 		int devtype = SUNOS_AUDIO_DEV_AMD;
829 		return copyout(&devtype, SCARG_P32(uap, data),
830 				sizeof (devtype));
831 	    }
832 
833 /*
834  * Selected streams ioctls.
835  */
836 #define SUNOS_S_FLUSHR		1
837 #define SUNOS_S_FLUSHW		2
838 #define SUNOS_S_FLUSHRW		3
839 
840 #define SUNOS_S_INPUT		1
841 #define SUNOS_S_HIPRI		2
842 #define SUNOS_S_OUTPUT		4
843 #define SUNOS_S_MSG		8
844 
845 	case _IO('S', 5):	/* I_FLUSH */
846 	    {
847 		int tmp = 0;
848 		switch ((intptr_t)SCARG_P32(uap, data)) {
849 		case SUNOS_S_FLUSHR:	tmp = FREAD;
850 		case SUNOS_S_FLUSHW:	tmp = FWRITE;
851 		case SUNOS_S_FLUSHRW:	tmp = FREAD|FWRITE;
852 		}
853                 return sunos32_do_ioctl(SCARG(&bsd_ua, fd), TIOCFLUSH, &tmp, l);
854 	    }
855 	case _IO('S', 9):	/* I_SETSIG */
856 	    {
857 		int on = 1;
858 		if (((intptr_t)SCARG_P32(uap, data) &
859 			(SUNOS_S_HIPRI|SUNOS_S_INPUT)) ==
860 		    SUNOS_S_HIPRI)
861 			return EOPNOTSUPP;
862                 return sunos32_do_ioctl(SCARG(&bsd_ua, fd), FIOASYNC, &on, l);
863 	    }
864 	/*
865 	 * SunOS disk ioctls, taken from arch/sparc/sparc/disksubr.c
866 	 * (which was from the old sparc/scsi/sun_disklabel.c), and
867 	 * modified to suite.
868 	 */
869 	case DKIOCGGEOM:
870             {
871 		struct disklabel dl;
872 
873 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), DIOCGDINFO, &dl, l);
874 		if (error)
875 			return (error);
876 
877 #define datageom	((struct sun_dkgeom *)SCARG_P32(uap, data))
878 		/* XXX can't do memset() on a user address (dsl) */
879 		memset(SCARG_P32(uap, data), 0, sizeof(*datageom));
880 
881 		datageom->sdkc_ncylinders = dl.d_ncylinders;
882 		datageom->sdkc_acylinders = dl.d_acylinders;
883 		datageom->sdkc_ntracks = dl.d_ntracks;
884 		datageom->sdkc_nsectors = dl.d_nsectors;
885 		datageom->sdkc_interleave = dl.d_interleave;
886 		datageom->sdkc_sparespercyl = dl.d_sparespercyl;
887 		datageom->sdkc_rpm = dl.d_rpm;
888 		datageom->sdkc_pcylinders = dl.d_ncylinders + dl.d_acylinders;
889 #undef datageom
890 		break;
891 	    }
892 
893 	case DKIOCINFO:
894 		/* Homey don't do DKIOCINFO */
895 		/* XXX can't do memset() on a user address (dsl) */
896 		memset(SCARG_P32(uap, data), 0, sizeof(struct sun_dkctlr));
897 		break;
898 
899 	case DKIOCGPART:
900             {
901 		struct partinfo pi;
902 
903 		error = sunos32_do_ioctl(SCARG(&bsd_ua, fd), DIOCGPART, &pi, l);
904 		if (error)
905 			return (error);
906 
907 		if (pi.disklab->d_secpercyl == 0)
908 			return (ERANGE);	/* XXX */
909 		if (pi.part->p_offset % pi.disklab->d_secpercyl != 0)
910 			return (ERANGE);	/* XXX */
911 		/* XXX can't do direct writes to a user address (dsl) */
912 #define datapart	((struct sun_dkpart *)SCARG_P32(uap, data))
913 		datapart->sdkp_cyloffset = pi.part->p_offset / pi.disklab->d_secpercyl;
914 		datapart->sdkp_nsectors = pi.part->p_size;
915 #undef datapart
916 	    }
917 
918 	}
919 	return (netbsd32_ioctl(l, &bsd_ua, retval));
920 }
921 
922 /* SunOS fcntl(2) cmds not implemented */
923 #define SUN_F_RGETLK	10
924 #define SUN_F_RSETLK	11
925 #define SUN_F_CNVT	12
926 #define SUN_F_RSETLKW	13
927 
928 /* SunOS flock translation */
929 struct sunos_flock {
930 	short	l_type;
931 	short	l_whence;
932 	netbsd32_long	l_start;
933 	netbsd32_long	l_len;
934 	short	l_pid;
935 	short	l_xxx;
936 };
937 
938 static void bsd_to_sunos_flock(struct flock *, struct sunos_flock *);
939 static void sunos_to_bsd_flock(struct sunos_flock *, struct flock *);
940 
941 #define SUNOS_F_RDLCK	1
942 #define	SUNOS_F_WRLCK	2
943 #define SUNOS_F_UNLCK	3
944 
945 static void
946 bsd_to_sunos_flock(struct flock *iflp, struct sunos_flock *oflp)
947 {
948 	switch (iflp->l_type) {
949 	case F_RDLCK:
950 		oflp->l_type = SUNOS_F_RDLCK;
951 		break;
952 	case F_WRLCK:
953 		oflp->l_type = SUNOS_F_WRLCK;
954 		break;
955 	case F_UNLCK:
956 		oflp->l_type = SUNOS_F_UNLCK;
957 		break;
958 	default:
959 		oflp->l_type = -1;
960 		break;
961 	}
962 
963 	oflp->l_whence = (short) iflp->l_whence;
964 	oflp->l_start = (netbsd32_long) iflp->l_start;
965 	oflp->l_len = (netbsd32_long) iflp->l_len;
966 	oflp->l_pid = (short) iflp->l_pid;
967 	oflp->l_xxx = 0;
968 }
969 
970 
971 static void
972 sunos_to_bsd_flock(struct sunos_flock *iflp, struct flock *oflp)
973 {
974 	switch (iflp->l_type) {
975 	case SUNOS_F_RDLCK:
976 		oflp->l_type = F_RDLCK;
977 		break;
978 	case SUNOS_F_WRLCK:
979 		oflp->l_type = F_WRLCK;
980 		break;
981 	case SUNOS_F_UNLCK:
982 		oflp->l_type = F_UNLCK;
983 		break;
984 	default:
985 		oflp->l_type = -1;
986 		break;
987 	}
988 
989 	oflp->l_whence = iflp->l_whence;
990 	oflp->l_start = (off_t) iflp->l_start;
991 	oflp->l_len = (off_t) iflp->l_len;
992 	oflp->l_pid = (pid_t) iflp->l_pid;
993 
994 }
995 static struct {
996 	netbsd32_long	sun_flg;
997 	netbsd32_long	bsd_flg;
998 } sunfcntl_flgtab[] = {
999 	/* F_[GS]ETFLags that differ: */
1000 #define SUN_FSETBLK	0x0010
1001 #define SUN_SHLOCK	0x0080
1002 #define SUN_EXLOCK	0x0100
1003 #define SUN_FNBIO	0x1000
1004 #define SUN_FSYNC	0x2000
1005 #define SUN_NONBLOCK	0x4000
1006 #define SUN_FNOCTTY	0x8000
1007 	{ SUN_NONBLOCK, O_NONBLOCK },
1008 	{ SUN_FNBIO, O_NONBLOCK },
1009 	{ SUN_SHLOCK, O_SHLOCK },
1010 	{ SUN_EXLOCK, O_EXLOCK },
1011 	{ SUN_FSYNC, O_FSYNC },
1012 	{ SUN_FSETBLK, 0 },
1013 	{ SUN_FNOCTTY, 0 }
1014 };
1015 
1016 int
1017 sunos32_sys_fcntl(struct lwp *l, const struct sunos32_sys_fcntl_args *uap, register_t *retval)
1018 {
1019 	/* {
1020 		syscallarg(int) fd;
1021 		syscallarg(int) cmd;
1022 		syscallarg(netbsd32_voidp) arg;
1023 	} */
1024 	struct sys_fcntl_args bsd_ua;
1025 	uintptr_t flg;
1026 	int n, ret;
1027 
1028 	SCARG(&bsd_ua, fd) = SCARG(uap, fd);
1029 	SCARG(&bsd_ua, cmd) = SCARG(uap, cmd);
1030 	SCARG(&bsd_ua, arg) = SCARG_P32(uap, arg);
1031 
1032 	switch (SCARG(uap, cmd)) {
1033 	case F_SETFL:
1034 		flg = (intptr_t)SCARG_P32(uap, arg);
1035 		n = sizeof(sunfcntl_flgtab) / sizeof(sunfcntl_flgtab[0]);
1036 		while (--n >= 0) {
1037 			if (flg & sunfcntl_flgtab[n].sun_flg) {
1038 				flg &= ~sunfcntl_flgtab[n].sun_flg;
1039 				flg |= sunfcntl_flgtab[n].bsd_flg;
1040 			}
1041 		}
1042 		SCARG(&bsd_ua, arg) = (void *)flg;
1043 		break;
1044 
1045 	case F_GETLK:
1046 	case F_SETLK:
1047 	case F_SETLKW:
1048 		{
1049 			int error;
1050 			struct sunos_flock	ifl;
1051 			struct flock		fl;
1052 
1053 			error = copyin(SCARG_P32(uap, arg), &ifl, sizeof ifl);
1054 			if (error)
1055 				return error;
1056 			sunos_to_bsd_flock(&ifl, &fl);
1057 
1058 			error = do_fcntl_lock(SCARG(uap, fd), SCARG(uap, cmd), &fl);
1059 			if (error || SCARG(uap, cmd) != F_GETLK)
1060 				return error;
1061 
1062 			bsd_to_sunos_flock(&fl, &ifl);
1063 			return copyout(&ifl, SCARG_P32(uap, arg), sizeof ifl);
1064 		}
1065 		break;
1066 	case SUN_F_RGETLK:
1067 	case SUN_F_RSETLK:
1068 	case SUN_F_CNVT:
1069 	case SUN_F_RSETLKW:
1070 		return (EOPNOTSUPP);
1071 	}
1072 
1073 	ret = sys_fcntl(l, &bsd_ua, retval);
1074 	if (ret != 0)
1075 		return ret;
1076 
1077 	switch (SCARG(uap, cmd)) {
1078 	case F_GETFL:
1079 		n = sizeof(sunfcntl_flgtab) / sizeof(sunfcntl_flgtab[0]);
1080 		ret = *retval;
1081 		while (--n >= 0) {
1082 			if (ret & sunfcntl_flgtab[n].bsd_flg) {
1083 				ret &= ~sunfcntl_flgtab[n].bsd_flg;
1084 				ret |= sunfcntl_flgtab[n].sun_flg;
1085 			}
1086 		}
1087 		*retval = ret;
1088 		break;
1089 	}
1090 
1091 	return 0;
1092 }
1093