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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 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 #include <assert.h>
30 #include <fcntl.h>
31 #include <sys/types.h>
32 #include <signal.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <stropts.h>
40 #include <strings.h>
41 #include <thread.h>
42 #include <errno.h>
43 #include <libintl.h>
44 #include <sys/bitmap.h>
45 #include <sys/lx_autofs.h>
46 #include <sys/modctl.h>
47 #include <sys/filio.h>
48 #include <sys/termios.h>
49 #include <sys/termio.h>
50 #include <sys/sockio.h>
51 #include <net/if.h>
52 #include <net/if_arp.h>
53 #include <sys/ptms.h>
54 #include <sys/ldlinux.h>
55 #include <sys/lx_ptm.h>
56 #include <sys/lx_socket.h>
57 #include <sys/syscall.h>
58 #include <sys/brand.h>
59 #include <sys/lx_audio.h>
60 #include <sys/lx_ioctl.h>
61 #include <sys/lx_misc.h>
62 #include <sys/lx_debug.h>
63 #include <sys/ptyvar.h>
64 #include <sys/audio.h>
65 #include <sys/mixer.h>
66
67 /* Define _KERNEL to get the devt manipulation macros. */
68 #define _KERNEL
69 #include <sys/sysmacros.h>
70 #undef _KERNEL
71
72 /* Maximum number of modules on a stream that we can handle. */
73 #define MAX_STRMODS 10
74
75 /* Maximum buffer size for debugging messages. */
76 #define MSGBUF 1024
77
78 /* Structure used to define an ioctl translator. */
79 typedef struct ioc_cmd_translator {
80 int ict_lx_cmd;
81 char *ict_lx_cmd_str;
82 int ict_cmd;
83 char *ict_cmd_str;
84 int (*ict_func)(int fd, struct stat *stat,
85 int cmd, char *cmd_str, intptr_t arg);
86 } ioc_cmd_translator_t;
87
88 /*
89 * Structures used to associate a group of ioctl translators with
90 * a specific device.
91 */
92 typedef struct ioc_dev_translator {
93 char *idt_driver;
94 major_t idt_major;
95
96 /* Array of command translators. */
97 ioc_cmd_translator_t *idt_cmds;
98 } ioc_dev_translator_t;
99
100 /*
101 * Structures used to associate a group of ioctl translators with
102 * a specific filesystem.
103 */
104 typedef struct ioc_fs_translator {
105 char *ift_filesystem;
106
107 /* Array of command translators. */
108 ioc_cmd_translator_t *ift_cmds;
109 } ioc_fs_translator_t;
110
111 /* Structure used to define a unsupported ioctl error codes. */
112 typedef struct ioc_errno_translator {
113 int iet_lx_cmd;
114 char *iet_lx_cmd_str;
115 int iet_errno;
116 } ioc_errno_translator_t;
117
118 /* Structure used to convert oss format flags into Solaris options. */
119 typedef struct oss_fmt_translator {
120 int oft_oss_fmt;
121 int oft_encoding;
122 int oft_precision;
123 } oss_fmt_translator_t;
124
125 /* Translator forward declerations. */
126 static oss_fmt_translator_t oft_table[];
127 static ioc_cmd_translator_t ioc_translators_file[];
128 static ioc_cmd_translator_t ioc_translators_fifo[];
129 static ioc_cmd_translator_t ioc_translators_sock[];
130 static ioc_dev_translator_t ioc_translator_ptm;
131 static ioc_dev_translator_t *ioc_translators_dev[];
132 static ioc_fs_translator_t *ioc_translators_fs[];
133 static ioc_errno_translator_t ioc_translators_errno[];
134
135 /*
136 * Interface name table.
137 */
138 typedef struct ifname_map {
139 char im_linux[IFNAMSIZ];
140 char im_solaris[IFNAMSIZ];
141 struct ifname_map *im_next;
142 } ifname_map_t;
143
144 static ifname_map_t *ifname_map;
145 static mutex_t ifname_mtx;
146
147 /*
148 * Macros and structures to help convert integers to string
149 * values that they represent (for displaying in debug output).
150 */
151 #define I2S_ENTRY(x) { x, #x },
152 #define I2S_END { 0, NULL }
153
154 typedef struct int2str {
155 int i2s_int;
156 char *i2s_str;
157 } int2str_t;
158
159 static int2str_t st_mode_strings[] = {
160 I2S_ENTRY(S_IFIFO)
161 I2S_ENTRY(S_IFCHR)
162 I2S_ENTRY(S_IFDIR)
163 I2S_ENTRY(S_IFBLK)
164 I2S_ENTRY(S_IFREG)
165 I2S_ENTRY(S_IFLNK)
166 I2S_ENTRY(S_IFSOCK)
167 I2S_ENTRY(S_IFDOOR)
168 I2S_ENTRY(S_IFPORT)
169 I2S_END
170 };
171
172 static int2str_t oss_fmt_str[] = {
173 I2S_ENTRY(LX_OSS_AFMT_QUERY)
174 I2S_ENTRY(LX_OSS_AFMT_MU_LAW)
175 I2S_ENTRY(LX_OSS_AFMT_A_LAW)
176 I2S_ENTRY(LX_OSS_AFMT_IMA_ADPCM)
177 I2S_ENTRY(LX_OSS_AFMT_U8)
178 I2S_ENTRY(LX_OSS_AFMT_S16_LE)
179 I2S_ENTRY(LX_OSS_AFMT_S16_BE)
180 I2S_ENTRY(LX_OSS_AFMT_S8)
181 I2S_ENTRY(LX_OSS_AFMT_U16_LE)
182 I2S_ENTRY(LX_OSS_AFMT_U16_BE)
183 I2S_ENTRY(LX_OSS_AFMT_MPEG)
184 I2S_END
185 };
186
187 static void
188 lx_ioctl_msg(int fd, int cmd, char *lx_cmd_str, struct stat *stat, char *msg)
189 {
190 int errno_backup = errno;
191 char *path, path_buf[MAXPATHLEN];
192
193 assert(msg != NULL);
194
195 if (lx_debug_enabled == 0)
196 return;
197
198 path = lx_fd_to_path(fd, path_buf, sizeof (path_buf));
199 if (path == NULL)
200 path = "?";
201
202 if (lx_cmd_str == NULL)
203 lx_cmd_str = "?";
204
205 /* Display the initial error message and extended ioctl information. */
206 lx_debug("\t%s", msg);
207 lx_debug("\tlx_ioctl(): cmd = 0x%x - %s, fd = %d - %s",
208 cmd, lx_cmd_str, fd, path);
209
210 /* Display information about the target file, if it's available. */
211 if (stat != NULL) {
212 major_t fd_major = getmajor(stat->st_rdev);
213 minor_t fd_minor = getminor(stat->st_rdev);
214 int fd_mode = stat->st_mode & S_IFMT;
215 char *fd_mode_str = "unknown";
216 char buf[LX_MSG_MAXLEN];
217 int i;
218
219 /* Translate the file type bits into a string. */
220 for (i = 0; st_mode_strings[i].i2s_str != NULL; i++) {
221 if (fd_mode != st_mode_strings[i].i2s_int)
222 continue;
223 fd_mode_str = st_mode_strings[i].i2s_str;
224 break;
225 }
226
227 (void) snprintf(buf, sizeof (buf),
228 "\tlx_ioctl(): mode = %s", fd_mode_str);
229
230 if ((fd_mode == S_IFCHR) || (fd_mode == S_IFBLK)) {
231 char *fd_driver[MODMAXNAMELEN + 1];
232 int i;
233
234 /* This is a device so display the devt. */
235 i = strlen(buf);
236 (void) snprintf(buf + i, sizeof (buf) - i,
237 "; rdev = [%d, %d]", fd_major, fd_minor);
238
239 /* Try to display the drivers name. */
240 if (modctl(MODGETNAME,
241 fd_driver, sizeof (fd_driver), &fd_major) == 0)
242 i = strlen(buf);
243 (void) snprintf(buf + i, sizeof (buf) - i,
244 "; driver = %s", fd_driver);
245 }
246 lx_debug(buf);
247 }
248
249 /* Restore errno. */
250 errno = errno_backup;
251 }
252
253 static int
254 ldlinux_check(int fd)
255 {
256 struct str_mlist mlist[MAX_STRMODS];
257 struct str_list strlist;
258 int i;
259
260 /* Get the number of modules on the stream. */
261 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
262 fd, I_LIST, "I_LIST");
263 if ((i = ioctl(fd, I_LIST, (struct str_list *)NULL)) < 0) {
264 lx_debug("\tldlinux_check(): unable to count stream modules");
265 return (-errno);
266 }
267
268 /* Sanity check the number of modules on the stream. */
269 assert(i <= MAX_STRMODS);
270
271 /* Get the list of modules on the stream. */
272 strlist.sl_nmods = i;
273 strlist.sl_modlist = mlist;
274 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
275 fd, I_LIST, "I_LIST");
276 if (ioctl(fd, I_LIST, &strlist) < 0) {
277 lx_debug("\tldlinux_check(): unable to list stream modules");
278 return (-errno);
279 }
280
281 for (i = 0; i < strlist.sl_nmods; i++)
282 if (strcmp(strlist.sl_modlist[i].l_name, LDLINUX_MOD) == 0)
283 return (1);
284
285 return (0);
286 }
287
288 static int
289 ioctl_istr(int fd, int cmd, char *cmd_str, void *arg, int arg_len)
290 {
291 struct strioctl istr;
292
293 istr.ic_cmd = cmd;
294 istr.ic_len = arg_len;
295 istr.ic_timout = 0;
296 istr.ic_dp = arg;
297
298 lx_debug("\tioctl_istr(%d, 0x%x - %s, ...)", fd, cmd, cmd_str);
299 if (ioctl(fd, I_STR, &istr) < 0)
300 return (-1);
301 return (0);
302 }
303
304 /*
305 * Add an interface name mapping if it doesn't already exist.
306 *
307 * Interfaces with IFF_LOOPBACK flag get renamed to loXXX.
308 * Interfaces with IFF_BROADCAST flag get renamed to ethXXX.
309 *
310 * Caller locks the name table.
311 */
312 static int
313 ifname_add(char *if_name, int if_flags)
314 {
315 static int eth_index = 0;
316 static int lo_index = 0;
317 ifname_map_t **im_pp;
318
319 for (im_pp = &ifname_map; *im_pp; im_pp = &(*im_pp)->im_next)
320 if (strncmp((*im_pp)->im_solaris, if_name, IFNAMSIZ) == 0)
321 return (0);
322
323 *im_pp = calloc(1, sizeof (ifname_map_t));
324 if (*im_pp == NULL)
325 return (-1);
326
327 (void) strlcpy((*im_pp)->im_solaris, if_name, IFNAMSIZ);
328 if (if_flags & IFF_LOOPBACK) {
329 /* Loopback */
330 if (lo_index == 0)
331 (void) strlcpy((*im_pp)->im_linux, "lo", IFNAMSIZ);
332 else
333 (void) snprintf((*im_pp)->im_linux, IFNAMSIZ,
334 "lo:%d", lo_index);
335 lo_index++;
336 } else if (if_flags & IFF_BROADCAST) {
337 /* Assume ether if it has a broadcast address */
338 (void) snprintf((*im_pp)->im_linux, IFNAMSIZ,
339 "eth%d", eth_index);
340 eth_index++;
341 } else {
342 /* Do not translate unknown interfaces */
343 (void) strlcpy((*im_pp)->im_linux, if_name, IFNAMSIZ);
344 }
345
346 lx_debug("map interface %s -> %s", if_name, (*im_pp)->im_linux);
347
348 return (0);
349 }
350
351 static int
352 ifname_cmp(const void *p1, const void *p2)
353 {
354 struct ifreq *rp1 = (struct ifreq *)p1;
355 struct ifreq *rp2 = (struct ifreq *)p2;
356
357 return (strncmp(rp1->ifr_name, rp2->ifr_name, IFNAMSIZ));
358 }
359
360 /*
361 * (Re-)scan all interfaces and add them to the name table.
362 * Caller locks the name table.
363 */
364 static int
365 ifname_scan(void)
366 {
367 struct ifconf conf;
368 int i, fd, ifcount;
369
370 conf.ifc_buf = NULL;
371
372 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
373 goto fail;
374 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, SIOCGIFNUM, "SIOCGIFNUM");
375 if (ioctl(fd, SIOCGIFNUM, &ifcount) < 0) {
376 lx_debug("\tifname_scan(): unable to get number of interfaces");
377 goto fail;
378 }
379
380 conf.ifc_len = ifcount * sizeof (struct ifreq);
381 if ((conf.ifc_buf = calloc(ifcount, sizeof (struct ifreq))) == NULL)
382 goto fail;
383 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, SIOCGIFCONF, "SIOCGIFCONF");
384 if (ioctl(fd, SIOCGIFCONF, &conf) < 0) {
385 lx_debug("\tifname_scan(): unable to get interfaces");
386 goto fail;
387 }
388
389 /* Get the interface flags */
390 for (i = 0; i < ifcount; i++) {
391 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
392 fd, SIOCGIFFLAGS, "SIOCGIFFLAGS");
393 if (ioctl(fd, SIOCGIFFLAGS, &conf.ifc_req[i]) < 0) {
394 conf.ifc_req[i].ifr_flags = 0;
395 lx_debug("\tifname_scan(): unable to get flags for %s",
396 conf.ifc_req[i].ifr_name);
397 }
398 }
399
400 /*
401 * Sort the interfaces by name to preserve the order
402 * across reboots of this zone. Note that the order of
403 * interface names won't be consistent across network
404 * configuration changes. ie. If network interfaces
405 * are added or removed from a zone (either dynamically
406 * or statically) the network interfaces names to physical
407 * network interface mappings that linux apps see may
408 * change.
409 */
410 qsort(conf.ifc_req, ifcount, sizeof (struct ifreq), ifname_cmp);
411
412 /* Add to the name table */
413 for (i = 0; i < ifcount; i++)
414 if (ifname_add(conf.ifc_req[i].ifr_name,
415 conf.ifc_req[i].ifr_flags) != 0)
416 goto fail;
417
418 (void) close(fd);
419 free(conf.ifc_buf);
420
421 return (0);
422
423 fail:
424 if (fd >= 0)
425 (void) close(fd);
426 if (conf.ifc_buf != NULL)
427 free(conf.ifc_buf);
428
429 return (-1);
430 }
431
432 static int
433 ifname_from_linux(char *name)
434 {
435 int pass;
436 ifname_map_t *im_p;
437
438 (void) mutex_lock(&ifname_mtx);
439
440 for (pass = 0; pass < 2; pass++) {
441 for (im_p = ifname_map; im_p; im_p = im_p->im_next)
442 if (strncmp(im_p->im_linux, name, IFNAMSIZ) == 0)
443 break;
444 if (im_p != NULL || (pass == 0 && ifname_scan() != 0))
445 break;
446 }
447
448 (void) mutex_unlock(&ifname_mtx);
449
450 if (im_p) {
451 (void) strlcpy(name, im_p->im_solaris, IFNAMSIZ);
452 return (0);
453 }
454
455 return (-1);
456 }
457
458 static int
459 ifname_from_solaris(char *name)
460 {
461 int pass;
462 ifname_map_t *im_p;
463
464 (void) mutex_lock(&ifname_mtx);
465
466 for (pass = 0; pass < 2; pass++) {
467 for (im_p = ifname_map; im_p; im_p = im_p->im_next)
468 if (strncmp(im_p->im_solaris, name, IFNAMSIZ) == 0)
469 break;
470 if (im_p != NULL || (pass == 0 && ifname_scan() != 0))
471 break;
472 }
473
474 (void) mutex_unlock(&ifname_mtx);
475
476 if (im_p) {
477 (void) strlcpy(name, im_p->im_linux, IFNAMSIZ);
478 return (0);
479 }
480
481 return (-1);
482 }
483
484 /*
485 * Called to initialize the ioctl translation subsystem.
486 */
487 int
488 lx_ioctl_init()
489 {
490 int i, ret;
491
492 /* Figure out the major numbers for our devices translators. */
493 for (i = 0; ioc_translators_dev[i] != NULL; i++) {
494 ioc_dev_translator_t *idt = ioc_translators_dev[i];
495
496 ret = modctl(MODGETMAJBIND,
497 idt->idt_driver, strlen(idt->idt_driver) + 1,
498 &idt->idt_major);
499
500 if (ret != 0) {
501 lx_err(gettext("%s%s) failed: %s\n"),
502 "lx_ioctl_init(): modctl(MODGETMAJBIND, ",
503 idt->idt_driver, strerror(errno));
504 lx_err(gettext("%s: %s translator disabled for: %s\n"),
505 "lx_ioctl_init()", "ioctl", idt->idt_driver);
506 idt->idt_major = (major_t)-1;
507 }
508 }
509
510 /* Create the interface name table */
511 if (ifname_scan() != 0)
512 lx_err("lx_ioctl_init(): ifname_scan() failed\n");
513
514 return (0);
515 }
516
517 static ioc_cmd_translator_t *
518 lx_ioctl_find_ict_cmd(ioc_cmd_translator_t *ict, int cmd)
519 {
520 assert(ict != NULL);
521 while ((ict != NULL) && (ict->ict_func != NULL)) {
522 if (cmd == ict->ict_lx_cmd)
523 return (ict);
524 ict++;
525 }
526 return (NULL);
527 }
528
529 /*
530 * Main entry point for the ioctl translater.
531 */
532 int
533 lx_ioctl(uintptr_t p1, uintptr_t p2, uintptr_t p3)
534 {
535 int fd = (int)p1;
536 int cmd = (int)p2;
537 intptr_t arg = (uintptr_t)p3;
538 struct stat stat;
539 ioc_cmd_translator_t *ict = NULL;
540 ioc_errno_translator_t *iet = NULL;
541 major_t fd_major;
542 int i, ret;
543
544 if (fstat(fd, &stat) != 0) {
545 lx_ioctl_msg(fd, cmd, NULL, NULL,
546 "lx_ioctl(): fstat() failed");
547
548 /*
549 * Linux ioctl(2) is only documented to return EBADF, EFAULT,
550 * EINVAL or ENOTTY.
551 *
552 * EINVAL is documented to be "Request or argp is not valid",
553 * so it's reasonable to force any errno that's not EBADF,
554 * EFAULT or ENOTTY to be EINVAL.
555 */
556 if ((errno != EBADF) && (errno != EFAULT) && (errno != ENOTTY))
557 errno = EINVAL;
558
559 return (-errno); /* errno already set. */
560 }
561
562 switch (stat.st_mode & S_IFMT) {
563 default:
564 break;
565 case S_IFREG:
566 /* Use file translators. */
567 ict = ioc_translators_file;
568 break;
569
570 case S_IFSOCK:
571 /* Use socket translators. */
572 ict = ioc_translators_sock;
573 break;
574
575 case S_IFIFO:
576 /* Use fifo translators. */
577 ict = ioc_translators_fifo;
578 break;
579
580 case S_IFCHR:
581 fd_major = getmajor(stat.st_rdev);
582
583 /*
584 * Look through all the device translators to see if there
585 * is one for this device.
586 */
587 for (i = 0; ioc_translators_dev[i] != NULL; i++) {
588 if (fd_major != ioc_translators_dev[i]->idt_major)
589 continue;
590
591 /* We found a translator for this device. */
592 ict = ioc_translators_dev[i]->idt_cmds;
593 break;
594 }
595 break;
596 }
597
598 /*
599 * Search the selected translator group to see if we have a
600 * translator for this specific command.
601 */
602 if ((ict != NULL) &&
603 ((ict = lx_ioctl_find_ict_cmd(ict, cmd)) != NULL)) {
604 /* We found a translator for this command, invoke it. */
605 lx_ioctl_msg(fd, cmd, ict->ict_lx_cmd_str, &stat,
606 "lx_ioctl(): emulating ioctl");
607
608 ret = ict->ict_func(fd, &stat, ict->ict_cmd, ict->ict_cmd_str,
609 arg);
610
611 if ((ret < 0) && (ret != -EBADF) && (ret != -EFAULT) &&
612 (ret != -ENOTTY))
613 ret = -EINVAL;
614
615 return (ret);
616 }
617
618 /*
619 * If we didn't find a file or device translator for this
620 * command then try to find a filesystem translator for
621 * this command.
622 */
623 for (i = 0; ioc_translators_fs[i] != NULL; i++) {
624 if (strcmp(stat.st_fstype,
625 ioc_translators_fs[i]->ift_filesystem) != 0)
626 continue;
627
628 /* We found a translator for this filesystem. */
629 ict = ioc_translators_fs[i]->ift_cmds;
630 break;
631 }
632
633 /*
634 * Search the selected translator group to see if we have a
635 * translator for this specific command.
636 */
637 if ((ict != NULL) &&
638 ((ict = lx_ioctl_find_ict_cmd(ict, cmd)) != NULL)) {
639 /* We found a translator for this command, invoke it. */
640 lx_ioctl_msg(fd, cmd, ict->ict_lx_cmd_str, &stat,
641 "lx_ioctl(): emulating ioctl");
642 ret = ict->ict_func(fd, &stat, ict->ict_cmd, ict->ict_cmd_str,
643 arg);
644
645 if ((ret < 0) && (ret != -EBADF) && (ret != -EFAULT) &&
646 (ret != -ENOTTY))
647 ret = -EINVAL;
648
649 return (ret);
650 }
651
652 /*
653 * No translator for this ioctl was found.
654 * Check if there is an errno translator.
655 */
656 for (iet = ioc_translators_errno; iet->iet_lx_cmd_str != NULL; iet++) {
657 if (cmd != iet->iet_lx_cmd)
658 continue;
659
660 /* We found a an errno translator for this ioctl. */
661 lx_ioctl_msg(fd, cmd, iet->iet_lx_cmd_str, &stat,
662 "lx_ioctl(): emulating errno");
663
664 ret = -iet->iet_errno;
665
666 if ((ret < 0) && (ret != -EBADF) && (ret != -EFAULT) &&
667 (ret != -ENOTTY))
668 ret = -EINVAL;
669
670 return (ret);
671 }
672
673 lx_ioctl_msg(fd, cmd, NULL, &stat,
674 "lx_ioctl(): unsupported linux ioctl");
675 lx_unsupported(gettext("lx_ioctl(): unsupported linux ioctl (%d)"),
676 cmd);
677 return (-EINVAL);
678 }
679
680
681 /*
682 * Ioctl translator functions.
683 */
684 /*
685 * Used by translators that want to explicitly return EINVAL for an
686 * ioctl(2) instead of having the translation framework do it implicitly.
687 * This allows us to indicate which unsupported ioctl(2)s should not
688 * trigger a SIGSYS when running in LX_STRICT mode.
689 */
690 /* ARGSUSED */
691 static int
692 ict_einval(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
693 {
694 return (-EINVAL);
695 }
696
697 static int
698 /*ARGSUSED*/
699 ict_pass(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
700 {
701 int ret;
702
703 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
704 fd, cmd, cmd_str);
705 ret = ioctl(fd, cmd, arg);
706 return (ret < 0 ? -errno : ret);
707 }
708
709 static int
710 /*ARGSUSED*/
711 ict_tcsbrkp(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
712 {
713 int ret, dur = 0;
714
715 assert(cmd == LX_TCSBRKP);
716 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
717 fd, TCSBRK, "TCSBRK");
718 ret = ioctl(fd, TCSBRK, (intptr_t)&dur);
719 return (ret < 0 ? -errno : ret);
720 }
721
722 static int
723 /*ARGSUSED*/
724 ict_sioifoob(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
725 {
726 int req, *reqp = (int *)arg;
727 int len, val;
728
729 assert(cmd == SIOCATMARK);
730
731 if (uucopy(reqp, &req, sizeof (req)) != 0)
732 return (-errno);
733
734 len = sizeof (val);
735
736 /*
737 * Linux expects a SIOCATMARK of a UDP socket to return EINVAL, while
738 * Solaris allows it.
739 */
740 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &val, &len) < 0) {
741 lx_debug("ict_siofmark: getsockopt failed, errno %d", errno);
742 return (-EINVAL);
743 }
744
745 if ((len != sizeof (val)) || (val != SOCK_STREAM))
746 return (-EINVAL);
747
748 if (ioctl(fd, cmd, &req) < 0)
749 return (-errno);
750
751 if (uucopy(&req, reqp, sizeof (req)) != 0)
752 return (-errno);
753
754 return (0);
755 }
756
757 static int
758 /*ARGSUSED*/
759 ict_sioifreq(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
760 {
761 struct ifreq req, *reqp = (struct ifreq *)arg;
762
763 assert(cmd == SIOCGIFFLAGS || cmd == SIOCSIFFLAGS ||
764 cmd == SIOCGIFADDR || cmd == SIOCSIFADDR ||
765 cmd == SIOCGIFDSTADDR || cmd == SIOCSIFDSTADDR ||
766 cmd == SIOCGIFBRDADDR || cmd == SIOCSIFBRDADDR ||
767 cmd == SIOCGIFNETMASK || cmd == SIOCSIFNETMASK ||
768 cmd == SIOCGIFMETRIC || cmd == SIOCSIFMETRIC ||
769 cmd == SIOCGIFMTU || cmd == SIOCSIFMTU);
770
771 /* Copy in the data */
772 if (uucopy(reqp, &req, sizeof (struct ifreq)) != 0)
773 return (-errno);
774
775 if (ifname_from_linux(req.ifr_name) < 0)
776 return (-EINVAL);
777
778 lx_debug("\tioctl(%d, 0x%x - %s, %.14s",
779 fd, cmd, cmd_str, req.ifr_name);
780
781 if (ioctl(fd, cmd, &req) < 0)
782 return (-errno);
783
784 if (ifname_from_solaris(req.ifr_name) < 0)
785 return (-EINVAL);
786
787 /* Copy out the data */
788 if (uucopy(&req, reqp, sizeof (struct ifreq)) != 0)
789 return (-errno);
790
791 return (0);
792 }
793
794 static int
795 /*ARGSUSED*/
796 ict_siocgifconf(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
797 {
798 struct ifconf conf, *confp = (struct ifconf *)arg;
799 int i, ifcount, ret;
800
801 assert(cmd == LX_SIOCGIFCONF);
802
803 /* Copy in the data. */
804 if (uucopy(confp, &conf, sizeof (conf)) != 0)
805 return (-errno);
806
807 if (conf.ifc_len == 0) {
808 /* They want to know how many interfaces there are. */
809 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
810 fd, SIOCGIFNUM, "SIOCGIFNUM");
811 if (ioctl(fd, SIOCGIFNUM, (intptr_t)&ifcount) < 0)
812 return (-errno);
813 conf.ifc_len = ifcount * sizeof (struct ifreq);
814
815 /* Check if we're done. */
816 if (conf.ifc_buf == NULL) {
817 /* Copy out the data. */
818 if (uucopy(&conf, confp, sizeof (conf)) != 0)
819 return (-errno);
820 return (0);
821 }
822 }
823
824 /* Get interface configuration list. */
825 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, SIOCGIFCONF, "SIOCGIFCONF");
826 ret = ioctl(fd, SIOCGIFCONF, &conf);
827 if (ret < 0)
828 return (-errno);
829
830 /* Rename interfaces to linux */
831 for (i = 0; i < conf.ifc_len / sizeof (struct ifreq); i++)
832 if (ifname_from_solaris(conf.ifc_req[i].ifr_name) < 0)
833 return (-EINVAL);
834
835 /* Copy out the data */
836 if (uucopy(&conf, confp, sizeof (conf)) != 0)
837 return (-errno);
838
839 return (0);
840 }
841
842 static int
843 /*ARGSUSED*/
844 ict_siocifhwaddr(int fd, struct stat *stat, int cmd, char *cmd_str,
845 intptr_t arg)
846 {
847 struct ifreq req, *reqp = (struct ifreq *)arg;
848 struct arpreq arpreq;
849
850 assert(cmd == LX_SIOCGIFHWADDR || cmd == LX_SIOCSIFHWADDR);
851
852 /* Copy in the data */
853 if (uucopy(reqp, &req, sizeof (struct ifreq)) != 0)
854 return (-errno);
855
856 lx_debug("\tioctl(%d, 0x%x - %s, lx %.14s)",
857 fd, cmd,
858 (cmd == LX_SIOCGIFHWADDR) ? "SIOCGIFHWADDR" : "SIOCSIFHWADDR",
859 req.ifr_name);
860
861 /*
862 * We're not going to support SIOCSIFHWADDR, but we need to be
863 * able to check the result of the uucopy first to see if the command
864 * should have returned EFAULT.
865 */
866 if (cmd == LX_SIOCSIFHWADDR) {
867 lx_unsupported(gettext(
868 "lx_ioctl(): unsupported linux ioctl: %s"),
869 "SIOCSIFHWADDR");
870 return (-EINVAL);
871 }
872
873 if (strcmp(req.ifr_name, "lo") == 0 ||
874 strncmp(req.ifr_name, "lo:", 3) == 0) {
875 /* Abuse ifr_addr for linux ifr_hwaddr */
876 bzero(&req.ifr_addr, sizeof (struct sockaddr));
877 req.ifr_addr.sa_family = LX_ARPHRD_LOOPBACK;
878
879 /* Copy out the data */
880 if (uucopy(&req, reqp, sizeof (struct ifreq)) != 0)
881 return (-errno);
882
883 return (0);
884 }
885
886 if (ifname_from_linux(req.ifr_name) < 0)
887 return (-EINVAL);
888
889 lx_debug("\tioctl(%d, 0x%x - %s, %.14s)",
890 fd, SIOCGIFADDR, "SIOCGIFADDR", req.ifr_name);
891
892 if (ioctl(fd, SIOCGIFADDR, &req) < 0)
893 return (-errno);
894
895 bcopy(&req.ifr_addr, &arpreq.arp_pa, sizeof (struct sockaddr));
896
897 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, SIOCGARP, "SIOCGARP");
898
899 if (ioctl(fd, SIOCGARP, &arpreq) < 0)
900 return (-errno);
901
902 if (ifname_from_solaris(req.ifr_name) < 0)
903 return (-EINVAL);
904
905 /* Abuse ifr_addr for linux ifr_hwaddr */
906 bcopy(&arpreq.arp_ha, &req.ifr_addr, sizeof (struct sockaddr));
907 if (strncmp(req.ifr_name, "eth", 3) == 0)
908 req.ifr_addr.sa_family = LX_ARPHRD_ETHER;
909 else
910 req.ifr_addr.sa_family = LX_ARPHRD_VOID;
911
912 /* Copy out the data */
913 if (uucopy(&req, reqp, sizeof (struct ifreq)) != 0)
914 return (-errno);
915
916 return (0);
917 }
918
919 static void
920 l2s_termios(struct lx_termios *l_tios, struct termios *s_tios)
921 {
922 assert((l_tios != NULL) && (s_tios != NULL));
923
924 bzero(s_tios, sizeof (*s_tios));
925
926 s_tios->c_iflag = l_tios->c_iflag;
927 s_tios->c_oflag = l_tios->c_oflag;
928 s_tios->c_cflag = l_tios->c_cflag;
929
930 s_tios->c_lflag = l_tios->c_lflag;
931 if (s_tios->c_lflag & ICANON) {
932 s_tios->c_cc[VEOF] = l_tios->c_cc[LX_VEOF];
933 s_tios->c_cc[VEOL] = l_tios->c_cc[LX_VEOL];
934 } else {
935 s_tios->c_cc[VMIN] = l_tios->c_cc[LX_VMIN];
936 s_tios->c_cc[VTIME] = l_tios->c_cc[LX_VTIME];
937 }
938
939 s_tios->c_cc[VEOL2] = l_tios->c_cc[LX_VEOL2];
940 s_tios->c_cc[VERASE] = l_tios->c_cc[LX_VERASE];
941 s_tios->c_cc[VKILL] = l_tios->c_cc[LX_VKILL];
942 s_tios->c_cc[VREPRINT] = l_tios->c_cc[LX_VREPRINT];
943 s_tios->c_cc[VLNEXT] = l_tios->c_cc[LX_VLNEXT];
944 s_tios->c_cc[VWERASE] = l_tios->c_cc[LX_VWERASE];
945 s_tios->c_cc[VINTR] = l_tios->c_cc[LX_VINTR];
946 s_tios->c_cc[VQUIT] = l_tios->c_cc[LX_VQUIT];
947 s_tios->c_cc[VSWTCH] = l_tios->c_cc[LX_VSWTC];
948 s_tios->c_cc[VSTART] = l_tios->c_cc[LX_VSTART];
949 s_tios->c_cc[VSTOP] = l_tios->c_cc[LX_VSTOP];
950 s_tios->c_cc[VSUSP] = l_tios->c_cc[LX_VSUSP];
951 s_tios->c_cc[VDISCARD] = l_tios->c_cc[LX_VDISCARD];
952 }
953
954 static void
955 l2s_termio(struct lx_termio *l_tio, struct termio *s_tio)
956 {
957 assert((l_tio != NULL) && (s_tio != NULL));
958
959 bzero(s_tio, sizeof (*s_tio));
960
961 s_tio->c_iflag = l_tio->c_iflag;
962 s_tio->c_oflag = l_tio->c_oflag;
963 s_tio->c_cflag = l_tio->c_cflag;
964
965 s_tio->c_lflag = l_tio->c_lflag;
966 if (s_tio->c_lflag & ICANON) {
967 s_tio->c_cc[VEOF] = l_tio->c_cc[LX_VEOF];
968 } else {
969 s_tio->c_cc[VMIN] = l_tio->c_cc[LX_VMIN];
970 s_tio->c_cc[VTIME] = l_tio->c_cc[LX_VTIME];
971 }
972
973 s_tio->c_cc[VINTR] = l_tio->c_cc[LX_VINTR];
974 s_tio->c_cc[VQUIT] = l_tio->c_cc[LX_VQUIT];
975 s_tio->c_cc[VERASE] = l_tio->c_cc[LX_VERASE];
976 s_tio->c_cc[VKILL] = l_tio->c_cc[LX_VKILL];
977 s_tio->c_cc[VSWTCH] = l_tio->c_cc[LX_VSWTC];
978 }
979
980 static void
981 termios2lx_cc(struct lx_termios *l_tios, struct lx_cc *lio)
982 {
983 assert((l_tios != NULL) && (lio != NULL));
984
985 bzero(lio, sizeof (*lio));
986
987 lio->veof = l_tios->c_cc[LX_VEOF];
988 lio->veol = l_tios->c_cc[LX_VEOL];
989 lio->vmin = l_tios->c_cc[LX_VMIN];
990 lio->vtime = l_tios->c_cc[LX_VTIME];
991 }
992
993 static void
994 termio2lx_cc(struct lx_termio *l_tio, struct lx_cc *lio)
995 {
996 assert((l_tio != NULL) && (lio != NULL));
997
998 bzero(lio, sizeof (*lio));
999
1000 lio->veof = l_tio->c_cc[LX_VEOF];
1001 lio->veol = 0;
1002 lio->vmin = l_tio->c_cc[LX_VMIN];
1003 lio->vtime = l_tio->c_cc[LX_VTIME];
1004 }
1005
1006 static void
1007 s2l_termios(struct termios *s_tios, struct lx_termios *l_tios)
1008 {
1009 assert((s_tios != NULL) && (l_tios != NULL));
1010
1011 bzero(l_tios, sizeof (*l_tios));
1012
1013 l_tios->c_iflag = s_tios->c_iflag;
1014 l_tios->c_oflag = s_tios->c_oflag;
1015 l_tios->c_cflag = s_tios->c_cflag;
1016 l_tios->c_lflag = s_tios->c_lflag;
1017
1018 if (s_tios->c_lflag & ICANON) {
1019 l_tios->c_cc[LX_VEOF] = s_tios->c_cc[VEOF];
1020 l_tios->c_cc[LX_VEOL] = s_tios->c_cc[VEOL];
1021 } else {
1022 l_tios->c_cc[LX_VMIN] = s_tios->c_cc[VMIN];
1023 l_tios->c_cc[LX_VTIME] = s_tios->c_cc[VTIME];
1024 }
1025
1026 l_tios->c_cc[LX_VEOL2] = s_tios->c_cc[VEOL2];
1027 l_tios->c_cc[LX_VERASE] = s_tios->c_cc[VERASE];
1028 l_tios->c_cc[LX_VKILL] = s_tios->c_cc[VKILL];
1029 l_tios->c_cc[LX_VREPRINT] = s_tios->c_cc[VREPRINT];
1030 l_tios->c_cc[LX_VLNEXT] = s_tios->c_cc[VLNEXT];
1031 l_tios->c_cc[LX_VWERASE] = s_tios->c_cc[VWERASE];
1032 l_tios->c_cc[LX_VINTR] = s_tios->c_cc[VINTR];
1033 l_tios->c_cc[LX_VQUIT] = s_tios->c_cc[VQUIT];
1034 l_tios->c_cc[LX_VSWTC] = s_tios->c_cc[VSWTCH];
1035 l_tios->c_cc[LX_VSTART] = s_tios->c_cc[VSTART];
1036 l_tios->c_cc[LX_VSTOP] = s_tios->c_cc[VSTOP];
1037 l_tios->c_cc[LX_VSUSP] = s_tios->c_cc[VSUSP];
1038 l_tios->c_cc[LX_VDISCARD] = s_tios->c_cc[VDISCARD];
1039 }
1040
1041 static void
1042 s2l_termio(struct termio *s_tio, struct lx_termio *l_tio)
1043 {
1044 assert((s_tio != NULL) && (l_tio != NULL));
1045
1046 bzero(l_tio, sizeof (*l_tio));
1047
1048 l_tio->c_iflag = s_tio->c_iflag;
1049 l_tio->c_oflag = s_tio->c_oflag;
1050 l_tio->c_cflag = s_tio->c_cflag;
1051 l_tio->c_lflag = s_tio->c_lflag;
1052
1053 if (s_tio->c_lflag & ICANON) {
1054 l_tio->c_cc[LX_VEOF] = s_tio->c_cc[VEOF];
1055 } else {
1056 l_tio->c_cc[LX_VMIN] = s_tio->c_cc[VMIN];
1057 l_tio->c_cc[LX_VTIME] = s_tio->c_cc[VTIME];
1058 }
1059
1060 l_tio->c_cc[LX_VINTR] = s_tio->c_cc[VINTR];
1061 l_tio->c_cc[LX_VQUIT] = s_tio->c_cc[VQUIT];
1062 l_tio->c_cc[LX_VERASE] = s_tio->c_cc[VERASE];
1063 l_tio->c_cc[LX_VKILL] = s_tio->c_cc[VKILL];
1064 l_tio->c_cc[LX_VSWTC] = s_tio->c_cc[VSWTCH];
1065 }
1066
1067 static int
1068 /*ARGSUSED*/
1069 ict_tcsets(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1070 {
1071 struct lx_termios l_tios, *l_tiosp = (struct lx_termios *)arg;
1072 struct termios s_tios;
1073 struct lx_cc lio;
1074 int ldlinux, ret;
1075
1076 assert(cmd == TCSETS || cmd == TCSETSW || cmd == TCSETSF);
1077
1078 /* Copy in the data. */
1079 if (uucopy(l_tiosp, &l_tios, sizeof (l_tios)) != 0)
1080 return (-errno);
1081
1082 /*
1083 * The TIOCSETLD/TIOCGETLD ioctls are only supported by the
1084 * ldlinux strmod. So make sure the module exists on the
1085 * target stream before we invoke the ioctl.
1086 */
1087 if ((ldlinux = ldlinux_check(fd)) < 0)
1088 return (ldlinux);
1089
1090 if (ldlinux == 1) {
1091 termios2lx_cc(&l_tios, &lio);
1092 if (ioctl_istr(fd, TIOCSETLD, "TIOCSETLD",
1093 &lio, sizeof (lio)) < 0)
1094 return (-errno);
1095 }
1096
1097 l2s_termios(&l_tios, &s_tios);
1098 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1099 fd, cmd, cmd_str);
1100 ret = ioctl(fd, cmd, (intptr_t)&s_tios);
1101 return ((ret < 0) ? -errno : ret);
1102 }
1103
1104 static int
1105 /*ARGSUSED*/
1106 ict_tcseta(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1107 {
1108 struct lx_termio l_tio, *l_tiop = (struct lx_termio *)arg;
1109 struct termio s_tio;
1110 struct lx_cc lio;
1111 int ldlinux, ret;
1112
1113 assert(cmd == TCSETA || cmd == TCSETAW || cmd == TCSETAF);
1114
1115 /* Copy in the data. */
1116 if (uucopy(l_tiop, &l_tio, sizeof (l_tio)) != 0)
1117 return (-errno);
1118
1119 /*
1120 * The TIOCSETLD/TIOCGETLD ioctls are only supported by the
1121 * ldlinux strmod. So make sure the module exists on the
1122 * target stream before we invoke the ioctl.
1123 */
1124 if ((ldlinux = ldlinux_check(fd)) < 0)
1125 return (ldlinux);
1126
1127 if (ldlinux == 1) {
1128 termio2lx_cc(&l_tio, &lio);
1129 if (ioctl_istr(fd, TIOCSETLD, "TIOCSETLD",
1130 &lio, sizeof (lio)) < 0)
1131 return (-errno);
1132 }
1133
1134 l2s_termio(&l_tio, &s_tio);
1135 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1136 fd, cmd, cmd_str);
1137 ret = ioctl(fd, cmd, (intptr_t)&s_tio);
1138 return ((ret < 0) ? -errno : ret);
1139 }
1140
1141 /*
1142 * The Solaris TIOCGPGRP ioctl does not have exactly the same semantics as
1143 * the Linux one. To mimic Linux semantics we have to do some extra work
1144 * normally done by the Solaris version of tcgetpgrp().
1145 */
1146 static int
1147 /*ARGSUSED*/
1148 ict_tiocgpgrp(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1149 {
1150 pid_t ttysid, mysid;
1151 int ret;
1152
1153 assert(cmd == LX_TIOCGPGRP);
1154
1155 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1156 fd, TIOCGSID, "TIOCGSID");
1157 if (ioctl(fd, TIOCGSID, (intptr_t)&ttysid) < 0)
1158 return (-errno);
1159 if ((mysid = getsid(0)) < 0)
1160 return (-errno);
1161 if (mysid != ttysid)
1162 return (-ENOTTY);
1163
1164 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1165 fd, TIOCGPGRP, "TIOCGPGRP");
1166 ret = ioctl(fd, TIOCGPGRP, arg);
1167 return ((ret < 0) ? -errno : ret);
1168 }
1169
1170 static int
1171 /*ARGSUSED*/
1172 ict_sptlock(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1173 {
1174 assert(cmd == LX_TIOCSPTLCK);
1175
1176 /*
1177 * The success/fail return values are different between Linux
1178 * and Solaris. Linux expects 0 or -1. Solaris can return
1179 * positive number on success.
1180 */
1181 if (ioctl_istr(fd, UNLKPT, "UNLKPT", NULL, 0) < 0)
1182 return (-errno);
1183 return (0);
1184 }
1185
1186 static int
1187 /*ARGSUSED*/
1188 ict_gptn(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1189 {
1190 int ptyno, *ptynop = (int *)arg;
1191 pt_own_t pto;
1192
1193 assert(cmd == LX_TIOCGPTN);
1194 assert(getmajor(stat->st_rdev) == ioc_translator_ptm.idt_major);
1195
1196 /* This operation is only valid for the lx_ptm device. */
1197 ptyno = LX_PTM_DEV_TO_PTS(stat->st_rdev);
1198
1199 /*
1200 * We'd like to just use grantpt() directly, but we can't since
1201 * it assumes the fd node that's passed to it is a ptm node,
1202 * and in our case it's an lx_ptm node. It also relies on
1203 * naming services to get the current process group name.
1204 * Hence we have to invoke the OWNERPT ioctl directly here.
1205 */
1206 pto.pto_ruid = getuid();
1207 pto.pto_rgid = getgid();
1208 if (ioctl_istr(fd, OWNERPT, "OWNERPT", &pto, sizeof (pto)) != 0)
1209 return (-EACCES);
1210
1211 /* Copy out the data. */
1212 if (uucopy(&ptyno, ptynop, sizeof (ptyno)) != 0)
1213 return (-errno);
1214
1215 return (0);
1216 }
1217
1218 static int
1219 /*ARGSUSED*/
1220 ict_tiocgwinsz(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1221 {
1222 struct winsize winsize, *winsizep = (struct winsize *)arg;
1223
1224 assert(cmd == LX_TIOCGWINSZ);
1225
1226 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, TIOCGWINSZ, "TIOCGWINSZ");
1227 if (ioctl(fd, TIOCGWINSZ, arg) >= 0)
1228 return (0);
1229 if (errno != EINVAL)
1230 return (-errno);
1231
1232 bzero(&winsize, sizeof (winsize));
1233 if (uucopy(&winsize, winsizep, sizeof (winsize)) != 0)
1234 return (-errno);
1235
1236 return (0);
1237 }
1238
1239 static int
1240 /*ARGSUSED*/
1241 ict_tcgets_emulate(int fd, struct stat *stat,
1242 int cmd, char *cmd_str, intptr_t arg)
1243 {
1244 struct lx_termios l_tios, *l_tiosp = (struct lx_termios *)arg;
1245 struct termios s_tios;
1246
1247 assert(cmd == LX_TCGETS);
1248
1249 if (syscall(SYS_brand, B_TTYMODES, &s_tios) < 0)
1250 return (-errno);
1251
1252 /* Now munge the data to how Linux wants it. */
1253 s2l_termios(&s_tios, &l_tios);
1254 if (uucopy(&l_tios, l_tiosp, sizeof (l_tios)) != 0)
1255 return (-errno);
1256
1257 return (0);
1258 }
1259
1260 static int
1261 /*ARGSUSED*/
1262 ict_tcgets_native(int fd, struct stat *stat,
1263 int cmd, char *cmd_str, intptr_t arg)
1264 {
1265 struct lx_termios l_tios, *l_tiosp = (struct lx_termios *)arg;
1266 struct termios s_tios;
1267 struct lx_cc lio;
1268 int ldlinux;
1269
1270 assert(cmd == LX_TCGETS);
1271
1272 if ((ldlinux = ldlinux_check(fd)) < 0)
1273 return (ldlinux);
1274
1275 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1276 fd, TCGETS, "TCGETS");
1277 if (ioctl(fd, TCGETS, (intptr_t)&s_tios) < 0)
1278 return (-errno);
1279
1280 /* Now munge the data to how Linux wants it. */
1281 s2l_termios(&s_tios, &l_tios);
1282
1283 /*
1284 * The TIOCSETLD/TIOCGETLD ioctls are only supported by the
1285 * ldlinux strmod. So make sure the module exists on the
1286 * target stream before we invoke the ioctl.
1287 */
1288 if (ldlinux != 0) {
1289 if (ioctl_istr(fd, TIOCGETLD, "TIOCGETLD",
1290 &lio, sizeof (lio)) < 0)
1291 return (-errno);
1292
1293 l_tios.c_cc[LX_VEOF] = lio.veof;
1294 l_tios.c_cc[LX_VEOL] = lio.veol;
1295 l_tios.c_cc[LX_VMIN] = lio.vmin;
1296 l_tios.c_cc[LX_VTIME] = lio.vtime;
1297 }
1298
1299 /* Copy out the data. */
1300 if (uucopy(&l_tios, l_tiosp, sizeof (l_tios)) != 0)
1301 return (-errno);
1302
1303 return (0);
1304 }
1305
1306 static int
1307 /*ARGSUSED*/
1308 ict_tcgeta(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1309 {
1310 struct lx_termio l_tio, *l_tiop = (struct lx_termio *)arg;
1311 struct termio s_tio;
1312 struct lx_cc lio;
1313 int ldlinux;
1314
1315 assert(cmd == LX_TCGETA);
1316
1317 if ((ldlinux = ldlinux_check(fd)) < 0)
1318 return (ldlinux);
1319
1320 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1321 fd, TCGETA, "TCGETA");
1322 if (ioctl(fd, TCGETA, (intptr_t)&s_tio) < 0)
1323 return (-errno);
1324
1325 /* Now munge the data to how Linux wants it. */
1326 s2l_termio(&s_tio, &l_tio);
1327
1328 /*
1329 * The TIOCSETLD/TIOCGETLD ioctls are only supported by the
1330 * ldlinux strmod. So make sure the module exists on the
1331 * target stream before we invoke the ioctl.
1332 */
1333 if (ldlinux != 0) {
1334 if (ioctl_istr(fd, TIOCGETLD, "TIOCGETLD",
1335 &lio, sizeof (lio)) < 0)
1336 return (-errno);
1337
1338 l_tio.c_cc[LX_VEOF] = lio.veof;
1339 l_tio.c_cc[LX_VMIN] = lio.vmin;
1340 l_tio.c_cc[LX_VTIME] = lio.vtime;
1341 }
1342
1343 /* Copy out the data. */
1344 if (uucopy(&l_tio, l_tiop, sizeof (l_tio)) != 0)
1345 return (-errno);
1346
1347 return (0);
1348 }
1349
1350 static int
1351 /*ARGSUSED*/
1352 ict_tiocsctty(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1353 {
1354 pid_t mysid, ttysid;
1355
1356 if ((mysid = getsid(0)) < 0)
1357 return (-errno);
1358
1359 /* Check if this fd is already our ctty. */
1360 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1361 fd, TIOCGSID, "TIOCGSID");
1362 if (ioctl(fd, TIOCGSID, (intptr_t)&ttysid) >= 0)
1363 if (mysid == ttysid)
1364 return (0);
1365
1366 /*
1367 * Need to make sure we're a session leader, otherwise the
1368 * TIOCSCTTY ioctl will fail.
1369 */
1370 if (mysid != getpid())
1371 (void) setpgrp();
1372
1373 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1374 fd, TIOCSCTTY, "TIOCSCTTY");
1375 if (ioctl(fd, TIOCSCTTY, 0) < 0)
1376 return (-errno);
1377 return (0);
1378 }
1379
1380 /*
1381 * /dev/dsp ioctl translators and support
1382 */
1383 static int
1384 i_is_dsp_dev(int fd)
1385 {
1386 int minor;
1387
1388 /*
1389 * This is a cloning device so we have to ask the driver
1390 * what kind of minor node this is.
1391 */
1392 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1393 fd, LXA_IOC_GETMINORNUM, "LXA_IOC_GETMINORNUM");
1394 if (ioctl(fd, LXA_IOC_GETMINORNUM, &minor) < 0)
1395 return (-EINVAL);
1396 if (minor != LXA_MINORNUM_DSP)
1397 return (-EINVAL);
1398 return (0);
1399 }
1400
1401 static int
1402 /*ARGSUSED*/
1403 ict_oss_sndctl_dsp_reset(int fd, struct stat *stat,
1404 int cmd, char *cmd_str, intptr_t arg)
1405 {
1406 int err;
1407
1408 /* Ioctl is only supported on dsp audio devices. */
1409 if ((err = i_is_dsp_dev(fd)) != 0)
1410 return (err);
1411
1412 /* Nothing to really do on Solaris. */
1413 return (0);
1414 }
1415
1416 static void
1417 i_oss_fmt_str(char *buf, int buf_size, uint_t mask)
1418 {
1419 int i, first = 1;
1420
1421 assert(buf != NULL);
1422
1423 buf[0] = '\0';
1424 for (i = 0; oss_fmt_str[i].i2s_str != NULL; i++) {
1425 if ((oss_fmt_str[i].i2s_int != mask) &&
1426 ((oss_fmt_str[i].i2s_int & mask) == 0))
1427 continue;
1428 if (first)
1429 first = 0;
1430 else
1431 (void) strlcat(buf, " | ", buf_size);
1432 (void) strlcat(buf, oss_fmt_str[i].i2s_str, buf_size);
1433 }
1434 }
1435
1436 static int
1437 /*ARGSUSED*/
1438 ict_oss_sndctl_dsp_getfmts(int fd, struct stat *stat,
1439 int cmd, char *cmd_str, intptr_t arg)
1440 {
1441 audio_info_t sa_info;
1442 char buf[MSGBUF];
1443 uint_t *maskp = (uint_t *)arg;
1444 uint_t mask = 0;
1445 int i, amode, err;
1446
1447 assert(cmd == LX_OSS_SNDCTL_DSP_GETFMTS);
1448
1449 /* Ioctl is only supported on dsp audio devices. */
1450 if ((err = i_is_dsp_dev(fd)) != 0)
1451 return (err);
1452
1453 /* We need to know the access mode for the file. */
1454 if ((amode = fcntl(fd, F_GETFL)) < 0)
1455 return (-EINVAL);
1456 amode &= O_ACCMODE;
1457 assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1458
1459 /* Test to see what Linux oss formats the target device supports. */
1460 for (i = 0; oft_table[i].oft_oss_fmt != 0; i++) {
1461
1462 /* Initialize the mode request. */
1463 AUDIO_INITINFO(&sa_info);
1464
1465 /* Translate a Linux oss format into Solaris settings. */
1466 if ((amode == O_RDONLY) || (amode == O_RDWR)) {
1467 sa_info.record.encoding = oft_table[i].oft_encoding;
1468 sa_info.record.precision = oft_table[i].oft_precision;
1469 }
1470 if ((amode == O_WRONLY) || (amode == O_RDWR)) {
1471 sa_info.play.encoding = oft_table[i].oft_encoding;
1472 sa_info.play.precision = oft_table[i].oft_precision;
1473 }
1474
1475 /* Send the request. */
1476 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1477 fd, AUDIO_SETINFO, "AUDIO_SETINFO");
1478 if (ioctl(fd, AUDIO_SETINFO, &sa_info) < 0)
1479 continue;
1480
1481 /* This Linux oss format is supported. */
1482 mask |= oft_table[i].oft_oss_fmt;
1483 }
1484
1485 if (lx_debug_enabled != 0) {
1486 i_oss_fmt_str(buf, sizeof (buf), mask);
1487 lx_debug("\toss formats supported = 0x%x (%s)", mask, buf);
1488 }
1489 if (uucopy(&mask, maskp, sizeof (mask)) != 0)
1490 return (-errno);
1491 return (0);
1492 }
1493
1494 static int
1495 /*ARGSUSED*/
1496 ict_oss_sndctl_dsp_setfmts(int fd, struct stat *stat,
1497 int cmd, char *cmd_str, intptr_t arg)
1498 {
1499 audio_info_t sa_info;
1500 char buf[MSGBUF];
1501 uint_t *maskp = (uint_t *)arg;
1502 uint_t mask;
1503 int i, amode, err;
1504
1505 assert(cmd == LX_OSS_SNDCTL_DSP_SETFMTS);
1506
1507 /* Ioctl is only supported on dsp audio devices. */
1508 if ((err = i_is_dsp_dev(fd)) != 0)
1509 return (err);
1510
1511 if (uucopy(maskp, &mask, sizeof (mask)) != 0)
1512 return (-errno);
1513
1514 if (lx_debug_enabled != 0) {
1515 i_oss_fmt_str(buf, sizeof (buf), mask);
1516 lx_debug("\toss formats request = 0x%x (%s)", mask, buf);
1517 }
1518
1519 if ((mask == (uint_t)-1) || (mask == 0)) {
1520 lx_debug("\tXXX: possible oss formats query?");
1521 return (-EINVAL);
1522 }
1523
1524 /* Check if multiple format bits were specified. */
1525 if (!BIT_ONLYONESET(mask))
1526 return (-EINVAL);
1527
1528 /* Decode the oss format request into a native format. */
1529 for (i = 0; oft_table[i].oft_oss_fmt != 0; i++) {
1530 if (oft_table[i].oft_oss_fmt == mask)
1531 break;
1532 }
1533 if (oft_table[i].oft_oss_fmt == 0)
1534 return (-EINVAL);
1535
1536 /* We need to know the access mode for the file. */
1537 if ((amode = fcntl(fd, F_GETFL)) < 0)
1538 return (-EINVAL);
1539 amode &= O_ACCMODE;
1540 assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1541
1542 /* Initialize the mode request. */
1543 AUDIO_INITINFO(&sa_info);
1544
1545 /* Translate the Linux oss request into a Solaris request. */
1546 if ((amode == O_RDONLY) || (amode == O_RDWR)) {
1547 sa_info.record.encoding = oft_table[i].oft_encoding;
1548 sa_info.record.precision = oft_table[i].oft_precision;
1549 }
1550 if ((amode == O_WRONLY) || (amode == O_RDWR)) {
1551 sa_info.play.encoding = oft_table[i].oft_encoding;
1552 sa_info.play.precision = oft_table[i].oft_precision;
1553 }
1554
1555 /* Send the request. */
1556 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1557 fd, AUDIO_SETINFO, "AUDIO_SETINFO");
1558 return ((ioctl(fd, AUDIO_SETINFO, &sa_info) < 0) ? -errno : 0);
1559 }
1560
1561 static int
1562 /*ARGSUSED*/
1563 ict_oss_sndctl_dsp_channels(int fd, struct stat *stat,
1564 int cmd, char *cmd_str, intptr_t arg)
1565 {
1566 audio_info_t sa_info;
1567 uint_t *channelsp = (uint_t *)arg;
1568 uint_t channels;
1569 int amode, err;
1570
1571 assert((cmd == LX_OSS_SNDCTL_DSP_CHANNELS) ||
1572 (cmd == LX_OSS_SNDCTL_DSP_STEREO));
1573
1574 /* Ioctl is only supported on dsp audio devices. */
1575 if ((err = i_is_dsp_dev(fd)) != 0)
1576 return (err);
1577
1578 if (uucopy(channelsp, &channels, sizeof (channels)) != 0)
1579 return (-errno);
1580
1581 lx_debug("\toss %s request = 0x%x (%u)",
1582 (cmd == LX_OSS_SNDCTL_DSP_CHANNELS) ? "channel" : "stereo",
1583 channels, channels);
1584
1585 if (channels == (uint_t)-1) {
1586 lx_debug("\tXXX: possible channel/stereo query?");
1587 return (-EINVAL);
1588 }
1589
1590 if (cmd == LX_OSS_SNDCTL_DSP_STEREO) {
1591 /*
1592 * There doesn't seem to be any documentation for
1593 * SNDCTL_DSP_STEREO. Looking at source that uses or
1594 * used this ioctl seems to indicate that the
1595 * functionality provided by this ioctl has been
1596 * subsumed by the SNDCTL_DSP_CHANNELS ioctl. It
1597 * seems that the only arguments ever passed to
1598 * the SNDCTL_DSP_STEREO. Ioctl are boolean values
1599 * of '0' or '1'. Hence we'll start out strict and
1600 * only support those values.
1601 *
1602 * Some online forum discussions about this ioctl
1603 * seemed to indicate that in case of success it
1604 * returns the "stereo" setting (ie, either
1605 * '0' for mono or '1' for stereo).
1606 */
1607 if ((channels != 0) && (channels != 1)) {
1608 lx_debug("\tinvalid stereo request");
1609 return (-EINVAL);
1610 }
1611 channels += 1;
1612 } else {
1613 /* Limit the system to one or two channels. */
1614 if ((channels != 1) && (channels != 2)) {
1615 lx_debug("\tinvalid channel request");
1616 return (-EINVAL);
1617 }
1618 }
1619
1620 /* We need to know the access mode for the file. */
1621 if ((amode = fcntl(fd, F_GETFL)) < 0)
1622 return (-EINVAL);
1623 amode &= O_ACCMODE;
1624 assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1625
1626 /* Initialize the channel request. */
1627 AUDIO_INITINFO(&sa_info);
1628
1629 /* Translate the Linux oss request into a Solaris request. */
1630 if ((amode == O_RDONLY) || (amode == O_RDWR))
1631 sa_info.record.channels = channels;
1632 if ((amode == O_WRONLY) || (amode == O_RDWR))
1633 sa_info.play.channels = channels;
1634
1635 /* Send the request. */
1636 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1637 fd, AUDIO_SETINFO, "AUDIO_SETINFO");
1638 if (ioctl(fd, AUDIO_SETINFO, &sa_info) < 0)
1639 return (-errno);
1640
1641 if (cmd == LX_OSS_SNDCTL_DSP_STEREO)
1642 return (channels - 1);
1643 return (0);
1644 }
1645
1646 static int
1647 /*ARGSUSED*/
1648 ict_oss_sndctl_dsp_speed(int fd, struct stat *stat,
1649 int cmd, char *cmd_str, intptr_t arg)
1650 {
1651 audio_info_t sa_info;
1652 uint_t *speedp = (uint_t *)arg;
1653 uint_t speed;
1654 int amode, err;
1655
1656 assert(cmd == LX_OSS_SNDCTL_DSP_SPEED);
1657
1658 /* Ioctl is only supported on dsp audio devices. */
1659 if ((err = i_is_dsp_dev(fd)) != 0)
1660 return (err);
1661
1662 if (uucopy(speedp, &speed, sizeof (speed)) != 0)
1663 return (-errno);
1664
1665 lx_debug("\toss speed request = 0x%x (%u)", speed, speed);
1666
1667 if (speed == (uint_t)-1) {
1668 lx_debug("\tXXX: possible oss speed query?");
1669 return (-EINVAL);
1670 }
1671
1672 /* We need to know the access mode for the file. */
1673 if ((amode = fcntl(fd, F_GETFL)) < 0)
1674 return (-EINVAL);
1675 amode &= O_ACCMODE;
1676 assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1677
1678 /* Initialize the speed request. */
1679 AUDIO_INITINFO(&sa_info);
1680
1681 /* Translate the Linux oss request into a Solaris request. */
1682 if ((amode == O_RDONLY) || (amode == O_RDWR))
1683 sa_info.record.sample_rate = speed;
1684 if ((amode == O_WRONLY) || (amode == O_RDWR))
1685 sa_info.play.sample_rate = speed;
1686
1687 /* Send the request. */
1688 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1689 fd, AUDIO_SETINFO, "AUDIO_SETINFO");
1690 return ((ioctl(fd, AUDIO_SETINFO, &sa_info) < 0) ? -errno : 0);
1691 }
1692
1693 static int
1694 /*ARGSUSED*/
1695 ict_oss_sndctl_dsp_getblksize(int fd, struct stat *stat,
1696 int cmd, char *cmd_str, intptr_t arg)
1697 {
1698 lxa_frag_info_t fi;
1699 uint_t *blksizep = (uint_t *)arg;
1700 uint_t blksize;
1701 int err;
1702
1703 assert(cmd == LX_OSS_SNDCTL_DSP_GETBLKSIZE);
1704
1705 /* Ioctl is only supported on dsp audio devices. */
1706 if ((err = i_is_dsp_dev(fd)) != 0)
1707 return (err);
1708
1709 /* Query the current fragment count and size. */
1710 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1711 fd, LXA_IOC_GET_FRAG_INFO, "LXA_IOC_GET_FRAG_INFO");
1712 if (ioctl(fd, LXA_IOC_GET_FRAG_INFO, &fi) < 0)
1713 return (-errno);
1714
1715 blksize = fi.lxa_fi_size;
1716
1717 if (uucopy(&blksize, blksizep, sizeof (blksize)) != 0)
1718 return (-errno);
1719 return (0);
1720 }
1721
1722 static int
1723 /*ARGSUSED*/
1724 ict_oss_sndctl_dsp_getspace(int fd, struct stat *stat,
1725 int cmd, char *cmd_str, intptr_t arg)
1726 {
1727 lx_oss_audio_buf_info_t *spacep = (lx_oss_audio_buf_info_t *)arg;
1728 lx_oss_audio_buf_info_t space;
1729 lxa_frag_info_t fi;
1730 int err;
1731
1732 assert((cmd == LX_OSS_SNDCTL_DSP_GETOSPACE) ||
1733 (cmd == LX_OSS_SNDCTL_DSP_GETISPACE));
1734
1735 /* Ioctl is only supported on dsp audio devices. */
1736 if ((err = i_is_dsp_dev(fd)) != 0)
1737 return (err);
1738
1739 /* Query the current fragment count and size. */
1740 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1741 fd, LXA_IOC_GET_FRAG_INFO, "LXA_IOC_GET_FRAG_INFO");
1742 if (ioctl(fd, LXA_IOC_GET_FRAG_INFO, &fi) < 0)
1743 return (-errno);
1744
1745 /* Return the current fragment count and size. */
1746 space.fragstotal = fi.lxa_fi_cnt;
1747 space.fragsize = fi.lxa_fi_size;
1748
1749 /*
1750 * We'll lie and tell applications that they can always write
1751 * out at least one fragment without blocking.
1752 */
1753 space.fragments = 1;
1754 space.bytes = space.fragsize;
1755
1756 if (cmd == LX_OSS_SNDCTL_DSP_GETOSPACE)
1757 lx_debug("\toss get output space result = ");
1758 if (cmd == LX_OSS_SNDCTL_DSP_GETISPACE)
1759 lx_debug("\toss get input space result = ");
1760
1761 lx_debug("\t\tbytes = 0x%x (%u), fragments = 0x%x (%u)",
1762 space.bytes, space.bytes, space.fragments, space.fragments);
1763 lx_debug("\t\tfragtotal = 0x%x (%u), fragsize = 0x%x (%u)",
1764 space.fragstotal, space.fragstotal,
1765 space.fragsize, space.fragsize);
1766
1767 if (uucopy(&space, spacep, sizeof (space)) != 0)
1768 return (-errno);
1769 return (0);
1770 }
1771
1772 static int
1773 /*ARGSUSED*/
1774 ict_oss_sndctl_dsp_setfragment(int fd, struct stat *stat,
1775 int cmd, char *cmd_str, intptr_t arg)
1776 {
1777 lxa_frag_info_t fi;
1778 uint_t *fraginfop = (uint_t *)arg;
1779 uint_t fraginfo, frag_size, frag_cnt;
1780 int err;
1781
1782 assert(cmd == LX_OSS_SNDCTL_DSP_SETFRAGMENT);
1783
1784 /* Ioctl is only supported on dsp audio devices. */
1785 if ((err = i_is_dsp_dev(fd)) != 0)
1786 return (err);
1787
1788 if (uucopy(fraginfop, &fraginfo, sizeof (fraginfo)) != 0)
1789 return (-errno);
1790
1791 /*
1792 * The argument to this ioctl is a 32-bit integer of the
1793 * format 0x MMMM SSSS where:
1794 * SSSS - requests a fragment size of 2^SSSS
1795 * MMMM - requests a maximum fragment count of 2^MMMM
1796 * if MMMM is 0x7fff then the application is requesting
1797 * no limits on the number of fragments.
1798 */
1799
1800 frag_size = fraginfo & 0xffff;
1801 frag_cnt = fraginfo >> 16;
1802
1803 lx_debug("\toss fragment request: "
1804 "power size = 0x%x (%u), power cnt = 0x%x (%u)",
1805 frag_size, frag_size, frag_cnt, frag_cnt);
1806
1807 /* Limit the supported fragment size from 2^4 to 2^31. */
1808 if ((frag_size < 4) || (frag_size > 31))
1809 return (-EINVAL);
1810
1811 /* Limit the number of fragments from 2^1 to 2^32. */
1812 if (((frag_cnt < 1) || (frag_cnt > 32)) && (frag_cnt != 0x7fff))
1813 return (-EINVAL);
1814
1815 /* Expand the fragment values. */
1816 frag_size = 1 << frag_size;
1817 if ((frag_cnt == 32) || (frag_cnt == 0x7fff)) {
1818 frag_cnt = UINT_MAX;
1819 } else {
1820 frag_cnt = 1 << frag_cnt;
1821 }
1822
1823 lx_debug("\toss fragment request: "
1824 "translated size = 0x%x (%u), translated cnt = 0x%x (%u)",
1825 frag_size, frag_size, frag_cnt, frag_cnt);
1826
1827 fi.lxa_fi_size = frag_size;
1828 fi.lxa_fi_cnt = frag_cnt;
1829
1830 /* Set the current fragment count and size. */
1831 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1832 fd, LXA_IOC_SET_FRAG_INFO, "LXA_IOC_SET_FRAG_INFO");
1833 return ((ioctl(fd, LXA_IOC_SET_FRAG_INFO, &fi) < 0) ? -errno : 0);
1834 }
1835
1836 static int
1837 /*ARGSUSED*/
1838 ict_oss_sndctl_dsp_getcaps(int fd, struct stat *stat,
1839 int cmd, char *cmd_str, intptr_t arg)
1840 {
1841 uint_t *capsp = (uint_t *)arg;
1842 uint_t caps;
1843 int err;
1844
1845 assert(cmd == LX_OSS_SNDCTL_DSP_GETCAPS);
1846
1847 /* Ioctl is only supported on dsp audio devices. */
1848 if ((err = i_is_dsp_dev(fd)) != 0)
1849 return (err);
1850
1851 /*
1852 * Report that we support mmap access
1853 * this is where things start to get fun.
1854 */
1855 caps = LX_OSS_DSP_CAP_MMAP | LX_OSS_DSP_CAP_TRIGGER;
1856
1857 if (uucopy(&caps, capsp, sizeof (caps)) != 0)
1858 return (-errno);
1859 return (0);
1860 }
1861
1862 static int
1863 /*ARGSUSED*/
1864 ict_oss_sndctl_dsp_settrigger(int fd, struct stat *stat,
1865 int cmd, char *cmd_str, intptr_t arg)
1866 {
1867 uint_t *triggerp = (uint_t *)arg;
1868 uint_t trigger;
1869 int err;
1870
1871 assert(cmd == LX_OSS_SNDCTL_DSP_SETTRIGGER);
1872
1873 /* Ioctl is only supported on dsp audio devices. */
1874 if ((err = i_is_dsp_dev(fd)) != 0)
1875 return (err);
1876
1877 if (uucopy(triggerp, &trigger, sizeof (trigger)) != 0)
1878 return (-errno);
1879
1880 lx_debug("\toss set trigger request = 0x%x (%u)",
1881 trigger, trigger);
1882
1883 /* We only support two types of trigger requests. */
1884 if ((trigger != LX_OSS_PCM_DISABLE_OUTPUT) &&
1885 (trigger != LX_OSS_PCM_ENABLE_OUTPUT))
1886 return (-EINVAL);
1887
1888 /*
1889 * We only support triggers on devices open for write access,
1890 * but we don't need to check for that here since the driver will
1891 * verify this for us.
1892 */
1893
1894 /* Send the trigger command to the audio device. */
1895 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1896 fd, LXA_IOC_MMAP_OUTPUT, "LXA_IOC_MMAP_OUTPUT");
1897 return ((ioctl(fd, LXA_IOC_MMAP_OUTPUT, &trigger) < 0) ? -errno : 0);
1898 }
1899
1900 static int
1901 /*ARGSUSED*/
1902 ict_oss_sndctl_dsp_getoptr(int fd, struct stat *stat,
1903 int cmd, char *cmd_str, intptr_t arg)
1904 {
1905 static uint_t bytes = 0;
1906 lx_oss_count_info_t ci;
1907 lxa_frag_info_t fi;
1908 audio_info_t ai;
1909 int ptr, err;
1910
1911 assert(cmd == LX_OSS_SNDCTL_DSP_GETOPTR);
1912
1913 /* Ioctl is only supported on dsp audio devices. */
1914 if ((err = i_is_dsp_dev(fd)) != 0)
1915 return (err);
1916
1917 /* Query the current fragment size. */
1918 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1919 fd, LXA_IOC_GET_FRAG_INFO, "LXA_IOC_GET_FRAG_INFO");
1920 if (ioctl(fd, LXA_IOC_GET_FRAG_INFO, &fi) < 0)
1921 return (-errno);
1922
1923 /* Figure out how many samples have been played. */
1924 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1925 fd, AUDIO_GETINFO, "AUDIO_GETINFO");
1926 if (ioctl(fd, AUDIO_GETINFO, &ai) < 0)
1927 return (-errno);
1928 ci.bytes = ai.play.samples + ai.record.samples;
1929
1930 /*
1931 * Figure out how many fragments of audio have gone out since
1932 * the last call to this ioctl.
1933 */
1934 ci.blocks = (ci.bytes - bytes) / fi.lxa_fi_size;
1935 bytes = ci.bytes;
1936
1937 /* Figure out the current fragment offset for mmap audio output. */
1938 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1939 fd, LXA_IOC_MMAP_PTR, "LXA_IOC_MMAP_PTR");
1940 if (ioctl(fd, LXA_IOC_MMAP_PTR, &ptr) < 0) {
1941 /*
1942 * We really should return an error here, but some
1943 * application (*cough* *cough* flash) expect this
1944 * ioctl to work even if they haven't mmaped the
1945 * device.
1946 */
1947 ci.ptr = 0;
1948 } else {
1949 ci.ptr = ptr;
1950 }
1951
1952 lx_debug("\toss get output ptr result = ");
1953 lx_debug("\t\t"
1954 "bytes = 0x%x (%u), blocks = 0x%x (%u), ptr = 0x%x (%u)",
1955 ci.bytes, ci.bytes, ci.blocks, ci.blocks, ci.ptr, ci.ptr);
1956
1957 if (uucopy(&ci, (void *)arg, sizeof (ci)) != 0)
1958 return (-errno);
1959 return (0);
1960 }
1961
1962 static int
1963 /*ARGSUSED*/
1964 ict_oss_sndctl_dsp_sync(int fd, struct stat *stat,
1965 int cmd, char *cmd_str, intptr_t arg)
1966 {
1967 int amode, err;
1968
1969 assert(cmd == LX_OSS_SNDCTL_DSP_SYNC);
1970
1971 /* Ioctl is only supported on dsp audio devices. */
1972 if ((err = i_is_dsp_dev(fd)) != 0)
1973 return (err);
1974
1975 /* We need to know the access mode for the file. */
1976 if ((amode = fcntl(fd, F_GETFL)) < 0)
1977 return (-EINVAL);
1978 amode &= O_ACCMODE;
1979 assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1980
1981 /*
1982 * A sync is basically a noop for record only device.
1983 * We check for this here because on Linux a sync on a record
1984 * only device returns success immediately. But the Solaris
1985 * equivalent to a drain operation is a AUDIO_DRAIN, and if
1986 * it's issued to a record only device it will fail and return
1987 * EINVAL.
1988 */
1989 if (amode == O_RDONLY)
1990 return (0);
1991
1992 /* Drain any pending output. */
1993 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1994 fd, AUDIO_DRAIN, "AUDIO_DRAIN");
1995 return ((ioctl(fd, AUDIO_DRAIN, NULL) < 0) ? -errno : 0);
1996 }
1997
1998 /*
1999 * /dev/mixer ioctl translators and support
2000 *
2001 * There are some interesting things to take note of for supporting
2002 * /dev/mixer ioctls.
2003 *
2004 * 1) We report support for the following mixer resources:
2005 * VOLUME, PCM, MIC
2006 *
2007 * 2) We assume the following number of channels for each mixer resource:
2008 * VOLUME: 2 channels
2009 * PCM: 2 channels
2010 * MIC: 1 channel
2011 *
2012 * 3) OSS sets the gain on each channel independently but on Solaris
2013 * there is only one gain value and a balance value. So we need
2014 * to do some translation back and forth.
2015 *
2016 * 4) OSS assumes direct access to hardware but Solaris provides
2017 * virtualized audio device access (where everyone who opens /dev/audio
2018 * get a virtualized audio channel stream, all of which are merged
2019 * together by a software mixer before reaching the hardware). Hence
2020 * mapping OSS mixer resources to Solaris mixer resources takes some
2021 * work. VOLUME and Mic resources are mapped to the actual underlying
2022 * audio hardware resources. PCM resource are mapped to the virtual
2023 * audio channel output level. This mapping becomes more complicated
2024 * if there are no open audio output channels. In this case the
2025 * lx_audio device caches the PCM channels setting for us and applies
2026 * them to any new audio output channels that get opened. (This
2027 * is the reason that we don't use AUDIO_SETINFO ioctls directly
2028 * but instead the lx_audio driver custom LXA_IOC_MIXER_SET_*
2029 * and LXA_IOC_MIXER_GET_* ioctls.) For more information see
2030 * the comments in lx_audio.c.
2031 */
2032 static int
2033 i_is_mixer_dev(int fd)
2034 {
2035 int minor;
2036
2037 /*
2038 * This is a cloning device so we have to ask the driver
2039 * what kind of minor node this is.
2040 */
2041 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
2042 fd, LXA_IOC_GETMINORNUM, "LXA_IOC_GETMINORNUM");
2043 if (ioctl(fd, LXA_IOC_GETMINORNUM, &minor) < 0)
2044 return (-EINVAL);
2045 if (minor != LXA_MINORNUM_MIXER)
2046 return (-EINVAL);
2047 return (0);
2048 }
2049
2050 static int
2051 i_oss_mixer_ml_to_val(lxa_mixer_levels_t *ml, uint_t *val)
2052 {
2053 int range, val1, val2;
2054
2055 /* Deal with the other easy case, both channels have the same level. */
2056 if (ml->lxa_ml_balance == AUDIO_MID_BALANCE) {
2057 *val = LX_OSS_MIXER_ENC2(
2058 LX_OSS_S2L_GAIN(ml->lxa_ml_gain),
2059 LX_OSS_S2L_GAIN(ml->lxa_ml_gain));
2060 assert(LX_OSS_MIXER_2CH_OK(*val));
2061 return (0);
2062 }
2063
2064 /* Decode the balance/gain into two separate levels. */
2065 if (ml->lxa_ml_balance > AUDIO_MID_BALANCE) {
2066 val2 = ml->lxa_ml_gain;
2067
2068 range = AUDIO_RIGHT_BALANCE - AUDIO_MID_BALANCE;
2069 val1 = AUDIO_RIGHT_BALANCE - ml->lxa_ml_balance;
2070 val1 = (val2 * val1) / range;
2071 } else {
2072 assert(ml->lxa_ml_balance < AUDIO_MID_BALANCE);
2073 val1 = ml->lxa_ml_gain;
2074
2075 range = AUDIO_MID_BALANCE - AUDIO_LEFT_BALANCE;
2076 val2 = ml->lxa_ml_balance;
2077 val2 = (val1 * val2) / range;
2078 }
2079
2080 *val = LX_OSS_MIXER_ENC2(LX_OSS_S2L_GAIN(val1),
2081 LX_OSS_S2L_GAIN(val2));
2082 return (0);
2083 }
2084
2085 static int
2086 i_oss_mixer_val_to_ml(uint_t val, lxa_mixer_levels_t *ml_old,
2087 lxa_mixer_levels_t *ml)
2088 {
2089 int range, val1, val2;
2090
2091 if (!LX_OSS_MIXER_2CH_OK(val))
2092 return (-EINVAL);
2093
2094 val1 = LX_OSS_MIXER_DEC1(val);
2095 val2 = LX_OSS_MIXER_DEC2(val);
2096
2097 /*
2098 * Deal with the easy case.
2099 * Both channels have the same non-zero level.
2100 */
2101 if ((val1 != 0) && (val1 == val2)) {
2102 ml->lxa_ml_gain = LX_OSS_L2S_GAIN(val1);
2103 ml->lxa_ml_balance = AUDIO_MID_BALANCE;
2104 return (0);
2105 }
2106
2107 /* If both levels are zero, preserve the current balance setting. */
2108 if ((val1 == 0) && (val2 == 0)) {
2109 ml->lxa_ml_gain = 0;
2110 ml->lxa_ml_balance = ml_old->lxa_ml_balance;
2111 return (0);
2112 }
2113
2114 /*
2115 * First set the gain to match the highest channel value volume.
2116 * Then use the balance to simulate lower volume on the second
2117 * channel.
2118 */
2119 if (val1 > val2) {
2120 ml->lxa_ml_gain = LX_OSS_L2S_GAIN(val1);
2121
2122 range = AUDIO_MID_BALANCE - AUDIO_LEFT_BALANCE;
2123 ml->lxa_ml_balance = 0;
2124 ml->lxa_ml_balance += ((val2 * range) / val1);
2125 } else {
2126 assert(val1 < val2);
2127
2128 ml->lxa_ml_gain = LX_OSS_L2S_GAIN(val2);
2129
2130 range = AUDIO_RIGHT_BALANCE - AUDIO_MID_BALANCE;
2131 ml->lxa_ml_balance = AUDIO_RIGHT_BALANCE;
2132 ml->lxa_ml_balance -= ((val1 * range) / val2);
2133 }
2134
2135 return (0);
2136 }
2137
2138 static int
2139 /*ARGSUSED*/
2140 ict_oss_mixer_read_volume(int fd, struct stat *stat,
2141 int cmd, char *cmd_str, intptr_t arg)
2142 {
2143 lxa_mixer_levels_t ml;
2144 uint_t *valp = (uint_t *)arg;
2145 uint_t val;
2146 char *cmd_txt;
2147 int err, cmd_new;
2148
2149 assert((cmd == LX_OSS_SOUND_MIXER_READ_VOLUME) ||
2150 (cmd == LX_OSS_SOUND_MIXER_READ_PCM));
2151
2152 /* Ioctl is only supported on mixer audio devices. */
2153 if ((err = i_is_mixer_dev(fd)) != 0)
2154 return (err);
2155
2156 if (cmd == LX_OSS_SOUND_MIXER_READ_VOLUME) {
2157 cmd_new = LXA_IOC_MIXER_GET_VOL;
2158 cmd_txt = "LXA_IOC_MIXER_GET_VOL";
2159 }
2160 if (cmd == LX_OSS_SOUND_MIXER_READ_PCM) {
2161 cmd_new = LXA_IOC_MIXER_GET_PCM;
2162 cmd_txt = "LXA_IOC_MIXER_GET_PCM";
2163 }
2164
2165 /* Attempt to set the device output gain. */
2166 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, cmd_new, cmd_txt);
2167 if (ioctl(fd, cmd_new, &ml) < 0)
2168 return (-errno);
2169
2170 lx_debug("\tlx_audio mixer results, "
2171 "gain = 0x%x (%u), balance = 0x%x (%u)",
2172 ml.lxa_ml_gain, ml.lxa_ml_gain,
2173 ml.lxa_ml_balance, ml.lxa_ml_balance);
2174
2175 assert(LXA_MIXER_LEVELS_OK(&ml));
2176
2177 /* Translate the mixer levels struct to an OSS mixer value. */
2178 if ((err = i_oss_mixer_ml_to_val(&ml, &val)) != 0)
2179 return (err);
2180 assert(LX_OSS_MIXER_2CH_OK(val));
2181
2182 lx_debug("\toss get mixer %s result = 0x%x (%u)",
2183 (cmd == LX_OSS_SOUND_MIXER_READ_VOLUME) ? "volume" : "pcm",
2184 val, val);
2185
2186 if (uucopy(&val, valp, sizeof (val)) != 0)
2187 return (-errno);
2188 return (0);
2189 }
2190
2191 static int
2192 /*ARGSUSED*/
2193 ict_oss_mixer_write_volume(int fd, struct stat *stat,
2194 int cmd, char *cmd_str, intptr_t arg)
2195 {
2196 lxa_mixer_levels_t ml, ml_old;
2197 uint_t *valp = (uint_t *)arg;
2198 uint_t val;
2199 char *cmd_txt;
2200 int err, cmd_new;
2201
2202 assert((cmd == LX_OSS_SOUND_MIXER_WRITE_VOLUME) ||
2203 (cmd == LX_OSS_SOUND_MIXER_WRITE_PCM));
2204
2205 /* Ioctl is only supported on mixer audio devices. */
2206 if ((err = i_is_mixer_dev(fd)) != 0)
2207 return (err);
2208
2209 if (uucopy(valp, &val, sizeof (val)) != 0)
2210 return (-errno);
2211
2212 if (cmd == LX_OSS_SOUND_MIXER_WRITE_VOLUME) {
2213 cmd_new = LXA_IOC_MIXER_SET_VOL;
2214 cmd_txt = "LXA_IOC_MIXER_SET_VOL";
2215
2216 /* Attempt to get the device output gain. */
2217 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd,
2218 LXA_IOC_MIXER_GET_VOL, "LXA_IOC_MIXER_GET_VOL");
2219 if (ioctl(fd, LXA_IOC_MIXER_GET_VOL, &ml_old) < 0)
2220 return (-errno);
2221 }
2222
2223 if (cmd == LX_OSS_SOUND_MIXER_WRITE_PCM) {
2224 cmd_new = LXA_IOC_MIXER_SET_PCM;
2225 cmd_txt = "LXA_IOC_MIXER_SET_PCM";
2226
2227 /* Attempt to get the device output gain. */
2228 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd,
2229 LXA_IOC_MIXER_GET_PCM, "LXA_IOC_MIXER_GET_PCM");
2230 if (ioctl(fd, LXA_IOC_MIXER_GET_PCM, &ml_old) < 0)
2231 return (-errno);
2232 }
2233
2234 lx_debug("\toss set mixer %s request = 0x%x (%u)",
2235 (cmd == LX_OSS_SOUND_MIXER_WRITE_VOLUME) ? "volume" : "pcm",
2236 val, val);
2237
2238 /* Translate an OSS mixer value to mixer levels. */
2239 if ((err = i_oss_mixer_val_to_ml(val, &ml_old, &ml)) != 0)
2240 return (err);
2241 assert(LXA_MIXER_LEVELS_OK(&ml));
2242
2243 lx_debug("\tlx_audio mixer request, "
2244 "gain = 0x%x (%u), balance = 0x%x (%u)",
2245 ml.lxa_ml_gain, ml.lxa_ml_gain,
2246 ml.lxa_ml_balance, ml.lxa_ml_balance);
2247
2248 /* Attempt to set the device output gain. */
2249 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, cmd_new, cmd_txt);
2250 if (ioctl(fd, cmd_new, &ml) < 0)
2251 return (-errno);
2252
2253 return (0);
2254 }
2255
2256 static int
2257 /*ARGSUSED*/
2258 ict_oss_mixer_read_mic(int fd, struct stat *stat,
2259 int cmd, char *cmd_str, intptr_t arg)
2260 {
2261 lxa_mixer_levels_t ml;
2262 uint_t *valp = (uint_t *)arg;
2263 uint_t val;
2264 int err;
2265
2266 assert((cmd == LX_OSS_SOUND_MIXER_READ_MIC) ||
2267 (cmd == LX_OSS_SOUND_MIXER_READ_IGAIN));
2268
2269 /* Ioctl is only supported on mixer audio devices. */
2270 if ((err = i_is_mixer_dev(fd)) != 0)
2271 return (err);
2272
2273 /* Attempt to get the device input gain. */
2274 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
2275 fd, LXA_IOC_MIXER_GET_MIC, "LXA_IOC_MIXER_GET_MIC");
2276 if (ioctl(fd, LXA_IOC_MIXER_GET_MIC, &ml) < 0)
2277 return (-errno);
2278
2279 /* Report the mixer as having two channels. */
2280 val = LX_OSS_MIXER_ENC2(
2281 LX_OSS_S2L_GAIN(ml.lxa_ml_gain),
2282 LX_OSS_S2L_GAIN(ml.lxa_ml_gain));
2283
2284 if (cmd == LX_OSS_SOUND_MIXER_READ_MIC)
2285 lx_debug("\toss get mixer mic result = 0x%x (%u)", val, val);
2286 if (cmd == LX_OSS_SOUND_MIXER_READ_IGAIN)
2287 lx_debug("\toss get mixer igain result = 0x%x (%u)", val, val);
2288
2289 if (uucopy(&val, valp, sizeof (val)) != 0)
2290 return (-errno);
2291 return (0);
2292 }
2293
2294 static int
2295 /*ARGSUSED*/
2296 ict_oss_mixer_write_mic(int fd, struct stat *stat,
2297 int cmd, char *cmd_str, intptr_t arg)
2298 {
2299 lxa_mixer_levels_t ml;
2300 uint_t *valp = (uint_t *)arg;
2301 uint_t val;
2302 int err;
2303
2304 assert((cmd == LX_OSS_SOUND_MIXER_WRITE_MIC) ||
2305 (cmd == LX_OSS_SOUND_MIXER_WRITE_IGAIN));
2306
2307 /* Ioctl is only supported on mixer audio devices. */
2308 if ((err = i_is_mixer_dev(fd)) != 0)
2309 return (err);
2310
2311 if (uucopy(valp, &val, sizeof (val)) != 0)
2312 return (-errno);
2313
2314 if (cmd == LX_OSS_SOUND_MIXER_WRITE_MIC)
2315 lx_debug("\toss set mixer mic request = 0x%x (%u)", val, val);
2316 if (cmd == LX_OSS_SOUND_MIXER_WRITE_IGAIN)
2317 lx_debug("\toss set mixer igain request = 0x%x (%u)", val, val);
2318
2319 /* The mic only supports one channel. */
2320 val = LX_OSS_MIXER_DEC1(val);
2321
2322 ml.lxa_ml_balance = AUDIO_MID_BALANCE;
2323 ml.lxa_ml_gain = LX_OSS_L2S_GAIN(val);
2324
2325 /* Attempt to set the device input gain. */
2326 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
2327 fd, LXA_IOC_MIXER_SET_MIC, "LXA_IOC_MIXER_SET_MIC");
2328 if (ioctl(fd, LXA_IOC_MIXER_SET_MIC, &ml) < 0)
2329 return (-errno);
2330
2331 return (0);
2332 }
2333
2334 static int
2335 /*ARGSUSED*/
2336 ict_oss_mixer_read_devs(int fd, struct stat *stat,
2337 int cmd, char *cmd_str, intptr_t arg)
2338 {
2339 uint_t *resultp = (uint_t *)arg;
2340 uint_t result = 0;
2341 int err;
2342
2343 if (cmd == LX_OSS_SOUND_MIXER_READ_DEVMASK) {
2344 /* Bitmap of all the mixer channels we supposedly support. */
2345 result = ((1 << LX_OSS_SM_PCM) |
2346 (1 << LX_OSS_SM_MIC) |
2347 (1 << LX_OSS_SM_VOLUME));
2348 }
2349 if (cmd == LX_OSS_SOUND_MIXER_READ_STEREODEVS) {
2350 /* Bitmap of the stereo mixer channels we supposedly support. */
2351 result = ((1 << LX_OSS_SM_PCM) |
2352 (1 << LX_OSS_SM_VOLUME));
2353 }
2354 if ((cmd == LX_OSS_SOUND_MIXER_READ_RECMASK) ||
2355 (cmd == LX_OSS_SOUND_MIXER_READ_RECSRC)) {
2356 /* Bitmap of the mixer input channels we supposedly support. */
2357 result = (1 << LX_OSS_SM_MIC);
2358 }
2359 assert(result != 0);
2360
2361 /* Ioctl is only supported on mixer audio devices. */
2362 if ((err = i_is_mixer_dev(fd)) != 0)
2363 return (err);
2364
2365 if (uucopy(&result, resultp, sizeof (result)) != 0)
2366 return (-errno);
2367
2368 return (0);
2369 }
2370
2371 /*
2372 * Audio ioctl conversion support structures.
2373 */
2374 static oss_fmt_translator_t oft_table[] = {
2375 { LX_OSS_AFMT_MU_LAW, AUDIO_ENCODING_ULAW, 8 },
2376 { LX_OSS_AFMT_A_LAW, AUDIO_ENCODING_ALAW, 8 },
2377 { LX_OSS_AFMT_S8, AUDIO_ENCODING_LINEAR, 8 },
2378 { LX_OSS_AFMT_U8, AUDIO_ENCODING_LINEAR8, 8 },
2379 { LX_OSS_AFMT_S16_NE, AUDIO_ENCODING_LINEAR, 16 },
2380 { 0, 0, 0 }
2381 };
2382
2383 /*
2384 * Ioctl translator definitions.
2385 */
2386
2387 /*
2388 * Defines to help with creating ioctl translators.
2389 *
2390 * IOC_CMD_TRANSLATOR_NONE - Ioctl has the same semantics and argument
2391 * values on Solaris and Linux but may have different command values.
2392 * (Macro assumes the symbolic Linux name assigned to the ioctl command
2393 * value is the same as the Solaris symbol but pre-pended with an "LX_")
2394 *
2395 * IOC_CMD_TRANSLATOR_PASS - Ioctl is a Linux specific ioctl and should
2396 * be passed through unmodified.
2397 *
2398 * IOC_CMD_TRANSLATOR_FILTER - Ioctl has the same command name on
2399 * Solaris and Linux and needs a translation function that is common to
2400 * more than one ioctl. (Macro assumes the symbolic Linux name assigned
2401 * to the ioctl command value is the same as the Solaris symbol but
2402 * pre-pended with an "LX_")
2403 *
2404 * IOC_CMD_TRANSLATOR_CUSTOM - Ioctl needs special handling via a
2405 * translation function.
2406 */
2407 #define IOC_CMD_TRANSLATOR_NONE(ioc_cmd_sym) \
2408 { (int)LX_##ioc_cmd_sym, "LX_" #ioc_cmd_sym, \
2409 ioc_cmd_sym, #ioc_cmd_sym, ict_pass },
2410
2411 #define IOC_CMD_TRANSLATOR_PASS(ioc_cmd_sym) \
2412 { (int)ioc_cmd_sym, #ioc_cmd_sym, \
2413 ioc_cmd_sym, #ioc_cmd_sym, ict_pass },
2414
2415 #define IOC_CMD_TRANSLATOR_FILTER(ioc_cmd_sym, ioct_handler) \
2416 { (int)LX_##ioc_cmd_sym, "LX_" #ioc_cmd_sym, \
2417 ioc_cmd_sym, #ioc_cmd_sym, ioct_handler },
2418
2419 #define IOC_CMD_TRANSLATOR_CUSTOM(ioc_cmd_sym, ioct_handler) \
2420 { (int)ioc_cmd_sym, #ioc_cmd_sym, \
2421 (int)ioc_cmd_sym, #ioc_cmd_sym, ioct_handler },
2422
2423 #define IOC_CMD_TRANSLATOR_END \
2424 { 0, NULL, 0, NULL, NULL }
2425
2426 /* All files will need to support these ioctls. */
2427 #define IOC_CMD_TRANSLATORS_ALL \
2428 IOC_CMD_TRANSLATOR_NONE(FIONREAD) \
2429 IOC_CMD_TRANSLATOR_NONE(FIONBIO)
2430
2431 /* Any files supporting streams semantics will need these ioctls. */
2432 #define IOC_CMD_TRANSLATORS_STREAMS \
2433 IOC_CMD_TRANSLATOR_NONE(TCXONC) \
2434 IOC_CMD_TRANSLATOR_NONE(TCFLSH) \
2435 IOC_CMD_TRANSLATOR_NONE(TIOCEXCL) \
2436 IOC_CMD_TRANSLATOR_NONE(TIOCNXCL) \
2437 IOC_CMD_TRANSLATOR_NONE(TIOCSPGRP) \
2438 IOC_CMD_TRANSLATOR_NONE(TIOCSTI) \
2439 IOC_CMD_TRANSLATOR_NONE(TIOCSWINSZ) \
2440 IOC_CMD_TRANSLATOR_NONE(TIOCMBIS) \
2441 IOC_CMD_TRANSLATOR_NONE(TIOCMBIC) \
2442 IOC_CMD_TRANSLATOR_NONE(TIOCMSET) \
2443 IOC_CMD_TRANSLATOR_NONE(TIOCSETD) \
2444 IOC_CMD_TRANSLATOR_NONE(FIOASYNC) \
2445 IOC_CMD_TRANSLATOR_NONE(FIOSETOWN) \
2446 IOC_CMD_TRANSLATOR_NONE(TCSBRK) \
2447 \
2448 IOC_CMD_TRANSLATOR_FILTER(TCSETS, ict_tcsets) \
2449 IOC_CMD_TRANSLATOR_FILTER(TCSETSW, ict_tcsets) \
2450 IOC_CMD_TRANSLATOR_FILTER(TCSETSF, ict_tcsets) \
2451 IOC_CMD_TRANSLATOR_FILTER(TCSETA, ict_tcseta) \
2452 IOC_CMD_TRANSLATOR_FILTER(TCSETAW, ict_tcseta) \
2453 IOC_CMD_TRANSLATOR_FILTER(TCSETAF, ict_tcseta) \
2454 \
2455 IOC_CMD_TRANSLATOR_CUSTOM(LX_TCSBRKP, ict_tcsbrkp)
2456
2457
2458 /*
2459 * Translators for non-device files.
2460 */
2461 static ioc_cmd_translator_t ioc_translators_file[] = {
2462 IOC_CMD_TRANSLATORS_ALL
2463 IOC_CMD_TRANSLATOR_END
2464 };
2465
2466 static ioc_cmd_translator_t ioc_translators_fifo[] = {
2467 IOC_CMD_TRANSLATORS_ALL
2468 IOC_CMD_TRANSLATORS_STREAMS
2469 IOC_CMD_TRANSLATOR_END
2470 };
2471
2472 static ioc_cmd_translator_t ioc_translators_sock[] = {
2473 IOC_CMD_TRANSLATORS_ALL
2474
2475 IOC_CMD_TRANSLATOR_NONE(FIOASYNC)
2476 IOC_CMD_TRANSLATOR_NONE(FIOGETOWN)
2477 IOC_CMD_TRANSLATOR_NONE(FIOSETOWN)
2478 IOC_CMD_TRANSLATOR_NONE(SIOCSPGRP)
2479 IOC_CMD_TRANSLATOR_NONE(SIOCGPGRP)
2480
2481 IOC_CMD_TRANSLATOR_FILTER(SIOCATMARK, ict_sioifoob)
2482
2483 IOC_CMD_TRANSLATOR_FILTER(SIOCGIFFLAGS, ict_sioifreq)
2484 IOC_CMD_TRANSLATOR_FILTER(SIOCSIFFLAGS, ict_sioifreq)
2485 IOC_CMD_TRANSLATOR_FILTER(SIOCGIFADDR, ict_sioifreq)
2486 IOC_CMD_TRANSLATOR_FILTER(SIOCSIFADDR, ict_sioifreq)
2487 IOC_CMD_TRANSLATOR_FILTER(SIOCGIFDSTADDR, ict_sioifreq)
2488 IOC_CMD_TRANSLATOR_FILTER(SIOCSIFDSTADDR, ict_sioifreq)
2489 IOC_CMD_TRANSLATOR_FILTER(SIOCGIFBRDADDR, ict_sioifreq)
2490 IOC_CMD_TRANSLATOR_FILTER(SIOCSIFBRDADDR, ict_sioifreq)
2491 IOC_CMD_TRANSLATOR_FILTER(SIOCGIFNETMASK, ict_sioifreq)
2492 IOC_CMD_TRANSLATOR_FILTER(SIOCSIFNETMASK, ict_sioifreq)
2493 IOC_CMD_TRANSLATOR_FILTER(SIOCGIFMETRIC, ict_sioifreq)
2494 IOC_CMD_TRANSLATOR_FILTER(SIOCSIFMETRIC, ict_sioifreq)
2495 IOC_CMD_TRANSLATOR_FILTER(SIOCGIFMTU, ict_sioifreq)
2496 IOC_CMD_TRANSLATOR_FILTER(SIOCSIFMTU, ict_sioifreq)
2497
2498 IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCGIFCONF, ict_siocgifconf)
2499 IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCGIFHWADDR, ict_siocifhwaddr)
2500 IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCSIFHWADDR, ict_siocifhwaddr)
2501
2502 IOC_CMD_TRANSLATOR_END
2503 };
2504
2505 /*
2506 * Translators for devices.
2507 */
2508 static ioc_cmd_translator_t ioc_cmd_translators_ptm[] = {
2509 IOC_CMD_TRANSLATORS_ALL
2510 IOC_CMD_TRANSLATORS_STREAMS
2511
2512 IOC_CMD_TRANSLATOR_NONE(TIOCPKT)
2513
2514 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGPGRP, ict_tiocgpgrp)
2515 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCSPTLCK, ict_sptlock)
2516 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGPTN, ict_gptn)
2517 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGWINSZ, ict_tiocgwinsz)
2518 IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETS, ict_tcgets_emulate)
2519
2520 IOC_CMD_TRANSLATOR_END
2521 };
2522 static ioc_dev_translator_t ioc_translator_ptm = {
2523 LX_PTM_DRV, /* idt_driver */
2524 0, /* idt_major */
2525 ioc_cmd_translators_ptm
2526 };
2527
2528 static ioc_cmd_translator_t ioc_cmd_translators_pts[] = {
2529 IOC_CMD_TRANSLATORS_ALL
2530 IOC_CMD_TRANSLATORS_STREAMS
2531
2532 IOC_CMD_TRANSLATOR_NONE(TIOCGETD)
2533 IOC_CMD_TRANSLATOR_NONE(TIOCGSID)
2534 IOC_CMD_TRANSLATOR_NONE(TIOCNOTTY)
2535
2536 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGPGRP, ict_tiocgpgrp)
2537 IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETS, ict_tcgets_native)
2538 IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETA, ict_tcgeta)
2539 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGWINSZ, ict_tiocgwinsz)
2540 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCSCTTY, ict_tiocsctty)
2541
2542 IOC_CMD_TRANSLATOR_END
2543 };
2544 static ioc_dev_translator_t ioc_translator_pts = {
2545 "pts", /* idt_driver */
2546 0, /* idt_major */
2547 ioc_cmd_translators_pts
2548 };
2549
2550 static ioc_dev_translator_t ioc_translator_sy = {
2551 "sy", /* idt_driver */
2552 0, /* idt_major */
2553
2554 /*
2555 * /dev/tty (which is implemented via the "sy" driver) is basically
2556 * a layered driver that passes on requests to the ctty for the
2557 * current process. Since ctty's are currently always implemented
2558 * via the pts driver, we should make sure to support all the
2559 * same ioctls on the sy driver as we do on the pts driver.
2560 */
2561 ioc_cmd_translators_pts
2562 };
2563
2564 static ioc_cmd_translator_t ioc_cmd_translators_zcons[] = {
2565 IOC_CMD_TRANSLATORS_ALL
2566 IOC_CMD_TRANSLATORS_STREAMS
2567
2568 IOC_CMD_TRANSLATOR_NONE(TIOCNOTTY)
2569
2570 IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETS, ict_tcgets_native)
2571 IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETA, ict_tcgeta)
2572 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGWINSZ, ict_tiocgwinsz)
2573 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCSCTTY, ict_tiocsctty)
2574
2575 IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCLINUX, ict_einval)
2576
2577 IOC_CMD_TRANSLATOR_END
2578 };
2579 static ioc_dev_translator_t ioc_translator_zcons = {
2580 "zcons", /* idt_driver */
2581 0, /* idt_major */
2582 ioc_cmd_translators_zcons
2583 };
2584
2585 static ioc_cmd_translator_t ioc_cmd_translators_lx_audio[] = {
2586 IOC_CMD_TRANSLATORS_ALL
2587
2588 /* /dev/dsp ioctls */
2589 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_RESET,
2590 ict_oss_sndctl_dsp_reset)
2591 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETFMTS,
2592 ict_oss_sndctl_dsp_getfmts)
2593 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SETFMTS,
2594 ict_oss_sndctl_dsp_setfmts)
2595 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_CHANNELS,
2596 ict_oss_sndctl_dsp_channels)
2597 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_STEREO,
2598 ict_oss_sndctl_dsp_channels)
2599 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SPEED,
2600 ict_oss_sndctl_dsp_speed)
2601 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETBLKSIZE,
2602 ict_oss_sndctl_dsp_getblksize)
2603 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SYNC,
2604 ict_oss_sndctl_dsp_sync)
2605 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SETFRAGMENT,
2606 ict_oss_sndctl_dsp_setfragment)
2607 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETOSPACE,
2608 ict_oss_sndctl_dsp_getspace)
2609 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETCAPS,
2610 ict_oss_sndctl_dsp_getcaps)
2611 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SETTRIGGER,
2612 ict_oss_sndctl_dsp_settrigger)
2613 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETOPTR,
2614 ict_oss_sndctl_dsp_getoptr)
2615 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETISPACE,
2616 ict_oss_sndctl_dsp_getspace)
2617
2618 /* /dev/mixer level ioctls */
2619 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_VOLUME,
2620 ict_oss_mixer_read_volume)
2621 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_PCM,
2622 ict_oss_mixer_read_volume)
2623 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_MIC,
2624 ict_oss_mixer_read_mic)
2625 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_IGAIN,
2626 ict_oss_mixer_read_mic)
2627 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_WRITE_VOLUME,
2628 ict_oss_mixer_write_volume)
2629 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_WRITE_PCM,
2630 ict_oss_mixer_write_volume)
2631 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_WRITE_MIC,
2632 ict_oss_mixer_write_mic)
2633 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_WRITE_IGAIN,
2634 ict_oss_mixer_write_mic)
2635
2636 /* /dev/mixer capability ioctls */
2637 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_STEREODEVS,
2638 ict_oss_mixer_read_devs)
2639 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_DEVMASK,
2640 ict_oss_mixer_read_devs)
2641 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_RECMASK,
2642 ict_oss_mixer_read_devs)
2643 IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_RECSRC,
2644 ict_oss_mixer_read_devs)
2645
2646 IOC_CMD_TRANSLATOR_END
2647 };
2648 static ioc_dev_translator_t ioc_translator_lx_audio = {
2649 "lx_audio", /* idt_driver */
2650 0, /* idt_major */
2651 ioc_cmd_translators_lx_audio
2652 };
2653
2654 /*
2655 * An array of all the device translators.
2656 */
2657 static ioc_dev_translator_t *ioc_translators_dev[] = {
2658 &ioc_translator_lx_audio,
2659 &ioc_translator_ptm,
2660 &ioc_translator_pts,
2661 &ioc_translator_sy,
2662 &ioc_translator_zcons,
2663 NULL
2664 };
2665
2666 /*
2667 * Translators for filesystems.
2668 */
2669 static ioc_cmd_translator_t ioc_cmd_translators_autofs[] = {
2670 IOC_CMD_TRANSLATOR_PASS(LX_AUTOFS_IOC_READY)
2671 IOC_CMD_TRANSLATOR_PASS(LX_AUTOFS_IOC_FAIL)
2672 IOC_CMD_TRANSLATOR_PASS(LX_AUTOFS_IOC_CATATONIC)
2673 IOC_CMD_TRANSLATOR_END
2674 };
2675
2676 static ioc_fs_translator_t ioc_translator_autofs = {
2677 LX_AUTOFS_NAME, /* ift_filesystem */
2678 ioc_cmd_translators_autofs
2679 };
2680
2681 /*
2682 * An array of all the filesystem translators.
2683 */
2684 static ioc_fs_translator_t *ioc_translators_fs[] = {
2685 &ioc_translator_autofs,
2686 NULL
2687 };
2688
2689 /*
2690 * Ioctl error translator definitions.
2691 */
2692 #define IOC_ERRNO_TRANSLATOR(iet_cmd_sym, iet_errno) \
2693 { (int)LX_##iet_cmd_sym, "LX_" #iet_cmd_sym, iet_errno },
2694
2695 #define IOC_ERRNO_TRANSLATOR_END \
2696 { 0, NULL, 0 }
2697
2698 static ioc_errno_translator_t ioc_translators_errno[] = {
2699 IOC_ERRNO_TRANSLATOR(TCGETS, ENOTTY)
2700 IOC_ERRNO_TRANSLATOR(TCSETS, ENOTTY)
2701 IOC_ERRNO_TRANSLATOR(TCSBRK, ENOTTY)
2702 IOC_ERRNO_TRANSLATOR(TCXONC, ENOTTY)
2703 IOC_ERRNO_TRANSLATOR(TCFLSH, ENOTTY)
2704 IOC_ERRNO_TRANSLATOR(TIOCGPGRP, ENOTTY)
2705 IOC_ERRNO_TRANSLATOR(TIOCSPGRP, ENOTTY)
2706 IOC_ERRNO_TRANSLATOR(TIOCGWINSZ, ENOTTY)
2707 IOC_ERRNO_TRANSLATOR_END
2708 };
2709
2710 int
2711 lx_vhangup(void)
2712 {
2713 if (geteuid() != 0)
2714 return (-EPERM);
2715
2716 vhangup();
2717
2718 return (0);
2719 }