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 }