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