xref: /titanic_52/usr/src/lib/libbc/libc/sys/common/ioctl.c (revision 5d54f3d8999eac1762fe0a8c7177d20f1f201fae)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Do not include sys/conf.h- it isn't in the compatibility include dirs.
31  */
32 #ifdef	THIS_IS_AVAIL
33 #include <sys/conf.h>
34 #endif
35 #include <stdio.h>
36 #include <signal.h>
37 #include <sys/types.h>
38 #include <sys/ioccom.h>
39 #include <sys/stropts.h>
40 #include <sys/des.h>
41 #include <sys/fcntl.h>
42 #include <sys/filio.h>
43 #include <sys/termios.h>
44 #include <sys/termio.h>
45 #include <sys/ttold.h>
46 #include <sys/ttycom.h>
47 #include <sys/msio.h>
48 #include <sys/errno.h>
49 #include <nettli/tihdr.h>
50 #include <nettli/timod.h>
51 #include <nettli/tiuser.h>
52 #include <sun/dkio.h>
53 #include <scsi/impl/uscsi.h>
54 #include "cdioctl.h"
55 #include "s5dkio.h"
56 #include "s5fdio.h"
57 
58 /*
59  * parameter for windows ioctls
60  */
61 struct winclip {
62         int     wc_blockbytes;          /* size of wc_block */
63         int     wc_clipid;              /* Current clip id of clipping */
64         short   wc_screenrect[4];       /* Screen relatived (used when paint) */
65         char    *wc_block;              /* Block where RectList is copied. */
66 };
67 
68 /*
69  * Ioctl control packet
70  */
71 struct s5termios {
72 	tcflag_t	c_iflag;	/* input modes */
73 	tcflag_t	c_oflag;	/* output modes */
74 	tcflag_t	c_cflag;	/* control modes */
75 	tcflag_t	c_lflag;	/* line discipline modes */
76 	cc_t		c_cc[19];	/* control chars */
77 };
78 
79 #define N_ENOMSG	35
80 #define N_I_FIND	('S'<<8)|013
81 #define N_I_PUSH	('S'<<8)|02
82 #define WINGETEXPOSEDRL	_IOWR('g',31,struct winclip)
83 #define WINGETDAMAGEDRL _IOWR('g',32,struct winclip)
84 
85 struct n_sgttyb {
86 	char    sg_ispeed;              /* input speed */
87 	char    sg_ospeed;              /* output speed */
88 	char    sg_erase;               /* erase character */
89 	char    sg_kill;                /* kill character */
90 	int     sg_flags;               /* mode flags */
91 };
92 
93 static int handle_dkio_partitions(int, int, int);
94 static int tcget(int, int, int);
95 static int tcset(int, int, int);
96 static int _bc_ioctl(int, int, int);
97 
98 int
99 ioctl(int des, int request, int arg)
100 {
101 	int ret;
102 
103 	if ((ret = _bc_ioctl(des, request, arg)) == -1)
104 		maperror();
105 	return (ret);
106 }
107 
108 int
109 bc_ioctl(int des, int request, int arg)
110 {
111 	int ret;
112 
113 	if ((ret = _bc_ioctl(des, request, arg)) == -1)
114 		maperror();
115 	return (ret);
116 }
117 
118 static int
119 _bc_ioctl(int des, int request, int arg)
120 {
121 	int ret;
122 	int nreq = (request >> 8) & 0xFF;
123 	struct n_sgttyb nsg;
124 	struct s5_dk_cinfo newArgs;
125 	struct dk_info *infoArgs;
126 	struct dk_conf *confArgs;
127 	extern int errno;
128 
129 	/* not all mappings for 'm' have been performed */
130 	switch (nreq) {
131 		case ((int) 't'):
132 			if (_ioctl(des, N_I_FIND, "ttcompat") == 0)
133 				if (_ioctl(des, N_I_PUSH, "ttcompat") == -1)
134 					perror("ioctl/I_PUSH");
135 			switch(request) {
136 				case TIOCSETD:
137 					     /* added for sunview */
138 					     return(0);
139 				case TIOCREMOTE: request = ('t'<<8)|30;
140 					     break;
141 				case TIOCNOTTY:
142 					     bc_setsid();
143 					     return(0);
144 				case TIOCGPGRP: request = ('t'<<8)|20;
145 					     break;
146 				case TIOCSPGRP:
147 				    {
148 					pid_t pgid;
149 					sigset_t set, oset;
150 
151 					request = ('t'<<8)|21;
152 					ret = _ioctl(des, request, arg);
153 
154 					/*
155 					 * SunOS4.x allows this to succeed
156 					 * even if the process group does
157 					 * not exist yet.  We emulate the 4.x
158 					 * bug by creating the process group
159 					 * and reissuing the ioctl().
160 					 * See bugid 1175044.
161 					 */
162 					if (ret != 0 && errno == EPERM &&
163 					    (pgid = *((pid_t *)arg)) != 0 &&
164 					    pgid == getpid() &&
165 					    setpgid(0, pgid) == 0) {
166 						sigemptyset(&set);
167 						sigaddset(&set, SIGTSTP);
168 						sigaddset(&set, SIGTTIN);
169 						sigaddset(&set, SIGTTOU);
170 						sigprocmask(SIG_BLOCK,
171 							&set, &oset);
172 						ret = _ioctl(des,
173 							request, arg);
174 						sigprocmask(SIG_SETMASK,
175 							&oset, NULL);
176 					}
177 					return(ret);
178 				    }
179 				case TIOCSTI: request = ('t'<<8)|23;
180 					     break;
181 				case TIOCSIGNAL: request = ('t'<<8)|31;
182 					     break;
183 				case TIOCCONS: request = ('t'<<8)|36;
184 					     break;
185 				case TIOCSWINSZ: request = ('T'<<8)|103;
186 					     break;
187 				case TIOCGWINSZ: request = ('T'<<8)|104;
188 					     break;
189 				case TIOCSETP:
190 				case TIOCSETN:
191 			  	    {
192 					struct sgttyb *sg = (struct sgttyb *)arg;
193 					nsg.sg_ispeed = sg->sg_ispeed;
194 					nsg.sg_ospeed = sg->sg_ospeed;
195 					nsg.sg_erase = sg->sg_erase;
196 					nsg.sg_kill = sg->sg_kill;
197 					nsg.sg_flags = (int)sg->sg_flags;
198 					arg = (int)&nsg;
199 				        request = request & 0x0FFFF;
200 					break;
201 				    }
202 
203 				case TIOCGETP:
204 				    {
205 					struct sgttyb *sg = (struct sgttyb *)arg;
206 
207 					ret = _ioctl(des, request&0xFFFF, &nsg);
208 					if (ret != -1) {
209 						sg->sg_ispeed = nsg.sg_ispeed;
210 						sg->sg_ospeed = nsg.sg_ospeed;
211 						sg->sg_erase = nsg.sg_erase;
212 						sg->sg_kill = nsg.sg_kill;
213 						sg->sg_flags = (short)nsg.sg_flags & 0x0FFFF;
214 					}
215 					return(ret);
216 				    }
217 				case TIOCPKT:
218 				case TIOCUCNTL:
219 				case TIOCTCNTL:
220 				case TIOCSSOFTCAR:
221 				case TIOCGSOFTCAR:
222 				case TIOCISPACE:
223 				case TIOCISIZE:
224 				case TIOCSSIZE:
225 				case TIOCGSIZE:
226 				    	     break;
227 				default:     request = request & 0x0FFFF;
228 				 	     break;
229 			}
230 			break;
231 		case ((int) 'T'):
232 			switch(request) {
233 				case TCGETS:
234 					request = ('T'<<8)|13;
235 					return(tcget(des, request, arg));
236 					break;
237 				case TCSETS:
238 					request = ('T'<<8)|14;
239 					return(tcset(des, request, arg));
240 					break;
241 				case TCSETSW:
242 					request = ('T'<<8)|15;
243 					return(tcset(des, request, arg));
244 					break;
245 				case TCSETSF:
246 					request = ('T'<<8)|16;
247 					return(tcset(des, request, arg));
248 					break;
249 				case TCGETA:
250 				case TCSETA:
251 				case TCSETAW:
252 				case TCSETAF:
253 				default:
254 					request = request & 0x0FFFF;
255 					break;
256 			}
257 			break;
258 		case ((int) 'S'):
259 			switch (request) {
260  				case I_PLINK: request = ('S'<<8)|026;
261 					      break;
262  				case I_PUNLINK: request = ('S'<<8)|027;
263 					      break;
264  				case I_STR: {
265 					struct strioctl *iarg =
266 					    (struct strioctl *)arg;
267 					int cmd = iarg->ic_cmd;
268 
269 					switch (cmd) {
270 					case TI_GETINFO: {
271 						/*
272 						 * The T_info_ack structure
273 						 * has one additional word
274 						 * added to it in 5.x.
275 						 * To prevent the module from
276 						 * overwritting user memory we
277 						 * use an internal buffer for
278 						 * the transfer and copy out
279 						 * the results to the caller.
280 						 */
281 						struct {
282 							struct T_info_ack info;
283 							long		pad[16];
284 						} args;
285 						char *dp = iarg->ic_dp;
286 
287 						memcpy(&args.info, iarg->ic_dp,
288 						    sizeof(struct T_info_ack));
289 						iarg->ic_dp =
290 						    (char *) &args.info;
291 						iarg->ic_cmd = (TIMOD | 140);
292 						ret = _ioctl(des,
293 						    request & 0xffff, arg);
294 						iarg->ic_cmd = cmd;
295 						iarg->ic_dp = dp;
296 						iarg->ic_len =
297 						    sizeof(struct T_info_ack);
298 						memcpy(iarg->ic_dp, &args.info,
299 						    iarg->ic_len);
300 						return (ret);
301 						break;
302 					}
303 					case TI_OPTMGMT:
304 						iarg->ic_cmd = (TIMOD | 141);
305 						break;
306 					case TI_BIND:
307 						iarg->ic_cmd = (TIMOD | 142);
308 						break;
309 					case TI_UNBIND:
310 						iarg->ic_cmd = (TIMOD | 143);
311 						break;
312 					}
313 					ret = _ioctl(des,
314 					    request & 0xffff, arg);
315 					iarg->ic_cmd = cmd;
316 					return ret;
317 				}
318 				default:      request = request & 0x0FFFF;
319 				  	      break;
320 			}
321 			break;
322 		case ((int) 'm'):
323 			switch (request) {
324 				case MSIOGETPARMS: request = ('m'<<8)|1;
325 					      break;
326 				case MSIOSETPARMS: request = ('m'<<8)|2;
327 					      break;
328 				default:      request = request & 0x0FFFF;
329 				  	      break;
330 			}
331 			break;
332 		case ((int) 'd'):
333 			switch (request) {
334 				case DKIOCGGEOM:
335 					request = S5DKIOCGGEOM;
336 					break;
337 				case DKIOCSGEOM:
338 					request = S5DKIOCSGEOM;
339 					break;
340 				case DKIOCSAPART:
341 					request = S5DKIOCSAPART;
342 					break;
343 				case DKIOCGAPART:
344 					request = S5DKIOCGAPART;
345 					break;
346 				case DKIOCSTYPE:
347 					request = S5HDKIOCSTYPE;
348 					break;
349 				case DKIOCGTYPE:
350 					request = S5HDKIOCGTYPE;
351 					break;
352 				case DKIOCSBAD:
353 					request = S5HDKIOCSBAD;
354 					break;
355 				case DKIOCGBAD:
356 					request = S5HDKIOCGBAD;
357 					break;
358 				case DKIOCSCMD:
359 					request = S5HDKIOCSCMD;
360 					break;
361 				case DKIOCGDIAG:
362 					request = S5HDKIOCGDIAG;
363 					break;
364 				case FDKIOGCHAR:
365 					request = S5FDIOGCHAR;
366 					break;
367 				case FDKIOSCHAR:
368 					request = S5FDIOSCHAR;
369 					break;
370 				case FDKEJECT:
371 					request = S5FDEJECT;
372 					break;
373 				case FDKGETCHANGE:
374 					request = S5FDGETCHANGE;
375 					break;
376 				case FDKGETDRIVECHAR:
377 					request = S5FDGETDRIVECHAR;
378 					break;
379 				case FDKSETDRIVECHAR:
380 					request = S5FDSETDRIVECHAR;
381 					break;
382 				case FDKGETSEARCH:
383 					request = S5FDGETSEARCH;
384 					break;
385 				case FDKSETSEARCH:
386 					request = S5FDSETSEARCH;
387 					break;
388 				case FDKIOCSCMD:
389 					request = S5FDIOCMD;
390 					break;
391 				case F_RAW:
392 					request = S5FDRAW;
393 					break;
394 				case DKIOCINFO:
395 					ret = _ioctl(des, S5DKIOCINFO, &newArgs);
396 					if (ret != -1) {
397 						infoArgs = (struct dk_info *)arg;
398 						infoArgs->dki_ctlr =
399 							newArgs.dki_addr;
400 						infoArgs->dki_unit =
401 							newArgs.dki_unit;
402 						infoArgs->dki_ctype =
403 							newArgs.dki_ctype;
404 						infoArgs->dki_flags =
405 							newArgs.dki_flags;
406 					}
407 					return ret;
408 					break;
409 				case DKIOCGCONF:
410 					ret = _ioctl(des, S5DKIOCINFO, &newArgs);
411 					if (ret != -1) {
412 						confArgs = (struct dk_conf *)arg;
413 						strncpy(confArgs->dkc_cname,
414 							newArgs.dki_cname,
415 							DK_DEVLEN);
416 						strncpy(confArgs->dkc_dname,
417 							newArgs.dki_dname,
418 							DK_DEVLEN);
419 						confArgs->dkc_ctype =
420 							(u_short)newArgs.dki_ctype;
421 						confArgs->dkc_flags =
422 							(u_short)newArgs.dki_flags;
423 						confArgs->dkc_cnum =
424 							newArgs.dki_cnum;
425 						confArgs->dkc_addr =
426 							newArgs.dki_addr;
427 						confArgs->dkc_space =
428 							(u_int)newArgs.dki_space;
429 						confArgs->dkc_prio =
430 							newArgs.dki_prio;
431 						confArgs->dkc_vec =
432 							newArgs.dki_vec;
433 						confArgs->dkc_unit =
434 							newArgs.dki_unit;
435 						confArgs->dkc_slave =
436 							newArgs.dki_slave;
437 					}
438 					return ret;
439 					break;
440 				case DKIOCWCHK:
441 					/*
442 					 * This is unsupported in SVR4. It
443 					 * turns on verify-after-write for
444 					 * the floppy. I don't think the
445 					 * system call should fail, however.
446 					 */
447 					return 0;
448 					break;
449 				case DKIOCGPART:
450 				case DKIOCSPART:
451 					return (handle_dkio_partitions(des,
452 					       request, arg));
453 				case DKIOCGLOG:
454 					/* unsupported */
455 					errno = EINVAL;
456 					return -1;
457 					break;
458 				case DESIOCBLOCK:
459 				case DESIOCQUICK:
460 					break; /* no change for these two */
461 				default:
462 					request = request & 0x0FFFF; /* try */
463 					break;
464 			}
465 			break;
466 		case ((int) 'c'):
467 			switch (request) {
468 				case CDROMPAUSE:
469 					request = S5CDROMPAUSE;
470 					break;
471 				case CDROMRESUME:
472 					request = S5CDROMRESUME;
473 					break;
474 				case CDROMPLAYMSF:
475 					request = S5CDROMPLAYMSF;
476 					break;
477 				case CDROMPLAYTRKIND:
478 					request = S5CDROMPLAYTRKIND;
479 					break;
480 				case CDROMREADTOCHDR:
481 					request = S5CDROMREADTOCHDR;
482 					break;
483 				case CDROMREADTOCENTRY:
484 					request = S5CDROMREADTOCENTRY;
485 					break;
486 				case CDROMSTOP:
487 					request = S5CDROMSTOP;
488 					break;
489 				case CDROMSTART:
490 					request = S5CDROMSTART;
491 					break;
492 				case CDROMEJECT:
493 					request = S5CDROMEJECT;
494 					break;
495 				case CDROMVOLCTRL:
496 					request = S5CDROMVOLCTRL;
497 					break;
498 				case CDROMSUBCHNL:
499 					request = S5CDROMSUBCHNL;
500 					break;
501 				case CDROMREADMODE1:
502 					request = S5CDROMREADMODE1;
503 					break;
504 				case CDROMREADMODE2:
505 					request = S5CDROMREADMODE2;
506 					break;
507 			}
508 			break;
509 		case ((int) 'u'):
510 			switch (request) {
511 				case USCSICMD:
512 				    {
513 					struct s5_uscsi_cmd s5_cmd;
514 					struct uscsi_cmd *cmd =
515 						(struct uscsi_cmd *) arg;
516 					request = S5USCSICMD;
517 					s5_cmd.uscsi_cdb = cmd->uscsi_cdb;
518 					s5_cmd.uscsi_cdblen =
519 						cmd->uscsi_cdblen;
520 					s5_cmd.uscsi_bufaddr =
521 						cmd->uscsi_bufaddr;
522 					s5_cmd.uscsi_buflen =
523 						cmd->uscsi_buflen;
524 					s5_cmd.uscsi_flags =
525 						cmd->uscsi_flags;
526 					ret = _ioctl(des, request, &s5_cmd);
527 					cmd->uscsi_status = s5_cmd.uscsi_status;
528 					return(ret);
529 				    }
530 			}
531 			break;
532 		case ((int) 'k'):
533 		case ((int) 'v'):
534 		case ((int) 'F'):
535 		case ((int) 'G'):
536 		case ((int) 'X'):
537 		case ((int) 'L'):
538 			request = request & 0x0FFFF;
539 			break;
540 		case ((int) 'f'):
541 			if ((request == FIOCLEX) || (request == FIONCLEX))
542 				return(fcntl(des, F_SETFD,
543 				    ((request == FIOCLEX) ? 1 : 0)));
544 			break;
545 		case ((int) 'g'):
546 			/* Treat the following 2 ioctls specially for
547 			 * sunview. */
548 			if (request == WINGETEXPOSEDRL ||
549 				request == WINGETDAMAGEDRL) {
550 				ret = _ioctl(des, request, arg);
551 				if (errno == N_ENOMSG)
552 					errno = EFBIG;
553 				return(ret);
554 			}
555 			break;
556 	}
557 	return (_ioctl(des, request, arg));
558 }
559 
560 
561 static int
562 handle_dkio_partitions(int des, int request, int arg)
563 {
564 	struct s5_dk_cinfo	cinfo;
565 	struct dk_allmap	map;
566 	struct dk_map		*part;
567 	int			ret;
568 	extern int		errno;
569 
570 	part = (struct dk_map *) arg;
571 
572 	ret = _ioctl(des, S5DKIOCINFO, &cinfo);
573 
574 	if ((cinfo.dki_partition < 0) || (cinfo.dki_partition >= NDKMAP)) {
575 		errno = EINVAL;
576 		return (-1);
577 	}
578 
579 	if (ret != -1) {
580 		ret = _ioctl(des, S5DKIOCGAPART, &map);
581 		if (ret != -1) {
582 			if (request == DKIOCGPART) {
583 				part->dkl_cylno =
584 				    map.dka_map[cinfo.dki_partition].dkl_cylno;
585 				part->dkl_nblk =
586 				    map.dka_map[cinfo.dki_partition].dkl_nblk;
587 			} else {
588 				map.dka_map[cinfo.dki_partition].dkl_cylno =
589 					part->dkl_cylno;
590 				map.dka_map[cinfo.dki_partition].dkl_nblk =
591 					part->dkl_nblk;
592 				ret = _ioctl(des, S5DKIOCSAPART, &map);
593 			}
594 		}
595 	}
596 	return (ret);
597 }
598 
599 static int
600 tcset(des, request, arg)
601 	register int	des;
602 	register int	request;
603 	int		arg;
604 {
605 	struct s5termios	s5termios;
606 	struct termios		*termios;
607 
608 	termios = (struct termios *)arg;
609 
610 	if (termios != NULL) {
611 		s5termios.c_iflag = termios->c_iflag;
612 		s5termios.c_oflag = termios->c_oflag;
613 		s5termios.c_cflag = termios->c_cflag;
614 		s5termios.c_lflag = termios->c_lflag;
615 		memcpy(s5termios.c_cc, termios->c_cc, NCCS);
616 		return (_ioctl(des, request, &s5termios));
617 	} else
618 		return (_ioctl(des, request, NULL));
619 
620 }
621 
622 static int
623 tcget(des, request, arg)
624 	register int	des;
625 	register int	request;
626 	int		arg;
627 {
628 	struct s5termios	s5termios;
629 	struct termios		*termios;
630 	int			ret;
631 
632 	termios = (struct termios *)arg;
633 
634 	ret = _ioctl(des, request, &s5termios);
635 
636 	if (termios != NULL) {
637 		termios->c_iflag = s5termios.c_iflag;
638 		termios->c_oflag = s5termios.c_oflag;
639 		termios->c_cflag = s5termios.c_cflag;
640 		termios->c_lflag = s5termios.c_lflag;
641 		memcpy(termios->c_cc, s5termios.c_cc, NCCS);
642 	}
643 
644 	return (ret);
645 }
646