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 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1988 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 #include "lint.h"
  31 #include <sys/mkdev.h>
  32 #include <limits.h>
  33 #include <stdarg.h>
  34 #include <unistd.h>
  35 #include <strings.h>
  36 #include <errno.h>
  37 #include <sys/stat.h>
  38 #include <sys/fcntl.h>
  39 #include <sys/stropts.h>
  40 #include <sys/stream.h>
  41 #include <sys/ptms.h>
  42 #include <sys/syscall.h>
  43 #include "libc.h"
  44 
  45 static int xpg4_fixup(int fd);
  46 static void push_module(int fd);
  47 static int isptsfd(int fd);
  48 static void itoa(int i, char *ptr);
  49 
  50 int
  51 __openat(int dfd, const char *path, int oflag, mode_t mode)
  52 {
  53         int fd = syscall(SYS_openat, dfd, path, oflag, mode);
  54         return (xpg4_fixup(fd));
  55 }
  56 
  57 int
  58 __open(const char *path, int oflag, mode_t mode)
  59 {
  60 #if defined(_RETAIN_OLD_SYSCALLS)
  61         int fd = syscall(SYS_open, path, oflag, mode);
  62         return (xpg4_fixup(fd));
  63 #else
  64         return (__openat(AT_FDCWD, path, oflag, mode));
  65 #endif
  66 }
  67 
  68 #if !defined(_LP64)
  69 
  70 int
  71 __openat64(int dfd, const char *path, int oflag, mode_t mode)
  72 {
  73         int fd = syscall(SYS_openat64, dfd, path, oflag, mode);
  74         return (xpg4_fixup(fd));
  75 }
  76 
  77 int
  78 __open64(const char *path, int oflag, mode_t mode)
  79 {
  80 #if defined(_RETAIN_OLD_SYSCALLS)
  81         int fd = syscall(SYS_open64, path, oflag, mode);
  82         return (xpg4_fixup(fd));
  83 #else
  84         return (__openat64(AT_FDCWD, path, oflag, mode));
  85 #endif
  86 }
  87 
  88 #endif  /* !_LP64 */
  89 
  90 /*
  91  * XPG4v2 requires that open of a slave pseudo terminal device
  92  * provides the process with an interface that is identical to
  93  * the terminal interface. For a more detailed discussion,
  94  * see bugid 4025044.
  95  */
  96 static int
  97 xpg4_fixup(int fd)
  98 {
  99         if (libc__xpg4 != 0 && fd >= 0 && isptsfd(fd))
 100                 push_module(fd);
 101         return (fd);
 102 }
 103 
 104 /*
 105  * Check if the file matches an entry in the /dev/pts directory.
 106  * Be careful to preserve errno.
 107  */
 108 static int
 109 isptsfd(int fd)
 110 {
 111         char buf[TTYNAME_MAX];
 112         char *str1 = buf;
 113         const char *str2 = "/dev/pts/";
 114         struct stat64 fsb, stb;
 115         int oerrno = errno;
 116         int rval = 0;
 117 
 118         if (fstat64(fd, &fsb) == 0 && S_ISCHR(fsb.st_mode)) {
 119                 /*
 120                  * Do this without strcpy() or strlen(),
 121                  * to avoid invoking the dynamic linker.
 122                  */
 123                 while (*str2 != '\0')
 124                         *str1++ = *str2++;
 125                 /*
 126                  * Inline version of minor(dev), to avoid the dynamic linker.
 127                  */
 128                 itoa(fsb.st_rdev & MAXMIN, str1);
 129                 if (stat64(buf, &stb) == 0)
 130                         rval = (stb.st_rdev == fsb.st_rdev);
 131         }
 132         errno = oerrno;
 133         return (rval);
 134 }
 135 
 136 /*
 137  * Converts a number to a string (null terminated).
 138  */
 139 static void
 140 itoa(int i, char *ptr)
 141 {
 142         int dig = 0;
 143         int tempi;
 144 
 145         tempi = i;
 146         do {
 147                 dig++;
 148                 tempi /= 10;
 149         } while (tempi);
 150 
 151         ptr += dig;
 152         *ptr = '\0';
 153         while (--dig >= 0) {
 154                 *(--ptr) = i % 10 + '0';
 155                 i /= 10;
 156         }
 157 }
 158 
 159 /*
 160  * Push modules to provide tty semantics
 161  */
 162 static void
 163 push_module(int fd)
 164 {
 165         struct strioctl istr;
 166         int oerrno = errno;
 167 
 168         istr.ic_cmd = PTSSTTY;
 169         istr.ic_len = 0;
 170         istr.ic_timout = 0;
 171         istr.ic_dp = NULL;
 172         if (ioctl(fd, I_STR, &istr) != -1) {
 173                 (void) ioctl(fd, __I_PUSH_NOCTTY, "ptem");
 174                 (void) ioctl(fd, __I_PUSH_NOCTTY, "ldterm");
 175                 (void) ioctl(fd, __I_PUSH_NOCTTY, "ttcompat");
 176                 istr.ic_cmd = PTSSTTY;
 177                 istr.ic_len = 0;
 178                 istr.ic_timout = 0;
 179                 istr.ic_dp = NULL;
 180                 (void) ioctl(fd, I_STR, &istr);
 181         }
 182         errno = oerrno;
 183 }